]> git.saurik.com Git - apple/xnu.git/blame - libkern/c++/OSKext.cpp
xnu-7195.101.1.tar.gz
[apple/xnu.git] / libkern / c++ / OSKext.cpp
CommitLineData
b0d623f7 1/*
39037602 2 * Copyright (c) 2008-2016 Apple Inc. All rights reserved.
b0d623f7
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
b0d623f7
A
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.
0a7de745 14 *
b0d623f7
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
b0d623f7
A
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.
0a7de745 25 *
b0d623f7
A
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
f427ee49
A
29#define IOKIT_ENABLE_SHARED_PTR
30
b0d623f7 31extern "C" {
39037602 32#include <string.h>
b0d623f7
A
33#include <kern/clock.h>
34#include <kern/host.h>
35#include <kern/kext_alloc.h>
39037602 36#include <firehose/tracepoint_private.h>
813fb2f6 37#include <firehose/chunk_private.h>
39037602 38#include <os/firehose_buffer_private.h>
3e170ce0 39#include <vm/vm_kern.h>
f427ee49 40#include <vm/vm_map.h>
b0d623f7
A
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>
6d2010ae 49#include <mach/host_special_ports.h>
b0d623f7 50#include <mach/mach_vm.h>
6d2010ae 51#include <mach/mach_time.h>
b0d623f7 52#include <sys/sysctl.h>
6d2010ae 53#include <uuid/uuid.h>
6d2010ae 54#include <sys/random.h>
f427ee49 55#include <pexpert/pexpert.h>
39236c6e 56
3e170ce0
A
57#include <sys/pgo.h>
58
39236c6e
A
59#if CONFIG_MACF
60#include <sys/kauth.h>
61#include <security/mac_framework.h>
62#endif
f427ee49
A
63
64#if CONFIG_CSR
65#include <sys/csr.h>
66#include <sys/stat.h>
67#include <sys/vnode.h>
68#endif /* CONFIG_CSR */
b0d623f7
A
69};
70
f427ee49
A
71#include <os/cpp_util.h>
72
b0d623f7
A
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>
f427ee49 81#include <IOKit/IOUserServer.h>
b0d623f7 82
6d2010ae 83#include <IOKit/IOStatisticsPrivate.h>
3e170ce0 84#include <IOKit/IOBSD.h>
f427ee49 85#include <IOKit/IOPlatformExpert.h>
6d2010ae 86
5ba3f43e
A
87#include <san/kasan.h>
88
b0d623f7
A
89#if PRAGMA_MARK
90#pragma mark External & Internal Function Protos
91#endif
92/*********************************************************************
93*********************************************************************/
94extern "C" {
b0d623f7
A
95extern int IODTGetLoaderInfo(const char * key, void ** infoAddr, int * infoSize);
96extern void IODTFreeLoaderInfo(const char * key, void * infoAddr, int infoSize);
b0d623f7
A
97
98extern ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va); /* osfmk/machine/pmap.h */
d9a64523 99extern int dtrace_keep_kernel_symbols(void);
f427ee49
A
100
101#if defined(__x86_64__) || defined(__i386__)
102extern kern_return_t i386_slide_individual_kext(kernel_mach_header_t *mh, uintptr_t slide);
103extern kern_return_t i386_slide_kext_collection_mh_addrs(kernel_mach_header_t *mh, uintptr_t slide, bool adjust_mach_headers);
104extern void *ubc_getobject_from_filename(const char *filename, struct vnode **, off_t *file_size);
105static void *allocate_kcfileset_map_entry_list(void);
106static void add_kcfileset_map_entry(void *map_entry_list, vm_map_offset_t start, vm_map_offset_t size);
107static void deallocate_kcfileset_map_entry_list_and_unmap_entries(void *map_entry_list, boolean_t unmap_entries, bool pageable);
108int vnode_put(struct vnode *vp);
109kern_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);
111kern_return_t vm_unmap_kcfileset_segment(vm_map_offset_t *start, vm_map_offset_t size);
112void * ubc_getobject(struct vnode *vp, __unused int flags);
113#endif //(__x86_64__) || defined(__i386__)
b0d623f7
A
114}
115
d9a64523
A
116extern unsigned long gVirtBase;
117extern unsigned long gPhysBase;
f427ee49
A
118extern vm_map_t g_kext_map;
119
120bool pageableKCloaded = false;
121bool auxKCloaded = false;
122bool resetAuxKCSegmentOnUnload = false;
123
124extern boolean_t pageablekc_uuid_valid;
125extern uuid_t pageablekc_uuid;
126extern uuid_string_t pageablekc_uuid_string;
127
128extern boolean_t auxkc_uuid_valid;
129extern uuid_t auxkc_uuid;
130extern uuid_string_t auxkc_uuid_string;
d9a64523 131
b0d623f7 132static OSReturn _OSKextCreateRequest(
0a7de745 133 const char * predicate,
f427ee49 134 OSSharedPtr<OSDictionary> & requestP);
b0d623f7
A
135static OSString * _OSKextGetRequestPredicate(OSDictionary * requestDict);
136static OSObject * _OSKextGetRequestArgument(
0a7de745
A
137 OSDictionary * requestDict,
138 const char * argName);
b0d623f7 139static bool _OSKextSetRequestArgument(
0a7de745
A
140 OSDictionary * requestDict,
141 const char * argName,
142 OSObject * value);
b0d623f7 143static void * _OSKextExtractPointer(OSData * wrapper);
f427ee49 144static OSKextRequestResourceCallback _OSKextExtractCallbackPointer(OSData * wrapper);
b0d623f7 145static OSReturn _OSDictionarySetCStringValue(
0a7de745
A
146 OSDictionary * dict,
147 const char * key,
148 const char * value);
316670eb 149static bool _OSKextInUnloadedPrelinkedKexts(const OSSymbol * theBundleID);
f427ee49
A
150#if CONFIG_KXLD
151static bool _OSKextInPrelinkRebuildWindow(void);
152#endif
0a7de745 153
6d2010ae
A
154// We really should add containsObject() & containsCString to OSCollection & subclasses.
155// So few pad slots, though....
156static bool _OSArrayContainsCString(OSArray * array, const char * cString);
cb323159 157static void OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code);
6d2010ae 158
316670eb
A
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
5ba3f43e
A
168#elif __arm__ || __arm64__
169#define VM_MAPPED_KEXTS 0
170#define KASLR_KEXT_DEBUG 0
316670eb
A
171#else
172#error Unsupported architecture
173#endif
b0d623f7
A
174
175#if PRAGMA_MARK
176#pragma mark Constants & Macros
177#endif
178/*********************************************************************
179* Constants & Macros
180*********************************************************************/
181
fe8ab488 182/* Use this number to create containers.
b0d623f7 183 */
fe8ab488 184#define kOSKextTypicalLoadCount (150)
b0d623f7
A
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
316670eb
A
211#define REBUILD_MAX_TIME (60 * 5) // 5 minutes
212#define MINIMUM_WAKEUP_SECONDS (30)
213
b0d623f7
A
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
39037602
A
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
b0d623f7
A
240#if PRAGMA_MARK
241#pragma mark Typedefs
242#endif
243/*********************************************************************
244* Typedefs
245*********************************************************************/
246
39037602
A
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*********************************************************************/
254typedef struct osLogDataHeader {
0a7de745
A
255 uint32_t version;
256 uint32_t sect_count;
257 struct {
258 uint32_t sect_offset;
259 uint32_t sect_size;
260 } sections[0];
39037602
A
261} osLogDataHeaderRef;
262
b0d623f7
A
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*********************************************************************/
272typedef struct MkextEntryRef {
0a7de745
A
273 mkext_basic_header * mkext; // beginning of whole mkext file
274 void * fileinfo;// mkext2_file_entry or equiv; see mkext.h
b0d623f7
A
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
284static bool sPrelinkBoot = false;
285static bool sSafeBoot = false;
6d2010ae 286static bool sKeepSymbols = false;
f427ee49
A
287static bool sPanicOnKCMismatch = false;
288static bool sOSKextWasResetAfterUserspaceReboot = false;
b0d623f7 289
6d2010ae 290/*********************************************************************
0a7de745
A
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 */
b0d623f7
A
309static IORecursiveLock * sKextLock = NULL;
310
f427ee49
A
311static OSSharedPtr<OSDictionary> sKextsByID;
312static OSSharedPtr<OSDictionary> sExcludeListByID;
313static OSKextVersion sExcludeListVersion = 0;
314static OSSharedPtr<OSArray> sLoadedKexts;
315static OSSharedPtr<OSDictionary> sNonLoadableKextsByID;
316static OSSharedPtr<OSArray> sUnloadedPrelinkedKexts;
317static OSSharedPtr<OSArray> sLoadedDriverKitKexts;
b0d623f7 318
f427ee49
A
319// Requests to the IOKit daemon waiting to be picked up.
320static OSSharedPtr<OSArray> sKernelRequests;
b0d623f7 321// Identifier of kext load requests in sKernelRequests
f427ee49
A
322static OSSharedPtr<OSSet> sPostedKextLoadIdentifiers;
323static OSSharedPtr<OSArray> sRequestCallbackRecords;
b0d623f7
A
324
325// Identifiers of all kexts ever requested in kernel; used for prelinked kernel
f427ee49
A
326static OSSharedPtr<OSSet> sAllKextLoadIdentifiers;
327#if CONFIG_KXLD
b0d623f7 328static KXLDContext * sKxldContext = NULL;
f427ee49 329#endif
b0d623f7
A
330static uint32_t sNextLoadTag = 0;
331static uint32_t sNextRequestTag = 0;
332
333static bool sUserLoadsActive = false;
f427ee49 334static bool sIOKitDaemonActive = false;
b0d623f7
A
335static bool sDeferredLoadSucceeded = false;
336static bool sConsiderUnloadsExecuted = false;
337
6d2010ae
A
338#if NO_KEXTD
339static bool sKernelRequestsEnabled = false;
340#else
b0d623f7 341static bool sKernelRequestsEnabled = true;
6d2010ae 342#endif
b0d623f7
A
343static bool sLoadEnabled = true;
344static bool sUnloadEnabled = true;
345
346/*********************************************************************
0a7de745
A
347 * Stuff for the OSKext representing the kernel itself.
348 **********/
b0d623f7
A
349static 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 */
363kmod_info_t g_kernel_kmod_info = {
cb323159
A
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
b0d623f7
A
376};
377
d9a64523
A
378/* Set up a fake kmod_info struct for statically linked kexts that don't have one. */
379
380kmod_info_t invalid_kmod_info = {
cb323159
A
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
d9a64523
A
393};
394
b0d623f7
A
395extern "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.
400kmod_info_t * kmod = NULL;
401
402#define KEXT_PANICLIST_SIZE (2 * PAGE_SIZE)
403
6d2010ae
A
404
405static char * loaded_kext_paniclist = NULL;
406static uint32_t loaded_kext_paniclist_size = 0;
0a7de745 407
b0d623f7 408AbsoluteTime last_loaded_timestamp;
0a7de745 409static char last_loaded_str_buf[2 * KMOD_MAX_NAME];
6d2010ae
A
410static u_long last_loaded_strlen = 0;
411static void * last_loaded_address = NULL;
412static u_long last_loaded_size = 0;
b0d623f7 413
b0d623f7 414AbsoluteTime last_unloaded_timestamp;
0a7de745 415static char last_unloaded_str_buf[2 * KMOD_MAX_NAME];
6d2010ae
A
416static u_long last_unloaded_strlen = 0;
417static void * last_unloaded_address = NULL;
418static u_long last_unloaded_size = 0;
b0d623f7 419
d9a64523
A
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
432static uint32_t gBuiltinKmodsCount;
433static kernel_section_t * gBuiltinKmodsSectionInfo;
434static kernel_section_t * gBuiltinKmodsSectionStart;
435
f427ee49 436const OSSymbol * gIOSurfaceIdentifier;
d9a64523
A
437vm_tag_t gIOSurfaceTag;
438
b0d623f7 439/*********************************************************************
0a7de745
A
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 **********/
b0d623f7
A
451static IORecursiveLock * sKextInnerLock = NULL;
452
453static bool sAutounloadEnabled = true;
454static bool sConsiderUnloadsCalled = false;
455static bool sConsiderUnloadsPending = false;
456
457static unsigned int sConsiderUnloadDelay = 60; // seconds
cb323159 458static thread_call_t sUnloadCallout = NULL;
f427ee49 459#if CONFIG_KXLD
cb323159 460static thread_call_t sDestroyLinkContextThread = NULL; // one-shot, one-at-a-time thread
f427ee49 461#endif // CONFIG_KXLD
b0d623f7 462static bool sSystemSleep = false; // true when system going to sleep
0a7de745 463static AbsoluteTime sLastWakeTime; // last time we woke up
b0d623f7 464
6d2010ae 465/*********************************************************************
0a7de745
A
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 **********/
6d2010ae 478static IOLock * sKextSummariesLock = NULL;
3e170ce0
A
479extern "C" lck_spin_t vm_allocation_sites_lock;
480static IOSimpleLock * sKextAccountsLock = &vm_allocation_sites_lock;
6d2010ae 481
cb323159 482void(*const sLoadedKextSummariesUpdated)(void) = OSKextLoadedKextSummariesUpdated;
39236c6e 483OSKextLoadedKextSummaryHeader * gLoadedKextSummaries __attribute__((used)) = NULL;
39037602 484uint64_t gLoadedKextSummariesTimestamp __attribute__((used)) = 0;
6d2010ae 485static size_t sLoadedKextSummariesAllocSize = 0;
3e170ce0 486
f427ee49 487static OSKextActiveAccount * sKextAccounts;
3e170ce0 488static uint32_t sKextAccountsCount;
6d2010ae
A
489};
490
491/*********************************************************************
0a7de745
A
492 * sKextLoggingLock protects the logging variables declared immediately below.
493 **********/
f427ee49 494static IOLock * sKextLoggingLock = NULL;
6d2010ae 495
f427ee49 496static const OSKextLogSpec kDefaultKernelLogFilter = kOSKextLogBasicLevel |
0a7de745 497 kOSKextLogVerboseFlagsMask;
f427ee49
A
498static OSKextLogSpec sKernelLogFilter = kDefaultKernelLogFilter;
499static bool sBootArgLogFilterFound = false;
39236c6e 500SYSCTL_UINT(_debug, OID_AUTO, kextlog, CTLFLAG_RW | CTLFLAG_LOCKED, &sKernelLogFilter,
39037602 501 0, "kernel kext logging");
b0d623f7 502
f427ee49
A
503static OSKextLogSpec sUserSpaceKextLogFilter = kOSKextLogSilentFilter;
504static OSSharedPtr<OSArray> sUserSpaceLogSpecArray;
505static OSSharedPtr<OSArray> sUserSpaceLogMessageArray;
b0d623f7
A
506
507/*********
0a7de745
A
508 * End scope for sKextInnerLock-protected variables.
509 *********************************************************************/
b0d623f7 510
3e170ce0
A
511
512/*********************************************************************
0a7de745 513 * helper function used for collecting PGO data upon unload of a kext
3e170ce0
A
514 */
515
516static int OSKextGrabPgoDataLocked(OSKext *kext,
0a7de745
A
517 bool metadata,
518 uuid_t instance_uuid,
519 uint64_t *pSize,
520 char *pBuffer,
521 uint64_t bufferSize);
3e170ce0
A
522
523/**********************************************************************/
524
525
526
b0d623f7
A
527#if PRAGMA_MARK
528#pragma mark OSData callbacks (need to move to OSData)
529#endif
530/*********************************************************************
531* C functions used for callbacks.
532*********************************************************************/
533extern "C" {
0a7de745
A
534void
535osdata_kmem_free(void * ptr, unsigned int length)
536{
537 kmem_free(kernel_map, (vm_address_t)ptr, length);
538 return;
b0d623f7
A
539}
540
0a7de745
A
541void
542osdata_phys_free(void * ptr, unsigned int length)
543{
544 ml_static_mfree((vm_offset_t)ptr, length);
545 return;
b0d623f7
A
546}
547
0a7de745
A
548void
549osdata_vm_deallocate(void * ptr, unsigned int length)
b0d623f7 550{
0a7de745
A
551 (void)vm_deallocate(kernel_map, (vm_offset_t)ptr, length);
552 return;
b0d623f7 553}
6d2010ae 554
0a7de745
A
555void
556osdata_kext_free(void * ptr, unsigned int length)
6d2010ae 557{
0a7de745 558 (void)kext_free((vm_offset_t)ptr, length);
6d2010ae 559}
b0d623f7
A
560};
561
562#if PRAGMA_MARK
563#pragma mark KXLD Allocation Callback
564#endif
f427ee49 565#if CONFIG_KXLD
b0d623f7
A
566/*********************************************************************
567* KXLD Allocation Callback
568*********************************************************************/
569kxld_addr_t
570kern_allocate(
0a7de745
A
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;
f427ee49
A
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);
0a7de745
A
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
f427ee49 622 theKext->setLinkedExecutable(linkBuffer.get());
0a7de745
A
623
624 *flags = kKxldAllocateWritable;
625 success = true;
b0d623f7
A
626
627finish:
0a7de745
A
628 if (!success && result) {
629 kext_free(result, roundSize);
630 result = 0;
631 }
b0d623f7 632
0a7de745 633 return (kxld_addr_t)result;
b0d623f7
A
634}
635
636/*********************************************************************
637*********************************************************************/
638void
639kxld_log_callback(
0a7de745
A
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);
b0d623f7 680}
f427ee49 681#endif // CONFIG_KXLD
b0d623f7 682
6d2010ae
A
683#if PRAGMA_MARK
684#pragma mark IOStatistics defines
685#endif
686
687#if IOKITSTATS
688
689#define notifyKextLoadObservers(kext, kmod_info) \
690do { \
316670eb 691 IOStatistics::onKextLoad(kext, kmod_info); \
6d2010ae
A
692} while (0)
693
694#define notifyKextUnloadObservers(kext) \
695do { \
316670eb 696 IOStatistics::onKextUnload(kext); \
6d2010ae
A
697} while (0)
698
699#define notifyAddClassObservers(kext, addedClass, flags) \
700do { \
316670eb 701 IOStatistics::onClassAdded(kext, addedClass); \
6d2010ae
A
702} while (0)
703
704#define notifyRemoveClassObservers(kext, removedClass, flags) \
705do { \
316670eb 706 IOStatistics::onClassRemoved(kext, removedClass); \
6d2010ae
A
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
b0d623f7
A
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
725OSDefineMetaClassAndStructors(OSKext, OSObject)
726
f427ee49
A
727OSDefineMetaClassAndStructors(OSKextSavedMutableSegment, OSObject);
728
b0d623f7
A
729/*********************************************************************
730*********************************************************************/
731/* static */
732void
733OSKext::initialize(void)
734{
f427ee49 735 OSSharedPtr<OSData> kernelExecutable = NULL;// do not release
0a7de745
A
736 u_char * kernelStart = NULL;// do not free
737 size_t kernelLength = 0;
0a7de745 738 IORegistryEntry * registryRoot = NULL;// do not release
f427ee49
A
739 OSSharedPtr<OSNumber> kernelCPUType;
740 OSSharedPtr<OSNumber> kernelCPUSubtype;
0a7de745
A
741 OSKextLogSpec bootLogFilter = kOSKextLogSilentFilter;
742 bool setResult = false;
cb323159 743 uint64_t * timestamp = NULL;
f427ee49 744 __unused char bootArgBuffer[16];// for PE_parse_boot_argn w/strings
0a7de745
A
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);
cb323159 759 sLoadedDriverKitKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
0a7de745
A
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);
cb323159 765 assert(sKextsByID && sLoadedKexts && sLoadedDriverKitKexts && sKernelRequests &&
0a7de745
A
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
f427ee49
A
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 */
0a7de745
A
790 sSafeBoot = PE_parse_boot_argn("-x", bootArgBuffer,
791 sizeof(bootArgBuffer)) ? true : false;
f427ee49 792#endif /* defined(__arm__) && defined(__arm64__) */
0a7de745
A
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));
d9a64523 803#if CONFIG_DTRACE
0a7de745
A
804 if (dtrace_keep_kernel_symbols()) {
805 sKeepSymbols = true;
806 }
d9a64523 807#endif /* CONFIG_DTRACE */
5ba3f43e 808#if KASAN_DYNAMIC_BLACKLIST
0a7de745
A
809 /* needed for function lookup */
810 sKeepSymbols = true;
5ba3f43e 811#endif
6d2010ae 812
f427ee49
A
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
0a7de745
A
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;
f427ee49 829 assert(kernelLength <= UINT_MAX);
0a7de745 830 kernelExecutable = OSData::withBytesNoCopy(
f427ee49 831 kernelStart, (unsigned int)kernelLength);
0a7de745
A
832 assert(kernelExecutable);
833
834#if KASLR_KEXT_DEBUG
cb323159 835 IOLog("kaslr: kernel start 0x%lx end 0x%lx length %lu vm_kernel_slide %lu (0x%016lx) \n",
0a7de745
A
836 (unsigned long)kernelStart,
837 (unsigned long)getlastaddr(),
838 kernelLength,
cb323159
A
839 (unsigned long)vm_kernel_slide,
840 (unsigned long)vm_kernel_slide);
316670eb
A
841#endif
842
0a7de745
A
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;
f427ee49 848 sKernelKext->linkedExecutable = os::move(kernelExecutable);
0a7de745
A
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,
f427ee49 871 sKernelKext->bundleID.get());
0a7de745
A
872 assert(setResult);
873 setResult = sKernelKext->infoDict->setObject(kOSKernelResourceKey,
874 kOSBooleanTrue);
875 assert(setResult);
876
f427ee49
A
877 {
878 OSSharedPtr<OSString> scratchString(OSString::withCStringNoCopy(osrelease));
879 assert(scratchString);
880 setResult = sKernelKext->infoDict->setObject(kCFBundleVersionKey,
881 scratchString.get());
882 assert(setResult);
883 }
0a7de745 884
f427ee49
A
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 }
0a7de745
A
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 */
f427ee49 897 setResult = sKextsByID->setObject(sKernelKext->bundleID.get(), sKernelKext);
0a7de745
A
898 assert(setResult);
899 setResult = sLoadedKexts->setObject(sKernelKext);
900 assert(setResult);
f427ee49
A
901
902 // XXX: better way with OSSharedPtr?
903 // sKernelKext remains a valid pointer even after the decref
0a7de745
A
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
f427ee49
A
915 registryRoot->setProperty(kOSKernelCPUTypeKey, kernelCPUType.get());
916 registryRoot->setProperty(kOSKernelCPUSubtypeKey, kernelCPUSubtype.get());
0a7de745
A
917
918 gBuiltinKmodsSectionInfo = getsectbyname(kPrelinkInfoSegment, kBuiltinInfoSection);
919 if (gBuiltinKmodsSectionInfo) {
920 uint32_t count;
921
922 assert(gBuiltinKmodsSectionInfo->addr);
923 assert(gBuiltinKmodsSectionInfo->size);
f427ee49
A
924 assert(gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *) <= UINT_MAX);
925 gBuiltinKmodsCount = (unsigned int)(gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *));
0a7de745
A
926
927 gBuiltinKmodsSectionStart = getsectbyname(kPrelinkInfoSegment, kBuiltinStartSection);
928 assert(gBuiltinKmodsSectionStart);
929 assert(gBuiltinKmodsSectionStart->addr);
930 assert(gBuiltinKmodsSectionStart->size);
f427ee49
A
931 assert(gBuiltinKmodsSectionStart->size / sizeof(uintptr_t) <= UINT_MAX);
932 count = (unsigned int)(gBuiltinKmodsSectionStart->size / sizeof(uintptr_t));
0a7de745
A
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 }
f427ee49
A
939
940 // Don't track this object -- it's never released
941 gIOSurfaceIdentifier = OSSymbol::withCStringNoCopy("com.apple.iokit.IOSurface").detach();
0a7de745
A
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;
b0d623f7
A
958}
959
960/*********************************************************************
d9a64523
A
961* This is expected to be called exactly once, from exactly one thread
962* context, during kernel bootstrap.
b0d623f7
A
963*********************************************************************/
964/* static */
965OSReturn
966OSKext::removeKextBootstrap(void)
967{
0a7de745 968 OSReturn result = kOSReturnError;
b0d623f7 969
0a7de745
A
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
c3c9b80d
A
978 kernel_segment_command_t * seg_kld = NULL;
979 kernel_segment_command_t * seg_klddata = NULL;
980 kernel_segment_command_t * seg_linkedit = NULL;
b0d623f7 981
f427ee49
A
982 const char __unused * dt_segment_name = NULL;
983 void __unused * segment_paddress = NULL;
984 int __unused segment_size = 0;
316670eb 985
0a7de745
A
986 OSKextLog(/* kext */ NULL,
987 kOSKextLogProgressLevel |
988 kOSKextLogGeneralFlag,
989 "Jettisoning kext bootstrap segments.");
990
f427ee49
A
991 /*
992 * keep the linkedit segment around when booted from a new MH_FILESET
993 * KC because all the kexts shared a linkedit segment.
994 */
995 kc_format_t kc_format;
996 if (!PE_get_primary_kc_format(&kc_format)) {
997 OSKextLog(/* kext */ NULL,
998 kOSKextLogErrorLevel |
999 kOSKextLogGeneralFlag,
1000 "Unable to determine primary KC format");
1001 }
1002
0a7de745
A
1003 /*****
1004 * Dispose of unnecessary stuff that the booter didn't need to load.
1005 */
1006 dt_result = IODTGetLoaderInfo(dt_kernel_header_name,
1007 (void **)&dt_mach_header, &dt_mach_header_size);
1008 if (dt_result == 0 && dt_mach_header) {
1009 IODTFreeLoaderInfo(dt_kernel_header_name, (void *)dt_mach_header,
1010 round_page_32(dt_mach_header_size));
1011 }
1012 dt_result = IODTGetLoaderInfo(dt_kernel_symtab_name,
1013 (void **)&dt_symtab, &dt_symtab_size);
1014 if (dt_result == 0 && dt_symtab) {
1015 IODTFreeLoaderInfo(dt_kernel_symtab_name, (void *)dt_symtab,
1016 round_page_32(dt_symtab_size));
1017 }
1018
1019 /*****
c3c9b80d 1020 * KLD & KLDDATA bootstrap segments.
0a7de745
A
1021 */
1022 // xxx - should rename KLD segment
c3c9b80d
A
1023 seg_kld = getsegbyname("__KLD");
1024 seg_klddata = getsegbyname("__KLDDATA");
1025 if (seg_klddata) {
1026 // __mod_term_func is part of __KLDDATA
1027 OSRuntimeUnloadCPPForSegment(seg_klddata);
0a7de745 1028 }
b0d623f7 1029
5ba3f43e 1030#if __arm__ || __arm64__
c3c9b80d
A
1031 /* Free the memory that was set up by iBoot.
1032 */
1033#if !defined(KERNEL_INTEGRITY_KTRR) && !defined(KERNEL_INTEGRITY_CTRR)
1034 /* We cannot free the KLD segment with CTRR enabled as it contains text and
1035 * is covered by the contiguous rorgn.
0a7de745
A
1036 */
1037 dt_segment_name = "Kernel-__KLD";
1038 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
0a7de745 1039 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
c3c9b80d
A
1040 (int)segment_size); // calls ml_static_mfree
1041 } else if (seg_kld && seg_kld->vmaddr && seg_kld->vmsize) {
1042 /* With fileset KCs, the Kernel KLD segment is not recorded in the DT. */
1043 ml_static_mfree(ml_static_ptovirt(seg_kld->vmaddr - gVirtBase + gPhysBase),
1044 seg_kld->vmsize);
1045 }
1046#endif
1047 dt_segment_name = "Kernel-__KLDDATA";
1048 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
1049 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1050 (int)segment_size); // calls ml_static_mfree
1051 } else if (seg_klddata && seg_klddata->vmaddr && seg_klddata->vmsize) {
1052 /* With fileset KCs, the Kernel KLDDATA segment is not recorded in the DT. */
1053 ml_static_mfree(ml_static_ptovirt(seg_klddata->vmaddr - gVirtBase + gPhysBase),
1054 seg_klddata->vmsize);
0a7de745 1055 }
5ba3f43e 1056#elif __i386__ || __x86_64__
0a7de745 1057 /* On x86, use the mapping data from the segment load command to
c3c9b80d 1058 * unload KLD & KLDDATA directly.
0a7de745
A
1059 * This may invalidate any assumptions about "avail_start"
1060 * defining the lower bound for valid physical addresses.
1061 */
c3c9b80d
A
1062 if (seg_kld && seg_kld->vmaddr && seg_kld->vmsize) {
1063 bzero((void *)seg_kld->vmaddr, seg_kld->vmsize);
1064 ml_static_mfree(seg_kld->vmaddr, seg_kld->vmsize);
1065 }
1066 if (seg_klddata && seg_klddata->vmaddr && seg_klddata->vmsize) {
1067 bzero((void *)seg_klddata->vmaddr, seg_klddata->vmsize);
1068 ml_static_mfree(seg_klddata->vmaddr, seg_klddata->vmsize);
0a7de745 1069 }
b0d623f7
A
1070#else
1071#error arch
1072#endif
1073
0a7de745
A
1074 /*****
1075 * Prelinked kernel's symtab (if there is one).
1076 */
f427ee49
A
1077 if (kc_format != KCFormatFileset) {
1078 kernel_section_t * sect;
1079 sect = getsectbyname("__PRELINK", "__symtab");
1080 if (sect && sect->addr && sect->size) {
1081 ml_static_mfree(sect->addr, sect->size);
1082 }
0a7de745 1083 }
b0d623f7 1084
c3c9b80d 1085 seg_linkedit = (kernel_segment_command_t *)getsegbyname("__LINKEDIT");
6d2010ae 1086
0a7de745
A
1087 /* kxld always needs the kernel's __LINKEDIT segment, but we can make it
1088 * pageable, unless keepsyms is set. To do that, we have to copy it from
1089 * its booter-allocated memory, free the booter memory, reallocate proper
1090 * managed memory, then copy the segment back in.
f427ee49
A
1091 *
1092 * NOTE: This optimization is not valid for fileset KCs because each
1093 * fileset entry (kext or xnu) in an MH_FILESET has a LINKEDIT segment
1094 * that points to one fileset-global LINKEDIT segment. This
1095 * optimization is also only valid for platforms that support vm
1096 * mapped kexts or mapped kext collections (pageable KCs)
0a7de745 1097 */
f427ee49
A
1098#if VM_MAPPED_KEXTS
1099 if (!sKeepSymbols && kc_format != KCFormatFileset) {
0a7de745
A
1100 kern_return_t mem_result;
1101 void *seg_copy = NULL;
1102 void *seg_data = NULL;
1103 vm_map_offset_t seg_offset = 0;
1104 vm_map_offset_t seg_copy_offset = 0;
1105 vm_map_size_t seg_length = 0;
1106
c3c9b80d
A
1107 seg_data = (void *) seg_linkedit->vmaddr;
1108 seg_offset = (vm_map_offset_t) seg_linkedit->vmaddr;
1109 seg_length = (vm_map_size_t) seg_linkedit->vmsize;
0a7de745
A
1110
1111 /* Allocate space for the LINKEDIT copy.
1112 */
1113 mem_result = kmem_alloc(kernel_map, (vm_offset_t *) &seg_copy,
1114 seg_length, VM_KERN_MEMORY_KEXT);
1115 if (mem_result != KERN_SUCCESS) {
1116 OSKextLog(/* kext */ NULL,
1117 kOSKextLogErrorLevel |
1118 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1119 "Can't copy __LINKEDIT segment for VM reassign.");
1120 return result;
1121 }
1122 seg_copy_offset = (vm_map_offset_t) seg_copy;
1123
1124 /* Copy it out.
1125 */
1126 memcpy(seg_copy, seg_data, seg_length);
1127
1128 /* Dump the booter memory.
1129 */
1130 ml_static_mfree(seg_offset, seg_length);
1131
1132 /* Set up the VM region.
1133 */
1134 mem_result = vm_map_enter_mem_object(
1135 kernel_map,
1136 &seg_offset,
1137 seg_length, /* mask */ 0,
1138 VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
1139 VM_MAP_KERNEL_FLAGS_NONE,
1140 VM_KERN_MEMORY_NONE,
1141 (ipc_port_t)NULL,
1142 (vm_object_offset_t) 0,
1143 /* copy */ FALSE,
1144 /* cur_protection */ VM_PROT_READ | VM_PROT_WRITE,
1145 /* max_protection */ VM_PROT_ALL,
1146 /* inheritance */ VM_INHERIT_DEFAULT);
1147 if ((mem_result != KERN_SUCCESS) ||
1148 (seg_offset != (vm_map_offset_t) seg_data)) {
1149 OSKextLog(/* kext */ NULL,
1150 kOSKextLogErrorLevel |
1151 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1152 "Can't create __LINKEDIT VM entry at %p, length 0x%llx (error 0x%x).",
1153 seg_data, seg_length, mem_result);
1154 return result;
1155 }
1156
1157 /* And copy it back.
1158 */
1159 memcpy(seg_data, seg_copy, seg_length);
1160
1161 /* Free the copy.
1162 */
1163 kmem_free(kernel_map, seg_copy_offset, seg_length);
f427ee49
A
1164 } else if (!sKeepSymbols && kc_format == KCFormatFileset) {
1165 /* Remove the linkedit segment of the Boot KC */
1166 kernel_mach_header_t *mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
1167 OSKext::jettisonFileSetLinkeditSegment(mh);
0a7de745 1168 }
f427ee49 1169#else // !VM_MAPPED_KEXTS
0a7de745
A
1170 /*****
1171 * Dump the LINKEDIT segment, unless keepsyms is set.
1172 */
f427ee49 1173 if (!sKeepSymbols && kc_format != KCFormatFileset) {
0a7de745
A
1174 dt_segment_name = "Kernel-__LINKEDIT";
1175 if (0 == IODTGetLoaderInfo(dt_segment_name,
1176 &segment_paddress, &segment_size)) {
316670eb 1177#ifdef SECURE_KERNEL
0a7de745
A
1178 vm_offset_t vmaddr = ml_static_ptovirt((vm_offset_t)segment_paddress);
1179 bzero((void*)vmaddr, segment_size);
316670eb 1180#endif
0a7de745
A
1181 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1182 (int)segment_size);
1183 }
1184 } else {
1185 OSKextLog(/* kext */ NULL,
1186 kOSKextLogBasicLevel |
1187 kOSKextLogGeneralFlag,
1188 "keepsyms boot arg specified; keeping linkedit segment for symbols.");
1189 }
f427ee49 1190#endif // VM_MAPPED_KEXTS
b0d623f7 1191
0a7de745 1192 result = kOSReturnSuccess;
b0d623f7 1193
0a7de745 1194 return result;
b0d623f7
A
1195}
1196
f427ee49 1197#if CONFIG_KXLD
b0d623f7
A
1198/*********************************************************************
1199*********************************************************************/
1200void
1201OSKext::flushNonloadedKexts(
0a7de745
A
1202 Boolean flushPrelinkedKexts)
1203{
f427ee49
A
1204 OSSharedPtr<OSSet> keepKexts;
1205
1206 /* TODO: make this more efficient with MH_FILESET kexts */
1207
1208 // Do not unload prelinked kexts on arm because the kernelcache is not
1209 // structured in a way that allows them to be unmapped
1210#if !defined(__x86_64__)
1211 flushPrelinkedKexts = false;
1212#endif /* defined(__x86_64__) */
0a7de745
A
1213
1214 IORecursiveLockLock(sKextLock);
1215
1216 OSKextLog(/* kext */ NULL,
1217 kOSKextLogProgressLevel |
1218 kOSKextLogKextBookkeepingFlag,
1219 "Flushing nonloaded kexts and other unused data.");
1220
1221 OSKext::considerDestroyingLinkContext();
1222
1223 /* If we aren't flushing unused prelinked kexts, we have to put them
1224 * aside while we flush everything else so make a container for them.
1225 */
cb323159
A
1226 keepKexts = OSSet::withCapacity(16);
1227 if (!keepKexts) {
1228 goto finish;
0a7de745
A
1229 }
1230
1231 /* Set aside prelinked kexts (in-use or not) and break
1232 * any lingering inter-kext references for nonloaded kexts
1233 * so they have min. retain counts.
1234 */
f427ee49
A
1235 {
1236 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1237 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1238 if (!thisKext) {
1239 return false;
1240 }
1241 if (!flushPrelinkedKexts && thisKext->isPrelinked()) {
1242 keepKexts->setObject(thisKext);
1243 } else if (!thisKext->declaresExecutable()) {
1244 /*
1245 * Don't unload codeless kexts, because they never appear in the loadedKexts array.
1246 * Requesting one from the IOKit daemon will load it and then immediately remove it by calling
1247 * flushNonloadedKexts().
1248 * And adding one to loadedKexts breaks code assuming they have kmod_info etc.
1249 */
1250 keepKexts->setObject(thisKext);
1251 } else if (thisKext->isInFileset()) {
1252 /* keep all kexts in the new MH_FILESET KC */
1253 keepKexts->setObject(thisKext);
1254 }
0a7de745 1255
f427ee49
A
1256 thisKext->flushDependencies(/* forceIfLoaded */ false);
1257 return false;
1258 });
1259 }
0a7de745
A
1260 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
1261 */
1262 sKextsByID->flushCollection();
1263
1264 /* Now put the loaded kexts back into the ID dictionary.
1265 */
cb323159
A
1266 sLoadedKexts->iterateObjects(^bool (OSObject * obj) {
1267 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1268 if (!thisKext) {
1269 return false;
1270 }
0a7de745 1271 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
cb323159
A
1272 return false;
1273 });
0a7de745 1274
cb323159 1275 /* Finally, put back the kept kexts if we saved any.
0a7de745 1276 */
cb323159
A
1277 keepKexts->iterateObjects(^bool (OSObject * obj) {
1278 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1279 if (!thisKext) {
1280 return false;
0a7de745 1281 }
cb323159
A
1282 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1283 return false;
1284 });
b0d623f7
A
1285
1286finish:
0a7de745 1287 IORecursiveLockUnlock(sKextLock);
f427ee49
A
1288 return;
1289}
1290#else /* !CONFIG_KXLD */
1291
1292void
1293OSKext::flushNonloadedKexts(
1294 Boolean flushPrelinkedKexts __unused)
1295{
1296 IORecursiveLockLock(sKextLock);
1297
1298 OSKextLog(/* kext */ NULL,
1299 kOSKextLogProgressLevel |
1300 kOSKextLogKextBookkeepingFlag,
1301 "Flushing dependency info for non-loaded kexts.");
b0d623f7 1302
f427ee49
A
1303 /*
1304 * In a world where we don't dynamically link kexts, they all come
1305 * from a kext collection that's either in wired memory, or
1306 * wire-on-demand. We don't need to mess around with moving kexts in
1307 * and out of the sKextsByID array - they can all just stay there.
1308 * Here we just flush the dependency list for kexts that are not
1309 * loaded.
1310 */
1311 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1312 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1313 if (!thisKext) {
1314 return false;
1315 }
1316 thisKext->flushDependencies(/* forceIfLoaded */ false);
1317 return false;
1318 });
b0d623f7 1319
f427ee49 1320 IORecursiveLockUnlock(sKextLock);
0a7de745 1321 return;
b0d623f7
A
1322}
1323
f427ee49
A
1324#endif /* CONFIG_KXLD */
1325
b0d623f7
A
1326/*********************************************************************
1327*********************************************************************/
1328/* static */
1329void
f427ee49 1330OSKext::setIOKitDaemonActive(bool active)
b0d623f7 1331{
f427ee49 1332 IOServiceTrace(IOSERVICE_KEXTD_ALIVE, 0, 0, 0, 0);
0a7de745 1333 IORecursiveLockLock(sKextLock);
f427ee49 1334 sIOKitDaemonActive = active;
0a7de745 1335 if (sKernelRequests->getCount()) {
f427ee49 1336 OSKext::pingIOKitDaemon();
0a7de745
A
1337 }
1338 IORecursiveLockUnlock(sKextLock);
b0d623f7 1339
0a7de745 1340 return;
b0d623f7
A
1341}
1342
6d2010ae
A
1343/*********************************************************************
1344* OSKextLib.cpp might need access to this someday but for now it's
1345* private.
1346*********************************************************************/
1347extern "C" {
1348extern void ipc_port_release_send(ipc_port_t);
1349};
1350
1351/* static */
1352OSReturn
f427ee49 1353OSKext::pingIOKitDaemon(void)
6d2010ae 1354{
0a7de745 1355 OSReturn result = kOSReturnError;
6d2010ae 1356#if !NO_KEXTD
0a7de745
A
1357 mach_port_t kextd_port = IPC_PORT_NULL;
1358
f427ee49 1359 if (!sIOKitDaemonActive) {
0a7de745
A
1360 result = kOSKextReturnDisabled; // basically unavailable
1361 goto finish;
1362 }
1363
1364 result = host_get_kextd_port(host_priv_self(), &kextd_port);
1365 if (result != KERN_SUCCESS || !IPC_PORT_VALID(kextd_port)) {
1366 OSKextLog(/* kext */ NULL,
1367 kOSKextLogErrorLevel |
1368 kOSKextLogIPCFlag,
f427ee49 1369 "Can't get " kIOKitDaemonName " port.");
0a7de745
A
1370 goto finish;
1371 }
1372
1373 result = kextd_ping(kextd_port);
1374 if (result != KERN_SUCCESS) {
1375 OSKextLog(/* kext */ NULL,
1376 kOSKextLogErrorLevel |
1377 kOSKextLogIPCFlag,
f427ee49 1378 kIOKitDaemonName " ping failed (0x%x).", (int)result);
0a7de745
A
1379 goto finish;
1380 }
6d2010ae
A
1381
1382finish:
0a7de745
A
1383 if (IPC_PORT_VALID(kextd_port)) {
1384 ipc_port_release_send(kextd_port);
1385 }
6d2010ae
A
1386#endif
1387
0a7de745 1388 return result;
6d2010ae
A
1389}
1390
b0d623f7
A
1391/*********************************************************************
1392*********************************************************************/
1393/* static */
1394void
1395OSKext::setDeferredLoadSucceeded(Boolean succeeded)
1396{
0a7de745
A
1397 IORecursiveLockLock(sKextLock);
1398 sDeferredLoadSucceeded = succeeded;
1399 IORecursiveLockUnlock(sKextLock);
b0d623f7 1400
0a7de745 1401 return;
b0d623f7
A
1402}
1403
1404/*********************************************************************
1405* Called from IOSystemShutdownNotification.
1406*********************************************************************/
1407/* static */
1408void
1409OSKext::willShutdown(void)
1410{
6d2010ae 1411#if !NO_KEXTD
0a7de745 1412 OSReturn checkResult = kOSReturnError;
6d2010ae 1413#endif
f427ee49 1414 OSSharedPtr<OSDictionary> exitRequest;
b0d623f7 1415
0a7de745 1416 IORecursiveLockLock(sKextLock);
b0d623f7 1417
0a7de745
A
1418 OSKext::setLoadEnabled(false);
1419 OSKext::setUnloadEnabled(false);
1420 OSKext::setAutounloadsEnabled(false);
1421 OSKext::setKernelRequestsEnabled(false);
b0d623f7 1422
f427ee49
A
1423#if defined(__x86_64__) || defined(__i386__)
1424 if (IOPMRootDomainGetWillShutdown()) {
1425 OSKext::freeKCFileSetcontrol();
1426 }
1427#endif // (__x86_64__) || defined(__i386__)
1428
6d2010ae 1429#if !NO_KEXTD
0a7de745
A
1430 OSKextLog(/* kext */ NULL,
1431 kOSKextLogProgressLevel |
1432 kOSKextLogGeneralFlag,
f427ee49 1433 "System shutdown; requesting immediate " kIOKitDaemonName " exit.");
0a7de745 1434
f427ee49
A
1435 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonExit,
1436 exitRequest);
0a7de745
A
1437 if (checkResult != kOSReturnSuccess) {
1438 goto finish;
1439 }
f427ee49 1440 if (!sKernelRequests->setObject(exitRequest.get())) {
0a7de745
A
1441 goto finish;
1442 }
1443
f427ee49 1444 OSKext::pingIOKitDaemon();
b0d623f7
A
1445
1446finish:
6d2010ae
A
1447#endif
1448
0a7de745 1449 IORecursiveLockUnlock(sKextLock);
0a7de745 1450 return;
b0d623f7
A
1451}
1452
f427ee49
A
1453void
1454OSKext::willUserspaceReboot(void)
1455{
1456 OSKext::willShutdown();
1457 IOService::userSpaceWillReboot();
1458 gIOCatalogue->terminateDriversForUserspaceReboot();
1459}
1460
1461void
1462OSKext::resetAfterUserspaceReboot(void)
1463{
1464 OSSharedPtr<OSArray> arr = OSArray::withCapacity(1);
1465 IOService::updateConsoleUsers(arr.get(), 0, true /* after_userspace_reboot */);
1466
1467 IORecursiveLockLock(sKextLock);
1468 gIOCatalogue->resetAfterUserspaceReboot();
1469 IOService::userSpaceDidReboot();
1470 OSKext::setLoadEnabled(true);
1471 OSKext::setUnloadEnabled(true);
1472 OSKext::setAutounloadsEnabled(true);
1473 OSKext::setKernelRequestsEnabled(true);
1474 sOSKextWasResetAfterUserspaceReboot = true;
1475 IORecursiveLockUnlock(sKextLock);
1476}
1477
1478extern "C" void
1479OSKextResetAfterUserspaceReboot(void)
1480{
1481 OSKext::resetAfterUserspaceReboot();
1482}
1483
b0d623f7
A
1484/*********************************************************************
1485*********************************************************************/
1486/* static */
1487bool
1488OSKext::getLoadEnabled(void)
1489{
0a7de745 1490 bool result;
b0d623f7 1491
0a7de745
A
1492 IORecursiveLockLock(sKextLock);
1493 result = sLoadEnabled;
1494 IORecursiveLockUnlock(sKextLock);
1495 return result;
b0d623f7
A
1496}
1497
1498/*********************************************************************
1499*********************************************************************/
1500/* static */
1501bool
1502OSKext::setLoadEnabled(bool flag)
1503{
0a7de745
A
1504 bool result;
1505
1506 IORecursiveLockLock(sKextLock);
1507 result = sLoadEnabled;
1508 sLoadEnabled = (flag ? true : false);
b0d623f7 1509
0a7de745
A
1510 if (sLoadEnabled != result) {
1511 OSKextLog(/* kext */ NULL,
1512 kOSKextLogBasicLevel |
1513 kOSKextLogLoadFlag,
1514 "Kext loading now %sabled.", sLoadEnabled ? "en" : "dis");
1515 }
b0d623f7 1516
0a7de745 1517 IORecursiveLockUnlock(sKextLock);
b0d623f7 1518
0a7de745 1519 return result;
b0d623f7
A
1520}
1521
1522/*********************************************************************
1523*********************************************************************/
1524/* static */
1525bool
1526OSKext::getUnloadEnabled(void)
1527{
0a7de745 1528 bool result;
b0d623f7 1529
0a7de745
A
1530 IORecursiveLockLock(sKextLock);
1531 result = sUnloadEnabled;
1532 IORecursiveLockUnlock(sKextLock);
1533 return result;
b0d623f7
A
1534}
1535
1536/*********************************************************************
1537*********************************************************************/
1538/* static */
1539bool
1540OSKext::setUnloadEnabled(bool flag)
1541{
0a7de745
A
1542 bool result;
1543
1544 IORecursiveLockLock(sKextLock);
1545 result = sUnloadEnabled;
1546 sUnloadEnabled = (flag ? true : false);
1547 IORecursiveLockUnlock(sKextLock);
b0d623f7 1548
0a7de745
A
1549 if (sUnloadEnabled != result) {
1550 OSKextLog(/* kext */ NULL,
1551 kOSKextLogBasicLevel |
1552 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1553 "Kext unloading now %sabled.", sUnloadEnabled ? "en" : "dis");
1554 }
b0d623f7 1555
0a7de745 1556 return result;
b0d623f7
A
1557}
1558
1559/*********************************************************************
1560* Do not call any function that takes sKextLock here!
1561*********************************************************************/
1562/* static */
1563bool
1564OSKext::getAutounloadEnabled(void)
1565{
0a7de745 1566 bool result;
b0d623f7 1567
0a7de745
A
1568 IORecursiveLockLock(sKextInnerLock);
1569 result = sAutounloadEnabled ? true : false;
1570 IORecursiveLockUnlock(sKextInnerLock);
1571 return result;
b0d623f7
A
1572}
1573
1574/*********************************************************************
1575* Do not call any function that takes sKextLock here!
1576*********************************************************************/
1577/* static */
1578bool
1579OSKext::setAutounloadsEnabled(bool flag)
1580{
0a7de745
A
1581 bool result;
1582
1583 IORecursiveLockLock(sKextInnerLock);
b0d623f7 1584
0a7de745
A
1585 result = sAutounloadEnabled;
1586 sAutounloadEnabled = (flag ? true : false);
1587 if (!sAutounloadEnabled && sUnloadCallout) {
1588 thread_call_cancel(sUnloadCallout);
1589 }
b0d623f7 1590
0a7de745
A
1591 if (sAutounloadEnabled != result) {
1592 OSKextLog(/* kext */ NULL,
1593 kOSKextLogBasicLevel |
1594 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1595 "Kext autounloading now %sabled.",
1596 sAutounloadEnabled ? "en" : "dis");
1597 }
b0d623f7 1598
0a7de745 1599 IORecursiveLockUnlock(sKextInnerLock);
b0d623f7 1600
0a7de745 1601 return result;
b0d623f7
A
1602}
1603
1604/*********************************************************************
1605*********************************************************************/
1606/* instance method operating on OSKext field */
1607bool
1608OSKext::setAutounloadEnabled(bool flag)
1609{
0a7de745 1610 bool result = flags.autounloadEnabled ? true : false;
c3c9b80d 1611 flags.autounloadEnabled = flag ? (0 == flags.unloadUnsupported) : 0;
0a7de745
A
1612
1613 if (result != (flag ? true : false)) {
1614 OSKextLog(this,
1615 kOSKextLogProgressLevel |
1616 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
1617 "Autounloading for kext %s now %sabled.",
1618 getIdentifierCString(),
1619 flags.autounloadEnabled ? "en" : "dis");
1620 }
1621 return result;
b0d623f7
A
1622}
1623
1624/*********************************************************************
1625*********************************************************************/
1626/* static */
1627bool
1628OSKext::setKernelRequestsEnabled(bool flag)
1629{
0a7de745 1630 bool result;
b0d623f7 1631
0a7de745
A
1632 IORecursiveLockLock(sKextLock);
1633 result = sKernelRequestsEnabled;
1634 sKernelRequestsEnabled = flag ? true : false;
1635
1636 if (sKernelRequestsEnabled != result) {
1637 OSKextLog(/* kext */ NULL,
1638 kOSKextLogBasicLevel |
1639 kOSKextLogGeneralFlag,
1640 "Kernel requests now %sabled.",
1641 sKernelRequestsEnabled ? "en" : "dis");
1642 }
1643 IORecursiveLockUnlock(sKextLock);
1644 return result;
b0d623f7
A
1645}
1646
1647/*********************************************************************
1648*********************************************************************/
1649/* static */
1650bool
1651OSKext::getKernelRequestsEnabled(void)
1652{
0a7de745 1653 bool result;
b0d623f7 1654
0a7de745
A
1655 IORecursiveLockLock(sKextLock);
1656 result = sKernelRequestsEnabled;
1657 IORecursiveLockUnlock(sKextLock);
1658 return result;
b0d623f7
A
1659}
1660
f427ee49
A
1661static bool
1662segmentIsMutable(kernel_segment_command_t *seg)
1663{
1664 /* Mutable segments have to have VM_PROT_WRITE */
1665 if ((seg->maxprot & VM_PROT_WRITE) == 0) {
1666 return false;
1667 }
1668 /* Exclude the __DATA_CONST segment */
1669 if (strncmp(seg->segname, "__DATA_CONST", sizeof(seg->segname)) == 0) {
1670 return false;
1671 }
1672 /* Exclude __LINKEDIT */
1673 if (strncmp(seg->segname, "__LINKEDIT", sizeof(seg->segname)) == 0) {
1674 return false;
1675 }
1676 return true;
1677}
1678
b0d623f7
A
1679#if PRAGMA_MARK
1680#pragma mark Kext Life Cycle
1681#endif
1682/*********************************************************************
1683*********************************************************************/
f427ee49 1684OSSharedPtr<OSKext>
b0d623f7 1685OSKext::withPrelinkedInfoDict(
0a7de745 1686 OSDictionary * anInfoDict,
f427ee49
A
1687 bool doCoalescedSlides,
1688 kc_kind_t type)
b0d623f7 1689{
f427ee49 1690 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
b0d623f7 1691
f427ee49 1692 if (newKext && !newKext->initWithPrelinkedInfoDict(anInfoDict, doCoalescedSlides, type)) {
0a7de745
A
1693 return NULL;
1694 }
b0d623f7 1695
0a7de745 1696 return newKext;
b0d623f7
A
1697}
1698
1699/*********************************************************************
1700*********************************************************************/
1701bool
1702OSKext::initWithPrelinkedInfoDict(
0a7de745 1703 OSDictionary * anInfoDict,
f427ee49
A
1704 bool doCoalescedSlides,
1705 kc_kind_t type)
0a7de745
A
1706{
1707 bool result = false;
f427ee49
A
1708 OSString * kextPath = NULL; // do not release
1709 OSNumber * addressNum = NULL; // reused; do not release
1710 OSNumber * lengthNum = NULL; // reused; do not release
1711 OSBoolean * scratchBool = NULL; // do not release
1712 void * data = NULL; // do not free
1713 void * srcData = NULL; // do not free
1714 OSSharedPtr<OSData> prelinkedExecutable;
1715 uint32_t length = 0; // reused
1716 uintptr_t kext_slide = PE_get_kc_slide(type);
1717 bool shouldSaveSegments = false;
0a7de745
A
1718
1719 if (!super::init()) {
1720 goto finish;
1721 }
1722
1723 /* Get the path. Don't look for an arch-specific path property.
1724 */
1725 kextPath = OSDynamicCast(OSString,
1726 anInfoDict->getObject(kPrelinkBundlePathKey));
1727
1728 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
1729 goto finish;
1730 }
f427ee49 1731
316670eb 1732#if KASLR_KEXT_DEBUG
f427ee49 1733 IOLog("kaslr: doCoalescedSlides %d kext %s \n", doCoalescedSlides, getIdentifierCString());
316670eb 1734#endif
b0d623f7 1735
0a7de745
A
1736 /* Also get the executable's bundle-relative path if present.
1737 * Don't look for an arch-specific path property.
1738 */
f427ee49
A
1739 executableRelPath.reset(OSDynamicCast(OSString,
1740 anInfoDict->getObject(kPrelinkExecutableRelativePathKey)), OSRetain);
1741 userExecutableRelPath.reset(OSDynamicCast(OSString,
1742 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
cb323159 1743
0a7de745
A
1744 /* Don't need the paths to be in the info dictionary any more.
1745 */
1746 anInfoDict->removeObject(kPrelinkBundlePathKey);
1747 anInfoDict->removeObject(kPrelinkExecutableRelativePathKey);
1748
f427ee49
A
1749 scratchBool = OSDynamicCast(OSBoolean,
1750 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
1751 if (scratchBool == kOSBooleanTrue) {
1752 flags.requireExplicitLoad = 1;
1753 }
1754
0a7de745
A
1755 /* Create an OSData wrapper around the linked executable.
1756 */
1757 addressNum = OSDynamicCast(OSNumber,
1758 anInfoDict->getObject(kPrelinkExecutableLoadKey));
f427ee49 1759 if (addressNum && addressNum->unsigned64BitValue() != kOSKextCodelessKextLoadAddr) {
0a7de745
A
1760 lengthNum = OSDynamicCast(OSNumber,
1761 anInfoDict->getObject(kPrelinkExecutableSizeKey));
1762 if (!lengthNum) {
1763 OSKextLog(this,
1764 kOSKextLogErrorLevel |
1765 kOSKextLogArchiveFlag,
1766 "Kext %s can't find prelinked kext executable size.",
1767 getIdentifierCString());
f427ee49 1768 return result;
0a7de745
A
1769 }
1770
f427ee49 1771 data = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
0a7de745 1772 length = (uint32_t) (lengthNum->unsigned32BitValue());
b0d623f7 1773
316670eb 1774#if KASLR_KEXT_DEBUG
0a7de745 1775 IOLog("kaslr: unslid 0x%lx slid 0x%lx length %u - prelink executable \n",
cb323159 1776 (unsigned long)ml_static_unslide((vm_offset_t)data),
0a7de745
A
1777 (unsigned long)data,
1778 length);
316670eb
A
1779#endif
1780
0a7de745
A
1781 anInfoDict->removeObject(kPrelinkExecutableLoadKey);
1782 anInfoDict->removeObject(kPrelinkExecutableSizeKey);
1783
1784 /* If the kext's load address differs from its source address, allocate
1785 * space in the kext map at the load address and copy the kext over.
1786 */
1787 addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject(kPrelinkExecutableSourceKey));
1788 if (addressNum) {
f427ee49 1789 srcData = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
b0d623f7 1790
316670eb 1791#if KASLR_KEXT_DEBUG
0a7de745 1792 IOLog("kaslr: unslid 0x%lx slid 0x%lx - prelink executable source \n",
cb323159 1793 (unsigned long)ml_static_unslide((vm_offset_t)srcData),
0a7de745 1794 (unsigned long)srcData);
316670eb 1795#endif
0a7de745
A
1796
1797 if (data != srcData) {
b0d623f7 1798#if __LP64__
0a7de745
A
1799 kern_return_t alloc_result;
1800
1801 alloc_result = kext_alloc((vm_offset_t *)&data, length, /* fixed */ TRUE);
1802 if (alloc_result != KERN_SUCCESS) {
1803 OSKextLog(this,
1804 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1805 "Failed to allocate space for prelinked kext %s.",
1806 getIdentifierCString());
1807 goto finish;
1808 }
1809 memcpy(data, srcData, length);
b0d623f7 1810#else
0a7de745
A
1811 OSKextLog(this,
1812 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1813 "Error: prelinked kext %s - source and load addresses "
1814 "differ on ILP32 architecture.",
1815 getIdentifierCString());
1816 goto finish;
b0d623f7 1817#endif /* __LP64__ */
0a7de745
A
1818 }
1819
1820 anInfoDict->removeObject(kPrelinkExecutableSourceKey);
1821 }
1822
1823 prelinkedExecutable = OSData::withBytesNoCopy(data, length);
1824 if (!prelinkedExecutable) {
1825 OSKextLog(this,
1826 kOSKextLogErrorLevel |
1827 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1828 "Kext %s failed to create executable wrapper.",
1829 getIdentifierCString());
1830 goto finish;
1831 }
316670eb
A
1832
1833#if VM_MAPPED_KEXTS
0a7de745 1834 prelinkedExecutable->setDeallocFunction(osdata_kext_free);
316670eb 1835#else
0a7de745 1836 prelinkedExecutable->setDeallocFunction(osdata_phys_free);
316670eb 1837#endif
f427ee49 1838 setLinkedExecutable(prelinkedExecutable.get());
0a7de745
A
1839 addressNum = OSDynamicCast(OSNumber,
1840 anInfoDict->getObject(kPrelinkKmodInfoKey));
1841 if (!addressNum) {
1842 OSKextLog(this,
1843 kOSKextLogErrorLevel |
1844 kOSKextLogArchiveFlag,
1845 "Kext %s can't find prelinked kext kmod_info address.",
1846 getIdentifierCString());
1847 goto finish;
1848 }
1849
1850 if (addressNum->unsigned64BitValue() != 0) {
f427ee49
A
1851 kmod_info = (kmod_info_t *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
1852 if (kmod_info->address) {
1853 kmod_info->address = (((uintptr_t)(kmod_info->address)) + kext_slide);
1854 } else {
1855 kmod_info->address = (uintptr_t)data;
1856 kmod_info->size = length;
1857 }
316670eb 1858#if KASLR_KEXT_DEBUG
0a7de745 1859 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info \n",
f427ee49 1860 (unsigned long)((vm_offset_t)kmod_info) - kext_slide,
0a7de745
A
1861 (unsigned long)kmod_info);
1862 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info->address \n",
f427ee49 1863 (unsigned long)((vm_offset_t)kmod_info->address) - kext_slide,
0a7de745 1864 (unsigned long)kmod_info->address);
316670eb 1865 #endif
0a7de745
A
1866 }
1867
1868 anInfoDict->removeObject(kPrelinkKmodInfoKey);
1869 }
1870
1871 if ((addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject("ModuleIndex")))) {
1872 uintptr_t builtinTextStart;
1873 uintptr_t builtinTextEnd;
1874
1875 flags.builtin = true;
1876 builtinKmodIdx = addressNum->unsigned32BitValue();
1877 assert(builtinKmodIdx < gBuiltinKmodsCount);
1878
1879 builtinTextStart = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx];
1880 builtinTextEnd = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx + 1];
1881
1882 kmod_info = ((kmod_info_t **)gBuiltinKmodsSectionInfo->addr)[builtinKmodIdx];
1883 kmod_info->address = builtinTextStart;
1884 kmod_info->size = builtinTextEnd - builtinTextStart;
1885 }
1886
1887 /* If the plist has a UUID for an interface, save that off.
1888 */
1889 if (isInterface()) {
f427ee49
A
1890 interfaceUUID.reset(OSDynamicCast(OSData,
1891 anInfoDict->getObject(kPrelinkInterfaceUUIDKey)), OSRetain);
0a7de745 1892 if (interfaceUUID) {
0a7de745
A
1893 anInfoDict->removeObject(kPrelinkInterfaceUUIDKey);
1894 }
1895 }
1896
f427ee49
A
1897 result = (kOSReturnSuccess == slidePrelinkedExecutable(doCoalescedSlides));
1898 if (!result) {
0a7de745
A
1899 goto finish;
1900 }
1901
f427ee49
A
1902 kc_type = type;
1903 /* Exclude builtin and codeless kexts */
1904 if (prelinkedExecutable && kmod_info) {
1905 switch (kc_type) {
1906 case KCKindPrimary:
1907 shouldSaveSegments = (
1908 getPropertyForHostArch(kOSMutableSegmentCopy) == kOSBooleanTrue ||
1909 getPropertyForHostArch(kOSBundleAllowUserLoadKey) == kOSBooleanTrue);
1910 if (shouldSaveSegments) {
1911 flags.resetSegmentsFromImmutableCopy = 1;
c3c9b80d
A
1912 } else {
1913 flags.unloadUnsupported = 1;
f427ee49
A
1914 }
1915 break;
1916 case KCKindPageable:
1917 flags.resetSegmentsFromVnode = 1;
1918 break;
1919 case KCKindAuxiliary:
1920 if (!pageableKCloaded) {
1921 flags.resetSegmentsFromImmutableCopy = 1;
1922 } else if (resetAuxKCSegmentOnUnload) {
1923 flags.resetSegmentsFromVnode = 1;
c3c9b80d
A
1924 } else {
1925 flags.unloadUnsupported = 1;
f427ee49
A
1926 }
1927 break;
1928 default:
1929 break;
1930 }
1931 }
1932
1933 if (flags.resetSegmentsFromImmutableCopy) {
1934 /* Save a pristine copy of the mutable segments */
1935 kernel_segment_command_t *seg = NULL;
1936 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
1937
1938 savedMutableSegments = OSArray::withCapacity(0);
1939
1940 for (seg = firstsegfromheader(k_mh); seg; seg = nextsegfromheader(k_mh, seg)) {
1941 if (!segmentIsMutable(seg)) {
1942 continue;
1943 }
1944 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
1945 uint64_t vmsize = seg->vmsize;
1946 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
1947 "Saving kext %s mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
1948 OSSharedPtr<OSKextSavedMutableSegment> savedSegment = OSKextSavedMutableSegment::withSegment(seg);
1949 if (!savedSegment) {
1950 OSKextLog(this,
1951 kOSKextLogErrorLevel |
1952 kOSKextLogGeneralFlag,
1953 "Kext %s failed to save mutable segment %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
1954 result = kOSKextReturnInternalError;
1955 goto finish;
1956 }
1957 savedMutableSegments->setObject(savedSegment);
1958 }
1959 }
1960
1961 if (doCoalescedSlides == false && !flags.resetSegmentsFromVnode) {
1962 /*
1963 * set VM protections now, wire pages for the old style Aux KC now,
1964 * wire pages for the rest of the KC types at load time.
1965 */
1966 result = (kOSReturnSuccess == setVMAttributes(true, (type == KCKindAuxiliary) ? true : false));
1967 if (!result) {
0a7de745
A
1968 goto finish;
1969 }
1970 }
1971
1972 flags.prelinked = true;
1973
1974 /* If we created a kext from prelink info,
1975 * we must be booting from a prelinked kernel.
1976 */
1977 sPrelinkBoot = true;
1978
1979 result = registerIdentifier();
b0d623f7
A
1980
1981finish:
f427ee49
A
1982 return result;
1983}
1984
1985/*********************************************************************
1986*********************************************************************/
1987/* static */
1988OSSharedPtr<OSKext>
1989OSKext::withCodelessInfo(OSDictionary * anInfoDict)
1990{
1991 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
1992
1993 if (newKext && !newKext->initWithCodelessInfo(anInfoDict)) {
1994 return NULL;
1995 }
1996
1997 return newKext;
1998}
1999
2000/*********************************************************************
2001*********************************************************************/
2002bool
2003OSKext::initWithCodelessInfo(OSDictionary * anInfoDict)
2004{
2005 bool result = false;
2006 OSString * kextPath = NULL; // do not release
2007 OSBoolean * scratchBool = NULL; // do not release
2008
2009 if (anInfoDict == NULL || !super::init()) {
2010 goto finish;
2011 }
2012
2013 /*
2014 * Get the path. Don't look for an arch-specific path property.
2015 */
2016 kextPath = OSDynamicCast(OSString,
2017 anInfoDict->getObject(kKextRequestArgumentCodelessInfoBundlePathKey));
2018 if (!kextPath) {
2019 OSKextLog(NULL,
2020 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2021 "Requested codeless kext dictionary does not contain the '%s' key",
2022 kKextRequestArgumentCodelessInfoBundlePathKey);
2023 goto finish;
2024 }
2025
2026 uniquePersonalityProperties(anInfoDict);
2027
2028 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
2029 goto finish;
2030 }
2031
2032 /*
2033 * This path is meant to initialize codeless kexts only. Refuse
2034 * anything that looks like it has an executable and/or declares
2035 * itself as a kernel component.
2036 */
2037 if (declaresExecutable() || isKernelComponent()) {
2038 OSKextLog(NULL,
2039 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2040 "Refusing to register codeless kext that declares an executable/kernel component: %s",
2041 getIdentifierCString());
2042 goto finish;
2043 }
2044
2045 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
2046 boolean_t updated = updateExcludeList(infoDict.get());
2047 if (updated) {
2048 OSKextLog(this,
2049 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2050 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
2051 }
2052 }
2053
2054 kc_type = KCKindNone;
2055
2056 scratchBool = OSDynamicCast(OSBoolean,
2057 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
2058 if (scratchBool == kOSBooleanTrue) {
2059 flags.requireExplicitLoad = 1;
2060 }
2061
2062 /* Also get the executable's bundle-relative path if present.
2063 * Don't look for an arch-specific path property.
2064 */
2065 userExecutableRelPath.reset(OSDynamicCast(OSString,
2066 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
2067
2068 /* remove unnecessary paths from the info dict */
2069 anInfoDict->removeObject(kKextRequestArgumentCodelessInfoBundlePathKey);
b0d623f7 2070
f427ee49
A
2071 result = registerIdentifier();
2072
2073finish:
0a7de745 2074 return result;
b0d623f7 2075}
39037602
A
2076
2077/*********************************************************************
0a7de745 2078*********************************************************************/
39037602 2079/* static */
0a7de745
A
2080void
2081OSKext::setAllVMAttributes(void)
2082{
f427ee49
A
2083 OSSharedPtr<OSCollectionIterator> kextIterator;
2084 const OSSymbol * thisID = NULL; // do not release
0a7de745
A
2085
2086 IORecursiveLockLock(sKextLock);
2087
f427ee49 2088 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
0a7de745
A
2089 if (!kextIterator) {
2090 goto finish;
2091 }
2092
2093 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
f427ee49 2094 OSKext * thisKext; // do not release
0a7de745
A
2095
2096 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
2097 if (!thisKext || thisKext->isInterface() || !thisKext->declaresExecutable()) {
2098 continue;
2099 }
2100
f427ee49
A
2101 if (!thisKext->flags.resetSegmentsFromVnode) {
2102 /*
2103 * set VM protections now, wire pages for the old style Aux KC now,
2104 * wire pages for the rest of the KC types at load time.
2105 */
2106 thisKext->setVMAttributes(true, (thisKext->kc_type == KCKindAuxiliary) ? true : false);
2107 }
0a7de745
A
2108 }
2109
39037602 2110finish:
0a7de745 2111 IORecursiveLockUnlock(sKextLock);
39037602 2112
0a7de745 2113 return;
39037602
A
2114}
2115
b0d623f7
A
2116/*********************************************************************
2117*********************************************************************/
f427ee49 2118OSSharedPtr<OSKext>
b0d623f7 2119OSKext::withBooterData(
0a7de745
A
2120 OSString * deviceTreeName,
2121 OSData * booterData)
b0d623f7 2122{
f427ee49 2123 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
0a7de745
A
2124
2125 if (newKext && !newKext->initWithBooterData(deviceTreeName, booterData)) {
0a7de745
A
2126 return NULL;
2127 }
b0d623f7 2128
0a7de745 2129 return newKext;
b0d623f7
A
2130}
2131
2132/*********************************************************************
2133*********************************************************************/
2134typedef struct _BooterKextFileInfo {
0a7de745
A
2135 uint32_t infoDictPhysAddr;
2136 uint32_t infoDictLength;
2137 uint32_t executablePhysAddr;
2138 uint32_t executableLength;
2139 uint32_t bundlePathPhysAddr;
2140 uint32_t bundlePathLength;
b0d623f7
A
2141} _BooterKextFileInfo;
2142
2143bool
2144OSKext::initWithBooterData(
0a7de745
A
2145 OSString * deviceTreeName,
2146 OSData * booterData)
2147{
2148 bool result = false;
f427ee49
A
2149 _BooterKextFileInfo * kextFileInfo = NULL; // do not free
2150 char * infoDictAddr = NULL; // do not free
2151 void * executableAddr = NULL; // do not free
2152 char * bundlePathAddr = NULL; // do not free
2153
2154 OSDictionary * theInfoDict = NULL; // do not release
2155 OSSharedPtr<OSObject> parsedXML;
2156 OSSharedPtr<OSString> kextPath;
0a7de745 2157
f427ee49
A
2158 OSSharedPtr<OSString> errorString;
2159 OSSharedPtr<OSData> executable;
0a7de745
A
2160
2161 if (!super::init()) {
2162 goto finish;
2163 }
2164
2165 kextFileInfo = (_BooterKextFileInfo *)booterData->getBytesNoCopy();
2166 if (!kextFileInfo) {
2167 OSKextLog(this,
2168 kOSKextLogErrorLevel |
2169 kOSKextLogGeneralFlag,
2170 "No booter-provided data for kext device tree entry %s.",
2171 deviceTreeName->getCStringNoCopy());
2172 goto finish;
2173 }
2174
2175 /* The info plist must exist or we can't read the kext.
2176 */
2177 if (!kextFileInfo->infoDictPhysAddr || !kextFileInfo->infoDictLength) {
2178 OSKextLog(this,
2179 kOSKextLogErrorLevel |
2180 kOSKextLogGeneralFlag,
2181 "No kext info dictionary for booter device tree entry %s.",
2182 deviceTreeName->getCStringNoCopy());
2183 goto finish;
2184 }
2185
2186 infoDictAddr = (char *)ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
2187 if (!infoDictAddr) {
2188 OSKextLog(this,
2189 kOSKextLogErrorLevel |
2190 kOSKextLogGeneralFlag,
2191 "Can't translate physical address 0x%x of kext info dictionary "
2192 "for device tree entry %s.",
2193 (int)kextFileInfo->infoDictPhysAddr,
2194 deviceTreeName->getCStringNoCopy());
2195 goto finish;
2196 }
2197
f427ee49 2198 parsedXML = OSUnserializeXML(infoDictAddr, errorString);
0a7de745 2199 if (parsedXML) {
f427ee49 2200 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
0a7de745
A
2201 }
2202 if (!theInfoDict) {
2203 const char * errorCString = "(unknown error)";
2204
2205 if (errorString && errorString->getCStringNoCopy()) {
2206 errorCString = errorString->getCStringNoCopy();
2207 } else if (parsedXML) {
2208 errorCString = "not a dictionary";
2209 }
2210 OSKextLog(this,
2211 kOSKextLogErrorLevel |
2212 kOSKextLogGeneralFlag,
2213 "Error unserializing info dictionary for device tree entry %s: %s.",
2214 deviceTreeName->getCStringNoCopy(), errorCString);
2215 goto finish;
2216 }
2217
2218 /* A bundle path is not mandatory.
2219 */
2220 if (kextFileInfo->bundlePathPhysAddr && kextFileInfo->bundlePathLength) {
2221 bundlePathAddr = (char *)ml_static_ptovirt(kextFileInfo->bundlePathPhysAddr);
2222 if (!bundlePathAddr) {
2223 OSKextLog(this,
2224 kOSKextLogErrorLevel |
2225 kOSKextLogGeneralFlag,
2226 "Can't translate physical address 0x%x of kext bundle path "
2227 "for device tree entry %s.",
2228 (int)kextFileInfo->bundlePathPhysAddr,
2229 deviceTreeName->getCStringNoCopy());
2230 goto finish;
2231 }
f427ee49 2232 bundlePathAddr[kextFileInfo->bundlePathLength - 1] = '\0'; // just in case!
0a7de745
A
2233
2234 kextPath = OSString::withCString(bundlePathAddr);
2235 if (!kextPath) {
2236 OSKextLog(this,
2237 kOSKextLogErrorLevel |
2238 kOSKextLogGeneralFlag,
2239 "Failed to create wrapper for device tree entry %s kext path %s.",
2240 deviceTreeName->getCStringNoCopy(), bundlePathAddr);
2241 goto finish;
2242 }
2243 }
2244
f427ee49 2245 if (!setInfoDictionaryAndPath(theInfoDict, kextPath.get())) {
0a7de745
A
2246 goto finish;
2247 }
2248
2249 /* An executable is not mandatory.
2250 */
2251 if (kextFileInfo->executablePhysAddr && kextFileInfo->executableLength) {
2252 executableAddr = (void *)ml_static_ptovirt(kextFileInfo->executablePhysAddr);
2253 if (!executableAddr) {
2254 OSKextLog(this,
2255 kOSKextLogErrorLevel |
2256 kOSKextLogGeneralFlag,
2257 "Can't translate physical address 0x%x of kext executable "
2258 "for device tree entry %s.",
2259 (int)kextFileInfo->executablePhysAddr,
2260 deviceTreeName->getCStringNoCopy());
2261 goto finish;
2262 }
2263
2264 executable = OSData::withBytesNoCopy(executableAddr,
2265 kextFileInfo->executableLength);
2266 if (!executable) {
2267 OSKextLog(this,
2268 kOSKextLogErrorLevel |
2269 kOSKextLogGeneralFlag,
2270 "Failed to create executable wrapper for device tree entry %s.",
2271 deviceTreeName->getCStringNoCopy());
2272 goto finish;
2273 }
2274
2275 /* A kext with an executable needs to retain the whole booterData
2276 * object to keep the executable in memory.
2277 */
f427ee49 2278 if (!setExecutable(executable.get(), booterData)) {
0a7de745
A
2279 OSKextLog(this,
2280 kOSKextLogErrorLevel |
2281 kOSKextLogGeneralFlag,
2282 "Failed to set kext executable for device tree entry %s.",
2283 deviceTreeName->getCStringNoCopy());
2284 goto finish;
2285 }
2286 }
2287
2288 result = registerIdentifier();
b0d623f7
A
2289
2290finish:
0a7de745 2291 return result;
b0d623f7
A
2292}
2293
2294/*********************************************************************
2295*********************************************************************/
2296bool
2297OSKext::registerIdentifier(void)
2298{
0a7de745 2299 bool result = false;
f427ee49 2300 OSKext * existingKext = NULL; // do not release
0a7de745
A
2301 bool existingIsLoaded = false;
2302 bool existingIsPrelinked = false;
f427ee49
A
2303 bool existingIsCodeless = false;
2304 bool existingIsDext = false;
0a7de745
A
2305 OSKextVersion newVersion = -1;
2306 OSKextVersion existingVersion = -1;
2307 char newVersionCString[kOSKextVersionMaxLength];
2308 char existingVersionCString[kOSKextVersionMaxLength];
f427ee49
A
2309 OSSharedPtr<OSData> newUUID;
2310 OSSharedPtr<OSData> existingUUID;
0a7de745
A
2311
2312 IORecursiveLockLock(sKextLock);
2313
2314 /* Get the new kext's version for checks & log messages.
2315 */
2316 newVersion = getVersion();
2317 OSKextVersionGetString(newVersion, newVersionCString,
2318 kOSKextVersionMaxLength);
2319
2320 /* If we don't have an existing kext with this identifier,
2321 * just record the new kext and we're done!
2322 */
f427ee49 2323 existingKext = OSDynamicCast(OSKext, sKextsByID->getObject(bundleID.get()));
0a7de745 2324 if (!existingKext) {
f427ee49 2325 sKextsByID->setObject(bundleID.get(), this);
0a7de745
A
2326 result = true;
2327 goto finish;
2328 }
2329
2330 /* Get the existing kext's version for checks & log messages.
2331 */
2332 existingVersion = existingKext->getVersion();
2333 OSKextVersionGetString(existingVersion,
2334 existingVersionCString, kOSKextVersionMaxLength);
2335
2336 existingIsLoaded = existingKext->isLoaded();
2337 existingIsPrelinked = existingKext->isPrelinked();
f427ee49
A
2338 existingIsDext = existingKext->isDriverKit();
2339 existingIsCodeless = !existingKext->declaresExecutable() && !existingIsDext;
0a7de745 2340
f427ee49
A
2341 /* If we have a non-codeless kext with this identifier that's already
2342 * loaded/prelinked, we can't use the new one, but let's be really
2343 * thorough and check how the two are related for a precise diagnostic
2344 * log message.
0a7de745 2345 *
f427ee49
A
2346 * This check is valid for kexts that declare an executable and for
2347 * dexts, but not for codeless kexts - we can just replace those.
0a7de745 2348 */
f427ee49
A
2349 if ((!existingIsCodeless || existingIsDext) &&
2350 (existingIsLoaded || existingIsPrelinked)) {
0a7de745 2351 bool sameVersion = (newVersion == existingVersion);
f427ee49 2352 bool sameExecutable = true; // assume true unless we have UUIDs
0a7de745
A
2353
2354 /* Only get the UUID if the existing kext is loaded. Doing so
2355 * might have to uncompress an mkext executable and we shouldn't
2356 * take that hit when neither kext is loaded.
f427ee49
A
2357 *
2358 * Note: there is no decompression that happens when all kexts
2359 * are loaded from kext collecitons.
0a7de745
A
2360 */
2361 newUUID = copyUUID();
2362 existingUUID = existingKext->copyUUID();
2363
f427ee49
A
2364 if (existingIsDext && !isDriverKit()) {
2365 OSKextLog(this,
2366 kOSKextLogWarningLevel |
2367 kOSKextLogKextBookkeepingFlag,
2368 "Notice - new kext %s, v%s matches a %s dext"
2369 "with the same bundle ID, v%s.",
2370 getIdentifierCString(), newVersionCString,
2371 (existingIsLoaded ? "loaded" : "prelinked"),
2372 existingVersionCString);
2373 goto finish;
2374 }
2375
0a7de745
A
2376 /* I'm entirely too paranoid about checking equivalence of executables,
2377 * but I remember nasty problems with it in the past.
2378 *
2379 * - If we have UUIDs for both kexts, compare them.
2380 * - If only one kext has a UUID, they're definitely different.
2381 */
2382 if (newUUID && existingUUID) {
f427ee49 2383 sameExecutable = newUUID->isEqualTo(existingUUID.get());
0a7de745
A
2384 } else if (newUUID || existingUUID) {
2385 sameExecutable = false;
2386 }
2387
2388 if (!newUUID && !existingUUID) {
2389 /* If there are no UUIDs, we can't really tell that the executables
2390 * are *different* without a lot of work; the loaded kext's
2391 * unrelocated executable is no longer around (and we never had it
2392 * in-kernel for a prelinked kext). We certainly don't want to do
2393 * a whole fake link for the new kext just to compare, either.
2394 */
0a7de745
A
2395 OSKextLog(this,
2396 kOSKextLogWarningLevel |
2397 kOSKextLogKextBookkeepingFlag,
2398 "Notice - new kext %s, v%s matches %s kext "
2399 "but can't determine if executables are the same (no UUIDs).",
2400 getIdentifierCString(),
2401 newVersionCString,
2402 (existingIsLoaded ? "loaded" : "prelinked"));
2403 }
2404
2405 if (sameVersion && sameExecutable) {
2406 OSKextLog(this,
2407 (existingIsLoaded ? kOSKextLogWarningLevel : kOSKextLogStepLevel) |
2408 kOSKextLogKextBookkeepingFlag,
2409 "Refusing new kext %s, v%s: a %s copy is already present "
2410 "(same version and executable).",
2411 getIdentifierCString(), newVersionCString,
2412 (existingIsLoaded ? "loaded" : "prelinked"));
2413 } else {
2414 if (!sameVersion) {
2415 /* This condition is significant so log it under warnings.
2416 */
2417 OSKextLog(this,
2418 kOSKextLogWarningLevel |
2419 kOSKextLogKextBookkeepingFlag,
2420 "Refusing new kext %s, v%s: already have %s v%s.",
2421 getIdentifierCString(),
2422 newVersionCString,
2423 (existingIsLoaded ? "loaded" : "prelinked"),
2424 existingVersionCString);
2425 } else {
2426 /* This condition is significant so log it under warnings.
2427 */
2428 OSKextLog(this,
2429 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2430 "Refusing new kext %s, v%s: a %s copy with a different "
2431 "executable UUID is already present.",
2432 getIdentifierCString(), newVersionCString,
2433 (existingIsLoaded ? "loaded" : "prelinked"));
2434 }
2435 }
2436 goto finish;
f427ee49
A
2437 } /* if ((!existingIsCodeless || existingIsDext) && (existingIsLoaded || existingIsPrelinked)) */
2438
2439 /* Refuse to allow an existing loaded codeless kext be replaced by a
2440 * normal kext with the same bundle ID.
2441 */
2442 if (existingIsCodeless && declaresExecutable()) {
2443 OSKextLog(this,
2444 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2445 "Refusing new kext %s, v%s: a codeless copy is already %s",
2446 getIdentifierCString(), newVersionCString,
2447 (existingIsLoaded ? "loaded" : "prelinked"));
2448 goto finish;
2449 }
2450
2451 /* Dexts packaged in the BootKC will be protected against replacement
2452 * by non-dexts by the logic above which checks if they are prelinked.
2453 * Dexts which are prelinked into the System KC will be registered
2454 * before any other kexts in the AuxKC are registered, and we never
2455 * put dexts in the AuxKC. Therefore, there is no need to check if an
2456 * existing object is a dext and is being replaced by a non-dext.
2457 * The scenario cannot happen by construction.
2458 *
2459 * See: OSKext::loadFileSetKexts()
2460 */
0a7de745
A
2461
2462 /* We have two nonloaded/nonprelinked kexts, so our decision depends on whether
2463 * user loads are happening or if we're still in early boot. User agents are
2464 * supposed to resolve dependencies topside and include only the exact
2465 * kexts needed; so we always accept the new kext (in fact we should never
2466 * see an older unloaded copy hanging around).
2467 */
2468 if (sUserLoadsActive) {
f427ee49 2469 sKextsByID->setObject(bundleID.get(), this);
0a7de745
A
2470 result = true;
2471
2472 OSKextLog(this,
2473 kOSKextLogStepLevel |
2474 kOSKextLogKextBookkeepingFlag,
2475 "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
2476 getIdentifierCString(),
2477 existingVersionCString,
2478 newVersionCString);
2479
2480 goto finish;
2481 }
2482
2483 /* During early boot, the kext with the highest version always wins out.
2484 * Prelinked kernels will never hit this, but mkexts and booter-read
2485 * kexts might have duplicates.
2486 */
2487 if (newVersion > existingVersion) {
f427ee49 2488 sKextsByID->setObject(bundleID.get(), this);
0a7de745
A
2489 result = true;
2490
2491 OSKextLog(this,
2492 kOSKextLogStepLevel |
2493 kOSKextLogKextBookkeepingFlag,
2494 "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
2495 existingVersionCString,
2496 getIdentifierCString(),
2497 newVersionCString);
2498 } else {
2499 OSKextLog(this,
2500 kOSKextLogStepLevel |
2501 kOSKextLogKextBookkeepingFlag,
2502 "Kext %s is already registered with a higher/same version (v%s); "
2503 "dropping newly-added (v%s).",
2504 getIdentifierCString(),
2505 existingVersionCString,
2506 newVersionCString);
2507 }
2508
2509 /* result has been set appropriately by now. */
b0d623f7
A
2510
2511finish:
2512
0a7de745 2513 IORecursiveLockUnlock(sKextLock);
6d2010ae 2514
0a7de745
A
2515 if (result) {
2516 OSKextLog(this,
2517 kOSKextLogStepLevel |
2518 kOSKextLogKextBookkeepingFlag,
2519 "Kext %s, v%s registered and available for loading.",
2520 getIdentifierCString(), newVersionCString);
2521 }
b0d623f7 2522
0a7de745 2523 return result;
b0d623f7
A
2524}
2525
2526/*********************************************************************
0a7de745
A
2527 * Does the bare minimum validation to look up a kext.
2528 * All other validation is done on the spot as needed.
2529 **********************************************************************/
b0d623f7
A
2530bool
2531OSKext::setInfoDictionaryAndPath(
0a7de745
A
2532 OSDictionary * aDictionary,
2533 OSString * aPath)
2534{
2535 bool result = false;
f427ee49
A
2536 OSString * bundleIDString = NULL; // do not release
2537 OSString * versionString = NULL; // do not release
2538 OSString * compatibleVersionString = NULL; // do not release
2539 const char * versionCString = NULL; // do not free
2540 const char * compatibleVersionCString = NULL; // do not free
2541 OSBoolean * scratchBool = NULL; // do not release
2542 OSDictionary * scratchDict = NULL; // do not release
0a7de745
A
2543
2544 if (infoDict) {
2545 panic("Attempt to set info dictionary on a kext "
2546 "that already has one (%s).",
2547 getIdentifierCString());
2548 }
2549
2550 if (!aDictionary || !OSDynamicCast(OSDictionary, aDictionary)) {
2551 goto finish;
2552 }
2553
f427ee49 2554 infoDict.reset(aDictionary, OSRetain);
0a7de745
A
2555
2556 /* Check right away if the info dictionary has any log flags.
2557 */
2558 scratchBool = OSDynamicCast(OSBoolean,
2559 getPropertyForHostArch(kOSBundleEnableKextLoggingKey));
2560 if (scratchBool == kOSBooleanTrue) {
2561 flags.loggingEnabled = 1;
2562 }
2563
2564 /* The very next thing to get is the bundle identifier. Unlike
2565 * in user space, a kext with no bundle identifier gets axed
2566 * immediately.
2567 */
2568 bundleIDString = OSDynamicCast(OSString,
2569 getPropertyForHostArch(kCFBundleIdentifierKey));
2570 if (!bundleIDString) {
2571 OSKextLog(this,
2572 kOSKextLogErrorLevel |
2573 kOSKextLogValidationFlag,
2574 "CFBundleIdentifier missing/invalid type in kext %s.",
2575 aPath ? aPath->getCStringNoCopy() : "(unknown)");
2576 goto finish;
2577 }
2578 bundleID = OSSymbol::withString(bundleIDString);
2579 if (!bundleID) {
2580 OSKextLog(this,
2581 kOSKextLogErrorLevel |
2582 kOSKextLogValidationFlag,
2583 "Can't copy bundle identifier as symbol for kext %s.",
2584 bundleIDString->getCStringNoCopy());
2585 goto finish;
2586 }
2587
2588 /* Save the path if we got one (it should always be available but it's
2589 * just something nice to have for bookkeeping).
2590 */
2591 if (aPath) {
f427ee49 2592 path.reset(aPath, OSRetain);
0a7de745
A
2593 }
2594
2595 /*****
2596 * Minimal validation to initialize. We'll do other validation on the spot.
2597 */
2598 if (bundleID->getLength() >= KMOD_MAX_NAME) {
2599 OSKextLog(this,
2600 kOSKextLogErrorLevel |
2601 kOSKextLogValidationFlag,
2602 "Kext %s error - CFBundleIdentifier over max length %d.",
2603 getIdentifierCString(), KMOD_MAX_NAME - 1);
2604 goto finish;
2605 }
2606
2607 version = compatibleVersion = -1;
2608
2609 versionString = OSDynamicCast(OSString,
2610 getPropertyForHostArch(kCFBundleVersionKey));
2611 if (!versionString) {
2612 OSKextLog(this,
2613 kOSKextLogErrorLevel |
2614 kOSKextLogValidationFlag,
2615 "Kext %s error - CFBundleVersion missing/invalid type.",
2616 getIdentifierCString());
2617 goto finish;
2618 }
2619 versionCString = versionString->getCStringNoCopy();
2620 version = OSKextParseVersionString(versionCString);
2621 if (version < 0) {
2622 OSKextLog(this,
2623 kOSKextLogErrorLevel |
2624 kOSKextLogValidationFlag,
2625 "Kext %s error - CFBundleVersion bad value '%s'.",
2626 getIdentifierCString(), versionCString);
2627 goto finish;
2628 }
2629
f427ee49 2630 compatibleVersion = -1; // set to illegal value for kexts that don't have
0a7de745
A
2631
2632 compatibleVersionString = OSDynamicCast(OSString,
2633 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
2634 if (compatibleVersionString) {
2635 compatibleVersionCString = compatibleVersionString->getCStringNoCopy();
2636 compatibleVersion = OSKextParseVersionString(compatibleVersionCString);
2637 if (compatibleVersion < 0) {
2638 OSKextLog(this,
2639 kOSKextLogErrorLevel |
2640 kOSKextLogValidationFlag,
2641 "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
2642 getIdentifierCString(), compatibleVersionCString);
2643 goto finish;
2644 }
2645
2646 if (compatibleVersion > version) {
2647 OSKextLog(this,
2648 kOSKextLogErrorLevel |
2649 kOSKextLogValidationFlag,
2650 "Kext %s error - %s %s > %s %s (must be <=).",
2651 getIdentifierCString(),
2652 kOSBundleCompatibleVersionKey, compatibleVersionCString,
2653 kCFBundleVersionKey, versionCString);
2654 goto finish;
2655 }
2656 }
2657
2658 /* Check to see if this kext is in exclude list */
2659 if (isInExcludeList()) {
2660 OSKextLog(this,
2661 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2662 "Kext %s is in exclude list, not loadable",
2663 getIdentifierCString());
2664 goto finish;
2665 }
2666
2667 /* Set flags for later use if the infoDict gets flushed. We only
2668 * check for true values, not false ones(!)
2669 */
2670 scratchBool = OSDynamicCast(OSBoolean,
2671 getPropertyForHostArch(kOSBundleIsInterfaceKey));
2672 if (scratchBool == kOSBooleanTrue) {
2673 flags.interface = 1;
2674 }
2675
2676 scratchBool = OSDynamicCast(OSBoolean,
2677 getPropertyForHostArch(kOSKernelResourceKey));
2678 if (scratchBool == kOSBooleanTrue) {
2679 flags.kernelComponent = 1;
f427ee49 2680 flags.interface = 1; // xxx - hm. the kernel itself isn't an interface...
0a7de745
A
2681 flags.started = 1;
2682
2683 /* A kernel component has one implicit dependency on the kernel.
2684 */
2685 flags.hasAllDependencies = 1;
2686 }
2687
2688 /* Make sure common string values in personalities are uniqued to OSSymbols.
2689 */
2690 scratchDict = OSDynamicCast(OSDictionary,
2691 getPropertyForHostArch(kIOKitPersonalitiesKey));
2692 if (scratchDict) {
2693 uniquePersonalityProperties(scratchDict);
2694 }
2695
2696 result = true;
b0d623f7
A
2697
2698finish:
2699
0a7de745 2700 return result;
b0d623f7
A
2701}
2702
2703/*********************************************************************
2704* Not used for prelinked kernel boot as there is no unrelocated
2705* executable.
2706*********************************************************************/
2707bool
2708OSKext::setExecutable(
0a7de745
A
2709 OSData * anExecutable,
2710 OSData * externalData,
2711 bool externalDataIsMkext)
2712{
2713 bool result = false;
f427ee49 2714 const char * executableKey = NULL; // do not free
0a7de745
A
2715
2716 if (!anExecutable) {
2717 infoDict->removeObject(_kOSKextExecutableKey);
2718 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
2719 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
2720 result = true;
2721 goto finish;
2722 }
b0d623f7 2723
0a7de745
A
2724 if (infoDict->getObject(_kOSKextExecutableKey) ||
2725 infoDict->getObject(_kOSKextMkextExecutableReferenceKey)) {
2726 panic("Attempt to set an executable on a kext "
2727 "that already has one (%s).",
2728 getIdentifierCString());
2729 goto finish;
2730 }
b0d623f7 2731
0a7de745
A
2732 if (externalDataIsMkext) {
2733 executableKey = _kOSKextMkextExecutableReferenceKey;
2734 } else {
2735 executableKey = _kOSKextExecutableKey;
2736 }
2737
2738 if (anExecutable) {
2739 infoDict->setObject(executableKey, anExecutable);
2740 if (externalData) {
2741 infoDict->setObject(_kOSKextExecutableExternalDataKey, externalData);
2742 }
2743 }
2744
2745 result = true;
2746
2747finish:
2748 return result;
2749}
2750
2751/*********************************************************************
2752*********************************************************************/
6d2010ae
A
2753static void
2754uniqueStringPlistProperty(OSDictionary * dict, const char * key)
2755{
f427ee49
A
2756 OSObject * value = NULL; // do not release
2757 OSString * stringValue = NULL; // do not release
2758 OSSharedPtr<const OSSymbol> symbolValue;
2759
2760 value = dict->getObject(key);
2761 if (!value) {
2762 goto finish;
2763 }
2764 if (OSDynamicCast(OSSymbol, value)) {
2765 /* this is already an OSSymbol: we're good */
2766 goto finish;
2767 }
0a7de745 2768
f427ee49 2769 stringValue = OSDynamicCast(OSString, value);
0a7de745
A
2770 if (!stringValue) {
2771 goto finish;
2772 }
2773
2774 symbolValue = OSSymbol::withString(stringValue);
2775 if (!symbolValue) {
2776 goto finish;
2777 }
2778
f427ee49 2779 dict->setObject(key, symbolValue.get());
0a7de745 2780
6d2010ae 2781finish:
0a7de745 2782 return;
6d2010ae
A
2783}
2784
2785/*********************************************************************
2786*********************************************************************/
2787static void
2788uniqueStringPlistProperty(OSDictionary * dict, const OSString * key)
2789{
f427ee49
A
2790 OSObject * value = NULL; // do not release
2791 OSString * stringValue = NULL; // do not release
2792 OSSharedPtr<const OSSymbol> symbolValue;
0a7de745 2793
f427ee49
A
2794 value = dict->getObject(key);
2795 if (!value) {
0a7de745
A
2796 goto finish;
2797 }
f427ee49
A
2798 if (OSDynamicCast(OSSymbol, value)) {
2799 /* this is already an OSSymbol: we're good */
0a7de745
A
2800 goto finish;
2801 }
2802
f427ee49
A
2803 stringValue = OSDynamicCast(OSString, value);
2804 if (!stringValue) {
2805 goto finish;
2806 }
0a7de745 2807
f427ee49
A
2808 symbolValue = OSSymbol::withString(stringValue);
2809 if (!symbolValue) {
2810 goto finish;
0a7de745 2811 }
6d2010ae 2812
f427ee49
A
2813 dict->setObject(key, symbolValue.get());
2814
2815finish:
0a7de745 2816 return;
6d2010ae
A
2817}
2818
f427ee49
A
2819void
2820OSKext::uniquePersonalityProperties(OSDictionary * personalityDict)
2821{
2822 OSKext::uniquePersonalityProperties(personalityDict, true);
2823}
2824
6d2010ae
A
2825/*********************************************************************
2826* Replace common personality property values with uniqued instances
2827* to save on wired memory.
2828*********************************************************************/
2829/* static */
2830void
f427ee49 2831OSKext::uniquePersonalityProperties(OSDictionary * personalityDict, bool defaultAddKernelBundleIdentifier)
6d2010ae 2832{
0a7de745
A
2833 /* Properties every personality has.
2834 */
2835 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKey);
2836 uniqueStringPlistProperty(personalityDict, kIOProviderClassKey);
f427ee49 2837 uniqueStringPlistProperty(personalityDict, gIOClassKey.get());
cb323159
A
2838 if (personalityDict->getObject(kCFBundleIdentifierKernelKey)) {
2839 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKernelKey);
f427ee49 2840 } else if (defaultAddKernelBundleIdentifier) {
cb323159
A
2841 personalityDict->setObject(kCFBundleIdentifierKernelKey, personalityDict->getObject(kCFBundleIdentifierKey));
2842 }
0a7de745
A
2843
2844 /* Other commonly used properties.
2845 */
2846 uniqueStringPlistProperty(personalityDict, gIOMatchCategoryKey);
2847 uniqueStringPlistProperty(personalityDict, gIOResourceMatchKey);
2848 uniqueStringPlistProperty(personalityDict, gIOUserClientClassKey);
2849
2850 uniqueStringPlistProperty(personalityDict, "HIDDefaultBehavior");
2851 uniqueStringPlistProperty(personalityDict, "HIDPointerAccelerationType");
2852 uniqueStringPlistProperty(personalityDict, "HIDRemoteControlType");
2853 uniqueStringPlistProperty(personalityDict, "HIDScrollAccelerationType");
2854 uniqueStringPlistProperty(personalityDict, "IOPersonalityPublisher");
2855 uniqueStringPlistProperty(personalityDict, "Physical Interconnect");
2856 uniqueStringPlistProperty(personalityDict, "Physical Interconnect Location");
2857 uniqueStringPlistProperty(personalityDict, "Vendor");
2858 uniqueStringPlistProperty(personalityDict, "Vendor Identification");
2859 uniqueStringPlistProperty(personalityDict, "Vendor Name");
2860 uniqueStringPlistProperty(personalityDict, "bConfigurationValue");
2861 uniqueStringPlistProperty(personalityDict, "bInterfaceNumber");
2862 uniqueStringPlistProperty(personalityDict, "idProduct");
2863
2864 return;
6d2010ae
A
2865}
2866
b0d623f7
A
2867/*********************************************************************
2868*********************************************************************/
2869void
2870OSKext::free(void)
2871{
0a7de745
A
2872 if (isLoaded()) {
2873 panic("Attempt to free loaded kext %s.", getIdentifierCString());
2874 }
b0d623f7 2875
f427ee49
A
2876 infoDict.reset();
2877 bundleID.reset();
2878 path.reset();
2879 executableRelPath.reset();
2880 userExecutableRelPath.reset();
2881 dependencies.reset();
2882 linkedExecutable.reset();
2883 metaClasses.reset();
2884 interfaceUUID.reset();
2885 driverKitUUID.reset();
0a7de745
A
2886
2887 if (isInterface() && kmod_info) {
2888 kfree(kmod_info, sizeof(kmod_info_t));
2889 }
b0d623f7 2890
0a7de745
A
2891 super::free();
2892 return;
b0d623f7
A
2893}
2894
2895#if PRAGMA_MARK
2896#pragma mark Mkext files
2897#endif
f427ee49
A
2898
2899#if CONFIG_KXLD
2900/*
2901 * mkext archives are really only relevant on kxld-enabled kernels.
2902 * Without a dynamic kernel linker, we don't need to support any mkexts.
2903 */
2904
b0d623f7
A
2905/*********************************************************************
2906*********************************************************************/
2907OSReturn
2908OSKext::readMkextArchive(OSData * mkextData,
2909 uint32_t * checksumPtr)
2910{
0a7de745
A
2911 OSReturn result = kOSKextReturnBadData;
2912 uint32_t mkextLength = 0;
f427ee49 2913 mkext_header * mkextHeader = NULL; // do not free
0a7de745
A
2914 uint32_t mkextVersion = 0;
2915
2916 /* Note default return of kOSKextReturnBadData above.
2917 */
2918 mkextLength = mkextData->getLength();
2919 if (mkextLength < sizeof(mkext_basic_header)) {
2920 OSKextLog(/* kext */ NULL,
2921 kOSKextLogErrorLevel |
2922 kOSKextLogArchiveFlag,
2923 "Mkext archive too small to be valid.");
2924 goto finish;
2925 }
2926
2927 mkextHeader = (mkext_header *)mkextData->getBytesNoCopy();
2928
2929 if (MKEXT_GET_MAGIC(mkextHeader) != MKEXT_MAGIC ||
2930 MKEXT_GET_SIGNATURE(mkextHeader) != MKEXT_SIGN) {
2931 OSKextLog(/* kext */ NULL,
2932 kOSKextLogErrorLevel |
2933 kOSKextLogArchiveFlag,
2934 "Mkext archive has invalid magic or signature.");
2935 goto finish;
2936 }
2937
2938 if (MKEXT_GET_LENGTH(mkextHeader) != mkextLength) {
2939 OSKextLog(/* kext */ NULL,
2940 kOSKextLogErrorLevel |
2941 kOSKextLogArchiveFlag,
2942 "Mkext archive recorded length doesn't match actual file length.");
2943 goto finish;
2944 }
2945
2946 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
2947
2948 if (mkextVersion == MKEXT_VERS_2) {
2949 result = OSKext::readMkext2Archive(mkextData, NULL, checksumPtr);
2950 } else {
2951 OSKextLog(/* kext */ NULL,
2952 kOSKextLogErrorLevel |
2953 kOSKextLogArchiveFlag,
2954 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion);
2955 result = kOSKextReturnUnsupported;
2956 }
b0d623f7
A
2957
2958finish:
0a7de745 2959 return result;
b0d623f7
A
2960}
2961
b0d623f7
A
2962/*********************************************************************
2963* Assumes magic, signature, version, length have been checked.
2964* xxx - need to add further bounds checking for each file entry
2965*
2966* Should keep track of all kexts created so far, and if we hit a
2967* fatal error halfway through, remove those kexts. If we've dropped
2968* an older version that had already been read, whoops! Might want to
2969* add a level of buffering?
2970*********************************************************************/
2971/* static */
2972OSReturn
2973OSKext::readMkext2Archive(
0a7de745
A
2974 OSData * mkextData,
2975 OSDictionary ** mkextPlistOut,
2976 uint32_t * checksumPtr)
2977{
2978 OSReturn result = kOSReturnError;
2979 uint32_t mkextLength;
f427ee49
A
2980 mkext2_header * mkextHeader = NULL; // do not free
2981 void * mkextEnd = NULL; // do not free
0a7de745
A
2982 uint32_t mkextVersion;
2983 uint8_t * crc_address = NULL;
f427ee49 2984 size_t crc_buffer_size = 0;
0a7de745
A
2985 uint32_t checksum;
2986 uint32_t mkextPlistOffset;
2987 uint32_t mkextPlistCompressedSize;
f427ee49 2988 char * mkextPlistEnd = NULL; // do not free
0a7de745 2989 uint32_t mkextPlistFullSize;
f427ee49
A
2990 OSSharedPtr<OSString> errorString;
2991 OSSharedPtr<OSData> mkextPlistUncompressedData;
2992 const char * mkextPlistDataBuffer = NULL; // do not free
2993 OSSharedPtr<OSObject> parsedXML;
2994 OSDictionary * mkextPlist = NULL; // do not release
2995 OSArray * mkextInfoDictArray = NULL; // do not release
0a7de745 2996 uint32_t count, i;
f427ee49
A
2997 kc_format_t kc_format;
2998
2999 if (!PE_get_primary_kc_format(&kc_format)) {
3000 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
3001 "Unable to determine primary KC format");
3002 goto finish;
3003 }
0a7de745
A
3004
3005 mkextLength = mkextData->getLength();
3006 mkextHeader = (mkext2_header *)mkextData->getBytesNoCopy();
3007 mkextEnd = (char *)mkextHeader + mkextLength;
3008 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
3009
3010 crc_address = (u_int8_t *)&mkextHeader->version;
f427ee49
A
3011 crc_buffer_size = (uintptr_t)mkextHeader +
3012 MKEXT_GET_LENGTH(mkextHeader) - (uintptr_t)crc_address;
3013 if (crc_buffer_size > INT32_MAX) {
3014 OSKextLog(/* kext */ NULL,
3015 kOSKextLogErrorLevel |
3016 kOSKextLogArchiveFlag,
3017 "Mkext archive size is too large (%lu > INT32_MAX).",
3018 crc_buffer_size);
3019 result = kOSKextReturnBadData;
3020 goto finish;
3021 }
3022 checksum = mkext_adler32(crc_address, (int32_t)crc_buffer_size);
0a7de745
A
3023
3024 if (MKEXT_GET_CHECKSUM(mkextHeader) != checksum) {
3025 OSKextLog(/* kext */ NULL,
3026 kOSKextLogErrorLevel |
3027 kOSKextLogArchiveFlag,
3028 "Mkext archive has bad checksum.");
3029 result = kOSKextReturnBadData;
3030 goto finish;
3031 }
3032
3033 if (checksumPtr) {
3034 *checksumPtr = checksum;
3035 }
3036
3037 /* Check that the CPU type & subtype match that of the running kernel. */
3038 if (MKEXT_GET_CPUTYPE(mkextHeader) == (UInt32)CPU_TYPE_ANY) {
3039 OSKextLog(/* kext */ NULL,
3040 kOSKextLogErrorLevel |
3041 kOSKextLogArchiveFlag,
3042 "Mkext archive must have a specific CPU type.");
3043 result = kOSKextReturnBadData;
3044 goto finish;
3045 } else {
3046 if ((UInt32)_mh_execute_header.cputype !=
3047 MKEXT_GET_CPUTYPE(mkextHeader)) {
3048 OSKextLog(/* kext */ NULL,
3049 kOSKextLogErrorLevel |
3050 kOSKextLogArchiveFlag,
3051 "Mkext archive does not match the running kernel's CPU type.");
3052 result = kOSKextReturnArchNotFound;
3053 goto finish;
3054 }
3055 }
3056
3057 mkextPlistOffset = MKEXT2_GET_PLIST(mkextHeader);
3058 mkextPlistCompressedSize = MKEXT2_GET_PLIST_COMPSIZE(mkextHeader);
3059 mkextPlistEnd = (char *)mkextHeader + mkextPlistOffset +
3060 mkextPlistCompressedSize;
3061 if (mkextPlistEnd > mkextEnd) {
3062 OSKextLog(/* kext */ NULL,
3063 kOSKextLogErrorLevel |
3064 kOSKextLogArchiveFlag,
3065 "Mkext archive file overrun.");
3066 result = kOSKextReturnBadData;
3067 }
3068
3069 mkextPlistFullSize = MKEXT2_GET_PLIST_FULLSIZE(mkextHeader);
3070 if (mkextPlistCompressedSize) {
3071 mkextPlistUncompressedData = sKernelKext->extractMkext2FileData(
3072 (UInt8 *)mkextHeader + mkextPlistOffset,
3073 "plist",
3074 mkextPlistCompressedSize, mkextPlistFullSize);
3075 if (!mkextPlistUncompressedData) {
3076 goto finish;
3077 }
3078 mkextPlistDataBuffer = (const char *)
3079 mkextPlistUncompressedData->getBytesNoCopy();
3080 } else {
3081 mkextPlistDataBuffer = (const char *)mkextHeader + mkextPlistOffset;
3082 }
3083
3084 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
3085 */
f427ee49 3086 parsedXML = OSUnserializeXML(mkextPlistDataBuffer, errorString);
0a7de745 3087 if (parsedXML) {
f427ee49 3088 mkextPlist = OSDynamicCast(OSDictionary, parsedXML.get());
0a7de745
A
3089 }
3090 if (!mkextPlist) {
3091 const char * errorCString = "(unknown error)";
3092
3093 if (errorString && errorString->getCStringNoCopy()) {
3094 errorCString = errorString->getCStringNoCopy();
3095 } else if (parsedXML) {
3096 errorCString = "not a dictionary";
3097 }
3098 OSKextLog(/* kext */ NULL,
3099 kOSKextLogErrorLevel |
3100 kOSKextLogArchiveFlag,
3101 "Error unserializing mkext plist: %s.", errorCString);
3102 goto finish;
3103 }
3104
0a7de745
A
3105 mkextInfoDictArray = OSDynamicCast(OSArray,
3106 mkextPlist->getObject(kMKEXTInfoDictionariesKey));
3107 if (!mkextInfoDictArray) {
3108 OSKextLog(/* kext */ NULL,
3109 kOSKextLogErrorLevel |
3110 kOSKextLogArchiveFlag,
3111 "Mkext archive contains no kext info dictionaries.");
3112 goto finish;
3113 }
3114
3115 count = mkextInfoDictArray->getCount();
3116 for (i = 0; i < count; i++) {
3117 OSDictionary * infoDict;
3118
3119
3120 infoDict = OSDynamicCast(OSDictionary,
3121 mkextInfoDictArray->getObject(i));
3122
3123 /* Create the kext for the entry, then release it, because the
3124 * kext system keeps them around until explicitly removed.
3125 * Any creation/registration failures are already logged for us.
3126 */
3127 if (infoDict) {
f427ee49
A
3128 OSSharedPtr<OSKext> newKext = OSKext::withMkext2Info(infoDict, mkextData);
3129
3130 /* Fail dynamic loading of a kext when booted from MH_FILESET */
3131 if (kc_format == KCFormatFileset &&
3132 newKext &&
3133 !(newKext->isPrelinked()) &&
3134 newKext->declaresExecutable()) {
3135 result = kOSReturnError;
3136 printf("Kext LOG: Dynamic loading of kext denied for kext %s\n",
3137 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3138
3139 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
3140 "Dynamic loading of kext denied for kext %s\n",
3141 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3142 goto finish;
3143 }
0a7de745
A
3144 }
3145 }
3146
f427ee49
A
3147 /* If the caller needs the plist, hand them back our copy
3148 */
3149 if (mkextPlistOut) {
3150 *mkextPlistOut = mkextPlist;
3151 parsedXML.detach();
3152 }
3153
0a7de745
A
3154 /* Even if we didn't keep any kexts from the mkext, we may have a load
3155 * request to process, so we are successful (no errors occurred).
3156 */
3157 result = kOSReturnSuccess;
b0d623f7
A
3158
3159finish:
f427ee49
A
3160 return result;
3161}
b0d623f7 3162
f427ee49
A
3163/* static */
3164OSReturn
3165OSKext::readMkext2Archive(
3166 OSData * mkextData,
3167 OSSharedPtr<OSDictionary> &mkextPlistOut,
3168 uint32_t * checksumPtr)
3169{
3170 OSDictionary * mkextPlist = NULL;
3171 OSReturn ret;
b0d623f7 3172
f427ee49
A
3173 if (kOSReturnSuccess == (ret = readMkext2Archive(mkextData,
3174 &mkextPlist,
3175 checksumPtr))) {
3176 mkextPlistOut.reset(mkextPlist, OSNoRetain);
3177 }
3178 return ret;
b0d623f7
A
3179}
3180
3181/*********************************************************************
3182*********************************************************************/
3183/* static */
f427ee49 3184OSSharedPtr<OSKext>
b0d623f7 3185OSKext::withMkext2Info(
0a7de745
A
3186 OSDictionary * anInfoDict,
3187 OSData * mkextData)
b0d623f7 3188{
f427ee49 3189 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
b0d623f7 3190
0a7de745 3191 if (newKext && !newKext->initWithMkext2Info(anInfoDict, mkextData)) {
0a7de745
A
3192 return NULL;
3193 }
b0d623f7 3194
0a7de745 3195 return newKext;
b0d623f7
A
3196}
3197
3198/*********************************************************************
3199*********************************************************************/
3200bool
3201OSKext::initWithMkext2Info(
0a7de745
A
3202 OSDictionary * anInfoDict,
3203 OSData * mkextData)
3204{
3205 bool result = false;
f427ee49
A
3206 OSString * kextPath = NULL; // do not release
3207 OSNumber * executableOffsetNum = NULL; // do not release
3208 OSSharedPtr<OSData> executable;
0a7de745
A
3209
3210 if (anInfoDict == NULL || !super::init()) {
3211 goto finish;
3212 }
3213
3214 /* Get the path. Don't look for an arch-specific path property.
3215 */
3216 kextPath = OSDynamicCast(OSString,
3217 anInfoDict->getObject(kMKEXTBundlePathKey));
3218
3219 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
3220 goto finish;
3221 }
3222
3223 /* If we have a path to the executable, save it.
3224 */
f427ee49
A
3225 executableRelPath.reset(OSDynamicCast(OSString,
3226 anInfoDict->getObject(kMKEXTExecutableRelativePathKey)), OSRetain);
0a7de745
A
3227
3228 /* Don't need the paths to be in the info dictionary any more.
3229 */
3230 anInfoDict->removeObject(kMKEXTBundlePathKey);
3231 anInfoDict->removeObject(kMKEXTExecutableRelativePathKey);
3232
3233 executableOffsetNum = OSDynamicCast(OSNumber,
3234 infoDict->getObject(kMKEXTExecutableKey));
3235 if (executableOffsetNum) {
3236 executable = createMkext2FileEntry(mkextData,
3237 executableOffsetNum, "executable");
3238 infoDict->removeObject(kMKEXTExecutableKey);
3239 if (!executable) {
3240 goto finish;
3241 }
f427ee49 3242 if (!setExecutable(executable.get(), mkextData, true)) {
0a7de745
A
3243 goto finish;
3244 }
3245 }
3246
3247 result = registerIdentifier();
b0d623f7
A
3248
3249finish:
0a7de745 3250 return result;
b0d623f7
A
3251}
3252
3253/*********************************************************************
3254*********************************************************************/
f427ee49 3255OSSharedPtr<OSData>
b0d623f7 3256OSKext::createMkext2FileEntry(
0a7de745
A
3257 OSData * mkextData,
3258 OSNumber * offsetNum,
3259 const char * name)
3260{
f427ee49 3261 OSSharedPtr<OSData> result;
0a7de745
A
3262 MkextEntryRef entryRef;
3263 uint8_t * mkextBuffer = (uint8_t *)mkextData->getBytesNoCopy();
3264 uint32_t entryOffset = offsetNum->unsigned32BitValue();
3265
3266 result = OSData::withCapacity(sizeof(entryRef));
3267 if (!result) {
3268 goto finish;
3269 }
3270
3271 entryRef.mkext = (mkext_basic_header *)mkextBuffer;
3272 entryRef.fileinfo = mkextBuffer + entryOffset;
3273 if (!result->appendBytes(&entryRef, sizeof(entryRef))) {
f427ee49 3274 result.reset();
0a7de745
A
3275 goto finish;
3276 }
b0d623f7
A
3277
3278finish:
0a7de745
A
3279 if (!result) {
3280 OSKextLog(this,
3281 kOSKextLogErrorLevel |
3282 kOSKextLogArchiveFlag,
3283 "Can't create wrapper for mkext file entry '%s' of kext %s.",
3284 name, getIdentifierCString());
3285 }
3286 return result;
b0d623f7
A
3287}
3288
3289/*********************************************************************
3290*********************************************************************/
3291extern "C" {
3292static void * z_alloc(void *, u_int items, u_int size);
3293static void z_free(void *, void *ptr);
3294
3295typedef struct z_mem {
0a7de745
A
3296 uint32_t alloc_size;
3297 uint8_t data[0];
b0d623f7
A
3298} z_mem;
3299
3300/*
3301 * Space allocation and freeing routines for use by zlib routines.
3302 */
3303void *
3304z_alloc(void * notused __unused, u_int num_items, u_int size)
3305{
0a7de745
A
3306 void * result = NULL;
3307 z_mem * zmem = NULL;
3308
3309 uint64_t total = ((uint64_t)num_items) * ((uint64_t)size);
3310 //Check for overflow due to multiplication
3311 if (total > UINT32_MAX) {
3312 panic("z_alloc(%p, %x, %x): overflow caused by %x * %x\n",
3313 notused, num_items, size, num_items, size);
3314 }
3315
3316 uint64_t allocSize64 = total + ((uint64_t)sizeof(zmem));
3317 //Check for overflow due to addition
3318 if (allocSize64 > UINT32_MAX) {
3319 panic("z_alloc(%p, %x, %x): overflow caused by %x + %lx\n",
3320 notused, num_items, size, (uint32_t)total, sizeof(zmem));
3321 }
3322 uint32_t allocSize = (uint32_t)allocSize64;
3323
f427ee49
A
3324 zmem = (z_mem *)kheap_alloc_tag(KHEAP_DATA_BUFFERS, allocSize,
3325 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
0a7de745
A
3326 if (!zmem) {
3327 goto finish;
3328 }
3329 zmem->alloc_size = allocSize;
3330 result = (void *)&(zmem->data);
b0d623f7 3331finish:
0a7de745 3332 return result;
b0d623f7
A
3333}
3334
3335void
3336z_free(void * notused __unused, void * ptr)
3337{
0a7de745
A
3338 uint32_t * skipper = (uint32_t *)ptr - 1;
3339 z_mem * zmem = (z_mem *)skipper;
f427ee49 3340 kheap_free(KHEAP_DATA_BUFFERS, zmem, zmem->alloc_size);
0a7de745 3341 return;
b0d623f7
A
3342}
3343};
3344
f427ee49 3345OSSharedPtr<OSData>
b0d623f7 3346OSKext::extractMkext2FileData(
0a7de745
A
3347 UInt8 * data,
3348 const char * name,
3349 uint32_t compressedSize,
3350 uint32_t fullSize)
3351{
f427ee49
A
3352 OSSharedPtr<OSData> result;
3353 OSSharedPtr<OSData> uncompressedData; // release on error
0a7de745 3354
f427ee49 3355 uint8_t * uncompressedDataBuffer = NULL; // do not free
0a7de745
A
3356 unsigned long uncompressedSize;
3357 z_stream zstream;
3358 bool zstream_inited = false;
3359 int zlib_result;
3360
3361 /* If the file isn't compressed, we want to make a copy
3362 * so that we don't have the tie to the larger mkext file buffer any more.
3363 */
3364 if (!compressedSize) {
3365 uncompressedData = OSData::withBytes(data, fullSize);
3366 // xxx - no check for failure?
3367 result = uncompressedData;
3368 goto finish;
3369 }
3370
3371 if (KERN_SUCCESS != kmem_alloc(kernel_map,
3372 (vm_offset_t*)&uncompressedDataBuffer, fullSize, VM_KERN_MEMORY_OSKEXT)) {
3373 /* How's this for cheesy? The kernel is only asked to extract
3374 * kext plists so we tailor the log messages.
3375 */
3376 if (isKernel()) {
3377 OSKextLog(this,
3378 kOSKextLogErrorLevel |
3379 kOSKextLogArchiveFlag,
3380 "Allocation failure extracting %s from mkext.", name);
3381 } else {
3382 OSKextLog(this,
3383 kOSKextLogErrorLevel |
3384 kOSKextLogArchiveFlag,
3385 "Allocation failure extracting %s from mkext for kext %s.",
3386 name, getIdentifierCString());
3387 }
3388
3389 goto finish;
3390 }
3391 uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer, fullSize);
3392 if (!uncompressedData) {
3393 if (isKernel()) {
3394 OSKextLog(this,
3395 kOSKextLogErrorLevel |
3396 kOSKextLogArchiveFlag,
3397 "Allocation failure extracting %s from mkext.", name);
3398 } else {
3399 OSKextLog(this,
3400 kOSKextLogErrorLevel |
3401 kOSKextLogArchiveFlag,
3402 "Allocation failure extracting %s from mkext for kext %s.",
3403 name, getIdentifierCString());
3404 }
3405 goto finish;
3406 }
3407 uncompressedData->setDeallocFunction(&osdata_kmem_free);
3408
3409 if (isKernel()) {
3410 OSKextLog(this,
3411 kOSKextLogDetailLevel |
3412 kOSKextLogArchiveFlag,
3413 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
3414 name, compressedSize, fullSize);
3415 } else {
3416 OSKextLog(this,
3417 kOSKextLogDetailLevel |
3418 kOSKextLogArchiveFlag,
3419 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
3420 getIdentifierCString(), name, compressedSize, fullSize);
3421 }
3422
3423 bzero(&zstream, sizeof(zstream));
3424 zstream.next_in = (UInt8 *)data;
3425 zstream.avail_in = compressedSize;
3426
3427 zstream.next_out = uncompressedDataBuffer;
3428 zstream.avail_out = fullSize;
3429
3430 zstream.zalloc = z_alloc;
3431 zstream.zfree = z_free;
3432
3433 zlib_result = inflateInit(&zstream);
3434 if (Z_OK != zlib_result) {
3435 if (isKernel()) {
3436 OSKextLog(this,
3437 kOSKextLogErrorLevel |
3438 kOSKextLogArchiveFlag,
3439 "Mkext error; zlib inflateInit failed (%d) for %s.",
3440 zlib_result, name);
3441 } else {
3442 OSKextLog(this,
3443 kOSKextLogErrorLevel |
3444 kOSKextLogArchiveFlag,
3445 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
3446 getIdentifierCString(), zlib_result, name);
3447 }
3448 goto finish;
3449 } else {
3450 zstream_inited = true;
3451 }
3452
3453 zlib_result = inflate(&zstream, Z_FINISH);
3454
3455 if (zlib_result == Z_STREAM_END || zlib_result == Z_OK) {
3456 uncompressedSize = zstream.total_out;
3457 } else {
3458 if (isKernel()) {
3459 OSKextLog(this,
3460 kOSKextLogErrorLevel |
3461 kOSKextLogArchiveFlag,
3462 "Mkext error; zlib inflate failed (%d) for %s.",
3463 zlib_result, name);
3464 } else {
3465 OSKextLog(this,
3466 kOSKextLogErrorLevel |
3467 kOSKextLogArchiveFlag,
3468 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
3469 getIdentifierCString(), zlib_result, name);
3470 }
3471 if (zstream.msg) {
3472 OSKextLog(this,
3473 kOSKextLogErrorLevel |
3474 kOSKextLogArchiveFlag,
3475 "zlib error: %s.", zstream.msg);
3476 }
3477 goto finish;
3478 }
3479
3480 if (uncompressedSize != fullSize) {
3481 if (isKernel()) {
3482 OSKextLog(this,
3483 kOSKextLogErrorLevel |
3484 kOSKextLogArchiveFlag,
3485 "Mkext error; zlib inflate discrepancy for %s, "
3486 "uncompressed size != original size.", name);
3487 } else {
3488 OSKextLog(this,
3489 kOSKextLogErrorLevel |
3490 kOSKextLogArchiveFlag,
3491 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
3492 "uncompressed size != original size.",
3493 getIdentifierCString(), name);
3494 }
3495 goto finish;
3496 }
3497
f427ee49 3498 result = os::move(uncompressedData);
b0d623f7
A
3499
3500finish:
0a7de745
A
3501 /* Don't bother checking return, nothing we can do on fail.
3502 */
3503 if (zstream_inited) {
3504 inflateEnd(&zstream);
3505 }
b0d623f7 3506
0a7de745 3507 return result;
b0d623f7
A
3508}
3509
3510/*********************************************************************
3511*********************************************************************/
3512/* static */
3513OSReturn
3514OSKext::loadFromMkext(
0a7de745
A
3515 OSKextLogSpec clientLogFilter,
3516 char * mkextBuffer,
3517 uint32_t mkextBufferLength,
3518 char ** logInfoOut,
3519 uint32_t * logInfoLengthOut)
3520{
3521 OSReturn result = kOSReturnError;
3522 OSReturn tempResult = kOSReturnError;
3523
f427ee49
A
3524 OSSharedPtr<OSData> mkextData;
3525 OSSharedPtr<OSDictionary> mkextPlist;
0a7de745 3526
f427ee49
A
3527 OSSharedPtr<OSArray> logInfoArray;
3528 OSSharedPtr<OSSerialize> serializer;
0a7de745 3529
f427ee49
A
3530 OSString * predicate = NULL; // do not release
3531 OSDictionary * requestArgs = NULL; // do not release
0a7de745 3532
f427ee49
A
3533 OSString * kextIdentifier = NULL; // do not release
3534 OSNumber * startKextExcludeNum = NULL; // do not release
3535 OSNumber * startMatchingExcludeNum = NULL; // do not release
3536 OSBoolean * delayAutounloadBool = NULL; // do not release
3537 OSArray * personalityNames = NULL; // do not release
0a7de745
A
3538
3539 /* Default values for these two options: regular autounload behavior,
3540 * load all kexts, send no personalities.
3541 */
3542 Boolean delayAutounload = false;
3543 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
3544 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeAll;
3545
3546 IORecursiveLockLock(sKextLock);
3547
3548 if (logInfoOut) {
3549 *logInfoOut = NULL;
3550 *logInfoLengthOut = 0;
3551 }
b0d623f7 3552
0a7de745
A
3553 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
3554
3555 OSKextLog(/* kext */ NULL,
3556 kOSKextLogDebugLevel |
3557 kOSKextLogIPCFlag,
3558 "Received kext load request from user space.");
3559
3560 /* Regardless of processing, the fact that we have gotten here means some
3561 * user-space program is up and talking to us, so we'll switch our kext
3562 * registration to reflect that.
3563 */
3564 if (!sUserLoadsActive) {
3565 OSKextLog(/* kext */ NULL,
3566 kOSKextLogProgressLevel |
3567 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
3568 "Switching to late startup (user-space) kext loading policy.");
3569
3570 sUserLoadsActive = true;
3571 }
3572
3573 if (!sLoadEnabled) {
3574 OSKextLog(/* kext */ NULL,
3575 kOSKextLogErrorLevel |
3576 kOSKextLogLoadFlag,
3577 "Kext loading is disabled.");
3578 result = kOSKextReturnDisabled;
3579 goto finish;
3580 }
3581
3582 /* Note that we do not set a dealloc function on this OSData
3583 * object! No references to it can remain after the loadFromMkext()
3584 * call since we are in a MIG function, and will vm_deallocate()
3585 * the buffer.
3586 */
3587 mkextData = OSData::withBytesNoCopy(mkextBuffer,
3588 mkextBufferLength);
3589 if (!mkextData) {
3590 OSKextLog(/* kext */ NULL,
3591 kOSKextLogErrorLevel |
3592 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3593 "Failed to create wrapper for kext load request.");
3594 result = kOSKextReturnNoMemory;
3595 goto finish;
3596 }
3597
f427ee49 3598 result = readMkext2Archive(mkextData.get(), mkextPlist, NULL);
0a7de745
A
3599 if (result != kOSReturnSuccess) {
3600 OSKextLog(/* kext */ NULL,
3601 kOSKextLogErrorLevel |
3602 kOSKextLogLoadFlag,
3603 "Failed to read kext load request.");
3604 goto finish;
3605 }
b0d623f7 3606
f427ee49 3607 predicate = _OSKextGetRequestPredicate(mkextPlist.get());
0a7de745
A
3608 if (!predicate || !predicate->isEqualTo(kKextRequestPredicateLoad)) {
3609 OSKextLog(/* kext */ NULL,
3610 kOSKextLogErrorLevel |
3611 kOSKextLogLoadFlag,
3612 "Received kext load request with no predicate; skipping.");
3613 result = kOSKextReturnInvalidArgument;
3614 goto finish;
3615 }
3616
3617 requestArgs = OSDynamicCast(OSDictionary,
3618 mkextPlist->getObject(kKextRequestArgumentsKey));
3619 if (!requestArgs || !requestArgs->getCount()) {
3620 OSKextLog(/* kext */ NULL,
3621 kOSKextLogErrorLevel |
3622 kOSKextLogLoadFlag,
3623 "Received kext load request with no arguments.");
3624 result = kOSKextReturnInvalidArgument;
3625 goto finish;
3626 }
3627
3628 kextIdentifier = OSDynamicCast(OSString,
3629 requestArgs->getObject(kKextRequestArgumentBundleIdentifierKey));
cb323159 3630
0a7de745
A
3631 if (!kextIdentifier) {
3632 OSKextLog(/* kext */ NULL,
3633 kOSKextLogErrorLevel |
3634 kOSKextLogLoadFlag,
3635 "Received kext load request with no kext identifier.");
3636 result = kOSKextReturnInvalidArgument;
3637 goto finish;
3638 }
3639
3640 startKextExcludeNum = OSDynamicCast(OSNumber,
3641 requestArgs->getObject(kKextRequestArgumentStartExcludeKey));
3642 startMatchingExcludeNum = OSDynamicCast(OSNumber,
3643 requestArgs->getObject(kKextRequestArgumentStartMatchingExcludeKey));
3644 delayAutounloadBool = OSDynamicCast(OSBoolean,
3645 requestArgs->getObject(kKextRequestArgumentDelayAutounloadKey));
3646 personalityNames = OSDynamicCast(OSArray,
3647 requestArgs->getObject(kKextRequestArgumentPersonalityNamesKey));
3648
3649 if (delayAutounloadBool) {
3650 delayAutounload = delayAutounloadBool->getValue();
3651 }
3652 if (startKextExcludeNum) {
3653 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
3654 }
3655 if (startMatchingExcludeNum) {
3656 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
3657 }
3658
3659 OSKextLog(/* kext */ NULL,
3660 kOSKextLogProgressLevel |
3661 kOSKextLogIPCFlag,
3662 "Received request from user space to load kext %s.",
3663 kextIdentifier->getCStringNoCopy());
3664
3665 /* Load the kext, with no deferral, since this is a load from outside
3666 * the kernel.
3667 * xxx - Would like a better way to handle the default values for the
3668 * xxx - start/match opt args.
3669 */
3670 result = OSKext::loadKextWithIdentifier(
3671 kextIdentifier,
cb323159 3672 /* kextRef */ NULL,
0a7de745
A
3673 /* allowDefer */ false,
3674 delayAutounload,
3675 startKextExcludeLevel,
3676 startMatchingExcludeLevel,
3677 personalityNames);
3678 if (result != kOSReturnSuccess) {
3679 goto finish;
3680 }
f427ee49 3681 /* If the load came down from the IOKit daemon, it will shortly inform IOCatalogue
0a7de745
A
3682 * for matching via a separate IOKit calldown.
3683 */
b0d623f7 3684
0a7de745 3685finish:
b0d623f7 3686
0a7de745
A
3687 /* Gather up the collected log messages for user space. Any
3688 * error messages past this call will not make it up as log messages
3689 * but will be in the system log.
3690 */
3691 logInfoArray = OSKext::clearUserSpaceLogFilter();
3692
3693 if (logInfoArray && logInfoOut && logInfoLengthOut) {
f427ee49 3694 tempResult = OSKext::serializeLogInfo(logInfoArray.get(),
0a7de745
A
3695 logInfoOut, logInfoLengthOut);
3696 if (tempResult != kOSReturnSuccess) {
3697 result = tempResult;
3698 }
3699 }
b0d623f7 3700
0a7de745
A
3701 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
3702
f427ee49
A
3703 IORecursiveLockUnlock(sKextLock);
3704
0a7de745
A
3705 /* Note: mkextDataObject will have been retained by every kext w/an
3706 * executable in it. That should all have been flushed out at the
3707 * and of the load operation, but you never know....
3708 */
3709 if (mkextData && mkextData->getRetainCount() > 1) {
3710 OSKextLog(/* kext */ NULL,
3711 kOSKextLogErrorLevel |
3712 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3713 "Kext load request buffer from user space still retained by a kext; "
3714 "probable memory leak.");
3715 }
b0d623f7 3716
0a7de745 3717 return result;
b0d623f7
A
3718}
3719
f427ee49
A
3720#endif // CONFIG_KXLD
3721
b0d623f7
A
3722/*********************************************************************
3723*********************************************************************/
3724/* static */
3725OSReturn
3726OSKext::serializeLogInfo(
0a7de745
A
3727 OSArray * logInfoArray,
3728 char ** logInfoOut,
3729 uint32_t * logInfoLengthOut)
3730{
3731 OSReturn result = kOSReturnError;
3732 char * buffer = NULL;
3733 kern_return_t kmem_result = KERN_FAILURE;
f427ee49
A
3734 OSSharedPtr<OSSerialize> serializer;
3735 char * logInfo = NULL; // returned by reference
0a7de745
A
3736 uint32_t logInfoLength = 0;
3737
3738 if (!logInfoArray || !logInfoOut || !logInfoLengthOut) {
3739 OSKextLog(/* kext */ NULL,
3740 kOSKextLogErrorLevel |
3741 kOSKextLogIPCFlag,
3742 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
3743 /* Bad programmer. */
3744 result = kOSKextReturnInvalidArgument;
3745 goto finish;
3746 }
3747
3748 serializer = OSSerialize::withCapacity(0);
3749 if (!serializer) {
3750 OSKextLog(/* kext */ NULL,
3751 kOSKextLogErrorLevel |
3752 kOSKextLogIPCFlag,
3753 "Failed to create serializer on log info for request from user space.");
3754 /* Incidental error; we're going to (try to) allow the request
3755 * itself to succeed. */
3756 }
3757
f427ee49 3758 if (!logInfoArray->serialize(serializer.get())) {
0a7de745
A
3759 OSKextLog(/* kext */ NULL,
3760 kOSKextLogErrorLevel |
3761 kOSKextLogIPCFlag,
3762 "Failed to serialize log info for request from user space.");
3763 /* Incidental error; we're going to (try to) allow the request
3764 * itself to succeed. */
3765 } else {
3766 logInfo = serializer->text();
3767 logInfoLength = serializer->getLength();
3768
3769 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer, round_page(logInfoLength), VM_KERN_MEMORY_OSKEXT);
3770 if (kmem_result != KERN_SUCCESS) {
3771 OSKextLog(/* kext */ NULL,
3772 kOSKextLogErrorLevel |
3773 kOSKextLogIPCFlag,
3774 "Failed to copy log info for request from user space.");
3775 /* Incidental error; we're going to (try to) allow the request
3776 * to succeed. */
3777 } else {
3778 /* 11981737 - clear uninitialized data in last page */
3779 bzero((void *)(buffer + logInfoLength),
3780 (round_page(logInfoLength) - logInfoLength));
3781 memcpy(buffer, logInfo, logInfoLength);
3782 *logInfoOut = buffer;
3783 *logInfoLengthOut = logInfoLength;
3784 }
3785 }
3786
3787 result = kOSReturnSuccess;
b0d623f7 3788finish:
0a7de745 3789 return result;
b0d623f7
A
3790}
3791
3792#if PRAGMA_MARK
3793#pragma mark Instance Management Methods
3794#endif
3795/*********************************************************************
3796*********************************************************************/
f427ee49 3797OSSharedPtr<OSKext>
b0d623f7
A
3798OSKext::lookupKextWithIdentifier(const char * kextIdentifier)
3799{
f427ee49 3800 OSSharedPtr<OSKext> foundKext;
b0d623f7 3801
0a7de745 3802 IORecursiveLockLock(sKextLock);
f427ee49 3803 foundKext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier)), OSRetain);
0a7de745 3804 IORecursiveLockUnlock(sKextLock);
b0d623f7 3805
0a7de745 3806 return foundKext;
b0d623f7
A
3807}
3808
3809/*********************************************************************
3810*********************************************************************/
f427ee49 3811OSSharedPtr<OSKext>
b0d623f7
A
3812OSKext::lookupKextWithIdentifier(OSString * kextIdentifier)
3813{
0a7de745 3814 return OSKext::lookupKextWithIdentifier(kextIdentifier->getCStringNoCopy());
b0d623f7
A
3815}
3816
3817/*********************************************************************
3818*********************************************************************/
f427ee49 3819OSSharedPtr<OSKext>
b0d623f7
A
3820OSKext::lookupKextWithLoadTag(uint32_t aTag)
3821{
f427ee49 3822 OSSharedPtr<OSKext> foundKext; // returned
cb323159 3823 uint32_t i, j;
f427ee49 3824 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
cb323159 3825 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
0a7de745
A
3826
3827 IORecursiveLockLock(sKextLock);
3828
cb323159
A
3829 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
3830 for (i = 0; i < count[j]; i++) {
3831 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
3832 if (thisKext->getLoadTag() == aTag) {
f427ee49 3833 foundKext.reset(thisKext, OSRetain);
cb323159
A
3834 goto finish;
3835 }
0a7de745
A
3836 }
3837 }
3838
b0d623f7 3839finish:
0a7de745 3840 IORecursiveLockUnlock(sKextLock);
b0d623f7 3841
0a7de745 3842 return foundKext;
b0d623f7
A
3843}
3844
3845/*********************************************************************
3846*********************************************************************/
f427ee49 3847OSSharedPtr<OSKext>
b0d623f7
A
3848OSKext::lookupKextWithAddress(vm_address_t address)
3849{
f427ee49 3850 OSSharedPtr<OSKext> foundKext; // returned
0a7de745 3851 uint32_t count, i;
f427ee49 3852 kmod_info_t *kmod_info;
2a1bd2d3 3853 vm_address_t originalAddress;
f427ee49
A
3854#if defined(__arm64__)
3855 uint64_t textExecBase;
3856 size_t textExecSize;
3857#endif /* defined(__arm64__) */
3858
2a1bd2d3 3859 originalAddress = address;
f427ee49
A
3860#if __has_feature(ptrauth_calls)
3861 address = (vm_address_t)VM_KERNEL_STRIP_PTR(address);
3862#endif /* __has_feature(ptrauth_calls) */
0a7de745
A
3863
3864 IORecursiveLockLock(sKextLock);
3865
3866 count = sLoadedKexts->getCount();
3867 for (i = 0; i < count; i++) {
3868 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
f427ee49
A
3869 if (thisKext == sKernelKext) {
3870 continue;
3871 }
3872 if (thisKext->kmod_info && thisKext->kmod_info->address) {
3873 kmod_info = thisKext->kmod_info;
3874 vm_address_t kext_start = kmod_info->address;
3875 vm_address_t kext_end = kext_start + kmod_info->size;
0a7de745 3876 if ((kext_start <= address) && (address < kext_end)) {
f427ee49 3877 foundKext.reset(thisKext, OSRetain);
0a7de745
A
3878 goto finish;
3879 }
f427ee49
A
3880#if defined(__arm64__)
3881 textExecBase = (uintptr_t) getsegdatafromheader((kernel_mach_header_t *)kmod_info->address, "__TEXT_EXEC", &textExecSize);
3882 if ((textExecBase <= address) && (address < textExecBase + textExecSize)) {
3883 foundKext.reset(thisKext, OSRetain);
3884 goto finish;
3885 }
3886#endif /* defined (__arm64__) */
0a7de745
A
3887 }
3888 }
f427ee49
A
3889 if ((address >= vm_kernel_stext) && (address < vm_kernel_etext)) {
3890 foundKext.reset(sKernelKext, OSRetain);
3891 goto finish;
3892 }
3893 /*
3894 * DriverKit userspace executables do not have a kernel linkedExecutable,
2a1bd2d3
A
3895 * so we "fake" their address range with the LoadTag. We cannot use the ptrauth-stripped address
3896 * here, so use the original address passed to this method.
f427ee49
A
3897 *
3898 * This is supposed to be used for logging reasons only. When logd
3899 * calls this function it ors the address with FIREHOSE_TRACEPOINT_PC_KERNEL_MASK, so we
3900 * remove it here before checking it against the LoadTag.
3901 * Also we need to remove FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT set when emitting the log line.
3902 */
0a7de745 3903
2a1bd2d3 3904 address = originalAddress & ~(FIREHOSE_TRACEPOINT_PC_KERNEL_MASK | FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT);
cb323159
A
3905 count = sLoadedDriverKitKexts->getCount();
3906 for (i = 0; i < count; i++) {
3907 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedDriverKitKexts->getObject(i));
cb323159 3908 if (thisKext->getLoadTag() == address) {
f427ee49 3909 foundKext.reset(thisKext, OSRetain);
cb323159
A
3910 }
3911 }
3912
b0d623f7 3913finish:
0a7de745 3914 IORecursiveLockUnlock(sKextLock);
b0d623f7 3915
0a7de745 3916 return foundKext;
b0d623f7
A
3917}
3918
f427ee49 3919OSSharedPtr<OSData>
813fb2f6
A
3920OSKext::copyKextUUIDForAddress(OSNumber *address)
3921{
f427ee49
A
3922 OSSharedPtr<OSData> uuid;
3923 OSSharedPtr<OSKext> kext;
813fb2f6
A
3924
3925 if (!address) {
3926 return NULL;
3927 }
3928
813fb2f6
A
3929#if CONFIG_MACF
3930 /* Is the calling process allowed to query kext info? */
3931 if (current_task() != kernel_task) {
3932 int macCheckResult = 0;
3933 kauth_cred_t cred = NULL;
3934
3935 cred = kauth_cred_get_with_ref();
3936 macCheckResult = mac_kext_check_query(cred);
3937 kauth_cred_unref(&cred);
3938
3939 if (macCheckResult != 0) {
3940 OSKextLog(/* kext */ NULL,
0a7de745
A
3941 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
3942 "Failed to query kext UUID (MAC policy error 0x%x).",
3943 macCheckResult);
813fb2f6
A
3944 return NULL;
3945 }
3946 }
3947#endif
2a1bd2d3
A
3948
3949 uintptr_t slidAddress = ml_static_slide((uintptr_t)address->unsigned64BitValue());
3950 if (slidAddress != 0) {
3951 kext = lookupKextWithAddress(slidAddress);
3952 if (kext) {
3953 uuid = kext->copyTextUUID();
3954 }
0a7de745 3955 }
2a1bd2d3
A
3956
3957 if (!uuid) {
3958 /*
3959 * If we still don't have a UUID, then we failed to match the slid + stripped address with
3960 * a kext. This might have happened because the log message came from a dext.
3961 *
3962 * Try again with the original address.
3963 */
3964 kext = lookupKextWithAddress((vm_address_t)address->unsigned64BitValue());
3965 if (kext && kext->isDriverKit()) {
3966 uuid = kext->copyTextUUID();
3967 }
3968 }
3969
813fb2f6
A
3970 return uuid;
3971}
3e170ce0
A
3972
3973/*********************************************************************
3974*********************************************************************/
f427ee49 3975OSSharedPtr<OSKext>
3e170ce0
A
3976OSKext::lookupKextWithUUID(uuid_t wanted)
3977{
f427ee49 3978 OSSharedPtr<OSKext> foundKext; // returned
cb323159 3979 uint32_t j, i;
f427ee49 3980 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
cb323159
A
3981 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
3982
3e170ce0 3983
0a7de745 3984 IORecursiveLockLock(sKextLock);
3e170ce0 3985
cb323159
A
3986 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
3987 for (i = 0; i < count[j]; i++) {
3988 OSKext * thisKext = NULL;
3e170ce0 3989
cb323159
A
3990 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
3991 if (!thisKext) {
3992 continue;
3993 }
3e170ce0 3994
f427ee49 3995 OSSharedPtr<OSData> uuid_data = thisKext->copyUUID();
cb323159
A
3996 if (!uuid_data) {
3997 continue;
3998 }
3e170ce0 3999
cb323159
A
4000 uuid_t uuid;
4001 memcpy(&uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
3e170ce0 4002
cb323159 4003 if (0 == uuid_compare(wanted, uuid)) {
f427ee49 4004 foundKext.reset(thisKext, OSRetain);
cb323159
A
4005 goto finish;
4006 }
0a7de745
A
4007 }
4008 }
3e170ce0 4009finish:
0a7de745 4010 IORecursiveLockUnlock(sKextLock);
3e170ce0 4011
0a7de745 4012 return foundKext;
3e170ce0
A
4013}
4014
4015
4016
4017
b0d623f7
A
4018/*********************************************************************
4019*********************************************************************/
4020/* static */
0a7de745
A
4021bool
4022OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
b0d623f7 4023{
0a7de745
A
4024 bool result = false;
4025 OSKext * foundKext = NULL; // returned
b0d623f7 4026
0a7de745
A
4027 IORecursiveLockLock(sKextLock);
4028
4029 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
4030 if (foundKext && foundKext->isLoaded()) {
4031 result = true;
4032 }
b0d623f7 4033
0a7de745 4034 IORecursiveLockUnlock(sKextLock);
b0d623f7 4035
0a7de745 4036 return result;
b0d623f7
A
4037}
4038
4039/*********************************************************************
4040* xxx - should spawn a separate thread so a kext can safely have
4041* xxx - itself unloaded.
4042*********************************************************************/
4043/* static */
4044OSReturn
4045OSKext::removeKext(
0a7de745 4046 OSKext * aKext,
5ba3f43e 4047#if CONFIG_EMBEDDED
0a7de745 4048 __unused
5ba3f43e 4049#endif
0a7de745
A
4050 bool terminateServicesAndRemovePersonalitiesFlag)
4051{
5ba3f43e 4052#if CONFIG_EMBEDDED
0a7de745
A
4053 OSKextLog(aKext,
4054 kOSKextLogErrorLevel |
4055 kOSKextLogKextBookkeepingFlag,
4056 "removeKext() called for %s, not supported on embedded",
4057 aKext->getIdentifier() ? aKext->getIdentifierCString() : "unknown kext");
5ba3f43e 4058
0a7de745 4059 return kOSReturnSuccess;
5ba3f43e 4060#else /* CONFIG_EMBEDDED */
39037602 4061
0a7de745 4062 OSReturn result = kOSKextReturnInUse;
f427ee49 4063 OSKext * checkKext = NULL; // do not release
39236c6e 4064#if CONFIG_MACF
0a7de745
A
4065 int macCheckResult = 0;
4066 kauth_cred_t cred = NULL;
39236c6e 4067#endif
b0d623f7 4068
0a7de745 4069 IORecursiveLockLock(sKextLock);
b0d623f7 4070
0a7de745
A
4071 /* If the kext has no identifier, it failed to init
4072 * so isn't in sKextsByID and it isn't loaded.
4073 */
4074 if (!aKext->getIdentifier()) {
4075 result = kOSReturnSuccess;
4076 goto finish;
4077 }
b0d623f7 4078
0a7de745
A
4079 checkKext = OSDynamicCast(OSKext,
4080 sKextsByID->getObject(aKext->getIdentifier()));
4081 if (checkKext != aKext) {
4082 result = kOSKextReturnNotFound;
4083 goto finish;
4084 }
b0d623f7 4085
0a7de745 4086 if (aKext->isLoaded()) {
39236c6e 4087#if CONFIG_MACF
0a7de745
A
4088 if (current_task() != kernel_task) {
4089 cred = kauth_cred_get_with_ref();
4090 macCheckResult = mac_kext_check_unload(cred, aKext->getIdentifierCString());
4091 kauth_cred_unref(&cred);
4092 }
4093
4094 if (macCheckResult != 0) {
4095 result = kOSReturnError;
4096 OSKextLog(aKext,
4097 kOSKextLogErrorLevel |
4098 kOSKextLogKextBookkeepingFlag,
4099 "Failed to remove kext %s (MAC policy error 0x%x).",
4100 aKext->getIdentifierCString(), macCheckResult);
4101 goto finish;
4102 }
39236c6e 4103#endif
6d2010ae 4104
0a7de745
A
4105 /* make sure there are no resource requests in flight - 17187548 */
4106 if (aKext->countRequestCallbacks()) {
4107 goto finish;
4108 }
c3c9b80d
A
4109 if (aKext->flags.unloadUnsupported) {
4110 result = kOSKextReturnInUse;
4111 OSKextLog(aKext,
4112 kOSKextLogErrorLevel |
4113 kOSKextLogKextBookkeepingFlag,
4114 "Can't remove kext %s; unsupported by cache.",
4115 aKext->getIdentifierCString());
4116 goto finish;
4117 }
0a7de745
A
4118
4119 /* If we are terminating, send the request to the IOCatalogue
4120 * (which will actually call us right back but that's ok we have
4121 * a recursive lock don't you know) but do not ask the IOCatalogue
4122 * to call back with an unload, we'll do that right here.
4123 */
4124 if (terminateServicesAndRemovePersonalitiesFlag) {
4125 result = gIOCatalogue->terminateDriversForModule(
4126 aKext->getIdentifierCString(), /* unload */ false);
4127 if (result != kOSReturnSuccess) {
4128 OSKextLog(aKext,
4129 kOSKextLogErrorLevel |
4130 kOSKextLogKextBookkeepingFlag,
4131 "Can't remove kext %s; services failed to terminate - 0x%x.",
4132 aKext->getIdentifierCString(), result);
4133 goto finish;
4134 }
4135 }
4136
4137 result = aKext->unload();
4138 if (result != kOSReturnSuccess) {
4139 goto finish;
4140 }
4141 }
4142
4143 /* Remove personalities as requested. This is a bit redundant for a loaded
4144 * kext as IOCatalogue::terminateDriversForModule() removes driver
4145 * personalities, but it doesn't restart matching, which we always want
4146 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
4147 * that happens.
4148 */
4149 if (terminateServicesAndRemovePersonalitiesFlag) {
4150 aKext->removePersonalitiesFromCatalog();
4151 }
4152
f427ee49
A
4153 if (aKext->isInFileset()) {
4154 OSKextLog(aKext,
4155 kOSKextLogProgressLevel |
4156 kOSKextLogKextBookkeepingFlag,
4157 "Fileset kext %s unloaded.",
4158 aKext->getIdentifierCString());
4159 } else {
4160 OSKextLog(aKext,
4161 kOSKextLogProgressLevel |
4162 kOSKextLogKextBookkeepingFlag,
4163 "Removing kext %s.",
4164 aKext->getIdentifierCString());
0a7de745 4165
f427ee49
A
4166 sKextsByID->removeObject(aKext->getIdentifier());
4167 }
0a7de745 4168 result = kOSReturnSuccess;
b0d623f7
A
4169
4170finish:
0a7de745
A
4171 IORecursiveLockUnlock(sKextLock);
4172 return result;
5ba3f43e 4173#endif /* CONFIG_EMBEDDED */
0a7de745 4174}
b0d623f7
A
4175
4176/*********************************************************************
4177*********************************************************************/
4178/* static */
4179OSReturn
4180OSKext::removeKextWithIdentifier(
0a7de745
A
4181 const char * kextIdentifier,
4182 bool terminateServicesAndRemovePersonalitiesFlag)
4183{
4184 OSReturn result = kOSReturnError;
4185
4186 IORecursiveLockLock(sKextLock);
4187
4188 OSKext * aKext = OSDynamicCast(OSKext,
4189 sKextsByID->getObject(kextIdentifier));
4190 if (!aKext) {
4191 result = kOSKextReturnNotFound;
4192 OSKextLog(/* kext */ NULL,
4193 kOSKextLogErrorLevel |
4194 kOSKextLogKextBookkeepingFlag,
4195 "Can't remove kext %s - not found.",
4196 kextIdentifier);
4197 goto finish;
4198 }
4199
4200 result = OSKext::removeKext(aKext,
4201 terminateServicesAndRemovePersonalitiesFlag);
b0d623f7
A
4202
4203finish:
0a7de745
A
4204 IORecursiveLockUnlock(sKextLock);
4205
4206 return result;
b0d623f7
A
4207}
4208
4209/*********************************************************************
4210*********************************************************************/
4211/* static */
4212OSReturn
4213OSKext::removeKextWithLoadTag(
0a7de745
A
4214 OSKextLoadTag loadTag,
4215 bool terminateServicesAndRemovePersonalitiesFlag)
4216{
4217 OSReturn result = kOSReturnError;
4218 OSKext * foundKext = NULL;
cb323159 4219 uint32_t i, j;
f427ee49 4220 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
cb323159
A
4221 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4222
0a7de745
A
4223
4224 IORecursiveLockLock(sKextLock);
4225
cb323159
A
4226 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4227 for (i = 0; i < count[j]; i++) {
4228 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4229 if (thisKext->loadTag == loadTag) {
4230 foundKext = thisKext;
4231 break;
4232 }
0a7de745
A
4233 }
4234 }
4235
4236 if (!foundKext) {
4237 result = kOSKextReturnNotFound;
4238 OSKextLog(/* kext */ NULL,
4239 kOSKextLogErrorLevel |
4240 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4241 "Can't remove kext with load tag %d - not found.",
4242 loadTag);
4243 goto finish;
4244 }
4245
4246 result = OSKext::removeKext(foundKext,
4247 terminateServicesAndRemovePersonalitiesFlag);
b0d623f7
A
4248
4249finish:
0a7de745
A
4250 IORecursiveLockUnlock(sKextLock);
4251
4252 return result;
4253}
b0d623f7
A
4254
4255/*********************************************************************
4256*********************************************************************/
f427ee49 4257OSSharedPtr<OSDictionary>
b0d623f7
A
4258OSKext::copyKexts(void)
4259{
f427ee49 4260 OSSharedPtr<OSDictionary> result;
b0d623f7 4261
0a7de745 4262 IORecursiveLockLock(sKextLock);
f427ee49 4263 result = OSDynamicPtrCast<OSDictionary>(sKextsByID->copyCollection());
0a7de745 4264 IORecursiveLockUnlock(sKextLock);
b0d623f7 4265
0a7de745 4266 return result;
b0d623f7 4267}
39236c6e
A
4268
4269/*********************************************************************
0a7de745 4270*********************************************************************/
39236c6e
A
4271#define BOOTER_KEXT_PREFIX "Driver-"
4272
4273typedef struct _DeviceTreeBuffer {
0a7de745
A
4274 uint32_t paddr;
4275 uint32_t length;
39236c6e
A
4276} _DeviceTreeBuffer;
4277
4278/*********************************************************************
0a7de745
A
4279* Create a dictionary of excluded kexts from the given booter data.
4280*********************************************************************/
39236c6e
A
4281/* static */
4282void
4283OSKext::createExcludeListFromBooterData(
0a7de745
A
4284 OSDictionary * theDictionary,
4285 OSCollectionIterator * theIterator )
4286{
f427ee49
A
4287 OSString * deviceTreeName = NULL; // do not release
4288 const _DeviceTreeBuffer * deviceTreeBuffer = NULL; // do not release
4289 char * booterDataPtr = NULL; // do not release
4290 _BooterKextFileInfo * kextFileInfo = NULL; // do not release
4291 char * infoDictAddr = NULL; // do not release
4292 OSSharedPtr<OSObject> parsedXML;
4293 OSDictionary * theInfoDict = NULL; // do not release
0a7de745
A
4294
4295 theIterator->reset();
4296
4297 /* look for AppleKextExcludeList.kext */
4298 while ((deviceTreeName =
4299 OSDynamicCast(OSString, theIterator->getNextObject()))) {
4300 const char * devTreeNameCString;
f427ee49
A
4301 OSData * deviceTreeEntry; // do not release
4302 OSString * myBundleID; // do not release
0a7de745
A
4303
4304 deviceTreeEntry =
4305 OSDynamicCast(OSData, theDictionary->getObject(deviceTreeName));
4306 if (!deviceTreeEntry) {
4307 continue;
4308 }
4309
4310 /* Make sure it is a kext */
4311 devTreeNameCString = deviceTreeName->getCStringNoCopy();
4312 if (strncmp(devTreeNameCString, BOOTER_KEXT_PREFIX,
4313 (sizeof(BOOTER_KEXT_PREFIX) - 1)) != 0) {
4314 OSKextLog(NULL,
4315 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4316 "\"%s\" not a kext",
4317 devTreeNameCString);
4318 continue;
4319 }
4320
4321 deviceTreeBuffer = (const _DeviceTreeBuffer *)
4322 deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
4323 if (!deviceTreeBuffer) {
4324 continue;
4325 }
4326
4327 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
4328 if (!booterDataPtr) {
4329 continue;
4330 }
4331
4332 kextFileInfo = (_BooterKextFileInfo *) booterDataPtr;
4333 if (!kextFileInfo->infoDictPhysAddr ||
4334 !kextFileInfo->infoDictLength) {
4335 continue;
4336 }
4337
4338 infoDictAddr = (char *)
4339 ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
4340 if (!infoDictAddr) {
4341 continue;
4342 }
4343
4344 parsedXML = OSUnserializeXML(infoDictAddr);
4345 if (!parsedXML) {
4346 continue;
4347 }
4348
f427ee49 4349 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
0a7de745
A
4350 if (!theInfoDict) {
4351 continue;
4352 }
4353
4354 myBundleID =
4355 OSDynamicCast(OSString,
4356 theInfoDict->getObject(kCFBundleIdentifierKey));
4357 if (myBundleID &&
f427ee49 4358 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
0a7de745
A
4359 boolean_t updated = updateExcludeList(theInfoDict);
4360 if (!updated) {
4361 /* 25322874 */
4362 panic("Missing OSKextExcludeList dictionary\n");
4363 }
4364 break;
4365 }
f427ee49 4366 } // while ( (deviceTreeName = ...) )
0a7de745 4367
0a7de745
A
4368 return;
4369}
4370
4371/*********************************************************************
4372* Create a dictionary of excluded kexts from the given prelink
4373* info (kernelcache).
4374*********************************************************************/
39236c6e
A
4375/* static */
4376void
4377OSKext::createExcludeListFromPrelinkInfo( OSArray * theInfoArray )
4378{
f427ee49
A
4379 OSDictionary * myInfoDict = NULL; // do not release
4380 OSString * myBundleID; // do not release
0a7de745
A
4381 u_int i;
4382
f427ee49 4383 /* Find the Apple Kext Exclude List. */
0a7de745
A
4384 for (i = 0; i < theInfoArray->getCount(); i++) {
4385 myInfoDict = OSDynamicCast(OSDictionary, theInfoArray->getObject(i));
4386 if (!myInfoDict) {
4387 continue;
4388 }
4389 myBundleID =
4390 OSDynamicCast(OSString,
4391 myInfoDict->getObject(kCFBundleIdentifierKey));
4392 if (myBundleID &&
f427ee49 4393 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
0a7de745
A
4394 boolean_t updated = updateExcludeList(myInfoDict);
4395 if (!updated) {
4396 /* 25322874 */
4397 panic("Missing OSKextExcludeList dictionary\n");
4398 }
4399 break;
4400 }
f427ee49 4401 } // for (i = 0; i < theInfoArray->getCount()...
0a7de745
A
4402
4403 return;
39236c6e
A
4404}
4405
cc8bc92a
A
4406/* static */
4407boolean_t
4408OSKext::updateExcludeList(OSDictionary *infoDict)
4409{
f427ee49
A
4410 OSDictionary *myTempDict = NULL; // do not free
4411 OSString *myTempString = NULL; // do not free
0a7de745
A
4412 OSKextVersion newVersion = 0;
4413 boolean_t updated = false;
cc8bc92a 4414
0a7de745
A
4415 if (!infoDict) {
4416 return false;
4417 }
cc8bc92a 4418
0a7de745
A
4419 myTempDict = OSDynamicCast(OSDictionary, infoDict->getObject("OSKextExcludeList"));
4420 if (!myTempDict) {
4421 return false;
4422 }
cc8bc92a 4423
0a7de745
A
4424 myTempString = OSDynamicCast(OSString, infoDict->getObject(kCFBundleVersionKey));
4425 if (!myTempString) {
4426 return false;
4427 }
cc8bc92a 4428
0a7de745
A
4429 newVersion = OSKextParseVersionString(myTempString->getCStringNoCopy());
4430 if (newVersion == 0) {
4431 return false;
4432 }
cc8bc92a 4433
0a7de745 4434 IORecursiveLockLock(sKextLock);
cc8bc92a 4435
0a7de745 4436 if (newVersion > sExcludeListVersion) {
0a7de745
A
4437 sExcludeListByID = OSDictionary::withDictionary(myTempDict, 0);
4438 sExcludeListVersion = newVersion;
4439 updated = true;
4440 }
cc8bc92a 4441
0a7de745
A
4442 IORecursiveLockUnlock(sKextLock);
4443 return updated;
cc8bc92a
A
4444}
4445
b0d623f7
A
4446#if PRAGMA_MARK
4447#pragma mark Accessors
4448#endif
4449/*********************************************************************
4450*********************************************************************/
4451const OSSymbol *
4452OSKext::getIdentifier(void)
4453{
f427ee49 4454 return bundleID.get();
b0d623f7
A
4455}
4456
4457/*********************************************************************
4458* A kext must have a bundle identifier to even survive initialization;
4459* this is guaranteed to exist past then.
4460*********************************************************************/
4461const char *
4462OSKext::getIdentifierCString(void)
4463{
0a7de745 4464 return bundleID->getCStringNoCopy();
b0d623f7
A
4465}
4466
4467/*********************************************************************
4468*********************************************************************/
4469OSKextVersion
4470OSKext::getVersion(void)
4471{
0a7de745 4472 return version;
b0d623f7
A
4473}
4474
4475/*********************************************************************
4476*********************************************************************/
4477OSKextVersion
4478OSKext::getCompatibleVersion(void)
4479{
0a7de745 4480 return compatibleVersion;
b0d623f7
A
4481}
4482
6d2010ae
A
4483/*********************************************************************
4484*********************************************************************/
4485bool
4486OSKext::isLibrary(void)
4487{
0a7de745 4488 return getCompatibleVersion() > 0;
6d2010ae
A
4489}
4490
b0d623f7
A
4491/*********************************************************************
4492*********************************************************************/
4493bool
4494OSKext::isCompatibleWithVersion(OSKextVersion aVersion)
4495{
0a7de745
A
4496 if ((compatibleVersion > -1 && version > -1) &&
4497 (compatibleVersion <= version && aVersion <= version)) {
4498 return true;
4499 }
4500 return false;
b0d623f7
A
4501}
4502
4503/*********************************************************************
4504*********************************************************************/
4505bool
4506OSKext::declaresExecutable(void)
4507{
cb323159
A
4508 if (isDriverKit()) {
4509 return false;
4510 }
0a7de745 4511 return getPropertyForHostArch(kCFBundleExecutableKey) != NULL;
b0d623f7
A
4512}
4513
4514/*********************************************************************
4515*********************************************************************/
4516OSData *
4517OSKext::getExecutable(void)
4518{
0a7de745 4519 OSData * result = NULL;
f427ee49 4520 OSSharedPtr<OSData> extractedExecutable;
0a7de745
A
4521
4522 if (flags.builtin) {
f427ee49 4523 return sKernelKext->linkedExecutable.get();
0a7de745
A
4524 }
4525
4526 result = OSDynamicCast(OSData, infoDict->getObject(_kOSKextExecutableKey));
4527 if (result) {
f427ee49 4528 return result;
0a7de745
A
4529 }
4530
f427ee49
A
4531#if CONFIG_KXLD
4532 OSData * mkextExecutableRef = NULL; // do not release
0a7de745
A
4533 mkextExecutableRef = OSDynamicCast(OSData,
4534 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey));
4535
4536 if (mkextExecutableRef) {
4537 MkextEntryRef * mkextEntryRef = (MkextEntryRef *)
4538 mkextExecutableRef->getBytesNoCopy();
4539 uint32_t mkextVersion = MKEXT_GET_VERSION(mkextEntryRef->mkext);
4540 if (mkextVersion == MKEXT_VERS_2) {
4541 mkext2_file_entry * fileinfo =
4542 (mkext2_file_entry *)mkextEntryRef->fileinfo;
4543 uint32_t compressedSize = MKEXT2_GET_ENTRY_COMPSIZE(fileinfo);
4544 uint32_t fullSize = MKEXT2_GET_ENTRY_FULLSIZE(fileinfo);
4545 extractedExecutable = extractMkext2FileData(
4546 MKEXT2_GET_ENTRY_DATA(fileinfo), "executable",
4547 compressedSize, fullSize);
4548 } else {
4549 OSKextLog(this, kOSKextLogErrorLevel |
4550 kOSKextLogArchiveFlag,
4551 "Kext %s - unknown mkext version 0x%x for executable.",
4552 getIdentifierCString(), mkextVersion);
4553 }
4554
4555 /* Regardless of success, remove the mkext executable,
4556 * and drop one reference on the mkext. (setExecutable() does not
4557 * replace, it removes, or panics if asked to replace.)
4558 */
4559 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
4560 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
4561
4562 if (extractedExecutable && extractedExecutable->getLength()) {
f427ee49 4563 if (!setExecutable(extractedExecutable.get())) {
0a7de745
A
4564 goto finish;
4565 }
f427ee49 4566 result = extractedExecutable.get();
0a7de745
A
4567 } else {
4568 goto finish;
4569 }
4570 }
b0d623f7
A
4571
4572finish:
f427ee49 4573#endif // CONFIG_KXLD
0a7de745 4574 return result;
b0d623f7
A
4575}
4576
4577/*********************************************************************
4578*********************************************************************/
4579bool
4580OSKext::isInterface(void)
4581{
0a7de745 4582 return flags.interface;
b0d623f7
A
4583}
4584
6d2010ae
A
4585/*********************************************************************
4586*********************************************************************/
4587bool
4588OSKext::isKernel(void)
4589{
0a7de745 4590 return this == sKernelKext;
6d2010ae
A
4591}
4592
b0d623f7
A
4593/*********************************************************************
4594*********************************************************************/
4595bool
4596OSKext::isKernelComponent(void)
4597{
0a7de745 4598 return flags.kernelComponent ? true : false;
b0d623f7
A
4599}
4600
6d2010ae
A
4601/*********************************************************************
4602*********************************************************************/
4603bool
4604OSKext::isExecutable(void)
4605{
0a7de745 4606 return !isKernel() && !isInterface() && declaresExecutable();
6d2010ae
A
4607}
4608
b0d623f7
A
4609/*********************************************************************
4610* We might want to check this recursively for all dependencies,
4611* since a subtree of dependencies could get loaded before we hit
4612* a dependency that isn't safe-boot-loadable.
4613*
4614* xxx - Might want to return false if OSBundleEnableKextLogging or
4615* OSBundleDebugLevel
4616* or IOKitDebug is nonzero too (we used to do that, but I don't see
4617* the point except it's usually development drivers, which might
4618* cause panics on startup, that have those properties). Heh; could
4619* use a "kx" boot-arg!
4620*********************************************************************/
4621bool
4622OSKext::isLoadableInSafeBoot(void)
4623{
0a7de745 4624 bool result = false;
f427ee49 4625 OSString * required = NULL; // do not release
0a7de745
A
4626
4627 if (isKernel()) {
4628 result = true;
4629 goto finish;
4630 }
4631
f427ee49
A
4632 if (isDriverKit()) {
4633 result = true;
4634 goto finish;
4635 }
4636
0a7de745
A
4637 required = OSDynamicCast(OSString,
4638 getPropertyForHostArch(kOSBundleRequiredKey));
4639 if (!required) {
4640 goto finish;
4641 }
4642 if (required->isEqualTo(kOSBundleRequiredRoot) ||
4643 required->isEqualTo(kOSBundleRequiredLocalRoot) ||
4644 required->isEqualTo(kOSBundleRequiredNetworkRoot) ||
4645 required->isEqualTo(kOSBundleRequiredSafeBoot) ||
4646 required->isEqualTo(kOSBundleRequiredConsole)) {
4647 result = true;
4648 }
4649
b0d623f7 4650finish:
0a7de745 4651 return result;
b0d623f7
A
4652}
4653
4654/*********************************************************************
4655*********************************************************************/
4656bool
4657OSKext::isPrelinked(void)
4658{
0a7de745 4659 return flags.prelinked ? true : false;
b0d623f7
A
4660}
4661
4662/*********************************************************************
4663*********************************************************************/
0a7de745
A
4664bool
4665OSKext::isLoaded(void)
b0d623f7 4666{
0a7de745 4667 return flags.loaded ? true : false;
b0d623f7
A
4668}
4669
4670/*********************************************************************
4671*********************************************************************/
4672bool
4673OSKext::isStarted(void)
4674{
0a7de745 4675 return flags.started ? true : false;
b0d623f7
A
4676}
4677
4678/*********************************************************************
4679*********************************************************************/
4680bool
4681OSKext::isCPPInitialized(void)
4682{
0a7de745 4683 return flags.CPPInitialized;
b0d623f7
A
4684}
4685
4686/*********************************************************************
4687*********************************************************************/
4688void
4689OSKext::setCPPInitialized(bool initialized)
4690{
0a7de745 4691 flags.CPPInitialized = initialized;
b0d623f7
A
4692}
4693
4694/*********************************************************************
4695*********************************************************************/
4696uint32_t
4697OSKext::getLoadTag(void)
4698{
0a7de745 4699 return loadTag;
b0d623f7
A
4700}
4701
6d2010ae 4702/*********************************************************************
0a7de745
A
4703*********************************************************************/
4704void
4705OSKext::getSizeInfo(uint32_t *loadSize, uint32_t *wiredSize)
6d2010ae 4706{
0a7de745
A
4707 if (linkedExecutable) {
4708 *loadSize = linkedExecutable->getLength();
4709
4710 /* If we have a kmod_info struct, calculated the wired size
4711 * from that. Otherwise it's the full load size.
4712 */
4713 if (kmod_info) {
f427ee49 4714 *wiredSize = *loadSize - (uint32_t)kmod_info->hdr_size;
0a7de745
A
4715 } else {
4716 *wiredSize = *loadSize;
4717 }
4718 } else {
4719 *wiredSize = 0;
4720 *loadSize = 0;
4721 }
6d2010ae
A
4722}
4723
b0d623f7
A
4724/*********************************************************************
4725*********************************************************************/
f427ee49 4726OSSharedPtr<OSData>
b0d623f7
A
4727OSKext::copyUUID(void)
4728{
f427ee49
A
4729 OSSharedPtr<OSData> result;
4730 OSData * theExecutable = NULL; // do not release
0a7de745
A
4731 const kernel_mach_header_t * header;
4732
4733 /* An interface kext doesn't have a linked executable with an LC_UUID,
4734 * we create one when it's linked.
4735 */
4736 if (interfaceUUID) {
4737 result = interfaceUUID;
0a7de745
A
4738 goto finish;
4739 }
4740
4741 if (flags.builtin || isInterface()) {
4742 return sKernelKext->copyUUID();
4743 }
4744
cb323159 4745 if (isDriverKit() && infoDict) {
f427ee49 4746 return driverKitUUID;
cb323159
A
4747 }
4748
0a7de745
A
4749 /* For real kexts, try to get the UUID from the linked executable,
4750 * or if is hasn't been linked yet, the unrelocated executable.
4751 */
f427ee49 4752 theExecutable = linkedExecutable.get();
0a7de745
A
4753 if (!theExecutable) {
4754 theExecutable = getExecutable();
4755 }
cb323159 4756
0a7de745
A
4757 if (!theExecutable) {
4758 goto finish;
4759 }
4760
4761 header = (const kernel_mach_header_t *)theExecutable->getBytesNoCopy();
4762 result = copyMachoUUID(header);
d9a64523
A
4763
4764finish:
0a7de745 4765 return result;
d9a64523
A
4766}
4767
4768/*********************************************************************
4769*********************************************************************/
f427ee49 4770OSSharedPtr<OSData>
d9a64523
A
4771OSKext::copyTextUUID(void)
4772{
0a7de745
A
4773 if (flags.builtin) {
4774 return copyMachoUUID((const kernel_mach_header_t *)kmod_info->address);
4775 }
4776 return copyUUID();
d9a64523
A
4777}
4778
4779/*********************************************************************
4780*********************************************************************/
f427ee49 4781OSSharedPtr<OSData>
d9a64523
A
4782OSKext::copyMachoUUID(const kernel_mach_header_t * header)
4783{
f427ee49 4784 OSSharedPtr<OSData> result;
0a7de745
A
4785 const struct load_command * load_cmd = NULL;
4786 const struct uuid_command * uuid_cmd = NULL;
4787 uint32_t i;
4788
4789 load_cmd = (const struct load_command *)&header[1];
4790
4791 if (header->magic != MH_MAGIC_KERNEL) {
4792 OSKextLog(NULL,
4793 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4794 "%s: bad header %p",
4795 __func__,
4796 header);
4797 goto finish;
4798 }
4799
4800 for (i = 0; i < header->ncmds; i++) {
4801 if (load_cmd->cmd == LC_UUID) {
4802 uuid_cmd = (struct uuid_command *)load_cmd;
4803 result = OSData::withBytes(uuid_cmd->uuid, sizeof(uuid_cmd->uuid));
4804 goto finish;
4805 }
4806 load_cmd = (struct load_command *)((caddr_t)load_cmd + load_cmd->cmdsize);
4807 }
b0d623f7
A
4808
4809finish:
0a7de745 4810 return result;
b0d623f7
A
4811}
4812
cb323159
A
4813void
4814OSKext::setDriverKitUUID(OSData *uuid)
4815{
4816 if (!OSCompareAndSwapPtr(nullptr, uuid, &driverKitUUID)) {
4817 OSSafeReleaseNULL(uuid);
4818 }
4819}
4820
b0d623f7
A
4821/*********************************************************************
4822*********************************************************************/
5ba3f43e
A
4823#if defined (__arm__)
4824#include <arm/arch.h>
4825#endif
316670eb 4826
39236c6e 4827#if defined (__x86_64__)
b0d623f7 4828#define ARCHNAME "x86_64"
5ba3f43e
A
4829#elif defined (__arm64__)
4830#define ARCHNAME "arm64"
4831#elif defined (__arm__)
4832
4833#if defined (__ARM_ARCH_7S__)
4834#define ARCHNAME "armv7s"
4835#elif defined (__ARM_ARCH_7F__)
4836#define ARCHNAME "armv7f"
4837#elif defined (__ARM_ARCH_7K__)
4838#define ARCHNAME "armv7k"
4839#elif defined (_ARM_ARCH_7) /* umbrella for all remaining */
4840#define ARCHNAME "armv7"
4841#elif defined (_ARM_ARCH_6) /* umbrella for all armv6 */
4842#define ARCHNAME "armv6"
4843#endif
4844
4845#elif defined (__arm64__)
4846#define ARCHNAME "arm64"
b0d623f7
A
4847#else
4848#error architecture not supported
4849#endif
4850
4851#define ARCH_SEPARATOR_CHAR '_'
4852
0a7de745 4853static char *
f427ee49 4854makeHostArchKey(const char * key, size_t * keySizeOut)
0a7de745
A
4855{
4856 char * result = NULL;
f427ee49
A
4857 size_t keyLength = strlen(key);
4858 size_t keySize;
0a7de745
A
4859
4860 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
4861 */
f427ee49
A
4862 keySize = 1 + 1 + keyLength + strlen(ARCHNAME);
4863 result = (char *)kheap_alloc_tag(KHEAP_TEMP, keySize,
4864 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
4865
0a7de745
A
4866 if (!result) {
4867 goto finish;
4868 }
4869 strlcpy(result, key, keySize);
4870 result[keyLength++] = ARCH_SEPARATOR_CHAR;
4871 result[keyLength] = '\0';
4872 strlcat(result, ARCHNAME, keySize);
4873 *keySizeOut = keySize;
b0d623f7
A
4874
4875finish:
0a7de745 4876 return result;
b0d623f7
A
4877}
4878
4879/*********************************************************************
4880*********************************************************************/
4881OSObject *
4882OSKext::getPropertyForHostArch(const char * key)
4883{
0a7de745 4884 OSObject * result = NULL;// do not release
f427ee49 4885 size_t hostArchKeySize = 0;
0a7de745
A
4886 char * hostArchKey = NULL;// must kfree
4887
4888 if (!key || !infoDict) {
4889 goto finish;
4890 }
4891
4892 /* Some properties are not allowed to be arch-variant:
4893 * - Any CFBundle... property.
4894 * - OSBundleIsInterface.
4895 * - OSKernelResource.
4896 */
4897 if (STRING_HAS_PREFIX(key, "OS") ||
4898 STRING_HAS_PREFIX(key, "IO")) {
4899 hostArchKey = makeHostArchKey(key, &hostArchKeySize);
4900 if (!hostArchKey) {
4901 OSKextLog(/* kext (this isn't about a kext) */ NULL,
4902 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4903 "Allocation failure.");
4904 goto finish;
4905 }
4906 result = infoDict->getObject(hostArchKey);
4907 }
4908
4909 if (!result) {
4910 result = infoDict->getObject(key);
4911 }
b0d623f7
A
4912
4913finish:
0a7de745 4914 if (hostArchKey) {
f427ee49 4915 kheap_free(KHEAP_TEMP, hostArchKey, hostArchKeySize);
0a7de745
A
4916 }
4917 return result;
b0d623f7
A
4918}
4919
4920#if PRAGMA_MARK
4921#pragma mark Load/Start/Stop/Unload
4922#endif
39236c6e 4923
0a7de745 4924#define isWhiteSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == ',' || (c) == '\n')
39236c6e
A
4925
4926/*********************************************************************
0a7de745
A
4927* sExcludeListByID is a dictionary with keys / values of:
4928* key = bundleID string of kext we will not allow to load
4929* value = version string(s) of the kext that is to be denied loading.
4930* The version strings can be comma delimited. For example if kext
4931* com.foocompany.fookext has two versions that we want to deny
4932* loading then the version strings might look like:
4933* 1.0.0, 1.0.1
4934* If the current fookext has a version of 1.0.0 OR 1.0.1 we will
4935* not load the kext.
4936*
4937* Value may also be in the form of "LE 2.0.0" (version numbers
4938* less than or equal to 2.0.0 will not load) or "LT 2.0.0" (version
4939* number less than 2.0.0 will not load)
4940*
4941* NOTE - we cannot use the characters "<=" or "<" because we have code
4942* that serializes plists and treats '<' as a special character.
4943*********************************************************************/
4944bool
39236c6e
A
4945OSKext::isInExcludeList(void)
4946{
f427ee49
A
4947 OSString * versionString = NULL; // do not release
4948 char * versionCString = NULL; // do not free
0a7de745
A
4949 size_t i;
4950 boolean_t wantLessThan = false;
4951 boolean_t wantLessThanEqualTo = false;
4952 boolean_t isInExcludeList = true;
4953 char myBuffer[32];
4954
4955 IORecursiveLockLock(sKextLock);
4956
4957 if (!sExcludeListByID) {
4958 isInExcludeList = false;
4959 } else {
4960 /* look up by bundleID in our exclude list and if found get version
4961 * string (or strings) that we will not allow to load
4962 */
f427ee49 4963 versionString = OSDynamicCast(OSString, sExcludeListByID->getObject(bundleID.get()));
0a7de745
A
4964 if (versionString == NULL || versionString->getLength() > (sizeof(myBuffer) - 1)) {
4965 isInExcludeList = false;
4966 }
4967 }
4968
4969 IORecursiveLockUnlock(sKextLock);
4970
4971 if (!isInExcludeList) {
4972 return false;
4973 }
4974
4975 /* parse version strings */
4976 versionCString = (char *) versionString->getCStringNoCopy();
4977
4978 /* look for "LT" or "LE" form of version string, must be in first two
4979 * positions.
4980 */
4981 if (*versionCString == 'L' && *(versionCString + 1) == 'T') {
4982 wantLessThan = true;
4983 versionCString += 2;
4984 } else if (*versionCString == 'L' && *(versionCString + 1) == 'E') {
4985 wantLessThanEqualTo = true;
4986 versionCString += 2;
4987 }
4988
4989 for (i = 0; *versionCString != 0x00; versionCString++) {
4990 /* skip whitespace */
4991 if (isWhiteSpace(*versionCString)) {
4992 continue;
4993 }
4994
4995 /* peek ahead for version string separator or null terminator */
4996 if (*(versionCString + 1) == ',' || *(versionCString + 1) == 0x00) {
4997 /* OK, we have a version string */
4998 myBuffer[i++] = *versionCString;
4999 myBuffer[i] = 0x00;
5000
5001 OSKextVersion excludeVers;
5002 excludeVers = OSKextParseVersionString(myBuffer);
5003
5004 if (wantLessThanEqualTo) {
5005 if (version <= excludeVers) {
5006 return true;
5007 }
5008 } else if (wantLessThan) {
5009 if (version < excludeVers) {
5010 return true;
5011 }
5012 } else if (version == excludeVers) {
5013 return true;
5014 }
5015
5016 /* reset for the next (if any) version string */
5017 i = 0;
5018 wantLessThan = false;
5019 wantLessThanEqualTo = false;
5020 } else {
5021 /* save valid version character */
5022 myBuffer[i++] = *versionCString;
5023
5024 /* make sure bogus version string doesn't overrun local buffer */
5025 if (i >= sizeof(myBuffer)) {
5026 break;
5027 }
5028 }
5029 }
5030
5031 return false;
5032}
39236c6e 5033
f427ee49
A
5034/*********************************************************************
5035* sNonLoadableKextsByID is a dictionary with keys / values of:
5036* key = bundleID string of kext we will not allow to load
5037* value = boolean (true == loadable, false == not loadable)
5038*
5039* Only kexts which are in the AuxKC will be marked as "not loadble,"
5040* i.e., the value for the kext's bundleID will be false. All kexts in
5041* the primary and system KCs will always be marked as "loadable."
5042*
5043* This list ultimately comes from kexts which have been uninstalled
5044* in user space by deleting the kext from disk, but which have not
5045* yet been removed from the AuxKC. Because the user could choose to
5046* re-install the exact same version of the kext, we need to keep
5047* a dictionary of boolean values so that user space only needs to
5048* keep a simple list of "uninstalled" or "missing" bundles. When
5049* a bundle is re-installed, the iokit daemon can use the
5050* AucKCBundleAvailable predicate to set the individual kext's
5051* availability to true.
5052*********************************************************************/
5053bool
5054OSKext::isLoadable(void)
5055{
5056 bool isLoadable = true;
5057
5058 if (kc_type != KCKindAuxiliary) {
5059 /* this filtering only applies to kexts in the auxkc */
5060 return true;
5061 }
5062
5063 IORecursiveLockLock(sKextLock);
5064
5065 if (sNonLoadableKextsByID) {
5066 /* look up by bundleID in our exclude list and if found get version
5067 * string (or strings) that we will not allow to load
5068 */
5069 OSBoolean *loadableVal;
5070 loadableVal = OSDynamicCast(OSBoolean, sNonLoadableKextsByID->getObject(bundleID.get()));
5071 if (loadableVal && !loadableVal->getValue()) {
5072 isLoadable = false;
5073 }
5074 }
5075 IORecursiveLockUnlock(sKextLock);
5076
5077 return isLoadable;
5078}
5079
b0d623f7
A
5080/*********************************************************************
5081*********************************************************************/
6d2010ae 5082/* static */
b0d623f7
A
5083OSReturn
5084OSKext::loadKextWithIdentifier(
0a7de745
A
5085 const char * kextIdentifierCString,
5086 Boolean allowDeferFlag,
5087 Boolean delayAutounloadFlag,
5088 OSKextExcludeLevel startOpt,
5089 OSKextExcludeLevel startMatchingOpt,
5090 OSArray * personalityNames)
5091{
5092 OSReturn result = kOSReturnError;
f427ee49 5093 OSSharedPtr<OSString> kextIdentifier;
0a7de745
A
5094
5095 kextIdentifier = OSString::withCString(kextIdentifierCString);
5096 if (!kextIdentifier) {
5097 result = kOSKextReturnNoMemory;
5098 goto finish;
5099 }
f427ee49 5100 result = OSKext::loadKextWithIdentifier(kextIdentifier.get(),
cb323159 5101 NULL /* kextRef */,
0a7de745
A
5102 allowDeferFlag, delayAutounloadFlag,
5103 startOpt, startMatchingOpt, personalityNames);
5104
b0d623f7 5105finish:
f427ee49
A
5106 return result;
5107}
5108
5109OSReturn
5110OSKext::loadKextWithIdentifier(
5111 OSString * kextIdentifier,
5112 OSSharedPtr<OSObject> &kextRef,
5113 Boolean allowDeferFlag,
5114 Boolean delayAutounloadFlag,
5115 OSKextExcludeLevel startOpt,
5116 OSKextExcludeLevel startMatchingOpt,
5117 OSArray * personalityNames)
5118{
5119 OSObject * kextRefRaw = NULL;
5120 OSReturn result;
5121
5122 result = loadKextWithIdentifier(kextIdentifier,
5123 &kextRefRaw,
5124 allowDeferFlag,
5125 delayAutounloadFlag,
5126 startOpt,
5127 startMatchingOpt,
5128 personalityNames);
5129 if ((kOSReturnSuccess == result) && kextRefRaw) {
5130 kextRef.reset(kextRefRaw, OSNoRetain);
5131 }
0a7de745 5132 return result;
b0d623f7
A
5133}
5134
b0d623f7
A
5135/*********************************************************************
5136*********************************************************************/
5137OSReturn
5138OSKext::loadKextWithIdentifier(
0a7de745 5139 OSString * kextIdentifier,
cb323159 5140 OSObject ** kextRef,
0a7de745
A
5141 Boolean allowDeferFlag,
5142 Boolean delayAutounloadFlag,
5143 OSKextExcludeLevel startOpt,
5144 OSKextExcludeLevel startMatchingOpt,
5145 OSArray * personalityNames)
5146{
5147 OSReturn result = kOSReturnError;
5148 OSReturn pingResult = kOSReturnError;
f427ee49
A
5149 OSKext * theKext = NULL; // do not release
5150 OSSharedPtr<OSDictionary> loadRequest;
5151 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
0a7de745 5152
cb323159
A
5153 if (kextRef) {
5154 *kextRef = NULL;
5155 }
5156
0a7de745
A
5157 IORecursiveLockLock(sKextLock);
5158
5159 if (!kextIdentifier) {
5160 result = kOSKextReturnInvalidArgument;
5161 goto finish;
5162 }
5163
5164 OSKext::recordIdentifierRequest(kextIdentifier);
5165
5166 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
5167 if (!theKext) {
5168 if (!allowDeferFlag) {
5169 OSKextLog(/* kext */ NULL,
5170 kOSKextLogErrorLevel |
5171 kOSKextLogLoadFlag,
5172 "Can't load kext %s - not found.",
5173 kextIdentifier->getCStringNoCopy());
5174 goto finish;
5175 }
5176
5177 if (!sKernelRequestsEnabled) {
5178 OSKextLog(theKext,
5179 kOSKextLogErrorLevel |
5180 kOSKextLogLoadFlag,
5181 "Can't load kext %s - requests to user space are disabled.",
5182 kextIdentifier->getCStringNoCopy());
5183 result = kOSKextReturnDisabled;
5184 goto finish;
5185 }
5186
5187 /* Create a new request unless one is already sitting
5188 * in sKernelRequests for this bundle identifier
5189 */
5190 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
f427ee49 5191 if (!sPostedKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
0a7de745 5192 result = _OSKextCreateRequest(kKextRequestPredicateRequestLoad,
f427ee49 5193 loadRequest);
0a7de745
A
5194 if (result != kOSReturnSuccess) {
5195 goto finish;
5196 }
f427ee49 5197 if (!_OSKextSetRequestArgument(loadRequest.get(),
0a7de745
A
5198 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
5199 result = kOSKextReturnNoMemory;
5200 goto finish;
5201 }
f427ee49 5202 if (!sKernelRequests->setObject(loadRequest.get())) {
0a7de745
A
5203 result = kOSKextReturnNoMemory;
5204 goto finish;
5205 }
5206
f427ee49 5207 if (!sPostedKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
0a7de745
A
5208 result = kOSKextReturnNoMemory;
5209 goto finish;
5210 }
5211
5212 OSKextLog(theKext,
5213 kOSKextLogDebugLevel |
5214 kOSKextLogLoadFlag,
5215 "Kext %s not found; queued load request to user space.",
5216 kextIdentifier->getCStringNoCopy());
5217 }
5218
f427ee49 5219 pingResult = OSKext::pingIOKitDaemon();
0a7de745
A
5220 if (pingResult == kOSKextReturnDisabled) {
5221 OSKextLog(/* kext */ NULL,
5222 ((sPrelinkBoot) ? kOSKextLogDebugLevel : kOSKextLogErrorLevel) |
5223 kOSKextLogLoadFlag,
f427ee49 5224 "Kext %s might not load - " kIOKitDaemonName " is currently unavailable.",
0a7de745
A
5225 kextIdentifier->getCStringNoCopy());
5226 }
5227
5228 result = kOSKextReturnDeferred;
5229 goto finish;
5230 }
5231
5232 result = theKext->load(startOpt, startMatchingOpt, personalityNames);
5233
5234 if (result != kOSReturnSuccess) {
5235 OSKextLog(theKext,
5236 kOSKextLogErrorLevel |
5237 kOSKextLogLoadFlag,
5238 "Failed to load kext %s (error 0x%x).",
5239 kextIdentifier->getCStringNoCopy(), (int)result);
5240
f427ee49
A
5241 if (theKext->kc_type == KCKindUnknown) {
5242 OSKext::removeKext(theKext,
5243 /* terminateService/removePersonalities */ true);
5244 }
0a7de745
A
5245 goto finish;
5246 }
5247
5248 if (delayAutounloadFlag) {
5249 OSKextLog(theKext,
5250 kOSKextLogProgressLevel |
5251 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5252 "Setting delayed autounload for %s.",
5253 kextIdentifier->getCStringNoCopy());
5254 theKext->flags.delayAutounload = 1;
5255 }
b0d623f7
A
5256
5257finish:
cb323159 5258 if ((kOSReturnSuccess == result) && kextRef) {
cb323159 5259 *kextRef = theKext;
f427ee49
A
5260 theKext->matchingRefCount++;
5261 theKext->retain();
cb323159
A
5262 }
5263
0a7de745 5264 IORecursiveLockUnlock(sKextLock);
b0d623f7 5265
0a7de745 5266 return result;
b0d623f7
A
5267}
5268
5269/*********************************************************************
5270*********************************************************************/
5271/* static */
f427ee49
A
5272OSReturn
5273OSKext::loadKextFromKC(OSKext *theKext, OSDictionary *requestDict)
0a7de745 5274{
f427ee49 5275 OSReturn result = kOSReturnError;
0a7de745 5276
f427ee49
A
5277 OSBoolean *delayAutounloadBool = NULL; // do not release
5278 OSNumber *startKextExcludeNum = NULL; // do not release
5279 OSNumber *startMatchingExcludeNum = NULL; // do not release
5280 OSArray *personalityNames = NULL; // do not release
0a7de745 5281
f427ee49
A
5282 /*
5283 * Default values for these options:
5284 * regular autounload behavior
5285 * start the kext
5286 * send all personalities to the catalog
5287 */
5288 Boolean delayAutounload = false;
5289 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
5290 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeNone;
0a7de745
A
5291
5292 IORecursiveLockLock(sKextLock);
d190cdc3 5293
f427ee49
A
5294 OSKextLog(/* kext */ NULL,
5295 kOSKextLogDebugLevel |
5296 kOSKextLogIPCFlag,
5297 "Received kext KC load request from user space.");
b0d623f7 5298
f427ee49
A
5299 /* Regardless of processing, the fact that we have gotten here means some
5300 * user-space program is up and talking to us, so we'll switch our kext
5301 * registration to reflect that.
5302 */
5303 if (!sUserLoadsActive) {
5304 OSKextLog(/* kext */ NULL,
5305 kOSKextLogProgressLevel |
5306 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5307 "Switching to late startup (user-space) kext loading policy.");
5308 sUserLoadsActive = true;
5309 }
5310
5311 delayAutounloadBool = OSDynamicCast(OSBoolean,
5312 _OSKextGetRequestArgument(requestDict,
5313 kKextRequestArgumentDelayAutounloadKey));
5314 startKextExcludeNum = OSDynamicCast(OSNumber,
5315 _OSKextGetRequestArgument(requestDict,
5316 kKextRequestArgumentStartExcludeKey));
5317 startMatchingExcludeNum = OSDynamicCast(OSNumber,
5318 _OSKextGetRequestArgument(requestDict,
5319 kKextRequestArgumentStartMatchingExcludeKey));
5320 personalityNames = OSDynamicCast(OSArray,
5321 _OSKextGetRequestArgument(requestDict,
5322 kKextRequestArgumentPersonalityNamesKey));
5323
5324 if (delayAutounloadBool) {
5325 delayAutounload = delayAutounloadBool->getValue();
5326 }
5327 if (startKextExcludeNum) {
5328 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
5329 }
5330 if (startMatchingExcludeNum) {
5331 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
5332 }
5333
5334 OSKextLog(/* kext */ NULL,
5335 kOSKextLogProgressLevel |
5336 kOSKextLogIPCFlag,
5337 "Received request from user space to load KC kext %s.",
5338 theKext->getIdentifierCString());
5339
5340 /* this could be in the Auxiliary KC, so record the load request */
5341 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, theKext->getIdentifier()));
5342
5343 /*
5344 * Load the kext
5345 */
5346 result = theKext->load(startKextExcludeLevel,
5347 startMatchingExcludeLevel, personalityNames);
5348
5349 if (result != kOSReturnSuccess) {
5350 OSKextLog(theKext,
5351 kOSKextLogErrorLevel |
5352 kOSKextLogLoadFlag,
5353 "Failed to load kext %s (error 0x%x).",
5354 theKext->getIdentifierCString(), (int)result);
5355
5356 OSKext::removeKext(theKext,
5357 /* terminateService/removePersonalities */ true);
5358 goto finish;
5359 } else {
5360 OSKextLog(theKext,
5361 kOSKextLogProgressLevel |
5362 kOSKextLogLoadFlag,
5363 "Kext %s Loaded successfully from %s KC",
5364 theKext->getIdentifierCString(), theKext->getKCTypeString());
5365 }
5366
5367 if (delayAutounload) {
5368 OSKextLog(theKext,
5369 kOSKextLogProgressLevel |
5370 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5371 "Setting delayed autounload for %s.",
5372 theKext->getIdentifierCString());
5373 theKext->flags.delayAutounload = 1;
5374 }
5375
5376finish:
5377 IORecursiveLockUnlock(sKextLock);
5378
5379 return result;
5380}
5381
5382/*********************************************************************
5383*********************************************************************/
5384/* static */
5385OSReturn
5386OSKext::loadCodelessKext(OSString *kextIdentifier, OSDictionary *requestDict)
5387{
5388 OSReturn result = kOSReturnError;
5389 OSDictionary *anInfoDict = NULL; // do not release
5390
5391 anInfoDict = OSDynamicCast(OSDictionary,
5392 _OSKextGetRequestArgument(requestDict,
5393 kKextRequestArgumentCodelessInfoKey));
5394 if (anInfoDict == NULL) {
5395 OSKextLog(/* kext */ NULL,
5396 kOSKextLogErrorLevel |
5397 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5398 "Missing 'Codeless Kext Info' dictionary in codeless kext load request of %s.",
5399 kextIdentifier->getCStringNoCopy());
5400 return kOSKextReturnInvalidArgument;
5401 }
5402
5403 IORecursiveLockLock(sKextLock);
5404
5405 OSKextLog(/* kext */ NULL,
5406 kOSKextLogProgressLevel |
5407 kOSKextLogIPCFlag,
5408 "Received request from user space to load codeless kext %s.",
5409 kextIdentifier->getCStringNoCopy());
5410
5411 {
5412 // instantiate a new kext, and don't hold a reference
5413 // (the kext subsystem will hold one implicitly)
5414 OSSharedPtr<OSKext> newKext = OSKext::withCodelessInfo(anInfoDict);
5415 if (!newKext) {
5416 OSKextLog(/* kext */ NULL,
5417 kOSKextLogErrorLevel |
5418 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5419 "Could not instantiate codeless kext.");
5420 result = kOSKextReturnNotLoadable;
5421 goto finish;
5422 }
5423 if (!kextIdentifier->isEqualTo(newKext->getIdentifierCString())) {
5424 OSKextLog(/* kext */ NULL,
5425 kOSKextLogErrorLevel |
5426 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5427 "Codeless kext identifiers don't match '%s' != '%s'",
5428 kextIdentifier->getCStringNoCopy(), newKext->getIdentifierCString());
5429
5430 OSKext::removeKext(newKext.get(), false);
5431 result = kOSKextReturnInvalidArgument;
5432 goto finish;
5433 }
5434
5435 /* Record the request for the codeless kext */
5436 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, newKext->getIdentifier()));
5437
5438 result = kOSReturnSuccess;
2a1bd2d3
A
5439 /* Send the kext's personalities to the IOCatalog. This is an explicit load. */
5440 result = newKext->sendPersonalitiesToCatalog(true, NULL);
f427ee49
A
5441 }
5442
5443finish:
5444 IORecursiveLockUnlock(sKextLock);
5445
5446 return result;
5447}
5448
5449/*********************************************************************
5450*********************************************************************/
5451/* static */
5452void
5453OSKext::dropMatchingReferences(
5454 OSSet * kexts)
5455{
5456 IORecursiveLockLock(sKextLock);
5457 kexts->iterateObjects(^bool (OSObject * obj) {
5458 OSKext * thisKext = OSDynamicCast(OSKext, obj);
5459 if (!thisKext) {
5460 return false;
5461 }
5462 thisKext->matchingRefCount--;
5463 return false;
5464 });
5465 IORecursiveLockUnlock(sKextLock);
5466}
5467
5468/*********************************************************************
5469*********************************************************************/
5470/* static */
5471void
5472OSKext::recordIdentifierRequest(
5473 OSString * kextIdentifier)
5474{
5475 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
5476 bool fail = false;
5477
5478 if (!sAllKextLoadIdentifiers || !kextIdentifier) {
5479 goto finish;
5480 }
5481
5482 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
5483 if (!kextIdentifierSymbol) {
5484 // xxx - this is really a basic alloc failure
5485 fail = true;
5486 goto finish;
5487 }
5488
5489 IORecursiveLockLock(sKextLock);
5490 if (!sAllKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
5491 if (!sAllKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
5492 fail = true;
5493 } else {
5494 // xxx - need to find a way to associate this whole func w/the kext
5495 OSKextLog(/* kext */ NULL,
5496 // xxx - check level
5497 kOSKextLogStepLevel |
5498 kOSKextLogArchiveFlag,
5499 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
5500 kextIdentifier->getCStringNoCopy());
5501 }
5502 }
5503 IORecursiveLockUnlock(sKextLock);
5504
5505finish:
5506
5507 if (fail) {
0a7de745
A
5508 OSKextLog(/* kext */ NULL,
5509 kOSKextLogErrorLevel |
5510 kOSKextLogArchiveFlag,
5511 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
5512 kextIdentifier->getCStringNoCopy());
5513 }
0a7de745 5514 return;
b0d623f7
A
5515}
5516
5517/*********************************************************************
5518*********************************************************************/
5519OSReturn
5520OSKext::load(
0a7de745
A
5521 OSKextExcludeLevel startOpt,
5522 OSKextExcludeLevel startMatchingOpt,
5523 OSArray * personalityNames)
5524{
5525 OSReturn result = kOSReturnError;
0a7de745
A
5526 OSKextExcludeLevel dependenciesStartOpt = startOpt;
5527 OSKextExcludeLevel dependenciesStartMatchingOpt = startMatchingOpt;
5528 unsigned int i, count;
5529 Boolean alreadyLoaded = false;
f427ee49 5530 OSKext * lastLoadedKext = NULL; // do not release
0a7de745
A
5531
5532 if (isInExcludeList()) {
5533 OSKextLog(this,
5534 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
5535 kOSKextLogLoadFlag,
5536 "Kext %s is in exclude list, not loadable",
5537 getIdentifierCString());
5538
5539 result = kOSKextReturnNotLoadable;
5540 goto finish;
5541 }
f427ee49
A
5542 if (!isLoadable()) {
5543 OSKextLog(this,
5544 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
5545 kOSKextLogLoadFlag,
5546 "Kext %s is not loadable",
5547 getIdentifierCString());
5548
5549 result = kOSKextReturnNotLoadable;
5550 goto finish;
5551 }
0a7de745
A
5552
5553 if (isLoaded()) {
5554 alreadyLoaded = true;
5555 result = kOSReturnSuccess;
5556
5557 OSKextLog(this,
5558 kOSKextLogDebugLevel |
5559 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5560 "Kext %s is already loaded.",
5561 getIdentifierCString());
5562 goto loaded;
5563 }
5564
f427ee49
A
5565#if CONFIG_MACF && XNU_TARGET_OS_OSX
5566#if CONFIG_KXLD
0a7de745 5567 if (current_task() != kernel_task) {
f427ee49
A
5568#else
5569 /*
5570 * On non-kxld systems, only check the mac-hook for kexts in the
5571 * Pageable and Aux KCs. This means on Apple silicon devices that
5572 * the mac hook will only be useful to block 3rd party kexts.
5573 *
5574 * Note that this should _not_ be called on kexts loaded from the
5575 * kernel bootstrap thread as the kernel proc's cred struct is not
5576 * yet initialized! This won't happen on macOS because all the kexts
5577 * in the BootKC are self-contained and their kc_type = KCKindPrimary.
5578 */
5579 if (kc_type != KCKindPrimary && kc_type != KCKindUnknown) {
5580#endif /* CONFIG_KXLD */
0a7de745
A
5581 int macCheckResult = 0;
5582 kauth_cred_t cred = NULL;
5583
5584 cred = kauth_cred_get_with_ref();
5585 macCheckResult = mac_kext_check_load(cred, getIdentifierCString());
5586 kauth_cred_unref(&cred);
5587
5588 if (macCheckResult != 0) {
5589 result = kOSReturnError;
5590 OSKextLog(this,
5591 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5592 "Failed to load kext %s (MAC policy error 0x%x).",
5593 getIdentifierCString(), macCheckResult);
5594 goto finish;
5595 }
5596 }
fe8ab488 5597#endif
b0d623f7 5598
0a7de745
A
5599 if (!sLoadEnabled) {
5600 OSKextLog(this,
5601 kOSKextLogErrorLevel |
5602 kOSKextLogLoadFlag,
5603 "Kext loading is disabled (attempt to load kext %s).",
5604 getIdentifierCString());
5605 result = kOSKextReturnDisabled;
5606 goto finish;
5607 }
5608
5609 /* If we've pushed the next available load tag to the invalid value,
5610 * we can't load any more kexts.
5611 */
5612 if (sNextLoadTag == kOSKextInvalidLoadTag) {
5613 OSKextLog(this,
5614 kOSKextLogErrorLevel |
5615 kOSKextLogLoadFlag,
5616 "Can't load kext %s - no more load tags to assign.",
5617 getIdentifierCString());
5618 result = kOSKextReturnNoResources;
5619 goto finish;
5620 }
5621
5622 /* This is a bit of a hack, because we shouldn't be handling
5623 * personalities within the load function.
5624 */
5625 if (!declaresExecutable()) {
5626 /* There is a special case where a non-executable kext can be loaded: the
5627 * AppleKextExcludeList. Detect that special kext by bundle identifier and
5628 * load its metadata into the global data structures, if appropriate
5629 */
f427ee49
A
5630 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
5631 boolean_t updated = updateExcludeList(infoDict.get());
0a7de745
A
5632 if (updated) {
5633 OSKextLog(this,
5634 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
5635 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
5636 }
5637 }
cb323159
A
5638
5639 if (isDriverKit()) {
5640 if (loadTag == 0) {
5641 sLoadedDriverKitKexts->setObject(this);
5642 loadTag = sNextLoadTag++;
5643 }
5644 }
0a7de745
A
5645 result = kOSReturnSuccess;
5646 goto loaded;
5647 }
5648
5649 /* Are we in safe boot?
5650 */
5651 if (sSafeBoot && !isLoadableInSafeBoot()) {
5652 OSKextLog(this,
5653 kOSKextLogErrorLevel |
5654 kOSKextLogLoadFlag,
5655 "Can't load kext %s - not loadable during safe boot.",
5656 getIdentifierCString());
5657 result = kOSKextReturnBootLevel;
5658 goto finish;
5659 }
5660
5661 OSKextLog(this,
5662 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5663 "Loading kext %s.",
5664 getIdentifierCString());
5665
f427ee49
A
5666#if !VM_MAPPED_KEXTS
5667 if (isPrelinked() == false) {
5668 OSKextLog(this,
5669 kOSKextLogErrorLevel |
5670 kOSKextLogLoadFlag,
5671 "Can't load kext %s - not in a kext collection.",
5672 getIdentifierCString());
5673 result = kOSKextReturnDisabled;
5674 goto finish;
5675 }
5676#endif /* defined(__x86_64__) */
5677
5678#if CONFIG_KXLD
0a7de745 5679 if (!sKxldContext) {
f427ee49 5680 kern_return_t kxldResult;
0a7de745
A
5681 kxldResult = kxld_create_context(&sKxldContext, &kern_allocate,
5682 &kxld_log_callback, /* Flags */ (KXLDFlags) 0,
5683 /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
5684 if (kxldResult) {
5685 OSKextLog(this,
5686 kOSKextLogErrorLevel |
5687 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
5688 "Can't load kext %s - failed to create link context.",
5689 getIdentifierCString());
5690 result = kOSKextReturnNoMemory;
5691 goto finish;
5692 }
5693 }
f427ee49 5694#endif // CONFIG_KXLD
0a7de745
A
5695
5696 /* We only need to resolve dependencies once for the whole graph, but
5697 * resolveDependencies will just return if there's no work to do, so it's
5698 * safe to call it more than once.
5699 */
5700 if (!resolveDependencies()) {
5701 // xxx - check resolveDependencies() for log msg
5702 OSKextLog(this,
5703 kOSKextLogErrorLevel |
5704 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5705 "Can't load kext %s - failed to resolve library dependencies.",
5706 getIdentifierCString());
5707 result = kOSKextReturnDependencies;
5708 goto finish;
5709 }
5710
5711 /* If we are excluding just the kext being loaded now (and not its
5712 * dependencies), drop the exclusion level to none so dependencies
5713 * start and/or add their personalities.
5714 */
5715 if (dependenciesStartOpt == kOSKextExcludeKext) {
5716 dependenciesStartOpt = kOSKextExcludeNone;
5717 }
5718
5719 if (dependenciesStartMatchingOpt == kOSKextExcludeKext) {
5720 dependenciesStartMatchingOpt = kOSKextExcludeNone;
5721 }
5722
5723 /* Load the dependencies, recursively.
5724 */
5725 count = getNumDependencies();
5726 for (i = 0; i < count; i++) {
5727 OSKext * dependency = OSDynamicCast(OSKext,
5728 dependencies->getObject(i));
5729 if (dependency == NULL) {
5730 OSKextLog(this,
5731 kOSKextLogErrorLevel |
5732 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5733 "Internal error loading kext %s; dependency disappeared.",
5734 getIdentifierCString());
5735 result = kOSKextReturnInternalError;
5736 goto finish;
5737 }
5738
5739 /* Dependencies must be started accorting to the opt,
5740 * but not given the personality names of the main kext.
5741 */
5742 result = dependency->load(dependenciesStartOpt,
5743 dependenciesStartMatchingOpt,
5744 /* personalityNames */ NULL);
5745 if (result != KERN_SUCCESS) {
5746 OSKextLog(this,
5747 kOSKextLogErrorLevel |
5748 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5749 "Dependency %s of kext %s failed to load.",
5750 dependency->getIdentifierCString(),
5751 getIdentifierCString());
5752
5753 OSKext::removeKext(dependency,
5754 /* terminateService/removePersonalities */ true);
5755 result = kOSKextReturnDependencyLoadError;
5756
5757 goto finish;
5758 }
5759 }
5760
5761 result = loadExecutable();
5762 if (result != KERN_SUCCESS) {
5763 goto finish;
5764 }
5765
5766 pendingPgoHead.next = &pendingPgoHead;
5767 pendingPgoHead.prev = &pendingPgoHead;
5768
5769 // The kernel PRNG is not initialized when the first kext is
5770 // loaded, so use early random
5771 uuid_generate_early_random(instance_uuid);
5772 account = IONew(OSKextAccount, 1);
5773 if (!account) {
5774 result = KERN_MEMORY_ERROR;
5775 goto finish;
5776 }
5777 bzero(account, sizeof(*account));
5778 account->loadTag = kmod_info->id;
5779 account->site.refcount = 0;
5780 account->site.flags = VM_TAG_KMOD;
5781 account->kext = this;
5782 if (gIOSurfaceIdentifier == bundleID) {
5783 vm_tag_alloc(&account->site);
5784 gIOSurfaceTag = account->site.tag;
5785 }
5786
5787 flags.loaded = true;
5788
5789 /* Add the kext to the list of loaded kexts and update the kmod_info
5790 * struct to point to that of the last loaded kext (which is the way
5791 * it's always been done, though I'd rather do them in order now).
5792 */
5793 lastLoadedKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
5794 sLoadedKexts->setObject(this);
5795
5796 /* Keep the kernel itself out of the kmod list.
5797 */
5798 if (lastLoadedKext->isKernel()) {
5799 lastLoadedKext = NULL;
5800 }
5801
5802 if (lastLoadedKext) {
5803 kmod_info->next = lastLoadedKext->kmod_info;
5804 }
5805
5806 notifyKextLoadObservers(this, kmod_info);
5807
5808 /* Make the global kmod list point at the just-loaded kext. Note that the
5809 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
5810 * although we do report it in kextstat these days by using the newer
5811 * OSArray of loaded kexts, which does contain it.
5812 *
5813 * (The OSKext object representing the kernel doesn't even have a kmod_info
5814 * struct, though I suppose we could stick a pointer to it from the
5815 * static struct in OSRuntime.cpp.)
5816 */
5817 kmod = kmod_info;
5818
5819 /* Save the list of loaded kexts in case we panic.
5820 */
5821 OSKext::saveLoadedKextPanicList();
5822
5823 if (isExecutable()) {
5824 OSKext::updateLoadedKextSummaries();
5825 savePanicString(/* isLoading */ true);
b7266188 5826
6d2010ae 5827#if CONFIG_DTRACE
0a7de745 5828 registerWithDTrace();
6d2010ae 5829#else
0a7de745 5830 jettisonLinkeditSegment();
6d2010ae 5831#endif /* CONFIG_DTRACE */
3e170ce0
A
5832
5833#if !VM_MAPPED_KEXTS
0a7de745
A
5834 /* If there is a page (or more) worth of padding after the end
5835 * of the last data section but before the end of the data segment
5836 * then free it in the same manner the LinkeditSegment is freed
5837 */
5838 jettisonDATASegmentPadding();
3e170ce0 5839#endif
0a7de745 5840 }
6d2010ae
A
5841
5842loaded:
0a7de745
A
5843 if (isExecutable() && !flags.started) {
5844 if (startOpt == kOSKextExcludeNone) {
5845 result = start();
5846 if (result != kOSReturnSuccess) {
5847 OSKextLog(this,
5848 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5849 "Kext %s start failed (result 0x%x).",
5850 getIdentifierCString(), result);
5851 result = kOSKextReturnStartStopError;
5852 }
5853 }
5854 }
5855
5856 /* If not excluding matching, send the personalities to the kernel.
5857 * This never affects the result of the load operation.
5858 * This is a bit of a hack, because we shouldn't be handling
5859 * personalities within the load function.
5860 */
5861 if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
5862 result = sendPersonalitiesToCatalog(true, personalityNames);
5863 }
6d2010ae 5864
b0d623f7 5865finish:
b7266188 5866
0a7de745
A
5867 if (result != kOSReturnSuccess) {
5868 OSKextLog(this,
5869 kOSKextLogErrorLevel |
5870 kOSKextLogLoadFlag,
5871 "Kext %s failed to load (0x%x).",
5872 getIdentifierCString(), (int)result);
5873 } else if (!alreadyLoaded) {
5874 OSKextLog(this,
5875 kOSKextLogProgressLevel |
5876 kOSKextLogLoadFlag,
5877 "Kext %s loaded.",
5878 getIdentifierCString());
5879
5880 queueKextNotification(kKextRequestPredicateLoadNotification,
f427ee49 5881 OSDynamicCast(OSString, bundleID.get()));
0a7de745
A
5882 }
5883 return result;
5884}
5885
f427ee49 5886#if CONFIG_KXLD
0a7de745
A
5887/*********************************************************************
5888*
5889*********************************************************************/
5890static char *
5891strdup(const char * string)
5892{
5893 char * result = NULL;
5894 size_t size;
5895
5896 if (!string) {
5897 goto finish;
5898 }
5899
5900 size = 1 + strlen(string);
f427ee49
A
5901 result = (char *)kheap_alloc_tag(KHEAP_DATA_BUFFERS, size,
5902 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
0a7de745
A
5903 if (!result) {
5904 goto finish;
5905 }
5906
5907 memcpy(result, string, size);
6d2010ae
A
5908
5909finish:
0a7de745 5910 return result;
6d2010ae 5911}
f427ee49 5912#endif // CONFIG_KXLD
6d2010ae 5913
316670eb 5914/*********************************************************************
0a7de745 5915*
316670eb 5916*********************************************************************/
3e170ce0
A
5917
5918kernel_section_t *
5919OSKext::lookupSection(const char *segname, const char *secname)
5920{
0a7de745
A
5921 kernel_section_t * found_section = NULL;
5922 kernel_mach_header_t * mh = NULL;
5923 kernel_segment_command_t * seg = NULL;
5924 kernel_section_t * sec = NULL;
3e170ce0 5925
0a7de745
A
5926 if (!linkedExecutable) {
5927 return NULL;
5928 }
3e170ce0 5929
0a7de745 5930 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
3e170ce0 5931
0a7de745 5932 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
cb323159 5933 if (0 != strncmp(seg->segname, segname, sizeof(seg->segname))) {
0a7de745
A
5934 continue;
5935 }
3e170ce0 5936
0a7de745 5937 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
cb323159 5938 if (0 == strncmp(sec->sectname, secname, sizeof(sec->sectname))) {
0a7de745
A
5939 found_section = sec;
5940 goto out;
5941 }
5942 }
5943 }
3e170ce0 5944
0a7de745
A
5945out:
5946 return found_section;
3e170ce0
A
5947}
5948
5949/*********************************************************************
5950*
5951*********************************************************************/
5952
316670eb 5953OSReturn
f427ee49 5954OSKext::slidePrelinkedExecutable(bool doCoalescedSlides)
39037602 5955{
0a7de745
A
5956 OSReturn result = kOSKextReturnBadData;
5957 kernel_mach_header_t * mh = NULL;
5958 kernel_segment_command_t * seg = NULL;
5959 kernel_segment_command_t * linkeditSeg = NULL;
5960 kernel_section_t * sec = NULL;
5961 char * linkeditBase = NULL;
5962 bool haveLinkeditBase = false;
5963 char * relocBase = NULL;
5964 bool haveRelocBase = false;
5965 struct dysymtab_command * dysymtab = NULL;
5966 struct linkedit_data_command * segmentSplitInfo = NULL;
5967 struct symtab_command * symtab = NULL;
5968 kernel_nlist_t * sym = NULL;
5969 struct relocation_info * reloc = NULL;
5970 uint32_t i = 0;
5971 int reloc_size;
5972 vm_offset_t new_kextsize;
5973
5974 if (linkedExecutable == NULL || flags.builtin) {
5975 result = kOSReturnSuccess;
5976 goto finish;
5977 }
5978
5979 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
f427ee49
A
5980 if (kernel_mach_header_is_in_fileset(mh)) {
5981 // kexts in filesets are slid as part of collection sliding
5982 result = kOSReturnSuccess;
5983 goto finish;
5984 }
5985
0a7de745
A
5986 segmentSplitInfo = (struct linkedit_data_command *) getcommandfromheader(mh, LC_SEGMENT_SPLIT_INFO);
5987
5988 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
5989 if (!seg->vmaddr) {
5990 continue;
5991 }
5992
5993 seg->vmaddr = ml_static_slide(seg->vmaddr);
d9a64523 5994
316670eb 5995#if KASLR_KEXT_DEBUG
0a7de745
A
5996 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
5997 seg->segname,
5998 (unsigned long)ml_static_unslide(seg->vmaddr),
5999 (unsigned long)seg->vmaddr);
316670eb 6000#endif
0a7de745
A
6001
6002 if (!haveRelocBase) {
6003 relocBase = (char *) seg->vmaddr;
6004 haveRelocBase = true;
6005 }
6006 if (!strcmp(seg->segname, "__LINKEDIT")) {
6007 linkeditBase = (char *) seg->vmaddr - seg->fileoff;
6008 haveLinkeditBase = true;
6009 linkeditSeg = seg;
6010 }
6011 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
6012 sec->addr = ml_static_slide(sec->addr);
316670eb
A
6013
6014#if KASLR_KEXT_DEBUG
0a7de745
A
6015 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
6016 sec->sectname,
6017 (unsigned long)ml_static_unslide(sec->addr),
6018 (unsigned long)sec->addr);
316670eb 6019#endif
0a7de745
A
6020 }
6021 }
6022
6023 dysymtab = (struct dysymtab_command *) getcommandfromheader(mh, LC_DYSYMTAB);
6024
6025 symtab = (struct symtab_command *) getcommandfromheader(mh, LC_SYMTAB);
6026
f427ee49 6027 if (symtab != NULL && doCoalescedSlides == false) {
0a7de745
A
6028 /* Some pseudo-kexts have symbol tables without segments.
6029 * Ignore them. */
6030 if (symtab->nsyms > 0 && haveLinkeditBase) {
6031 sym = (kernel_nlist_t *) (linkeditBase + symtab->symoff);
6032 for (i = 0; i < symtab->nsyms; i++) {
6033 if (sym[i].n_type & N_STAB) {
6034 continue;
6035 }
6036 sym[i].n_value = ml_static_slide(sym[i].n_value);
6037
316670eb
A
6038#if KASLR_KEXT_DEBUG
6039#define MAX_SYMS_TO_LOG 5
0a7de745
A
6040 if (i < MAX_SYMS_TO_LOG) {
6041 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
6042 (unsigned long)ml_static_unslide(sym[i].n_value),
6043 (unsigned long)sym[i].n_value);
6044 }
316670eb 6045#endif
0a7de745
A
6046 }
6047 }
6048 }
6049
f427ee49 6050 if (dysymtab != NULL && doCoalescedSlides == false) {
0a7de745
A
6051 if (dysymtab->nextrel > 0) {
6052 OSKextLog(this,
6053 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6054 kOSKextLogLinkFlag,
6055 "Sliding kext %s: External relocations found.",
6056 getIdentifierCString());
6057 goto finish;
6058 }
6059
6060 if (dysymtab->nlocrel > 0) {
6061 if (!haveLinkeditBase) {
6062 OSKextLog(this,
6063 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6064 kOSKextLogLinkFlag,
6065 "Sliding kext %s: No linkedit segment.",
6066 getIdentifierCString());
6067 goto finish;
6068 }
6069
6070 if (!haveRelocBase) {
6071 OSKextLog(this,
6072 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6073 kOSKextLogLinkFlag,
316670eb 6074#if __x86_64__
0a7de745 6075 "Sliding kext %s: No writable segments.",
316670eb 6076#else
0a7de745 6077 "Sliding kext %s: No segments.",
316670eb 6078#endif
0a7de745
A
6079 getIdentifierCString());
6080 goto finish;
6081 }
6082
6083 reloc = (struct relocation_info *) (linkeditBase + dysymtab->locreloff);
6084 reloc_size = dysymtab->nlocrel * sizeof(struct relocation_info);
6085
6086 for (i = 0; i < dysymtab->nlocrel; i++) {
6087 if (reloc[i].r_extern != 0
6088 || reloc[i].r_type != 0
6089 || reloc[i].r_length != (sizeof(void *) == 8 ? 3 : 2)
6090 ) {
6091 OSKextLog(this,
6092 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6093 kOSKextLogLinkFlag,
6094 "Sliding kext %s: Unexpected relocation found.",
6095 getIdentifierCString());
6096 goto finish;
6097 }
6098 if (reloc[i].r_pcrel != 0) {
6099 continue;
6100 }
6101 uintptr_t *relocAddr = (uintptr_t*)(relocBase + reloc[i].r_address);
6102 *relocAddr = ml_static_slide(*relocAddr);
316670eb
A
6103
6104#if KASLR_KEXT_DEBUG
6105#define MAX_DYSYMS_TO_LOG 5
0a7de745
A
6106 if (i < MAX_DYSYMS_TO_LOG) {
6107 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
6108 (unsigned long)ml_static_unslide(*((uintptr_t *)(relocAddr))),
6109 (unsigned long)*((uintptr_t *)(relocBase + reloc[i].r_address)));
6110 }
316670eb 6111#endif
0a7de745
A
6112 }
6113
6114 /* We should free these relocations, not just delete the reference to them.
6115 * <rdar://problem/10535549> Free relocations from PIE kexts.
6116 *
6117 * For now, we do not free LINKEDIT for kexts with split segments.
6118 */
6119 new_kextsize = round_page(kmod_info->size - reloc_size);
f427ee49
A
6120 if (new_kextsize > UINT_MAX) {
6121 OSKextLog(this,
6122 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6123 kOSKextLogLinkFlag,
6124 "Kext %s: new kext size is too large.",
6125 getIdentifierCString());
6126 goto finish;
6127 }
0a7de745
A
6128 if (((kmod_info->size - new_kextsize) > PAGE_SIZE) && (!segmentSplitInfo)) {
6129 vm_offset_t endofkext = kmod_info->address + kmod_info->size;
6130 vm_offset_t new_endofkext = kmod_info->address + new_kextsize;
6131 vm_offset_t endofrelocInfo = (vm_offset_t) (((uint8_t *)reloc) + reloc_size);
f427ee49
A
6132 size_t bytes_remaining = endofkext - endofrelocInfo;
6133 OSSharedPtr<OSData> new_osdata;
0a7de745
A
6134
6135 /* fix up symbol offsets if they are after the dsymtab local relocs */
6136 if (symtab) {
6137 if (dysymtab->locreloff < symtab->symoff) {
6138 symtab->symoff -= reloc_size;
6139 }
6140 if (dysymtab->locreloff < symtab->stroff) {
6141 symtab->stroff -= reloc_size;
6142 }
6143 }
6144 if (dysymtab->locreloff < dysymtab->extreloff) {
6145 dysymtab->extreloff -= reloc_size;
6146 }
6147
6148 /* move data behind reloc info down to new offset */
6149 if (endofrelocInfo < endofkext) {
6150 memcpy(reloc, (void *)endofrelocInfo, bytes_remaining);
6151 }
6152
6153 /* Create a new OSData for the smaller kext object and reflect
6154 * new linkedit segment size.
6155 */
6156 linkeditSeg->vmsize = round_page(linkeditSeg->vmsize - reloc_size);
6157 linkeditSeg->filesize = linkeditSeg->vmsize;
6158
f427ee49 6159 new_osdata = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)new_kextsize);
0a7de745
A
6160 if (new_osdata) {
6161 /* Fix up kmod info and linkedExecutable.
6162 */
6163 kmod_info->size = new_kextsize;
39236c6e 6164#if VM_MAPPED_KEXTS
0a7de745 6165 new_osdata->setDeallocFunction(osdata_kext_free);
39236c6e 6166#else
0a7de745 6167 new_osdata->setDeallocFunction(osdata_phys_free);
39236c6e 6168#endif
0a7de745 6169 linkedExecutable->setDeallocFunction(NULL);
f427ee49 6170 linkedExecutable = os::move(new_osdata);
0a7de745 6171
316670eb 6172#if VM_MAPPED_KEXTS
0a7de745 6173 kext_free(new_endofkext, (endofkext - new_endofkext));
316670eb 6174#else
0a7de745 6175 ml_static_mfree(new_endofkext, (endofkext - new_endofkext));
316670eb 6176#endif
0a7de745
A
6177 }
6178 }
6179 dysymtab->nlocrel = 0;
6180 dysymtab->locreloff = 0;
6181 }
6182 }
6183
6184 result = kOSReturnSuccess;
316670eb 6185finish:
0a7de745 6186 return result;
316670eb
A
6187}
6188
b0d623f7
A
6189/*********************************************************************
6190* called only by load()
6191*********************************************************************/
6192OSReturn
6193OSKext::loadExecutable()
6194{
0a7de745 6195 OSReturn result = kOSReturnError;
f427ee49 6196 OSSharedPtr<OSArray> linkDependencies;
0a7de745 6197 uint32_t num_kmod_refs = 0;
f427ee49
A
6198 OSData * theExecutable = NULL; // do not release
6199 OSString * versString = NULL; // do not release
6200 const char * versCString = NULL; // do not free
6201 const char * string = NULL; // do not free
6202
6203#if CONFIG_KXLD
0a7de745 6204 unsigned int i;
f427ee49
A
6205 uint32_t numDirectDependencies = 0;
6206 kern_return_t kxldResult;
6207 KXLDDependency * kxlddeps = NULL; // must kfree
6208 uint32_t num_kxlddeps = 0;
6209 struct mach_header ** kxldHeaderPtr = NULL; // do not free
6210 struct mach_header * kxld_header = NULL; // xxx - need to free here?
6211#endif // CONFIG_KXLD
0a7de745
A
6212
6213 /* We need the version string for a variety of bits below.
6214 */
6215 versString = OSDynamicCast(OSString,
6216 getPropertyForHostArch(kCFBundleVersionKey));
6217 if (!versString) {
6218 goto finish;
6219 }
6220 versCString = versString->getCStringNoCopy();
6221
6222 if (isKernelComponent()) {
6223 if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
6224 if (strncmp(versCString, KERNEL6_VERSION, strlen(KERNEL6_VERSION))) {
6225 OSKextLog(this,
6226 kOSKextLogErrorLevel |
6227 kOSKextLogLoadFlag,
6228 "Kernel component %s has incorrect version %s; "
6229 "expected %s.",
6230 getIdentifierCString(),
6231 versCString, KERNEL6_VERSION);
6232 result = kOSKextReturnInternalError;
6233 goto finish;
6234 } else if (strcmp(versCString, osrelease)) {
6235 OSKextLog(this,
6236 kOSKextLogErrorLevel |
6237 kOSKextLogLoadFlag,
6238 "Kernel component %s has incorrect version %s; "
6239 "expected %s.",
6240 getIdentifierCString(),
6241 versCString, osrelease);
6242 result = kOSKextReturnInternalError;
6243 goto finish;
6244 }
6245 }
6246 }
b0d623f7 6247
f427ee49
A
6248#if defined(__x86_64__) || defined(__i386__)
6249 if (flags.resetSegmentsFromVnode) {
6250 /* Fixup the chains and slide the mach headers */
6251 kernel_mach_header_t *mh = (kernel_mach_header_t *)kmod_info->address;
6252
6253 if (i386_slide_individual_kext(mh, PE_get_kc_slide(kc_type)) != KERN_SUCCESS) {
6254 result = kOSKextReturnValidation;
6255 goto finish;
6256 }
6257 }
6258#endif //(__x86_64__) || defined(__i386__)
6259
0a7de745
A
6260 if (isPrelinked()) {
6261 goto register_kmod;
6262 }
b0d623f7 6263
0a7de745 6264 /* <rdar://problem/21444003> all callers must be entitled */
f427ee49 6265 if (FALSE == IOTaskHasEntitlement(current_task(), kOSKextCollectionManagementEntitlement)) {
0a7de745
A
6266 OSKextLog(this,
6267 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6268 "Not entitled to link kext '%s'",
6269 getIdentifierCString());
6270 result = kOSKextReturnNotPrivileged;
6271 goto finish;
6272 }
b0d623f7 6273
0a7de745
A
6274 theExecutable = getExecutable();
6275 if (!theExecutable) {
6276 if (declaresExecutable()) {
6277 OSKextLog(this,
6278 kOSKextLogErrorLevel |
6279 kOSKextLogLoadFlag,
6280 "Can't load kext %s - executable is missing.",
6281 getIdentifierCString());
6282 result = kOSKextReturnValidation;
6283 goto finish;
6284 }
6285 goto register_kmod;
6286 }
b0d623f7 6287
0a7de745 6288 if (isInterface()) {
f427ee49
A
6289 OSSharedPtr<OSData> executableCopy = OSData::withData(theExecutable);
6290 if (executableCopy) {
6291 setLinkedExecutable(executableCopy.get());
6292 }
0a7de745
A
6293 goto register_kmod;
6294 }
5ba3f43e 6295
f427ee49 6296#if CONFIG_KXLD
0a7de745
A
6297 numDirectDependencies = getNumDependencies();
6298
6299 if (flags.hasBleedthrough) {
6300 linkDependencies = dependencies;
0a7de745 6301 } else {
f427ee49 6302 linkDependencies = OSArray::withArray(dependencies.get());
0a7de745
A
6303 if (!linkDependencies) {
6304 OSKextLog(this,
6305 kOSKextLogErrorLevel |
6306 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6307 "Can't allocate link dependencies to load kext %s.",
6308 getIdentifierCString());
6309 goto finish;
6310 }
b0d623f7 6311
0a7de745
A
6312 for (i = 0; i < numDirectDependencies; ++i) {
6313 OSKext * dependencyKext = OSDynamicCast(OSKext,
6314 dependencies->getObject(i));
f427ee49 6315 dependencyKext->addBleedthroughDependencies(linkDependencies.get());
0a7de745
A
6316 }
6317 }
6318
6319 num_kxlddeps = linkDependencies->getCount();
6320 if (!num_kxlddeps) {
6321 OSKextLog(this,
6322 kOSKextLogErrorLevel |
6323 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6324 "Can't load kext %s - it has no library dependencies.",
6325 getIdentifierCString());
6326 goto finish;
6327 }
6328
6329 kxlddeps = (KXLDDependency *)kalloc_tag(num_kxlddeps * sizeof(*kxlddeps), VM_KERN_MEMORY_OSKEXT);
6330 if (!kxlddeps) {
6331 OSKextLog(this,
6332 kOSKextLogErrorLevel |
6333 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6334 "Can't allocate link context to load kext %s.",
6335 getIdentifierCString());
6336 goto finish;
6337 }
6338 bzero(kxlddeps, num_kxlddeps * sizeof(*kxlddeps));
6339
6340 for (i = 0; i < num_kxlddeps; ++i) {
6341 OSKext * dependency = OSDynamicCast(OSKext, linkDependencies->getObject(i));
6342
6343 if (dependency->isInterface()) {
f427ee49
A
6344 OSKext *interfaceTargetKext = NULL; //do not release
6345 OSData * interfaceTarget = NULL; //do not release
0a7de745
A
6346
6347 if (dependency->isKernelComponent()) {
6348 interfaceTargetKext = sKernelKext;
f427ee49 6349 interfaceTarget = sKernelKext->linkedExecutable.get();
0a7de745
A
6350 } else {
6351 interfaceTargetKext = OSDynamicCast(OSKext,
6352 dependency->dependencies->getObject(0));
6353
f427ee49 6354 interfaceTarget = interfaceTargetKext->linkedExecutable.get();
0a7de745
A
6355 }
6356
6357 if (!interfaceTarget) {
6358 // panic?
6359 goto finish;
6360 }
6361
6362 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
6363 * it will be useful to have them in the debugger.
6364 * strdup() failing isn't critical right here so we don't check that.
6365 */
6366 kxlddeps[i].kext = (u_char *) interfaceTarget->getBytesNoCopy();
6367 kxlddeps[i].kext_size = interfaceTarget->getLength();
6368 kxlddeps[i].kext_name = strdup(interfaceTargetKext->getIdentifierCString());
6369
f427ee49
A
6370 if (dependency->linkedExecutable != NULL) {
6371 kxlddeps[i].interface = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
6372 kxlddeps[i].interface_size = dependency->linkedExecutable->getLength();
6373 } else {
6374 kxlddeps[i].interface = (u_char *) NULL;
6375 kxlddeps[i].interface_size = 0;
6376 }
0a7de745
A
6377 kxlddeps[i].interface_name = strdup(dependency->getIdentifierCString());
6378 } else {
6379 kxlddeps[i].kext = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
6380 kxlddeps[i].kext_size = dependency->linkedExecutable->getLength();
6381 kxlddeps[i].kext_name = strdup(dependency->getIdentifierCString());
6382 }
6383
6384 kxlddeps[i].is_direct_dependency = (i < numDirectDependencies);
6385 }
6386
6387 kxldHeaderPtr = &kxld_header;
6388
6389#if DEBUG
6390 OSKextLog(this,
6391 kOSKextLogExplicitLevel |
6392 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6393 "Kext %s - calling kxld_link_file:\n"
6394 " kxld_context: %p\n"
6395 " executable: %p executable_length: %d\n"
6396 " user_data: %p\n"
6397 " kxld_dependencies: %p num_dependencies: %d\n"
6398 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
6399 getIdentifierCString(), sKxldContext,
6400 theExecutable->getBytesNoCopy(), theExecutable->getLength(),
6401 this, kxlddeps, num_kxlddeps,
6402 kxldHeaderPtr, &kmod_info);
6403#endif
6404
6405 /* After this call, the linkedExecutable instance variable
6406 * should exist.
6407 */
6408 kxldResult = kxld_link_file(sKxldContext,
6409 (u_char *)theExecutable->getBytesNoCopy(),
6410 theExecutable->getLength(),
6411 getIdentifierCString(), this, kxlddeps, num_kxlddeps,
6412 (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info);
6413
6414 if (kxldResult != KERN_SUCCESS) {
6415 // xxx - add kxldResult here?
6416 OSKextLog(this,
6417 kOSKextLogErrorLevel |
6418 kOSKextLogLoadFlag,
6419 "Can't load kext %s - link failed.",
6420 getIdentifierCString());
6421 result = kOSKextReturnLinkError;
6422 goto finish;
6423 }
6424
6425 /* We've written data & instructions into kernel memory, so flush the data
6426 * cache and invalidate the instruction cache.
6427 * I/D caches are coherent on x86
6428 */
6429#if !defined(__i386__) && !defined(__x86_64__)
6430 flush_dcache(kmod_info->address, kmod_info->size, false);
6431 invalidate_icache(kmod_info->address, kmod_info->size, false);
6432#endif
f427ee49
A
6433
6434#else // !CONFIG_KXLD
6435 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6436 "Refusing to link non-prelinked kext: %s (no kxld support)", getIdentifierCString());
6437 result = kOSKextReturnLinkError;
6438 goto finish;
6439#endif // CONFIG_KXLD
6440
0a7de745
A
6441register_kmod:
6442
6443 if (isInterface()) {
6444 /* Whip up a fake kmod_info entry for the interface kext.
6445 */
6446 kmod_info = (kmod_info_t *)kalloc_tag(sizeof(kmod_info_t), VM_KERN_MEMORY_OSKEXT);
6447 if (!kmod_info) {
6448 result = KERN_MEMORY_ERROR;
6449 goto finish;
6450 }
6451
6452 /* A pseudokext has almost nothing in its kmod_info struct.
6453 */
6454 bzero(kmod_info, sizeof(kmod_info_t));
6455
6456 kmod_info->info_version = KMOD_INFO_VERSION;
6457
6458 /* An interface kext doesn't have a linkedExecutable, so save a
6459 * copy of the UUID out of the original executable via copyUUID()
6460 * while we still have the original executable.
6461 */
6462 interfaceUUID = copyUUID();
6463 }
6464
6465 kmod_info->id = loadTag = sNextLoadTag++;
f427ee49 6466 kmod_info->reference_count = 0; // KMOD_DECL... sets it to -1 (invalid).
0a7de745
A
6467
6468 /* Stamp the bundle ID and version from the OSKext over anything
6469 * resident inside the kmod_info.
6470 */
6471 string = getIdentifierCString();
6472 strlcpy(kmod_info->name, string, sizeof(kmod_info->name));
6473
6474 string = versCString;
6475 strlcpy(kmod_info->version, string, sizeof(kmod_info->version));
6476
6477 /* Add the dependencies' kmod_info structs as kmod_references.
6478 */
6479 num_kmod_refs = getNumDependencies();
6480 if (num_kmod_refs) {
6481 kmod_info->reference_list = (kmod_reference_t *)kalloc_tag(
6482 num_kmod_refs * sizeof(kmod_reference_t), VM_KERN_MEMORY_OSKEXT);
6483 if (!kmod_info->reference_list) {
6484 result = KERN_MEMORY_ERROR;
6485 goto finish;
6486 }
6487 bzero(kmod_info->reference_list,
6488 num_kmod_refs * sizeof(kmod_reference_t));
6489 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
6490 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
6491 OSKext * refKext = OSDynamicCast(OSKext, dependencies->getObject(refIndex));
6492 ref->info = refKext->kmod_info;
6493 ref->info->reference_count++;
6494
6495 if (refIndex + 1 < num_kmod_refs) {
6496 ref->next = kmod_info->reference_list + refIndex + 1;
6497 }
6498 }
6499 }
6500
f427ee49
A
6501 if (kmod_info->hdr_size > UINT32_MAX) {
6502 OSKextLog(this,
6503 kOSKextLogErrorLevel |
6504 kOSKextLogLoadFlag,
6505#if __LP64__
6506 "Kext %s header size is too large (%lu > UINT32_MAX).",
6507#else
6508 "Kext %s header size is too large (%u > UINT32_MAX).",
6509#endif
6510 kmod_info->name,
6511 kmod_info->hdr_size);
6512 result = KERN_FAILURE;
6513 goto finish;
6514 }
6515
6516 if (kmod_info->size > UINT32_MAX) {
6517 OSKextLog(this,
6518 kOSKextLogErrorLevel |
6519 kOSKextLogLoadFlag,
6520#if __LP64__
6521 "Kext %s size is too large (%lu > UINT32_MAX).",
6522#else
6523 "Kext %s size is too large (%u > UINT32_MAX).",
6524#endif
6525 kmod_info->name,
6526 kmod_info->size);
6527 result = KERN_FAILURE;
6528 goto finish;
6529 }
6530
0a7de745
A
6531 if (!isInterface() && linkedExecutable) {
6532 OSKextLog(this,
6533 kOSKextLogProgressLevel |
6534 kOSKextLogLoadFlag,
6535 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
6536 kmod_info->name,
6537 (unsigned)kmod_info->size / PAGE_SIZE,
6538 (unsigned long)ml_static_unslide(kmod_info->address),
6539 (unsigned)kmod_info->id);
6540 }
6541
f427ee49
A
6542 /* VM protections and wiring for the Aux KC are done at collection loading time */
6543 if (kc_type != KCKindAuxiliary || flags.resetSegmentsFromVnode) {
6544 /* if prelinked and primary KC, VM protections are already set */
6545 result = setVMAttributes(!isPrelinked() || flags.resetSegmentsFromVnode, true);
6546 if (result != KERN_SUCCESS) {
6547 goto finish;
6548 }
0a7de745
A
6549 }
6550
6551#if KASAN
6552 if (linkedExecutable) {
6553 kasan_load_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(),
6554 linkedExecutable->getLength(), getIdentifierCString());
6555 }
6556#else
6557 if (lookupSection(KASAN_GLOBAL_SEGNAME, KASAN_GLOBAL_SECTNAME)) {
6558 OSKextLog(this,
6559 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6560 "KASAN: cannot load KASAN-ified kext %s on a non-KASAN kernel\n",
6561 getIdentifierCString()
6562 );
6563 result = KERN_FAILURE;
6564 goto finish;
6565 }
6566#endif
6567
6568 result = kOSReturnSuccess;
6569
6570finish:
0a7de745 6571
f427ee49 6572#if CONFIG_KXLD
0a7de745
A
6573 /* Clear up locally allocated dependency info.
6574 */
6575 for (i = 0; i < num_kxlddeps; ++i) {
6576 size_t size;
6577
6578 if (kxlddeps[i].kext_name) {
6579 size = 1 + strlen(kxlddeps[i].kext_name);
f427ee49 6580 kheap_free(KHEAP_DATA_BUFFERS, kxlddeps[i].kext_name, size);
0a7de745
A
6581 }
6582 if (kxlddeps[i].interface_name) {
6583 size = 1 + strlen(kxlddeps[i].interface_name);
f427ee49 6584 kheap_free(KHEAP_DATA_BUFFERS, kxlddeps[i].interface_name, size);
0a7de745
A
6585 }
6586 }
6587 if (kxlddeps) {
6588 kfree(kxlddeps, (num_kxlddeps * sizeof(*kxlddeps)));
6589 }
f427ee49 6590#endif // CONFIG_KXLD
0a7de745
A
6591
6592 /* We no longer need the unrelocated executable (which the linker
6593 * has altered anyhow).
6594 */
6595 setExecutable(NULL);
6596
6597 if (result != kOSReturnSuccess) {
6598 OSKextLog(this,
6599 kOSKextLogErrorLevel |
6600 kOSKextLogLoadFlag,
6601 "Failed to load executable for kext %s.",
6602 getIdentifierCString());
6603
6604 if (kmod_info && kmod_info->reference_list) {
6605 kfree(kmod_info->reference_list,
6606 num_kmod_refs * sizeof(kmod_reference_t));
6607 }
6608 if (isInterface()) {
6609 kfree(kmod_info, sizeof(kmod_info_t));
f427ee49 6610 kmod_info = NULL;
0a7de745 6611 }
f427ee49
A
6612 if (kc_type == KCKindUnknown) {
6613 kmod_info = NULL;
6614 if (linkedExecutable) {
6615 linkedExecutable.reset();
6616 }
0a7de745
A
6617 }
6618 }
6619
6620 return result;
6621}
b0d623f7 6622
f427ee49
A
6623#if VM_MAPPED_KEXTS
6624/* static */
6625void
6626OSKext::jettisonFileSetLinkeditSegment(kernel_mach_header_t *mh)
6627{
6628 kernel_segment_command_t *linkeditseg = NULL;
6629
6630 linkeditseg = getsegbynamefromheader(mh, SEG_LINKEDIT);
6631 assert(linkeditseg != NULL);
6632
6633 /* BootKC on x86_64 is not vm mapped */
6634 ml_static_mfree(linkeditseg->vmaddr, linkeditseg->vmsize);
6635
6636 OSKextLog(/* kext */ NULL,
6637 kOSKextLogProgressLevel |
6638 kOSKextLogGeneralFlag,
6639 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
6640 linkeditseg->vmaddr, linkeditseg->vmsize);
6641}
6642#endif /* VM_MAPPED_KEXTS */
6643
b0d623f7 6644/*********************************************************************
6d2010ae
A
6645* The linkedit segment is used by the kext linker for dependency
6646* resolution, and by dtrace for probe initialization. We can free it
6647* for non-library kexts, since no kexts depend on non-library kexts
6648* by definition, once dtrace has been initialized.
6649*********************************************************************/
6650void
6651OSKext::jettisonLinkeditSegment(void)
6652{
0a7de745
A
6653 kernel_mach_header_t * machhdr = (kernel_mach_header_t *)kmod_info->address;
6654 kernel_segment_command_t * linkedit = NULL;
6655 vm_offset_t start;
6656 vm_size_t linkeditsize, kextsize;
f427ee49
A
6657 OSSharedPtr<OSData> data;
6658
6659 if (isInFileset()) {
6660 return;
6661 }
316670eb
A
6662
6663#if NO_KEXTD
0a7de745
A
6664 /* We can free symbol tables for all embedded kexts because we don't
6665 * support runtime kext linking.
6666 */
6667 if (sKeepSymbols || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
316670eb 6668#else
0a7de745 6669 if (sKeepSymbols || isLibrary() || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
316670eb 6670#endif
0a7de745
A
6671 goto finish;
6672 }
6673
6674 /* Find the linkedit segment. If it's not the last segment, then freeing
6675 * it will fragment the kext into multiple VM regions, which OSKext is not
6676 * designed to handle, so we'll have to skip it.
6677 */
6678 linkedit = getsegbynamefromheader(machhdr, SEG_LINKEDIT);
6679 if (!linkedit) {
6680 goto finish;
6681 }
6682
6683 if (round_page(kmod_info->address + kmod_info->size) !=
6684 round_page(linkedit->vmaddr + linkedit->vmsize)) {
6685 goto finish;
6686 }
6687
6688 /* Create a new OSData for the smaller kext object.
6689 */
6690 linkeditsize = round_page(linkedit->vmsize);
6691 kextsize = kmod_info->size - linkeditsize;
6692 start = linkedit->vmaddr;
6693
f427ee49
A
6694 if (kextsize > UINT_MAX) {
6695 goto finish;
6696 }
6697 data = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)kextsize);
6698 if (!data) {
0a7de745
A
6699 goto finish;
6700 }
6701
6702 /* Fix the kmod info and linkedExecutable.
6703 */
6704 kmod_info->size = kextsize;
6705
39236c6e 6706#if VM_MAPPED_KEXTS
0a7de745 6707 data->setDeallocFunction(osdata_kext_free);
39236c6e 6708#else
0a7de745 6709 data->setDeallocFunction(osdata_phys_free);
39236c6e 6710#endif
0a7de745 6711 linkedExecutable->setDeallocFunction(NULL);
f427ee49 6712 linkedExecutable = os::move(data);
0a7de745
A
6713 flags.jettisonLinkeditSeg = 1;
6714
6715 /* Free the linkedit segment.
6716 */
316670eb 6717#if VM_MAPPED_KEXTS
0a7de745 6718 kext_free(start, linkeditsize);
316670eb 6719#else
0a7de745 6720 ml_static_mfree(start, linkeditsize);
316670eb 6721#endif
6d2010ae
A
6722
6723finish:
0a7de745 6724 return;
6d2010ae
A
6725}
6726
3e170ce0
A
6727/*********************************************************************
6728* If there are whole pages that are unused betweem the last section
6729* of the DATA segment and the end of the DATA segment then we can free
6730* them
6731*********************************************************************/
6732void
6733OSKext::jettisonDATASegmentPadding(void)
6734{
0a7de745
A
6735 kernel_mach_header_t * mh;
6736 kernel_segment_command_t * dataSeg;
6737 kernel_section_t * sec, * lastSec;
6738 vm_offset_t dataSegEnd, lastSecEnd;
6739 vm_size_t padSize;
3e170ce0 6740
0a7de745
A
6741 if (flags.builtin) {
6742 return;
6743 }
6744 mh = (kernel_mach_header_t *)kmod_info->address;
3e170ce0 6745
f427ee49
A
6746 if (isInFileset()) {
6747 return;
6748 }
6749
0a7de745
A
6750 dataSeg = getsegbynamefromheader(mh, SEG_DATA);
6751 if (dataSeg == NULL) {
6752 return;
6753 }
3e170ce0 6754
0a7de745
A
6755 lastSec = NULL;
6756 sec = firstsect(dataSeg);
6757 while (sec != NULL) {
6758 lastSec = sec;
6759 sec = nextsect(dataSeg, sec);
6760 }
3e170ce0 6761
0a7de745
A
6762 if (lastSec == NULL) {
6763 return;
6764 }
3e170ce0 6765
0a7de745
A
6766 if ((dataSeg->vmaddr != round_page(dataSeg->vmaddr)) ||
6767 (dataSeg->vmsize != round_page(dataSeg->vmsize))) {
6768 return;
6769 }
3e170ce0 6770
0a7de745
A
6771 dataSegEnd = dataSeg->vmaddr + dataSeg->vmsize;
6772 lastSecEnd = round_page(lastSec->addr + lastSec->size);
3e170ce0 6773
0a7de745
A
6774 if (dataSegEnd <= lastSecEnd) {
6775 return;
6776 }
3e170ce0 6777
0a7de745 6778 padSize = dataSegEnd - lastSecEnd;
3e170ce0 6779
0a7de745 6780 if (padSize >= PAGE_SIZE) {
3e170ce0 6781#if VM_MAPPED_KEXTS
0a7de745 6782 kext_free(lastSecEnd, padSize);
3e170ce0 6783#else
0a7de745 6784 ml_static_mfree(lastSecEnd, padSize);
3e170ce0 6785#endif
0a7de745 6786 }
3e170ce0
A
6787}
6788
6d2010ae 6789/*********************************************************************
b0d623f7
A
6790*********************************************************************/
6791void
6792OSKext::setLinkedExecutable(OSData * anExecutable)
6793{
0a7de745
A
6794 if (linkedExecutable) {
6795 panic("Attempt to set linked executable on kext "
6796 "that already has one (%s).\n",
6797 getIdentifierCString());
6798 }
f427ee49 6799 linkedExecutable.reset(anExecutable, OSRetain);
0a7de745 6800 return;
b0d623f7
A
6801}
6802
6d2010ae
A
6803#if CONFIG_DTRACE
6804/*********************************************************************
6805* Go through all loaded kexts and tell them to register with dtrace.
6806* The instance method only registers if necessary.
6807*********************************************************************/
6808/* static */
6809void
6810OSKext::registerKextsWithDTrace(void)
6811{
0a7de745
A
6812 uint32_t count = sLoadedKexts->getCount();
6813 uint32_t i;
6d2010ae 6814
0a7de745 6815 IORecursiveLockLock(sKextLock);
6d2010ae 6816
0a7de745 6817 for (i = 0; i < count; i++) {
f427ee49 6818 OSKext * thisKext = NULL; // do not release
6d2010ae 6819
0a7de745
A
6820 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
6821 if (!thisKext || !thisKext->isExecutable()) {
6822 continue;
6823 }
6d2010ae 6824
0a7de745
A
6825 thisKext->registerWithDTrace();
6826 }
6d2010ae 6827
0a7de745 6828 IORecursiveLockUnlock(sKextLock);
6d2010ae 6829
0a7de745 6830 return;
6d2010ae
A
6831}
6832
6833extern "C" {
0a7de745
A
6834extern int (*dtrace_modload)(struct kmod_info *, uint32_t);
6835extern int (*dtrace_modunload)(struct kmod_info *);
6d2010ae
A
6836};
6837
6838/*********************************************************************
6839*********************************************************************/
6840void
6841OSKext::registerWithDTrace(void)
6842{
0a7de745
A
6843 /* Register kext with dtrace. A dtrace_modload failure should not
6844 * prevent a kext from loading, so we ignore the return code.
6845 */
6846 if (!flags.dtraceInitialized && (dtrace_modload != NULL)) {
6847 uint32_t modflag = 0;
6848 OSObject * forceInit = getPropertyForHostArch("OSBundleForceDTraceInit");
f427ee49
A
6849
6850#if VM_MAPPED_KEXTS
6851 if (!sKeepSymbols && kc_type == KCKindPrimary) {
6852 if (forceInit == kOSBooleanTrue) {
6853 /* Make sure the kext is not from the Boot KC */
6854 panic("OSBundleForceDTraceInit key specified for the Boot KC kext : %s", getIdentifierCString());
6855 } else {
6856 /* Linkedit segment of the Boot KC is gone, make sure fbt_provide_module don't use kernel symbols */
6857 modflag |= KMOD_DTRACE_NO_KERNEL_SYMS;
6858 }
6859 }
6860#endif /* VM_MAPPED_KEXTS */
0a7de745
A
6861 if (forceInit == kOSBooleanTrue) {
6862 modflag |= KMOD_DTRACE_FORCE_INIT;
6863 }
6864 if (flags.builtin) {
6865 modflag |= KMOD_DTRACE_STATIC_KEXT;
6866 }
316670eb 6867
0a7de745
A
6868 (void)(*dtrace_modload)(kmod_info, modflag);
6869 flags.dtraceInitialized = true;
6870 jettisonLinkeditSegment();
6871 }
6872 return;
6d2010ae
A
6873}
6874/*********************************************************************
6875*********************************************************************/
6876void
6877OSKext::unregisterWithDTrace(void)
6878{
0a7de745
A
6879 /* Unregister kext with dtrace. A dtrace_modunload failure should not
6880 * prevent a kext from loading, so we ignore the return code.
6881 */
6882 if (flags.dtraceInitialized && (dtrace_modunload != NULL)) {
6883 (void)(*dtrace_modunload)(kmod_info);
6884 flags.dtraceInitialized = false;
6885 }
6886 return;
6d2010ae
A
6887}
6888#endif /* CONFIG_DTRACE */
6889
6890
b0d623f7
A
6891/*********************************************************************
6892* called only by loadExecutable()
6893*********************************************************************/
316670eb 6894#if !VM_MAPPED_KEXTS
5ba3f43e
A
6895#if defined(__arm__) || defined(__arm64__)
6896static inline kern_return_t
6897OSKext_protect(
f427ee49 6898 kernel_mach_header_t *kext_mh,
0a7de745
A
6899 vm_map_t map,
6900 vm_map_offset_t start,
6901 vm_map_offset_t end,
6902 vm_prot_t new_prot,
f427ee49
A
6903 boolean_t set_max,
6904 kc_kind_t kc_type)
5ba3f43e 6905{
f427ee49
A
6906#pragma unused(kext_mh,map,kc_type)
6907 assert(map == kernel_map); // we can handle KEXTs arising from the PRELINK segment and no others
0a7de745
A
6908 assert(start <= end);
6909 if (start >= end) {
f427ee49 6910 return KERN_SUCCESS; // Punt segments of length zero (e.g., headers) or less (i.e., blunders)
0a7de745 6911 } else if (set_max) {
f427ee49 6912 return KERN_SUCCESS; // Punt set_max, as there's no mechanism to record that state
0a7de745
A
6913 } else {
6914 return ml_static_protect(start, end - start, new_prot);
6915 }
5ba3f43e
A
6916}
6917
6918static inline kern_return_t
6919OSKext_wire(
f427ee49 6920 kernel_mach_header_t *kext_mh,
0a7de745
A
6921 vm_map_t map,
6922 vm_map_offset_t start,
6923 vm_map_offset_t end,
6924 vm_prot_t access_type,
f427ee49
A
6925 boolean_t user_wire,
6926 kc_kind_t kc_type)
5ba3f43e 6927{
f427ee49
A
6928#pragma unused(kext_mh,map,start,end,access_type,user_wire,kc_type)
6929 return KERN_SUCCESS; // No-op as PRELINK kexts are cemented into physical memory at boot
5ba3f43e
A
6930}
6931#else
0a7de745 6932#error Unrecognized architecture
5ba3f43e 6933#endif
316670eb
A
6934#else
6935static inline kern_return_t
6936OSKext_protect(
f427ee49 6937 kernel_mach_header_t *kext_mh,
0a7de745
A
6938 vm_map_t map,
6939 vm_map_offset_t start,
6940 vm_map_offset_t end,
6941 vm_prot_t new_prot,
f427ee49
A
6942 boolean_t set_max,
6943 kc_kind_t kc_type)
0a7de745 6944{
f427ee49 6945 if (start == end) { // 10538581
0a7de745
A
6946 return KERN_SUCCESS;
6947 }
f427ee49
A
6948 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
6949 /*
6950 * XXX: This will probably need to be different for AuxKC and
6951 * pageableKC!
6952 */
6953 return ml_static_protect(start, end - start, new_prot);
6954 }
0a7de745 6955 return vm_map_protect(map, start, end, new_prot, set_max);
316670eb
A
6956}
6957
6958static inline kern_return_t
6959OSKext_wire(
f427ee49 6960 kernel_mach_header_t *kext_mh,
0a7de745
A
6961 vm_map_t map,
6962 vm_map_offset_t start,
6963 vm_map_offset_t end,
6964 vm_prot_t access_type,
f427ee49
A
6965 boolean_t user_wire,
6966 kc_kind_t kc_type)
316670eb 6967{
f427ee49
A
6968 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
6969 /* TODO: we may need to hook this for the pageableKC */
6970 return KERN_SUCCESS;
6971 }
5ba3f43e 6972 return vm_map_wire_kernel(map, start, end, access_type, VM_KERN_MEMORY_KEXT, user_wire);
316670eb
A
6973}
6974#endif
6975
b0d623f7 6976OSReturn
3e170ce0 6977OSKext::setVMAttributes(bool protect, bool wire)
b0d623f7 6978{
0a7de745
A
6979 vm_map_t kext_map = NULL;
6980 kernel_segment_command_t * seg = NULL;
f427ee49
A
6981 vm_map_offset_t start_protect = 0;
6982 vm_map_offset_t start_wire = 0;
6983 vm_map_offset_t end_protect = 0;
6984 vm_map_offset_t end_wire = 0;
0a7de745 6985 OSReturn result = kOSReturnError;
b0d623f7 6986
0a7de745
A
6987 if (isInterface() || !declaresExecutable() || flags.builtin) {
6988 result = kOSReturnSuccess;
6989 goto finish;
6990 }
b0d623f7 6991
0a7de745
A
6992 /* Get the kext's vm map */
6993 kext_map = kext_get_vm_map(kmod_info);
6994 if (!kext_map) {
6995 result = KERN_MEMORY_ERROR;
6996 goto finish;
6997 }
b0d623f7 6998
39037602 6999#if !VM_MAPPED_KEXTS
0a7de745
A
7000 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
7001 /* This is a split kext in a prelinked kernelcache; we'll let the
7002 * platform code take care of protecting it. It is already wired.
7003 */
7004 /* TODO: Should this still allow protections for the first segment
7005 * to go through, in the event that we have a mix of split and
7006 * unsplit kexts?
7007 */
7008 result = KERN_SUCCESS;
7009 goto finish;
7010 }
f427ee49
A
7011
7012 if (isInFileset() && kc_type != KCKindPageable) {
7013 // kexts in filesets have protections setup as part of collection loading
7014 result = KERN_SUCCESS;
7015 goto finish;
7016 }
39037602
A
7017#endif
7018
0a7de745 7019 /* Protect the headers as read-only; they do not need to be wired */
f427ee49
A
7020 result = (protect) ? OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7021 kext_map, kmod_info->address,
7022 kmod_info->address + kmod_info->hdr_size, VM_PROT_READ, TRUE, kc_type)
0a7de745
A
7023 : KERN_SUCCESS;
7024 if (result != KERN_SUCCESS) {
7025 goto finish;
7026 }
3e170ce0 7027
0a7de745
A
7028 /* Set the VM protections and wire down each of the segments */
7029 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7030 while (seg) {
5ba3f43e 7031#if __arm__
0a7de745
A
7032 /* We build all ARM kexts, so we can ensure they are aligned */
7033 assert((seg->vmaddr & PAGE_MASK) == 0);
7034 assert((seg->vmsize & PAGE_MASK) == 0);
5ba3f43e 7035#endif
3e170ce0 7036
f427ee49
A
7037 /*
7038 * For the non page aligned segments, the range calculation for protection
7039 * and wiring differ as follows:
7040 *
7041 * Protection: The non page aligned data at the start or at the end of the
7042 * segment is excluded from the protection. This exclusion is needed to make
7043 * sure OSKext_protect is not called twice on same page, if the page is shared
7044 * between two segments.
7045 *
7046 * Wiring: The non page aligned data at the start or at the end of the
7047 * segment is included in the wiring range, this inclusion is needed to make sure
7048 * all the data of the segment is wired.
7049 */
7050 start_protect = round_page(seg->vmaddr);
7051 end_protect = trunc_page(seg->vmaddr + seg->vmsize);
7052
7053 start_wire = trunc_page(seg->vmaddr);
7054 end_wire = round_page(seg->vmaddr + seg->vmsize);
0a7de745 7055
f427ee49
A
7056 /*
7057 * Linkedit and Linkinfo for the Pageable KC and the Aux KC are shared
7058 * across kexts and data from kexts is not page aligned
7059 */
7060 if (protect && (end_protect > start_protect) &&
7061 ((strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0 &&
7062 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) != 0) ||
7063 (kc_type != KCKindPageable && kc_type != KCKindAuxiliary))) {
7064 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7065 kext_map, start_protect, end_protect, seg->maxprot, TRUE, kc_type);
0a7de745
A
7066 if (result != KERN_SUCCESS) {
7067 OSKextLog(this,
7068 kOSKextLogErrorLevel |
7069 kOSKextLogLoadFlag,
7070 "Kext %s failed to set maximum VM protections "
7071 "for segment %s - 0x%x.",
7072 getIdentifierCString(), seg->segname, (int)result);
7073 goto finish;
7074 }
7075
f427ee49
A
7076 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7077 kext_map, start_protect, end_protect, seg->initprot, FALSE, kc_type);
0a7de745
A
7078 if (result != KERN_SUCCESS) {
7079 OSKextLog(this,
7080 kOSKextLogErrorLevel |
7081 kOSKextLogLoadFlag,
7082 "Kext %s failed to set initial VM protections "
7083 "for segment %s - 0x%x.",
7084 getIdentifierCString(), seg->segname, (int)result);
7085 goto finish;
7086 }
7087 }
7088
7089 if (segmentShouldBeWired(seg) && wire) {
f427ee49
A
7090 result = OSKext_wire((kernel_mach_header_t *)kmod_info->address,
7091 kext_map, start_wire, end_wire, seg->initprot, FALSE, kc_type);
0a7de745
A
7092 if (result != KERN_SUCCESS) {
7093 goto finish;
7094 }
7095 }
7096
7097 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7098 }
b0d623f7
A
7099
7100finish:
0a7de745 7101 return result;
b0d623f7
A
7102}
7103
6d2010ae
A
7104/*********************************************************************
7105*********************************************************************/
0a7de745 7106boolean_t
6d2010ae
A
7107OSKext::segmentShouldBeWired(kernel_segment_command_t *seg)
7108{
f427ee49
A
7109 return sKeepSymbols || (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) &&
7110 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)));
6d2010ae
A
7111}
7112
b0d623f7
A
7113/*********************************************************************
7114*********************************************************************/
7115OSReturn
7116OSKext::validateKextMapping(bool startFlag)
7117{
0a7de745
A
7118 OSReturn result = kOSReturnError;
7119 const char * whichOp = startFlag ? "start" : "stop";
7120 kern_return_t kern_result = 0;
7121 vm_map_t kext_map = NULL;
7122 kernel_segment_command_t * seg = NULL;
7123 mach_vm_address_t address = 0;
7124 mach_vm_size_t size = 0;
7125 uint32_t depth = 0;
f427ee49
A
7126 uint64_t kext_segbase = 0;
7127 uint64_t kext_segsize = 0;
0a7de745
A
7128 mach_msg_type_number_t count;
7129 vm_region_submap_short_info_data_64_t info;
f427ee49 7130 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
0a7de745
A
7131
7132 if (flags.builtin) {
7133 return kOSReturnSuccess;
7134 }
7135
7136 count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
7137 bzero(&info, sizeof(info));
7138
7139 // xxx - do we need a distinct OSReturn value for these or is "bad data"
7140 // xxx - sufficient?
7141
7142 /* Verify that the kmod_info and start/stop pointers are non-NULL.
7143 */
7144 if (!kmod_info) {
7145 OSKextLog(this,
7146 kOSKextLogErrorLevel |
7147 kOSKextLogLoadFlag,
7148 "Kext %s - NULL kmod_info pointer.",
7149 getIdentifierCString());
7150 result = kOSKextReturnBadData;
7151 goto finish;
7152 }
7153
7154 if (startFlag) {
7155 address = (mach_vm_address_t)kmod_info->start;
7156 } else {
7157 address = (mach_vm_address_t)kmod_info->stop;
7158 }
7159
7160 if (!address) {
7161 OSKextLog(this,
7162 kOSKextLogErrorLevel |
7163 kOSKextLogLoadFlag,
7164 "Kext %s - NULL module %s pointer.",
7165 getIdentifierCString(), whichOp);
7166 result = kOSKextReturnBadData;
7167 goto finish;
7168 }
7169
7170 kext_map = kext_get_vm_map(kmod_info);
7171 depth = (kernel_map == kext_map) ? 1 : 2;
f427ee49
A
7172 if (isInFileset()) {
7173#if defined(HAS_APPLE_PAC)
7174 address = (mach_vm_address_t)ptrauth_auth_data((void*)address, ptrauth_key_function_pointer, 0);
7175#endif /* defined(HAS_APPLE_PAC) */
7176 }
0a7de745
A
7177
7178 /* Verify that the start/stop function lies within the kext's address range.
7179 */
f427ee49
A
7180 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO) ||
7181 isInFileset()) {
0a7de745
A
7182 /* This will likely be how we deal with split kexts; walk the segments to
7183 * check that the function lies inside one of the segments of this kext.
7184 */
7185 for (seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7186 seg != NULL;
7187 seg = nextsegfromheader((kernel_mach_header_t *)kmod_info->address, seg)) {
7188 if ((address >= seg->vmaddr) && address < (seg->vmaddr + seg->vmsize)) {
f427ee49
A
7189 kext_segbase = seg->vmaddr;
7190 kext_segsize = seg->vmsize;
0a7de745
A
7191 break;
7192 }
7193 }
7194
7195 if (!seg) {
7196 OSKextLog(this,
7197 kOSKextLogErrorLevel |
7198 kOSKextLogLoadFlag,
7199 "Kext %s module %s pointer is outside of kext range "
7200 "(%s %p - kext starts at %p).",
7201 getIdentifierCString(),
7202 whichOp,
7203 whichOp,
f427ee49
A
7204 (void *)(((uintptr_t)address) - kext_slide),
7205 (void *)(((uintptr_t)kmod_info->address) - kext_slide));
0a7de745
A
7206 result = kOSKextReturnBadData;
7207 goto finish;
7208 }
7209
7210 seg = NULL;
7211 } else {
7212 if (address < kmod_info->address + kmod_info->hdr_size ||
7213 kmod_info->address + kmod_info->size <= address) {
7214 OSKextLog(this,
7215 kOSKextLogErrorLevel |
7216 kOSKextLogLoadFlag,
7217 "Kext %s module %s pointer is outside of kext range "
7218 "(%s %p - kext at %p-%p).",
7219 getIdentifierCString(),
7220 whichOp,
7221 whichOp,
f427ee49
A
7222 (void *)(((uintptr_t)address) - kext_slide),
7223 (void *)(((uintptr_t)kmod_info->address) - kext_slide),
7224 (void *)((((uintptr_t)kmod_info->address) - kext_slide) + kmod_info->size));
0a7de745
A
7225 result = kOSKextReturnBadData;
7226 goto finish;
7227 }
7228 }
7229
7230 /* Only do these checks before calling the start function;
7231 * If anything goes wrong with the mapping while the kext is running,
7232 * we'll likely have panicked well before any attempt to stop the kext.
7233 */
7234 if (startFlag) {
f427ee49
A
7235 if (!isInFileset() || kc_type != KCKindPrimary) {
7236 /*
7237 * Verify that the start/stop function is executable.
7238 */
7239 kern_result = mach_vm_region_recurse(kernel_map, &address, &size, &depth,
7240 (vm_region_recurse_info_t)&info, &count);
7241 if (kern_result != KERN_SUCCESS) {
7242 OSKextLog(this,
7243 kOSKextLogErrorLevel |
7244 kOSKextLogLoadFlag,
7245 "Kext %s - bad %s pointer %p.",
7246 getIdentifierCString(),
7247 whichOp, (void *)ml_static_unslide(address));
7248 result = kOSKextReturnBadData;
7249 goto finish;
7250 }
7251 } else {
7252 /*
7253 * Since kexts loaded from the primary KC are held in memory
7254 * allocated by efiboot, we cannot use mach_vm_region_recurse() to
7255 * discover that memory's protection flags. Instead, we need to
7256 * get that information from the kernel pmap itself. Above, we
7257 * (potentially) saved the size of the segment in which the address
7258 * in question was located. If we have a non-zero size, verify
7259 * that all pages in the (address, address + kext_segsize) range
7260 * are marked executable. If we somehow did not record the size
7261 * (or the base) just verify the single page that includes the address.
7262 */
7263 if (kext_segbase == 0 || kext_segsize == 0) {
7264 kext_segbase = address & ~(uint64_t)PAGE_MASK;
7265 kext_segsize = PAGE_SIZE;
7266 }
0a7de745 7267 }
b0d623f7 7268
316670eb 7269#if VM_MAPPED_KEXTS
f427ee49
A
7270 if (((!isInFileset() || kc_type != KCKindPrimary) && !(info.protection & VM_PROT_EXECUTE)) ||
7271 ((isInFileset() && kc_type == KCKindPrimary) &&
7272 ml_static_verify_page_protections(kext_segbase, kext_segsize, VM_PROT_EXECUTE) != KERN_SUCCESS)) {
0a7de745
A
7273 OSKextLog(this,
7274 kOSKextLogErrorLevel |
7275 kOSKextLogLoadFlag,
7276 "Kext %s - memory region containing module %s function "
7277 "is not executable.",
7278 getIdentifierCString(), whichOp);
7279 result = kOSKextReturnBadData;
7280 goto finish;
7281 }
316670eb 7282#endif
b0d623f7 7283
0a7de745
A
7284 /* Verify that the kext's segments are backed by physical memory.
7285 */
7286 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7287 while (seg) {
7288 if (!verifySegmentMapping(seg)) {
7289 result = kOSKextReturnBadData;
7290 goto finish;
7291 }
6d2010ae 7292
0a7de745
A
7293 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7294 }
7295 }
b0d623f7 7296
0a7de745 7297 result = kOSReturnSuccess;
b0d623f7 7298finish:
0a7de745 7299 return result;
b0d623f7
A
7300}
7301
6d2010ae
A
7302/*********************************************************************
7303*********************************************************************/
7304boolean_t
7305OSKext::verifySegmentMapping(kernel_segment_command_t *seg)
7306{
0a7de745 7307 mach_vm_address_t address = 0;
6d2010ae 7308
f427ee49
A
7309 if (seg->vmsize > UINT32_MAX) {
7310 return false;
7311 }
7312
0a7de745
A
7313 if (!segmentShouldBeWired(seg)) {
7314 return true;
7315 }
6d2010ae 7316
0a7de745
A
7317 for (address = seg->vmaddr;
7318 address < round_page(seg->vmaddr + seg->vmsize);
7319 address += PAGE_SIZE) {
7320 if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
7321 OSKextLog(this,
7322 kOSKextLogErrorLevel |
7323 kOSKextLogLoadFlag,
7324 "Kext %s - page %p is not backed by physical memory.",
7325 getIdentifierCString(),
7326 (void *)address);
7327 return false;
7328 }
7329 }
6d2010ae 7330
0a7de745 7331 return true;
6d2010ae
A
7332}
7333
39037602
A
7334/*********************************************************************
7335*********************************************************************/
7336static void
7337OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code)
7338{
0a7de745
A
7339 uint64_t stamp = 0;
7340 firehose_tracepoint_id_u trace_id;
7341 struct firehose_trace_uuid_info_s uuid_info_s;
7342 firehose_trace_uuid_info_t uuid_info = &uuid_info_s;
7343 size_t uuid_info_len = sizeof(struct firehose_trace_uuid_info_s);
f427ee49 7344 OSSharedPtr<OSData> uuid_data;
39037602 7345
0a7de745
A
7346 stamp = firehose_tracepoint_time(firehose_activity_flags_default);
7347 trace_id.ftid_value = FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata, _firehose_tracepoint_type_metadata_kext, (firehose_tracepoint_flags_t)0, code);
39037602 7348
0a7de745
A
7349 uuid_data = aKext->copyTextUUID();
7350 if (uuid_data) {
7351 memcpy(uuid_info->ftui_uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_info->ftui_uuid));
0a7de745 7352 }
39037602 7353
0a7de745 7354 uuid_info->ftui_size = size;
cb323159
A
7355 if (aKext->isDriverKit()) {
7356 uuid_info->ftui_address = address;
7357 } else {
7358 uuid_info->ftui_address = ml_static_unslide(address);
7359 }
0a7de745
A
7360 firehose_trace_metadata(firehose_stream_metadata, trace_id, stamp, uuid_info, uuid_info_len);
7361 return;
39037602
A
7362}
7363
cb323159
A
7364void
7365OSKext::OSKextLogDriverKitInfoLoad(OSKext *kext)
7366{
7367 OSKextLogKextInfo(kext, kext->getLoadTag(), 1, firehose_tracepoint_code_load);
7368}
7369
b0d623f7
A
7370/*********************************************************************
7371*********************************************************************/
7372OSReturn
7373OSKext::start(bool startDependenciesFlag)
7374{
0a7de745
A
7375 OSReturn result = kOSReturnError;
7376 kern_return_t (* startfunc)(kmod_info_t *, void *);
7377 unsigned int i, count;
7378 void * kmodStartData = NULL;
7379
7380 if (isStarted() || isInterface() || isKernelComponent()) {
7381 result = kOSReturnSuccess;
7382 goto finish;
7383 }
7384
7385 if (!isLoaded()) {
7386 OSKextLog(this,
7387 kOSKextLogErrorLevel |
7388 kOSKextLogLoadFlag,
7389 "Attempt to start nonloaded kext %s.",
7390 getIdentifierCString());
7391 result = kOSKextReturnInvalidArgument;
7392 goto finish;
7393 }
7394
7395 if (!sLoadEnabled) {
7396 OSKextLog(this,
7397 kOSKextLogErrorLevel |
7398 kOSKextLogLoadFlag,
7399 "Kext loading is disabled (attempt to start kext %s).",
7400 getIdentifierCString());
7401 result = kOSKextReturnDisabled;
7402 goto finish;
7403 }
7404
7405 result = validateKextMapping(/* start? */ true);
7406 if (result != kOSReturnSuccess) {
7407 goto finish;
7408 }
7409
7410 startfunc = kmod_info->start;
7411
7412 count = getNumDependencies();
7413 for (i = 0; i < count; i++) {
7414 OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
7415 if (dependency == NULL) {
7416 OSKextLog(this,
7417 kOSKextLogErrorLevel |
7418 kOSKextLogLoadFlag,
7419 "Kext %s start - internal error, dependency disappeared.",
7420 getIdentifierCString());
7421 goto finish;
7422 }
7423 if (!dependency->isStarted()) {
7424 if (startDependenciesFlag) {
7425 OSReturn dependencyResult =
7426 dependency->start(startDependenciesFlag);
7427 if (dependencyResult != KERN_SUCCESS) {
7428 OSKextLog(this,
7429 kOSKextLogErrorLevel |
7430 kOSKextLogLoadFlag,
7431 "Kext %s start - dependency %s failed to start (error 0x%x).",
7432 getIdentifierCString(),
7433 dependency->getIdentifierCString(),
7434 dependencyResult);
7435 goto finish;
7436 }
7437 } else {
7438 OSKextLog(this,
7439 kOSKextLogErrorLevel |
7440 kOSKextLogLoadFlag,
7441 "Not starting %s - dependency %s not started yet.",
7442 getIdentifierCString(),
7443 dependency->getIdentifierCString());
f427ee49 7444 result = kOSKextReturnStartStopError; // xxx - make new return?
0a7de745
A
7445 goto finish;
7446 }
7447 }
7448 }
7449
7450 OSKextLog(this,
7451 kOSKextLogDetailLevel |
7452 kOSKextLogLoadFlag,
7453 "Kext %s calling module start function.",
7454 getIdentifierCString());
7455
7456 flags.starting = 1;
7457
7458 // Drop a log message so logd can grab the needed information to decode this kext
7459 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_load);
7460 result = OSRuntimeInitializeCPP(this);
7461 if (result == KERN_SUCCESS) {
7462 result = startfunc(kmod_info, kmodStartData);
7463 }
7464
7465 flags.starting = 0;
7466
7467 /* On success overlap the setting of started/starting. On failure just
7468 * clear starting.
7469 */
7470 if (result == KERN_SUCCESS) {
7471 flags.started = 1;
7472
7473 // xxx - log start error from kernel?
7474 OSKextLog(this,
7475 kOSKextLogProgressLevel |
7476 kOSKextLogLoadFlag,
7477 "Kext %s is now started.",
7478 getIdentifierCString());
7479 } else {
7480 invokeOrCancelRequestCallbacks(
7481 /* result not actually used */ kOSKextReturnStartStopError,
7482 /* invokeFlag */ false);
7483 OSKextLog(this,
f427ee49 7484 kOSKextLogWarningLevel |
0a7de745
A
7485 kOSKextLogLoadFlag,
7486 "Kext %s did not start (return code 0x%x).",
7487 getIdentifierCString(), result);
7488 }
b0d623f7
A
7489
7490finish:
0a7de745 7491 return result;
b0d623f7
A
7492}
7493
7494/*********************************************************************
7495*********************************************************************/
7496/* static */
0a7de745
A
7497bool
7498OSKext::canUnloadKextWithIdentifier(
7499 OSString * kextIdentifier,
7500 bool checkClassesFlag)
b0d623f7 7501{
0a7de745 7502 bool result = false;
f427ee49 7503 OSKext * aKext = NULL; // do not release
b0d623f7 7504
0a7de745 7505 IORecursiveLockLock(sKextLock);
b0d623f7 7506
0a7de745 7507 aKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
b0d623f7 7508
0a7de745 7509 if (!aKext) {
f427ee49 7510 goto finish; // can't unload what's not loaded
0a7de745 7511 }
b0d623f7 7512
0a7de745
A
7513 if (aKext->isLoaded()) {
7514 if (aKext->getRetainCount() > kOSKextMinLoadedRetainCount) {
7515 goto finish;
7516 }
7517 if (checkClassesFlag && aKext->hasOSMetaClassInstances()) {
7518 goto finish;
7519 }
7520 }
b0d623f7 7521
0a7de745 7522 result = true;
b0d623f7
A
7523
7524finish:
0a7de745
A
7525 IORecursiveLockUnlock(sKextLock);
7526 return result;
b0d623f7
A
7527}
7528
7529/*********************************************************************
7530*********************************************************************/
7531OSReturn
7532OSKext::stop(void)
7533{
0a7de745
A
7534 OSReturn result = kOSReturnError;
7535 kern_return_t (*stopfunc)(kmod_info_t *, void *);
7536
7537 if (!isStarted() || isInterface()) {
7538 result = kOSReturnSuccess;
7539 goto finish;
7540 }
7541
7542 if (!isLoaded()) {
7543 OSKextLog(this,
7544 kOSKextLogErrorLevel |
7545 kOSKextLogLoadFlag,
7546 "Attempt to stop nonloaded kext %s.",
7547 getIdentifierCString());
7548 result = kOSKextReturnInvalidArgument;
7549 goto finish;
7550 }
7551
7552 /* Refuse to stop if we have clients or instances. It is up to
7553 * the caller to make sure those aren't true.
7554 */
7555 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7556 OSKextLog(this,
7557 kOSKextLogErrorLevel |
7558 kOSKextLogLoadFlag,
7559 "Kext %s - C++ instances; can't stop.",
7560 getIdentifierCString());
7561 result = kOSKextReturnInUse;
7562 goto finish;
7563 }
7564
7565 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7566 OSKextLog(this,
7567 kOSKextLogErrorLevel |
7568 kOSKextLogLoadFlag,
7569 "Kext %s - has references (linkage or tracking object); "
7570 "can't stop.",
7571 getIdentifierCString());
7572 result = kOSKextReturnInUse;
7573 goto finish;
7574 }
7575
7576 /* Note: If validateKextMapping fails on the stop & unload path,
7577 * we are in serious trouble and a kernel panic is likely whether
7578 * we stop & unload the kext or not.
7579 */
7580 result = validateKextMapping(/* start? */ false);
7581 if (result != kOSReturnSuccess) {
7582 goto finish;
7583 }
7584
7585 stopfunc = kmod_info->stop;
7586 if (stopfunc) {
7587 OSKextLog(this,
7588 kOSKextLogDetailLevel |
7589 kOSKextLogLoadFlag,
7590 "Kext %s calling module stop function.",
7591 getIdentifierCString());
7592
7593 flags.stopping = 1;
7594
7595 result = stopfunc(kmod_info, /* userData */ NULL);
7596 if (result == KERN_SUCCESS) {
7597 result = OSRuntimeFinalizeCPP(this);
7598 }
7599
7600 flags.stopping = 0;
7601
7602 if (result == KERN_SUCCESS) {
7603 flags.started = 0;
7604
7605 OSKextLog(this,
7606 kOSKextLogDetailLevel |
7607 kOSKextLogLoadFlag,
7608 "Kext %s is now stopped and ready to unload.",
7609 getIdentifierCString());
7610 } else {
7611 OSKextLog(this,
7612 kOSKextLogErrorLevel |
7613 kOSKextLogLoadFlag,
7614 "Kext %s did not stop (return code 0x%x).",
7615 getIdentifierCString(), result);
7616 result = kOSKextReturnStartStopError;
7617 }
7618 }
b0d623f7
A
7619
7620finish:
0a7de745
A
7621 // Drop a log message so logd can update this kext's metadata
7622 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_unload);
7623 return result;
b0d623f7
A
7624}
7625
7626/*********************************************************************
7627*********************************************************************/
7628OSReturn
7629OSKext::unload(void)
7630{
0a7de745
A
7631 OSReturn result = kOSReturnError;
7632 unsigned int index;
7633 uint32_t num_kmod_refs = 0;
7634 OSKextAccount * freeAccount;
f427ee49 7635 bool in_fileset = false;
0a7de745
A
7636
7637 if (!sUnloadEnabled) {
7638 OSKextLog(this,
7639 kOSKextLogErrorLevel |
7640 kOSKextLogLoadFlag,
7641 "Kext unloading is disabled (%s).",
7642 this->getIdentifierCString());
7643
7644 result = kOSKextReturnDisabled;
7645 goto finish;
7646 }
7647
f427ee49
A
7648 // cache this result so we don't need to access the kmod_info after
7649 // it's been potentially free'd
7650 in_fileset = isInFileset();
7651
0a7de745
A
7652 /* Refuse to unload if we have clients or instances. It is up to
7653 * the caller to make sure those aren't true.
7654 */
7655 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7656 // xxx - Don't log under errors? this is more of an info thing
7657 OSKextLog(this,
7658 kOSKextLogErrorLevel |
7659 kOSKextLogKextBookkeepingFlag,
7660 "Can't unload kext %s; outstanding references (linkage or tracking object).",
7661 getIdentifierCString());
7662 result = kOSKextReturnInUse;
7663 goto finish;
7664 }
7665
cb323159
A
7666 if (isDriverKit()) {
7667 index = sLoadedKexts->getNextIndexOfObject(this, 0);
7668 if (index != (unsigned int)-1) {
7669 sLoadedDriverKitKexts->removeObject(index);
7670 OSKextLogKextInfo(this, loadTag, 1, firehose_tracepoint_code_unload);
7671 loadTag = 0;
7672 }
7673 }
7674
0a7de745
A
7675 if (!isLoaded()) {
7676 result = kOSReturnSuccess;
7677 goto finish;
7678 }
7679
7680 if (isKernelComponent()) {
7681 result = kOSKextReturnInvalidArgument;
7682 goto finish;
7683 }
7684
f427ee49 7685 if (metaClasses && !OSMetaClass::removeClasses(metaClasses.get())) {
0a7de745
A
7686 OSKextLog(this,
7687 kOSKextLogErrorLevel |
7688 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
7689 "Can't unload kext %s; classes have instances:",
7690 getIdentifierCString());
7691 reportOSMetaClassInstances(kOSKextLogErrorLevel |
7692 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag);
7693 result = kOSKextReturnInUse;
7694 goto finish;
7695 }
7696
7697 /* Note that the kext is unloading before running any code that
7698 * might be in the kext (request callbacks, module stop function).
7699 * We will deny certain requests made against a kext in the process
7700 * of unloading.
7701 */
7702 flags.unloading = 1;
7703
7704 /* Update the string describing the last kext to unload in case we panic.
7705 */
7706 savePanicString(/* isLoading */ false);
7707
7708 if (isStarted()) {
7709 result = stop();
7710 if (result != KERN_SUCCESS) {
7711 OSKextLog(this,
7712 kOSKextLogErrorLevel |
7713 kOSKextLogLoadFlag,
7714 "Kext %s can't unload - module stop returned 0x%x.",
7715 getIdentifierCString(), (unsigned)result);
7716 result = kOSKextReturnStartStopError;
7717 goto finish;
7718 }
7719 }
7720
7721 OSKextLog(this,
7722 kOSKextLogProgressLevel |
7723 kOSKextLogLoadFlag,
7724 "Kext %s unloading.",
7725 getIdentifierCString());
7726
7727 {
7728 struct list_head *p;
7729 struct list_head *prev;
7730 struct list_head *next;
7731 for (p = pendingPgoHead.next; p != &pendingPgoHead; p = next) {
7732 OSKextGrabPgoStruct *s = container_of(p, OSKextGrabPgoStruct, list_head);
7733 s->err = OSKextGrabPgoDataLocked(this, s->metadata, instance_uuid, s->pSize, s->pBuffer, s->bufferSize);
7734 prev = p->prev;
7735 next = p->next;
7736 prev->next = next;
7737 next->prev = prev;
7738 p->prev = p;
7739 p->next = p;
7740 IORecursiveLockWakeup(sKextLock, s, false);
7741 }
7742 }
7743
7744
7745 /* Even if we don't call the stop function, we want to be sure we
7746 * have no OSMetaClass references before unloading the kext executable
7747 * from memory. OSMetaClasses may have pointers into the kext executable
7748 * and that would cause a panic on OSKext::free() when metaClasses is freed.
7749 */
7750 if (metaClasses) {
7751 metaClasses->flushCollection();
7752 }
7753 (void) OSRuntimeFinalizeCPP(this);
7754
7755 /* Remove the kext from the list of loaded kexts, patch the gap
7756 * in the kmod_info_t linked list, and reset "kmod" to point to the
7757 * last loaded kext that isn't the fake kernel kext (sKernelKext).
7758 */
7759 index = sLoadedKexts->getNextIndexOfObject(this, 0);
7760 if (index != (unsigned int)-1) {
7761 sLoadedKexts->removeObject(index);
7762
7763 OSKext * nextKext = OSDynamicCast(OSKext,
7764 sLoadedKexts->getObject(index));
7765
7766 if (nextKext) {
7767 if (index > 0) {
7768 OSKext * gapKext = OSDynamicCast(OSKext,
7769 sLoadedKexts->getObject(index - 1));
7770
7771 nextKext->kmod_info->next = gapKext->kmod_info;
f427ee49 7772 } else { /* index == 0 */
0a7de745
A
7773 nextKext->kmod_info->next = NULL;
7774 }
7775 }
7776
7777 OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
7778 if (lastKext && !lastKext->isKernel()) {
7779 kmod = lastKext->kmod_info;
7780 } else {
f427ee49 7781 kmod = NULL; // clear the global kmod variable
0a7de745
A
7782 }
7783 }
7784
7785 /* Clear out the kmod references that we're keeping for compatibility
7786 * with current panic backtrace code & kgmacros.
7787 * xxx - will want to update those bits sometime and remove this.
7788 */
7789 num_kmod_refs = getNumDependencies();
7790 if (num_kmod_refs && kmod_info && kmod_info->reference_list) {
7791 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
7792 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
7793 ref->info->reference_count--;
7794 }
7795 kfree(kmod_info->reference_list,
7796 num_kmod_refs * sizeof(kmod_reference_t));
7797 }
b0d623f7 7798
6d2010ae 7799#if CONFIG_DTRACE
0a7de745 7800 unregisterWithDTrace();
6d2010ae
A
7801#endif /* CONFIG_DTRACE */
7802
0a7de745 7803 notifyKextUnloadObservers(this);
6d2010ae 7804
0a7de745
A
7805 freeAccount = NULL;
7806 IOSimpleLockLock(sKextAccountsLock);
7807 account->kext = NULL;
7808 if (account->site.tag) {
7809 account->site.flags |= VM_TAG_UNLOAD;
7810 } else {
7811 freeAccount = account;
7812 }
7813 IOSimpleLockUnlock(sKextAccountsLock);
7814 if (freeAccount) {
7815 IODelete(freeAccount, OSKextAccount, 1);
7816 }
3e170ce0 7817
0a7de745
A
7818 /* Unwire and free the linked executable.
7819 */
7820 if (linkedExecutable) {
5ba3f43e 7821#if KASAN
0a7de745 7822 kasan_unload_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(), linkedExecutable->getLength());
5ba3f43e
A
7823#endif
7824
316670eb 7825#if VM_MAPPED_KEXTS
f427ee49 7826 if (!isInterface() && (!in_fileset || flags.resetSegmentsFromVnode)) {
0a7de745
A
7827 kernel_segment_command_t *seg = NULL;
7828 vm_map_t kext_map = kext_get_vm_map(kmod_info);
7829
7830 if (!kext_map) {
7831 OSKextLog(this,
7832 kOSKextLogErrorLevel |
7833 kOSKextLogLoadFlag,
7834 "Failed to free kext %s; couldn't find the kext map.",
7835 getIdentifierCString());
7836 result = kOSKextReturnInternalError;
7837 goto finish;
7838 }
7839
7840 OSKextLog(this,
7841 kOSKextLogProgressLevel |
7842 kOSKextLogLoadFlag,
7843 "Kext %s unwiring and unmapping linked executable.",
7844 getIdentifierCString());
7845
7846 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7847 while (seg) {
7848 if (segmentShouldBeWired(seg)) {
f427ee49
A
7849 vm_map_offset_t start_wire = trunc_page(seg->vmaddr);
7850 vm_map_offset_t end_wire = round_page(seg->vmaddr + seg->vmsize);
7851
7852 result = vm_map_unwire(kext_map, start_wire,
7853 end_wire, FALSE);
0a7de745
A
7854 if (result != KERN_SUCCESS) {
7855 OSKextLog(this,
7856 kOSKextLogErrorLevel |
7857 kOSKextLogLoadFlag,
7858 "Failed to unwire kext %s.",
7859 getIdentifierCString());
7860 result = kOSKextReturnInternalError;
7861 goto finish;
7862 }
7863 }
7864
7865 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7866 }
f427ee49
A
7867#if defined(__x86_64__) || defined(__i386__)
7868 if (in_fileset && flags.resetSegmentsFromVnode) {
7869 IORecursiveLockLock(sKextLock);
7870 resetKCFileSetSegments();
7871 IORecursiveLockUnlock(sKextLock);
7872 }
7873#endif // (__x86_64__) || defined(__i386__)
7874 }
7875#endif /* VM_MAPPED_KEXTS */
7876 if (flags.resetSegmentsFromImmutableCopy) {
7877 result = resetMutableSegments();
7878 if (result != kOSReturnSuccess) {
7879 OSKextLog(this,
7880 kOSKextLogErrorLevel |
7881 kOSKextLogLoadFlag,
7882 "Failed to reset kext %s.",
7883 getIdentifierCString());
7884 result = kOSKextReturnInternalError;
7885 goto finish;
7886 }
7887 }
7888 if (kc_type == KCKindUnknown) {
7889 linkedExecutable.reset();
0a7de745 7890 }
0a7de745
A
7891 }
7892
7893 /* An interface kext has a fake kmod_info that was allocated,
7894 * so we have to free it.
7895 */
7896 if (isInterface()) {
7897 kfree(kmod_info, sizeof(kmod_info_t));
f427ee49 7898 kmod_info = NULL;
0a7de745
A
7899 }
7900
f427ee49
A
7901 if (!in_fileset) {
7902 kmod_info = NULL;
7903 }
0a7de745
A
7904
7905 flags.loaded = false;
7906 flushDependencies();
7907
7908 /* save a copy of the bundle ID for us to check when deciding to
7909 * rebuild the kernel cache file. If a kext was already in the kernel
7910 * cache and unloaded then later loaded we do not need to rebuild the
7911 * kernel cache. 9055303
7912 */
7913 if (isPrelinked()) {
f427ee49 7914 if (!_OSKextInUnloadedPrelinkedKexts(bundleID.get())) {
0a7de745
A
7915 IORecursiveLockLock(sKextLock);
7916 if (sUnloadedPrelinkedKexts) {
f427ee49 7917 sUnloadedPrelinkedKexts->setObject(bundleID.get());
0a7de745
A
7918 }
7919 IORecursiveLockUnlock(sKextLock);
7920 }
7921 }
7922
7923 OSKextLog(this,
7924 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
7925 "Kext %s unloaded.", getIdentifierCString());
7926
7927 queueKextNotification(kKextRequestPredicateUnloadNotification,
f427ee49 7928 OSDynamicCast(OSString, bundleID.get()));
6d2010ae 7929
b0d623f7 7930finish:
0a7de745
A
7931 OSKext::saveLoadedKextPanicList();
7932 OSKext::updateLoadedKextSummaries();
b0d623f7 7933
0a7de745
A
7934 flags.unloading = 0;
7935 return result;
b0d623f7
A
7936}
7937
6d2010ae
A
7938/*********************************************************************
7939* Assumes sKextLock is held.
7940*********************************************************************/
7941/* static */
7942OSReturn
7943OSKext::queueKextNotification(
0a7de745
A
7944 const char * notificationName,
7945 OSString * kextIdentifier)
7946{
7947 OSReturn result = kOSReturnError;
f427ee49 7948 OSSharedPtr<OSDictionary> loadRequest;
0a7de745
A
7949
7950 if (!kextIdentifier) {
7951 result = kOSKextReturnInvalidArgument;
7952 goto finish;
7953 }
7954
7955 /* Create a new request unless one is already sitting
7956 * in sKernelRequests for this bundle identifier
7957 */
f427ee49 7958 result = _OSKextCreateRequest(notificationName, loadRequest);
0a7de745
A
7959 if (result != kOSReturnSuccess) {
7960 goto finish;
7961 }
f427ee49 7962 if (!_OSKextSetRequestArgument(loadRequest.get(),
0a7de745
A
7963 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
7964 result = kOSKextReturnNoMemory;
7965 goto finish;
7966 }
f427ee49 7967 if (!sKernelRequests->setObject(loadRequest.get())) {
0a7de745
A
7968 result = kOSKextReturnNoMemory;
7969 goto finish;
7970 }
7971
f427ee49 7972 /* We might want to only queue the notification if the IOKit daemon is active,
0a7de745
A
7973 * but that wouldn't work for embedded. Note that we don't care if
7974 * the ping immediately succeeds here so don't do anything with the
7975 * result of this call.
7976 */
f427ee49 7977 OSKext::pingIOKitDaemon();
0a7de745
A
7978
7979 result = kOSReturnSuccess;
6d2010ae
A
7980
7981finish:
0a7de745 7982 return result;
6d2010ae
A
7983}
7984
f427ee49
A
7985
7986#if CONFIG_KXLD
b0d623f7
A
7987/*********************************************************************
7988*********************************************************************/
7989static void
7990_OSKextConsiderDestroyingLinkContext(
0a7de745
A
7991 __unused thread_call_param_t p0,
7992 __unused thread_call_param_t p1)
7993{
7994 /* Take multiple locks in the correct order.
7995 */
7996 IORecursiveLockLock(sKextLock);
7997 IORecursiveLockLock(sKextInnerLock);
7998
7999 /* The first time we destroy the kxldContext is in the first
8000 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
8001 * before calling this function. Thereafter any call to this function
8002 * will actually destroy the context.
8003 */
8004 if (sConsiderUnloadsCalled && sKxldContext) {
8005 kxld_destroy_context(sKxldContext);
8006 sKxldContext = NULL;
8007 }
8008
8009 /* Free the thread_call that was allocated to execute this function.
8010 */
8011 if (sDestroyLinkContextThread) {
8012 if (!thread_call_free(sDestroyLinkContextThread)) {
8013 OSKextLog(/* kext */ NULL,
8014 kOSKextLogErrorLevel |
8015 kOSKextLogGeneralFlag,
8016 "thread_call_free() failed for kext link context.");
8017 }
cb323159 8018 sDestroyLinkContextThread = NULL;
0a7de745
A
8019 }
8020
8021 IORecursiveLockUnlock(sKextInnerLock);
8022 IORecursiveLockUnlock(sKextLock);
8023
8024 return;
b0d623f7
A
8025}
8026
8027/*********************************************************************
8028* Destroying the kxldContext requires checking variables under both
8029* sKextInnerLock and sKextLock, so we do it on a separate thread
8030* to avoid deadlocks with IOService, with which OSKext has a reciprocal
8031* call relationship.
8032*
6d2010ae
A
8033* This function must be invoked with sKextInnerLock held.
8034* Do not call any function that takes sKextLock here!
b0d623f7
A
8035*********************************************************************/
8036/* static */
8037void
8038OSKext::considerDestroyingLinkContext(void)
8039{
0a7de745
A
8040 IORecursiveLockLock(sKextInnerLock);
8041
8042 /* If we have already queued a thread to destroy the link context,
8043 * don't bother resetting; that thread will take care of it.
8044 */
8045 if (sDestroyLinkContextThread) {
8046 goto finish;
8047 }
8048
8049 /* The function to be invoked in the thread will deallocate
8050 * this thread_call, so don't share it around.
8051 */
8052 sDestroyLinkContextThread = thread_call_allocate(
cb323159 8053 &_OSKextConsiderDestroyingLinkContext, NULL);
0a7de745
A
8054 if (!sDestroyLinkContextThread) {
8055 OSKextLog(/* kext */ NULL,
8056 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogLinkFlag,
8057 "Can't create thread to destroy kext link context.");
8058 goto finish;
8059 }
8060
8061 thread_call_enter(sDestroyLinkContextThread);
b0d623f7
A
8062
8063finish:
0a7de745
A
8064 IORecursiveLockUnlock(sKextInnerLock);
8065 return;
b0d623f7
A
8066}
8067
f427ee49
A
8068#else // !CONFIG_KXLD
8069
8070/* static */
8071void
8072OSKext::considerDestroyingLinkContext(void)
8073{
8074 return;
8075}
8076
8077#endif // CONFIG_KXLD
8078
b0d623f7
A
8079#if PRAGMA_MARK
8080#pragma mark Autounload
8081#endif
8082/*********************************************************************
8083* This is a static method because the kext will be deallocated if it
8084* does unload!
8085*********************************************************************/
6d2010ae 8086/* static */
b0d623f7
A
8087OSReturn
8088OSKext::autounloadKext(OSKext * aKext)
8089{
0a7de745
A
8090 OSReturn result = kOSKextReturnInUse;
8091
f427ee49
A
8092#if NO_KEXTD
8093 /*
8094 * Do not unload prelinked kexts on platforms that do not have an
8095 * IOKit daemon as there is no way to reload the kext or restart
8096 * matching.
8097 */
8098 if (aKext->isPrelinked()) {
8099 goto finish;
8100 }
8101#endif /* defined(__x86_64__) */
8102
0a7de745
A
8103 /* Check for external references to this kext (usu. dependents),
8104 * instances of defined classes (or classes derived from them),
8105 * outstanding requests.
8106 */
8107 if ((aKext->getRetainCount() > kOSKextMinLoadedRetainCount) ||
8108 !aKext->flags.autounloadEnabled ||
8109 aKext->isKernelComponent()) {
8110 goto finish;
8111 }
8112
8113 /* Skip a delay-autounload kext, once.
8114 */
8115 if (aKext->flags.delayAutounload) {
8116 OSKextLog(aKext,
8117 kOSKextLogProgressLevel |
8118 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
8119 "Kext %s has delayed autounload set; skipping and clearing flag.",
8120 aKext->getIdentifierCString());
8121 aKext->flags.delayAutounload = 0;
8122 goto finish;
8123 }
8124
8125 if (aKext->hasOSMetaClassInstances() ||
8126 aKext->countRequestCallbacks()) {
8127 goto finish;
8128 }
8129
8130 result = OSKext::removeKext(aKext);
8131
8132finish:
8133 return result;
8134}
b0d623f7 8135
b0d623f7
A
8136/*********************************************************************
8137*********************************************************************/
8138void
8139_OSKextConsiderUnloads(
0a7de745
A
8140 __unused thread_call_param_t p0,
8141 __unused thread_call_param_t p1)
8142{
8143 bool didUnload = false;
8144 unsigned int count, i;
8145
8146 /* Take multiple locks in the correct order
8147 * (note also sKextSummaries lock further down).
8148 */
8149 IORecursiveLockLock(sKextLock);
8150 IORecursiveLockLock(sKextInnerLock);
8151
8152 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
8153
8154 /* If the system is powering down, don't try to unload anything.
8155 */
8156 if (sSystemSleep) {
8157 goto finish;
8158 }
8159
8160 OSKextLog(/* kext */ NULL,
8161 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
8162 "Checking for unused kexts to autounload.");
8163
8164 /*****
8165 * Remove any request callbacks marked as stale,
8166 * and mark as stale any currently in flight.
8167 */
8168 count = sRequestCallbackRecords->getCount();
8169 if (count) {
8170 i = count - 1;
8171 do {
8172 OSDictionary * callbackRecord = OSDynamicCast(OSDictionary,
8173 sRequestCallbackRecords->getObject(i));
8174 OSBoolean * stale = OSDynamicCast(OSBoolean,
8175 callbackRecord->getObject(kKextRequestStaleKey));
8176
8177 if (stale == kOSBooleanTrue) {
8178 OSKext::invokeRequestCallback(callbackRecord,
8179 kOSKextReturnTimeout);
8180 } else {
8181 callbackRecord->setObject(kKextRequestStaleKey,
8182 kOSBooleanTrue);
8183 }
8184 } while (i--);
8185 }
8186
8187 /*****
8188 * Make multiple passes through the array of loaded kexts until
8189 * we don't unload any. This handles unwinding of dependency
8190 * chains. We have to go *backwards* through the array because
8191 * kexts are removed from it when unloaded, and we cannot make
8192 * a copy or we'll mess up the retain counts we rely on to
8193 * check whether a kext will unload. If only we could have
8194 * nonretaining collections like CF has....
8195 */
8196 do {
8197 didUnload = false;
8198
8199 count = sLoadedKexts->getCount();
8200 if (count) {
8201 i = count - 1;
8202 do {
8203 OSKext * thisKext = OSDynamicCast(OSKext,
8204 sLoadedKexts->getObject(i));
8205 didUnload |= (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
8206 } while (i--);
8207 }
8208 } while (didUnload);
b0d623f7
A
8209
8210finish:
0a7de745
A
8211 sConsiderUnloadsPending = false;
8212 sConsiderUnloadsExecuted = true;
8213
8214 (void) OSKext::considerRebuildOfPrelinkedKernel();
b0d623f7 8215
0a7de745
A
8216 IORecursiveLockUnlock(sKextInnerLock);
8217 IORecursiveLockUnlock(sKextLock);
b0d623f7 8218
0a7de745 8219 return;
b0d623f7
A
8220}
8221
8222/*********************************************************************
8223* Do not call any function that takes sKextLock here!
8224*********************************************************************/
0a7de745
A
8225void
8226OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
b0d623f7 8227{
0a7de745 8228 AbsoluteTime when;
b0d623f7 8229
0a7de745 8230 IORecursiveLockLock(sKextInnerLock);
b0d623f7 8231
0a7de745 8232 if (!sUnloadCallout) {
cb323159 8233 sUnloadCallout = thread_call_allocate(&_OSKextConsiderUnloads, NULL);
0a7de745 8234 }
b0d623f7 8235
0a7de745
A
8236 /* we only reset delay value for unloading if we already have something
8237 * pending. rescheduleOnlyFlag should not start the count down.
8238 */
8239 if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
8240 goto finish;
8241 }
b0d623f7 8242
0a7de745 8243 thread_call_cancel(sUnloadCallout);
f427ee49
A
8244 if (OSKext::getAutounloadEnabled() && !sSystemSleep
8245#if !NO_KEXTD
8246 && sIOKitDaemonActive
8247#endif
8248 ) {
0a7de745
A
8249 clock_interval_to_deadline(sConsiderUnloadDelay,
8250 1000 * 1000 * 1000, &when);
8251
8252 OSKextLog(/* kext */ NULL,
8253 kOSKextLogProgressLevel |
8254 kOSKextLogLoadFlag,
8255 "%scheduling %sscan for unused kexts in %lu seconds.",
8256 sConsiderUnloadsPending ? "Res" : "S",
8257 sConsiderUnloadsCalled ? "" : "initial ",
8258 (unsigned long)sConsiderUnloadDelay);
8259
8260 sConsiderUnloadsPending = true;
8261 thread_call_enter_delayed(sUnloadCallout, when);
8262 }
b0d623f7
A
8263
8264finish:
0a7de745
A
8265 /* The kxld context should be reused throughout boot. We mark the end of
8266 * period as the first time considerUnloads() is called, and we destroy
8267 * the first kxld context in that function. Afterwards, it will be
8268 * destroyed in flushNonloadedKexts.
8269 */
8270 if (!sConsiderUnloadsCalled) {
8271 sConsiderUnloadsCalled = true;
8272 OSKext::considerDestroyingLinkContext();
8273 }
b0d623f7 8274
0a7de745
A
8275 IORecursiveLockUnlock(sKextInnerLock);
8276 return;
b0d623f7
A
8277}
8278
8279/*********************************************************************
8280* Do not call any function that takes sKextLock here!
8281*********************************************************************/
8282extern "C" {
39037602 8283IOReturn OSKextSystemSleepOrWake(UInt32 messageType);
0a7de745
A
8284IOReturn
8285OSKextSystemSleepOrWake(UInt32 messageType)
8286{
8287 IORecursiveLockLock(sKextInnerLock);
8288
8289 /* If the system is going to sleep, cancel the reaper thread timer,
8290 * and note that we're in a sleep state in case it just fired but hasn't
8291 * taken the lock yet. If we are coming back from sleep, just
8292 * clear the sleep flag; IOService's normal operation will cause
8293 * unloads to be considered soon enough.
8294 */
8295 if (messageType == kIOMessageSystemWillSleep) {
8296 if (sUnloadCallout) {
8297 thread_call_cancel(sUnloadCallout);
8298 }
8299 sSystemSleep = true;
8300 AbsoluteTime_to_scalar(&sLastWakeTime) = 0;
8301 } else if (messageType == kIOMessageSystemHasPoweredOn) {
8302 sSystemSleep = false;
8303 clock_get_uptime(&sLastWakeTime);
8304 }
8305 IORecursiveLockUnlock(sKextInnerLock);
b0d623f7 8306
0a7de745
A
8307 return kIOReturnSuccess;
8308}
b0d623f7
A
8309};
8310
8311
8312#if PRAGMA_MARK
8313#pragma mark Prelinked Kernel
8314#endif
f427ee49
A
8315
8316#ifdef CONFIG_KXLD
b0d623f7
A
8317/*********************************************************************
8318* Do not access sConsiderUnloads... variables other than
8319* sConsiderUnloadsExecuted in this function. They are guarded by a
8320* different lock.
8321*********************************************************************/
8322/* static */
8323void
316670eb
A
8324OSKext::considerRebuildOfPrelinkedKernel(void)
8325{
0a7de745
A
8326 static bool requestedPrelink = false;
8327 OSReturn checkResult = kOSReturnError;
f427ee49
A
8328 OSSharedPtr<OSDictionary> prelinkRequest;
8329 OSSharedPtr<OSCollectionIterator> kextIterator;
8330 const OSSymbol * thisID = NULL; // do not release
0a7de745
A
8331 bool doRebuild = false;
8332 AbsoluteTime my_abstime;
8333 UInt64 my_ns;
8334 SInt32 delta_secs;
8335
8336 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
8337 if (requestedPrelink || !sPrelinkBoot) {
8338 return;
8339 }
8340
8341 /* no direct return from this point */
8342 IORecursiveLockLock(sKextLock);
8343
f427ee49 8344 /* We need to wait for the IOKit daemon to get up and running with unloads already done
0a7de745
A
8345 * and any new startup kexts loaded.
8346 */
8347 if (!sConsiderUnloadsExecuted ||
8348 !sDeferredLoadSucceeded) {
8349 goto finish;
8350 }
8351
8352 /* we really only care about boot / system start up related kexts so bail
8353 * if we're here after REBUILD_MAX_TIME.
8354 */
8355 if (!_OSKextInPrelinkRebuildWindow()) {
8356 OSKextLog(/* kext */ NULL,
8357 kOSKextLogArchiveFlag,
8358 "%s prebuild rebuild has expired",
8359 __FUNCTION__);
8360 requestedPrelink = true;
8361 goto finish;
8362 }
8363
8364 /* we do not want to trigger a rebuild if we get here too close to waking
8365 * up. (see radar 10233768)
8366 */
8367 IORecursiveLockLock(sKextInnerLock);
8368
8369 clock_get_uptime(&my_abstime);
8370 delta_secs = MINIMUM_WAKEUP_SECONDS + 1;
8371 if (AbsoluteTime_to_scalar(&sLastWakeTime) != 0) {
8372 SUB_ABSOLUTETIME(&my_abstime, &sLastWakeTime);
8373 absolutetime_to_nanoseconds(my_abstime, &my_ns);
8374 delta_secs = (SInt32)(my_ns / NSEC_PER_SEC);
8375 }
8376 IORecursiveLockUnlock(sKextInnerLock);
8377
8378 if (delta_secs < MINIMUM_WAKEUP_SECONDS) {
8379 /* too close to time of last wake from sleep */
8380 goto finish;
8381 }
8382 requestedPrelink = true;
8383
8384 /* Now it's time to see if we have a reason to rebuild. We may have done
8385 * some loads and unloads but the kernel cache didn't actually change.
8386 * We will rebuild if any kext is not marked prelinked AND is not in our
8387 * list of prelinked kexts that got unloaded. (see radar 9055303)
8388 */
f427ee49 8389 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
0a7de745
A
8390 if (!kextIterator) {
8391 goto finish;
8392 }
8393
8394 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
f427ee49 8395 OSKext * thisKext; // do not release
0a7de745
A
8396
8397 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
8398 if (!thisKext || thisKext->isPrelinked() || thisKext->isKernel()) {
8399 continue;
8400 }
8401
f427ee49 8402 if (_OSKextInUnloadedPrelinkedKexts(thisKext->bundleID.get())) {
0a7de745
A
8403 continue;
8404 }
8405 /* kext is loaded and was not in current kernel cache so let's rebuild
8406 */
8407 doRebuild = true;
8408 OSKextLog(/* kext */ NULL,
8409 kOSKextLogArchiveFlag,
8410 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
8411 thisKext->bundleID->getCStringNoCopy());
8412 break;
8413 }
8414 sUnloadedPrelinkedKexts->flushCollection();
8415
8416 if (!doRebuild) {
8417 goto finish;
8418 }
8419
8420 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
f427ee49 8421 prelinkRequest);
0a7de745
A
8422 if (checkResult != kOSReturnSuccess) {
8423 goto finish;
8424 }
8425
f427ee49 8426 if (!sKernelRequests->setObject(prelinkRequest.get())) {
0a7de745
A
8427 goto finish;
8428 }
8429
f427ee49 8430 OSKext::pingIOKitDaemon();
0a7de745 8431
b0d623f7 8432finish:
0a7de745 8433 IORecursiveLockUnlock(sKextLock);
0a7de745
A
8434
8435 return;
b0d623f7
A
8436}
8437
f427ee49
A
8438#else /* !CONFIG_KXLD */
8439
8440void
8441OSKext::considerRebuildOfPrelinkedKernel(void)
8442{
8443 /* in a non-dynamic kext loading world, there is never a reason to rebuild */
8444 return;
8445}
8446
8447#endif /* CONFIG_KXLD */
8448
b0d623f7
A
8449#if PRAGMA_MARK
8450#pragma mark Dependencies
8451#endif
8452/*********************************************************************
8453*********************************************************************/
8454bool
8455OSKext::resolveDependencies(
0a7de745
A
8456 OSArray * loopStack)
8457{
8458 bool result = false;
f427ee49 8459 OSSharedPtr<OSArray> localLoopStack;
0a7de745 8460 bool addedToLoopStack = false;
f427ee49
A
8461 OSDictionary * libraries = NULL; // do not release
8462 OSSharedPtr<OSCollectionIterator> libraryIterator;
8463 OSString * libraryID = NULL; // do not release
8464 OSKext * libraryKext = NULL; // do not release
0a7de745
A
8465 bool hasRawKernelDependency = false;
8466 bool hasKernelDependency = false;
8467 bool hasKPIDependency = false;
8468 bool hasPrivateKPIDependency = false;
8469 unsigned int count;
8470
f427ee49
A
8471#if CONFIG_KXLD
8472 OSString * infoString = NULL; // do not release
8473 OSString * readableString = NULL; // do not release
8474#endif // CONFIG_KXLD
8475
0a7de745
A
8476 /* A kernel component will automatically have this flag set,
8477 * and a loaded kext should also have it set (as should all its
8478 * loaded dependencies).
8479 */
8480 if (flags.hasAllDependencies) {
8481 result = true;
8482 goto finish;
8483 }
8484
8485 /* Check for loops in the dependency graph.
8486 */
8487 if (loopStack) {
8488 if (loopStack->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
8489 OSKextLog(this,
8490 kOSKextLogErrorLevel |
8491 kOSKextLogDependenciesFlag,
8492 "Kext %s has a dependency loop; can't resolve dependencies.",
8493 getIdentifierCString());
8494 goto finish;
8495 }
8496 } else {
8497 OSKextLog(this,
8498 kOSKextLogStepLevel |
8499 kOSKextLogDependenciesFlag,
8500 "Kext %s resolving dependencies.",
8501 getIdentifierCString());
8502
f427ee49
A
8503 localLoopStack = OSArray::withCapacity(6); // any small capacity will do
8504 if (!localLoopStack) {
0a7de745
A
8505 OSKextLog(this,
8506 kOSKextLogErrorLevel |
8507 kOSKextLogDependenciesFlag,
8508 "Kext %s can't create bookkeeping stack to resolve dependencies.",
8509 getIdentifierCString());
8510 goto finish;
8511 }
f427ee49 8512 loopStack = localLoopStack.get();
0a7de745
A
8513 }
8514 if (!loopStack->setObject(this)) {
8515 OSKextLog(this,
8516 kOSKextLogErrorLevel |
8517 kOSKextLogDependenciesFlag,
8518 "Kext %s - internal error resolving dependencies.",
8519 getIdentifierCString());
8520 goto finish;
8521 }
8522 addedToLoopStack = true;
8523
8524 /* Purge any existing kexts in the dependency list and start over.
8525 */
8526 flushDependencies();
8527 if (dependencies) {
8528 OSKextLog(this,
8529 kOSKextLogErrorLevel |
8530 kOSKextLogDependenciesFlag,
8531 "Kext %s - internal error resolving dependencies.",
8532 getIdentifierCString());
8533 }
8534
8535 libraries = OSDynamicCast(OSDictionary,
8536 getPropertyForHostArch(kOSBundleLibrariesKey));
8537 if (libraries == NULL || libraries->getCount() == 0) {
8538 OSKextLog(this,
8539 kOSKextLogErrorLevel |
8540 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8541 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
8542 getIdentifierCString(), kOSBundleLibrariesKey);
8543 goto finish;
8544 }
8545
8546 /* Make a new array to hold the dependencies (flush freed the old one).
8547 */
8548 dependencies = OSArray::withCapacity(libraries->getCount());
8549 if (!dependencies) {
8550 OSKextLog(this,
8551 kOSKextLogErrorLevel |
8552 kOSKextLogDependenciesFlag,
8553 "Kext %s - can't allocate dependencies array.",
8554 getIdentifierCString());
8555 goto finish;
8556 }
8557
8558 // xxx - compat: We used to add an implicit dependency on kernel 6.0
8559 // xxx - compat: if none were declared.
8560
8561 libraryIterator = OSCollectionIterator::withCollection(libraries);
8562 if (!libraryIterator) {
8563 OSKextLog(this,
8564 kOSKextLogErrorLevel |
8565 kOSKextLogDependenciesFlag,
8566 "Kext %s - can't allocate dependencies iterator.",
8567 getIdentifierCString());
8568 goto finish;
8569 }
8570
8571 while ((libraryID = OSDynamicCast(OSString,
8572 libraryIterator->getNextObject()))) {
8573 const char * library_id = libraryID->getCStringNoCopy();
8574
8575 OSString * libraryVersion = OSDynamicCast(OSString,
8576 libraries->getObject(libraryID));
8577 if (libraryVersion == NULL) {
8578 OSKextLog(this,
8579 kOSKextLogErrorLevel |
8580 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8581 "Kext %s - illegal type in OSBundleLibraries.",
8582 getIdentifierCString());
8583 goto finish;
8584 }
8585
8586 OSKextVersion libraryVers =
8587 OSKextParseVersionString(libraryVersion->getCStringNoCopy());
8588 if (libraryVers == -1) {
8589 OSKextLog(this,
8590 kOSKextLogErrorLevel |
8591 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8592 "Kext %s - invalid library version %s.",
8593 getIdentifierCString(),
8594 libraryVersion->getCStringNoCopy());
8595 goto finish;
8596 }
8597
8598 libraryKext = OSDynamicCast(OSKext, sKextsByID->getObject(libraryID));
8599 if (libraryKext == NULL) {
8600 OSKextLog(this,
8601 kOSKextLogErrorLevel |
8602 kOSKextLogDependenciesFlag,
8603 "Kext %s - library kext %s not found.",
8604 getIdentifierCString(), library_id);
8605 goto finish;
8606 }
8607
8608 if (!libraryKext->isCompatibleWithVersion(libraryVers)) {
8609 OSKextLog(this,
8610 kOSKextLogErrorLevel |
8611 kOSKextLogDependenciesFlag,
8612 "Kext %s - library kext %s not compatible "
8613 "with requested version %s.",
8614 getIdentifierCString(), library_id,
8615 libraryVersion->getCStringNoCopy());
8616 goto finish;
8617 }
8618
8619 /* If a nonprelinked library somehow got into the mix for a
8620 * prelinked kext, at any point in the chain, we must fail
8621 * because the prelinked relocs for the library will be all wrong.
8622 */
8623 if (this->isPrelinked() &&
8624 libraryKext->declaresExecutable() &&
8625 !libraryKext->isPrelinked()) {
8626 OSKextLog(this,
8627 kOSKextLogErrorLevel |
8628 kOSKextLogDependenciesFlag,
8629 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
8630 getIdentifierCString(), library_id,
8631 libraryVersion->getCStringNoCopy());
8632 goto finish;
8633 }
8634
8635 if (!libraryKext->resolveDependencies(loopStack)) {
8636 goto finish;
8637 }
8638
8639 /* Add the library directly only if it has an executable to link.
8640 * Otherwise it's just used to collect other dependencies, so put
8641 * *its* dependencies on the list for this kext.
8642 */
8643 // xxx - We are losing info here; would like to make fake entries or
8644 // xxx - keep these in the dependency graph for loaded kexts.
8645 // xxx - I really want to make kernel components not a special case!
8646 if (libraryKext->declaresExecutable() ||
8647 libraryKext->isInterface()) {
8648 if (dependencies->getNextIndexOfObject(libraryKext, 0) == (unsigned)-1) {
8649 dependencies->setObject(libraryKext);
8650
8651 OSKextLog(this,
8652 kOSKextLogDetailLevel |
8653 kOSKextLogDependenciesFlag,
8654 "Kext %s added dependency %s.",
8655 getIdentifierCString(),
8656 libraryKext->getIdentifierCString());
8657 }
8658 } else {
8659 int numLibDependencies = libraryKext->getNumDependencies();
8660 OSArray * libraryDependencies = libraryKext->getDependencies();
8661 int index;
8662
8663 if (numLibDependencies) {
8664 // xxx - this msg level should be 1 lower than the per-kext one
8665 OSKextLog(this,
8666 kOSKextLogDetailLevel |
8667 kOSKextLogDependenciesFlag,
8668 "Kext %s pulling %d dependencies from codeless library %s.",
8669 getIdentifierCString(),
8670 numLibDependencies,
8671 libraryKext->getIdentifierCString());
8672 }
8673 for (index = 0; index < numLibDependencies; index++) {
8674 OSKext * thisLibDependency = OSDynamicCast(OSKext,
8675 libraryDependencies->getObject(index));
8676 if (dependencies->getNextIndexOfObject(thisLibDependency, 0) == (unsigned)-1) {
8677 dependencies->setObject(thisLibDependency);
8678 OSKextLog(this,
8679 kOSKextLogDetailLevel |
8680 kOSKextLogDependenciesFlag,
8681 "Kext %s added dependency %s from codeless library %s.",
8682 getIdentifierCString(),
8683 thisLibDependency->getIdentifierCString(),
8684 libraryKext->getIdentifierCString());
8685 }
8686 }
8687 }
8688
8689 if ((strlen(library_id) == strlen(KERNEL_LIB)) &&
8690 0 == strncmp(library_id, KERNEL_LIB, sizeof(KERNEL_LIB) - 1)) {
8691 hasRawKernelDependency = true;
8692 } else if (STRING_HAS_PREFIX(library_id, KERNEL_LIB_PREFIX)) {
8693 hasKernelDependency = true;
8694 } else if (STRING_HAS_PREFIX(library_id, KPI_LIB_PREFIX)) {
8695 hasKPIDependency = true;
8696 if (!strncmp(library_id, PRIVATE_KPI, sizeof(PRIVATE_KPI) - 1)) {
8697 hasPrivateKPIDependency = true;
8698 }
8699 }
8700 }
8701
8702 if (hasRawKernelDependency) {
8703 OSKextLog(this,
8704 kOSKextLogErrorLevel |
8705 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8706 "Error - kext %s declares a dependency on %s, which is not permitted.",
8707 getIdentifierCString(), KERNEL_LIB);
8708 goto finish;
8709 }
b0d623f7 8710#if __LP64__
0a7de745
A
8711 if (hasKernelDependency) {
8712 OSKextLog(this,
8713 kOSKextLogErrorLevel |
8714 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8715 "Error - kext %s declares %s dependencies. "
8716 "Only %s* dependencies are supported for 64-bit kexts.",
8717 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
8718 goto finish;
8719 }
8720 if (!hasKPIDependency) {
8721 OSKextLog(this,
8722 kOSKextLogWarningLevel |
8723 kOSKextLogDependenciesFlag,
8724 "Warning - kext %s declares no %s* dependencies. "
8725 "If it uses any KPIs, the link may fail with undefined symbols.",
8726 getIdentifierCString(), KPI_LIB_PREFIX);
8727 }
b0d623f7 8728#else /* __LP64__ */
0a7de745
A
8729 // xxx - will change to flatly disallow "kernel" dependencies at some point
8730 // xxx - is it invalid to do both "com.apple.kernel" and any
8731 // xxx - "com.apple.kernel.*"?
8732
8733 if (hasKernelDependency && hasKPIDependency) {
8734 OSKextLog(this,
8735 kOSKextLogWarningLevel |
8736 kOSKextLogDependenciesFlag,
8737 "Warning - kext %s has immediate dependencies on both "
8738 "%s* and %s* components; use only one style.",
8739 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
8740 }
8741
8742 if (!hasKernelDependency && !hasKPIDependency) {
8743 // xxx - do we want to use validation flag for these too?
8744 OSKextLog(this,
8745 kOSKextLogWarningLevel |
8746 kOSKextLogDependenciesFlag,
8747 "Warning - %s declares no kernel dependencies; using %s.",
8748 getIdentifierCString(), KERNEL6_LIB);
8749 OSKext * kernelKext = OSDynamicCast(OSKext,
8750 sKextsByID->getObject(KERNEL6_LIB));
8751 if (kernelKext) {
8752 dependencies->setObject(kernelKext);
8753 } else {
8754 OSKextLog(this,
8755 kOSKextLogErrorLevel |
8756 kOSKextLogDependenciesFlag,
8757 "Error - Library %s not found for %s.",
8758 KERNEL6_LIB, getIdentifierCString());
8759 }
8760 }
8761
8762 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
8763 * its indirect dependencies to simulate old-style linking. XXX - Should
8764 * check for duplicates.
8765 */
8766 if (!hasKPIDependency) {
8767 unsigned int i;
8768
8769 flags.hasBleedthrough = true;
8770
8771 count = getNumDependencies();
8772
8773 /* We add to the dependencies array in this loop, but do not iterate
8774 * past its original count.
8775 */
8776 for (i = 0; i < count; i++) {
8777 OSKext * dependencyKext = OSDynamicCast(OSKext,
8778 dependencies->getObject(i));
f427ee49 8779 dependencyKext->addBleedthroughDependencies(dependencies.get());
0a7de745
A
8780 }
8781 }
b0d623f7
A
8782#endif /* __LP64__ */
8783
f427ee49
A
8784#if CONFIG_KXLD
8785 /*
8786 * If we're not dynamically linking kexts, then we don't need to check
8787 * copyright strings. The linker in user space has already done this.
8788 */
0a7de745
A
8789 if (hasPrivateKPIDependency) {
8790 bool hasApplePrefix = false;
8791 bool infoCopyrightIsValid = false;
8792 bool readableCopyrightIsValid = false;
8793
8794 hasApplePrefix = STRING_HAS_PREFIX(getIdentifierCString(),
8795 APPLE_KEXT_PREFIX);
8796
8797 infoString = OSDynamicCast(OSString,
8798 getPropertyForHostArch("CFBundleGetInfoString"));
8799 if (infoString) {
8800 infoCopyrightIsValid =
8801 kxld_validate_copyright_string(infoString->getCStringNoCopy());
8802 }
8803
8804 readableString = OSDynamicCast(OSString,
8805 getPropertyForHostArch("NSHumanReadableCopyright"));
8806 if (readableString) {
8807 readableCopyrightIsValid =
8808 kxld_validate_copyright_string(readableString->getCStringNoCopy());
8809 }
8810
8811 if (!hasApplePrefix || (!infoCopyrightIsValid && !readableCopyrightIsValid)) {
8812 OSKextLog(this,
8813 kOSKextLogErrorLevel |
8814 kOSKextLogDependenciesFlag,
8815 "Error - kext %s declares a dependency on %s. "
8816 "Only Apple kexts may declare a dependency on %s.",
8817 getIdentifierCString(), PRIVATE_KPI, PRIVATE_KPI);
8818 goto finish;
8819 }
8820 }
f427ee49 8821#endif // CONFIG_KXLD
0a7de745
A
8822
8823 result = true;
8824 flags.hasAllDependencies = 1;
b0d623f7
A
8825
8826finish:
8827
0a7de745
A
8828 if (addedToLoopStack) {
8829 count = loopStack->getCount();
8830 if (count > 0 && (this == loopStack->getObject(count - 1))) {
8831 loopStack->removeObject(count - 1);
8832 } else {
8833 OSKextLog(this,
8834 kOSKextLogErrorLevel |
8835 kOSKextLogDependenciesFlag,
8836 "Kext %s - internal error resolving dependencies.",
8837 getIdentifierCString());
8838 }
8839 }
8840
8841 if (result && localLoopStack) {
8842 OSKextLog(this,
8843 kOSKextLogStepLevel |
8844 kOSKextLogDependenciesFlag,
8845 "Kext %s successfully resolved dependencies.",
8846 getIdentifierCString());
8847 }
b0d623f7 8848
0a7de745 8849 return result;
b0d623f7
A
8850}
8851
8852/*********************************************************************
8853*********************************************************************/
8854bool
8855OSKext::addBleedthroughDependencies(OSArray * anArray)
8856{
0a7de745
A
8857 bool result = false;
8858 unsigned int dependencyIndex, dependencyCount;
8859
8860 dependencyCount = getNumDependencies();
8861
8862 for (dependencyIndex = 0;
8863 dependencyIndex < dependencyCount;
8864 dependencyIndex++) {
8865 OSKext * dependency = OSDynamicCast(OSKext,
8866 dependencies->getObject(dependencyIndex));
8867 if (!dependency) {
8868 OSKextLog(this,
8869 kOSKextLogErrorLevel |
8870 kOSKextLogDependenciesFlag,
8871 "Kext %s - internal error propagating compatibility dependencies.",
8872 getIdentifierCString());
8873 goto finish;
8874 }
8875 if (anArray->getNextIndexOfObject(dependency, 0) == (unsigned int)-1) {
8876 anArray->setObject(dependency);
8877 }
8878 dependency->addBleedthroughDependencies(anArray);
8879 }
8880
8881 result = true;
b0d623f7
A
8882
8883finish:
0a7de745 8884 return result;
b0d623f7
A
8885}
8886
8887/*********************************************************************
8888*********************************************************************/
8889bool
8890OSKext::flushDependencies(bool forceFlag)
8891{
0a7de745
A
8892 bool result = false;
8893
8894 /* Only clear the dependencies if the kext isn't loaded;
8895 * we need the info for loaded kexts to track references.
8896 */
8897 if (!isLoaded() || forceFlag) {
8898 if (dependencies) {
8899 // xxx - check level
8900 OSKextLog(this,
8901 kOSKextLogProgressLevel |
8902 kOSKextLogDependenciesFlag,
8903 "Kext %s flushing dependencies.",
8904 getIdentifierCString());
f427ee49 8905 dependencies.reset();
0a7de745
A
8906 }
8907 if (!isKernelComponent()) {
8908 flags.hasAllDependencies = 0;
8909 }
8910 result = true;
8911 }
b0d623f7 8912
0a7de745 8913 return result;
b0d623f7
A
8914}
8915
8916/*********************************************************************
8917*********************************************************************/
8918uint32_t
8919OSKext::getNumDependencies(void)
8920{
0a7de745
A
8921 if (!dependencies) {
8922 return 0;
8923 }
8924 return dependencies->getCount();
b0d623f7
A
8925}
8926
8927/*********************************************************************
8928*********************************************************************/
8929OSArray *
8930OSKext::getDependencies(void)
8931{
f427ee49
A
8932 return dependencies.get();
8933}
8934
8935bool
8936OSKext::hasDependency(const OSSymbol * depID)
8937{
8938 bool result __block;
8939
8940 if (depID == getIdentifier()) {
8941 return true;
8942 }
8943 if (!dependencies) {
8944 return false;
8945 }
8946 result = false;
8947 dependencies->iterateObjects(^bool (OSObject * obj) {
8948 OSKext * kext;
8949 kext = OSDynamicCast(OSKext, obj);
8950 if (!kext) {
8951 return false;
8952 }
8953 result = (depID == kext->getIdentifier());
8954 return result;
8955 });
8956 return result;
b0d623f7
A
8957}
8958
8959#if PRAGMA_MARK
8960#pragma mark OSMetaClass Support
8961#endif
8962/*********************************************************************
8963*********************************************************************/
8964OSReturn
8965OSKext::addClass(
0a7de745
A
8966 OSMetaClass * aClass,
8967 uint32_t numClasses)
8968{
8969 OSReturn result = kOSMetaClassNoInsKModSet;
8970
8971 if (!metaClasses) {
8972 metaClasses = OSSet::withCapacity(numClasses);
8973 if (!metaClasses) {
8974 goto finish;
8975 }
8976 }
8977
8978 if (metaClasses->containsObject(aClass)) {
8979 OSKextLog(this,
8980 kOSKextLogWarningLevel |
8981 kOSKextLogLoadFlag,
8982 "Notice - kext %s has already registered class %s.",
8983 getIdentifierCString(),
8984 aClass->getClassName());
8985 result = kOSReturnSuccess;
8986 goto finish;
8987 }
8988
8989 if (!metaClasses->setObject(aClass)) {
8990 goto finish;
8991 } else {
8992 OSKextLog(this,
8993 kOSKextLogDetailLevel |
8994 kOSKextLogLoadFlag,
8995 "Kext %s registered class %s.",
8996 getIdentifierCString(),
8997 aClass->getClassName());
8998 }
8999
9000 if (!flags.autounloadEnabled) {
f427ee49 9001 const OSMetaClass * metaScan = NULL; // do not release
0a7de745
A
9002
9003 for (metaScan = aClass; metaScan; metaScan = metaScan->getSuperClass()) {
9004 if (metaScan == OSTypeID(IOService)) {
9005 OSKextLog(this,
9006 kOSKextLogProgressLevel |
9007 kOSKextLogLoadFlag,
9008 "Kext %s has IOService subclass %s; enabling autounload.",
9009 getIdentifierCString(),
9010 aClass->getClassName());
9011
c3c9b80d 9012 flags.autounloadEnabled = (0 == flags.unloadUnsupported);
0a7de745
A
9013 break;
9014 }
9015 }
9016 }
9017
9018 notifyAddClassObservers(this, aClass, flags);
9019
9020 result = kOSReturnSuccess;
b0d623f7
A
9021
9022finish:
0a7de745
A
9023 if (result != kOSReturnSuccess) {
9024 OSKextLog(this,
9025 kOSKextLogErrorLevel |
9026 kOSKextLogLoadFlag,
9027 "Kext %s failed to register class %s.",
9028 getIdentifierCString(),
9029 aClass->getClassName());
9030 }
b0d623f7 9031
0a7de745 9032 return result;
b0d623f7
A
9033}
9034
9035/*********************************************************************
9036*********************************************************************/
9037OSReturn
9038OSKext::removeClass(
0a7de745
A
9039 OSMetaClass * aClass)
9040{
9041 OSReturn result = kOSMetaClassNoKModSet;
9042
9043 if (!metaClasses) {
9044 goto finish;
9045 }
9046
9047 if (!metaClasses->containsObject(aClass)) {
9048 OSKextLog(this,
9049 kOSKextLogWarningLevel |
9050 kOSKextLogLoadFlag,
9051 "Notice - kext %s asked to unregister unknown class %s.",
9052 getIdentifierCString(),
9053 aClass->getClassName());
9054 result = kOSReturnSuccess;
9055 goto finish;
9056 }
9057
9058 OSKextLog(this,
9059 kOSKextLogDetailLevel |
9060 kOSKextLogLoadFlag,
9061 "Kext %s unregistering class %s.",
9062 getIdentifierCString(),
9063 aClass->getClassName());
9064
9065 metaClasses->removeObject(aClass);
9066
9067 notifyRemoveClassObservers(this, aClass, flags);
9068
9069 result = kOSReturnSuccess;
b0d623f7
A
9070
9071finish:
0a7de745
A
9072 if (result != kOSReturnSuccess) {
9073 OSKextLog(this,
9074 kOSKextLogErrorLevel |
9075 kOSKextLogLoadFlag,
9076 "Failed to unregister kext %s class %s.",
9077 getIdentifierCString(),
9078 aClass->getClassName());
9079 }
9080 return result;
b0d623f7
A
9081}
9082
9083/*********************************************************************
9084*********************************************************************/
9085OSSet *
9086OSKext::getMetaClasses(void)
9087{
f427ee49 9088 return metaClasses.get();
b0d623f7
A
9089}
9090
9091/*********************************************************************
9092*********************************************************************/
9093bool
9094OSKext::hasOSMetaClassInstances(void)
9095{
0a7de745 9096 bool result = false;
f427ee49
A
9097 OSSharedPtr<OSCollectionIterator> classIterator;
9098 OSMetaClass * checkClass = NULL; // do not release
0a7de745
A
9099
9100 if (!metaClasses) {
9101 goto finish;
9102 }
9103
f427ee49 9104 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
0a7de745
A
9105 if (!classIterator) {
9106 // xxx - log alloc failure?
9107 goto finish;
9108 }
9109 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
9110 if (checkClass->getInstanceCount()) {
9111 result = true;
9112 goto finish;
9113 }
9114 }
b0d623f7
A
9115
9116finish:
0a7de745 9117 return result;
b0d623f7
A
9118}
9119
9120/*********************************************************************
9121*********************************************************************/
9122/* static */
9123void
9124OSKext::reportOSMetaClassInstances(
0a7de745
A
9125 const char * kextIdentifier,
9126 OSKextLogSpec msgLogSpec)
9127{
f427ee49 9128 OSSharedPtr<OSKext> theKext;
0a7de745
A
9129
9130 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
9131 if (!theKext) {
9132 goto finish;
9133 }
9134
9135 theKext->reportOSMetaClassInstances(msgLogSpec);
b0d623f7 9136finish:
0a7de745 9137 return;
b0d623f7
A
9138}
9139
9140/*********************************************************************
9141*********************************************************************/
9142void
9143OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
9144{
f427ee49
A
9145 OSSharedPtr<OSCollectionIterator> classIterator;
9146 OSMetaClass * checkClass = NULL; // do not release
0a7de745
A
9147
9148 if (!metaClasses) {
9149 goto finish;
9150 }
9151
f427ee49 9152 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
0a7de745
A
9153 if (!classIterator) {
9154 goto finish;
9155 }
9156 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
9157 if (checkClass->getInstanceCount()) {
9158 OSKextLog(this,
9159 msgLogSpec,
9160 " Kext %s class %s has %d instance%s.",
9161 getIdentifierCString(),
9162 checkClass->getClassName(),
9163 checkClass->getInstanceCount(),
9164 checkClass->getInstanceCount() == 1 ? "" : "s");
9165 }
9166 }
b0d623f7
A
9167
9168finish:
0a7de745 9169 return;
b0d623f7
A
9170}
9171
9172#if PRAGMA_MARK
9173#pragma mark User-Space Requests
9174#endif
f427ee49
A
9175
9176static kern_return_t
9177patchDextLaunchRequests(task_t calling_task, OSArray *requests)
9178{
9179 OSReturn result = kOSReturnSuccess;
9180 for (uint32_t requestIndex = 0; requestIndex < requests->getCount(); requestIndex++) {
9181 OSDictionary * request = NULL; //do not release
9182 IOUserServerCheckInToken * token = NULL; //do not release
9183 OSString * requestPredicate = NULL; //do not release
9184 OSSharedPtr<OSNumber> portNameNumber;
9185 mach_port_name_t portName = 0;
9186 request = OSDynamicCast(OSDictionary, requests->getObject(requestIndex));
9187 if (!request) {
9188 OSKextLog(/* kext */ NULL,
9189 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9190 "Elements of request should be of type OSDictionary");
9191 result = kOSKextReturnInternalError;
9192 goto finish;
9193 }
9194 requestPredicate = _OSKextGetRequestPredicate(request);
9195 if (!requestPredicate) {
9196 OSKextLog(/* kext */ NULL,
9197 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9198 "Failed to get request predicate");
9199 result = kOSKextReturnInternalError;
9200 goto finish;
9201 }
9202 // is this a dext launch?
9203 if (requestPredicate->isEqualTo(kKextRequestPredicateRequestDaemonLaunch)) {
9204 token = OSDynamicCast(IOUserServerCheckInToken, _OSKextGetRequestArgument(request, kKextRequestArgumentCheckInToken));
9205 if (!token) {
9206 OSKextLog(/* kext */ NULL,
9207 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9208 "Could not find a IOUserServerCheckInToken in daemon launch request.");
9209 result = kOSKextReturnInternalError;
9210 goto finish;
9211 }
9212 portName = iokit_make_send_right(calling_task, token, IKOT_IOKIT_IDENT);
9213 if (portName == 0 || portName == MACH_PORT_DEAD) {
9214 OSKextLog(/* kext */ NULL,
9215 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9216 "Could not create send right for object.");
9217 result = kOSKextReturnInternalError;
9218 goto finish;
9219 }
9220 // Store the mach port name as a OSNumber
9221 portNameNumber = OSNumber::withNumber(portName, CHAR_BIT * sizeof(portName));
9222 if (!portNameNumber) {
9223 OSKextLog(/* kext */ NULL,
9224 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9225 "Could not create OSNumber object.");
9226 result = kOSKextReturnNoMemory;
9227 goto finish;
9228 }
9229 if (!_OSKextSetRequestArgument(request, kKextRequestArgumentCheckInToken, portNameNumber.get())) {
9230 OSKextLog(/* kext */ NULL,
9231 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9232 "Could not set OSNumber object as request " kKextRequestArgumentCheckInToken);
9233 result = kOSKextReturnNoMemory;
9234 goto finish;
9235 }
9236 }
9237finish:
9238 if (result != kOSReturnSuccess) {
9239 break;
9240 }
9241 }
9242 return result;
9243}
9244
b0d623f7
A
9245/*********************************************************************
9246* XXX - this function is a big ugly mess
9247*********************************************************************/
9248/* static */
9249OSReturn
9250OSKext::handleRequest(
0a7de745
A
9251 host_priv_t hostPriv,
9252 OSKextLogSpec clientLogFilter,
9253 char * requestBuffer,
9254 uint32_t requestLength,
9255 char ** responseOut,
9256 uint32_t * responseLengthOut,
9257 char ** logInfoOut,
9258 uint32_t * logInfoLengthOut)
9259{
9260 OSReturn result = kOSReturnError;
9261 kern_return_t kmem_result = KERN_FAILURE;
b0d623f7 9262
f427ee49 9263 char * response = NULL; // returned by reference
0a7de745
A
9264 uint32_t responseLength = 0;
9265
f427ee49
A
9266 bool taskCanManageAllKCs = false;
9267 bool taskOnlyManagesBootKC = false;
0a7de745 9268
f427ee49
A
9269 OSSharedPtr<OSObject> parsedXML;
9270 OSDictionary * requestDict = NULL; // do not release
9271 OSSharedPtr<OSString> errorString;
0a7de745 9272
f427ee49 9273 OSSharedPtr<OSObject> responseObject;
0a7de745 9274
f427ee49 9275 OSSharedPtr<OSSerialize> serializer;
0a7de745 9276
f427ee49
A
9277 OSSharedPtr<OSArray> logInfoArray;
9278
9279 OSString * predicate = NULL; // do not release
9280 OSString * kextIdentifier = NULL; // do not release
9281 OSArray * kextIdentifiers = NULL; // do not release
9282 OSKext * theKext = NULL; // do not release
9283 OSBoolean * boolArg = NULL; // do not release
0a7de745
A
9284
9285 IORecursiveLockLock(sKextLock);
9286
9287 if (responseOut) {
9288 *responseOut = NULL;
9289 *responseLengthOut = 0;
9290 }
9291 if (logInfoOut) {
9292 *logInfoOut = NULL;
9293 *logInfoLengthOut = 0;
9294 }
9295
9296 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
9297
9298 /* XML must be nul-terminated.
9299 */
9300 if (requestBuffer[requestLength - 1] != '\0') {
9301 OSKextLog(/* kext */ NULL,
9302 kOSKextLogErrorLevel |
9303 kOSKextLogIPCFlag,
9304 "Invalid request from user space (not nul-terminated).");
9305 result = kOSKextReturnBadData;
9306 goto finish;
9307 }
f427ee49 9308 parsedXML = OSUnserializeXML((const char *)requestBuffer, errorString);
0a7de745 9309 if (parsedXML) {
f427ee49 9310 requestDict = OSDynamicCast(OSDictionary, parsedXML.get());
0a7de745
A
9311 }
9312 if (!requestDict) {
9313 const char * errorCString = "(unknown error)";
9314
9315 if (errorString && errorString->getCStringNoCopy()) {
9316 errorCString = errorString->getCStringNoCopy();
9317 } else if (parsedXML) {
9318 errorCString = "not a dictionary";
9319 }
9320 OSKextLog(/* kext */ NULL,
9321 kOSKextLogErrorLevel |
9322 kOSKextLogIPCFlag,
9323 "Error unserializing request from user space: %s.",
9324 errorCString);
9325 result = kOSKextReturnSerialization;
9326 goto finish;
9327 }
9328
9329 predicate = _OSKextGetRequestPredicate(requestDict);
9330 if (!predicate) {
9331 OSKextLog(/* kext */ NULL,
9332 kOSKextLogErrorLevel |
9333 kOSKextLogIPCFlag,
9334 "Recieved kext request from user space with no predicate.");
9335 result = kOSKextReturnInvalidArgument;
9336 goto finish;
9337 }
9338
9339 OSKextLog(/* kext */ NULL,
9340 kOSKextLogDebugLevel |
9341 kOSKextLogIPCFlag,
9342 "Received '%s' request from user space.",
9343 predicate->getCStringNoCopy());
9344
f427ee49
A
9345 /*
9346 * All management of file sets requires an entitlement
9347 */
0a7de745 9348 result = kOSKextReturnNotPrivileged;
f427ee49
A
9349 if (predicate->isEqualTo(kKextRequestPredicateUnload) ||
9350 predicate->isEqualTo(kKextRequestPredicateStart) ||
9351 predicate->isEqualTo(kKextRequestPredicateStop) ||
9352 predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
9353 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
9354 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
9355 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
9356 predicate->isEqualTo(kKextRequestPredicateLoadFromKC) ||
9357 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
9358 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
9359 predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
9360 if (hostPriv == HOST_PRIV_NULL) {
0a7de745
A
9361 OSKextLog(/* kext */ NULL,
9362 kOSKextLogErrorLevel |
9363 kOSKextLogIPCFlag,
9364 "Access Failure - must be root user.");
9365 goto finish;
9366 }
f427ee49
A
9367 taskCanManageAllKCs = IOTaskHasEntitlement(current_task(), kOSKextCollectionManagementEntitlement) == TRUE;
9368 taskOnlyManagesBootKC = IOTaskHasEntitlement(current_task(), kOSKextOnlyBootKCManagementEntitlement) == TRUE;
9369
9370 if (!taskCanManageAllKCs && !taskOnlyManagesBootKC) {
9371 OSKextLog(/* kext */ NULL,
9372 kOSKextLogErrorLevel |
9373 kOSKextLogIPCFlag,
9374 "Access Failure - client not entitled to manage file sets.");
9375 goto finish;
9376 }
9377
9378 /*
9379 * The OnlyBootKC entitlement restricts the
9380 * collection-management entitlement to only managing kexts in
9381 * the BootKC. All other predicates that alter global state or
9382 * add new KCs are disallowed.
9383 */
9384 if (taskOnlyManagesBootKC &&
9385 (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
9386 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
9387 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
9388 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
9389 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
9390 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
9391 predicate->isEqualTo(kKextRequestPredicateDaemonReady))) {
9392 OSKextLog(/* kext */ NULL,
9393 kOSKextLogErrorLevel |
9394 kOSKextLogIPCFlag,
9395 "Access Failure - client not entitled to manage non-primary KCs");
9396 goto finish;
9397 }
9398
9399 /*
9400 * If we get here, then the process either has the full KC
9401 * management entitlement, or it has the BootKC-only
9402 * entitlement and the request is about the BootKC.
9403 */
0a7de745
A
9404 }
9405
9406 /* Get common args in anticipation of use.
9407 */
9408 kextIdentifier = OSDynamicCast(OSString, _OSKextGetRequestArgument(
9409 requestDict, kKextRequestArgumentBundleIdentifierKey));
9410 kextIdentifiers = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
9411 requestDict, kKextRequestArgumentBundleIdentifierKey));
9412 if (kextIdentifier) {
9413 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
9414 }
9415 boolArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
9416 requestDict, kKextRequestArgumentValueKey));
9417
f427ee49
A
9418 if (taskOnlyManagesBootKC &&
9419 theKext &&
9420 theKext->isInFileset() &&
9421 theKext->kc_type != KCKindPrimary) {
9422 OSKextLog(/* kext */ NULL,
9423 kOSKextLogErrorLevel |
9424 kOSKextLogIPCFlag,
9425 "Access Failure - client not entitled to manage kext in non-primary KC");
9426 result = kOSKextReturnNotPrivileged;
9427 goto finish;
9428 }
9429
0a7de745
A
9430 result = kOSKextReturnInvalidArgument;
9431
9432 if (predicate->isEqualTo(kKextRequestPredicateStart)) {
9433 if (!kextIdentifier) {
9434 OSKextLog(/* kext */ NULL,
9435 kOSKextLogErrorLevel |
9436 kOSKextLogIPCFlag,
9437 "Invalid arguments to kext start request.");
9438 } else if (!theKext) {
9439 OSKextLog(/* kext */ NULL,
9440 kOSKextLogErrorLevel |
9441 kOSKextLogIPCFlag,
9442 "Kext %s not found for start request.",
9443 kextIdentifier->getCStringNoCopy());
9444 result = kOSKextReturnNotFound;
9445 } else {
9446 result = theKext->start();
9447 }
9448 } else if (predicate->isEqualTo(kKextRequestPredicateStop)) {
9449 if (!kextIdentifier) {
9450 OSKextLog(/* kext */ NULL,
9451 kOSKextLogErrorLevel |
9452 kOSKextLogIPCFlag,
9453 "Invalid arguments to kext stop request.");
9454 } else if (!theKext) {
9455 OSKextLog(/* kext */ NULL,
9456 kOSKextLogErrorLevel |
9457 kOSKextLogIPCFlag,
9458 "Kext %s not found for stop request.",
9459 kextIdentifier->getCStringNoCopy());
9460 result = kOSKextReturnNotFound;
9461 } else {
9462 result = theKext->stop();
9463 }
f427ee49
A
9464 } else if (predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles)) {
9465 result = OSKext::setMissingAuxKCBundles(requestDict);
9466 } else if (predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable)) {
9467 if (!kextIdentifier) {
9468 OSKextLog(/* kext */ NULL,
9469 kOSKextLogErrorLevel |
9470 kOSKextLogIPCFlag,
9471 "Invalid arguments to AuxKC Bundle Available request.");
9472 } else {
9473 result = OSKext::setAuxKCBundleAvailable(kextIdentifier, requestDict);
9474 }
9475 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFromKC)) {
9476 if (!kextIdentifier) {
9477 OSKextLog(/* kext */ NULL,
9478 kOSKextLogErrorLevel |
9479 kOSKextLogIPCFlag,
9480 "Invalid arguments to kext load from KC request.");
9481 } else if (!theKext) {
9482 OSKextLog(/* kext */ NULL,
9483 kOSKextLogErrorLevel |
9484 kOSKextLogIPCFlag,
9485 "Kext %s not found for load from KC request.",
9486 kextIdentifier->getCStringNoCopy());
9487 result = kOSKextReturnNotFound;
9488 } else if (!theKext->isInFileset()) {
9489 OSKextLog(/* kext */ NULL,
9490 kOSKextLogErrorLevel |
9491 kOSKextLogIPCFlag,
9492 "Kext %s does not exist in a KC: refusing to load.",
9493 kextIdentifier->getCStringNoCopy());
9494 result = kOSKextReturnNotLoadable;
9495 } else {
9496 result = OSKext::loadKextFromKC(theKext, requestDict);
9497 }
9498 } else if (predicate->isEqualTo(kKextRequestPredicateLoadCodeless)) {
9499 if (!kextIdentifier) {
9500 OSKextLog(/* kext */ NULL,
9501 kOSKextLogErrorLevel |
9502 kOSKextLogIPCFlag,
9503 "Invalid arguments to codeless kext load interface (missing identifier).");
9504 } else {
9505 result = OSKext::loadCodelessKext(kextIdentifier, requestDict);
9506 }
0a7de745
A
9507 } else if (predicate->isEqualTo(kKextRequestPredicateUnload)) {
9508 if (!kextIdentifier) {
9509 OSKextLog(/* kext */ NULL,
9510 kOSKextLogErrorLevel |
9511 kOSKextLogIPCFlag,
9512 "Invalid arguments to kext unload request.");
9513 } else if (!theKext) {
9514 OSKextLog(/* kext */ NULL,
9515 kOSKextLogErrorLevel |
9516 kOSKextLogIPCFlag,
9517 "Kext %s not found for unload request.",
9518 kextIdentifier->getCStringNoCopy());
9519 result = kOSKextReturnNotFound;
9520 } else {
9521 OSBoolean * terminateFlag = OSDynamicCast(OSBoolean,
9522 _OSKextGetRequestArgument(requestDict,
9523 kKextRequestArgumentTerminateIOServicesKey));
9524 result = OSKext::removeKext(theKext, terminateFlag == kOSBooleanTrue);
9525 }
9526 } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
9527 result = OSKext::dispatchResource(requestDict);
9528 } else if (predicate->isEqualTo(kKextRequestPredicateGetUUIDByAddress)) {
9529 OSNumber *lookupNum = NULL;
9530 lookupNum = OSDynamicCast(OSNumber,
9531 _OSKextGetRequestArgument(requestDict,
9532 kKextRequestArgumentLookupAddressKey));
9533
9534 responseObject = OSKext::copyKextUUIDForAddress(lookupNum);
9535 if (responseObject) {
9536 result = kOSReturnSuccess;
9537 } else {
9538 goto finish;
9539 }
9540 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded) ||
f427ee49
A
9541 predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID) ||
9542 predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
0a7de745
A
9543 OSBoolean * delayAutounloadBool = NULL;
9544 OSObject * infoKeysRaw = NULL;
9545 OSArray * infoKeys = NULL;
9546 uint32_t infoKeysCount = 0;
9547
9548 delayAutounloadBool = OSDynamicCast(OSBoolean,
9549 _OSKextGetRequestArgument(requestDict,
9550 kKextRequestArgumentDelayAutounloadKey));
9551
9552 /* If asked to delay autounload, reset the timer if it's currently set.
9553 * (That is, don't schedule an unload if one isn't already pending.
9554 */
9555 if (delayAutounloadBool == kOSBooleanTrue) {
9556 OSKext::considerUnloads(/* rescheduleOnly? */ true);
9557 }
9558
9559 infoKeysRaw = _OSKextGetRequestArgument(requestDict,
9560 kKextRequestArgumentInfoKeysKey);
9561 infoKeys = OSDynamicCast(OSArray, infoKeysRaw);
9562 if (infoKeysRaw && !infoKeys) {
9563 OSKextLog(/* kext */ NULL,
9564 kOSKextLogErrorLevel |
9565 kOSKextLogIPCFlag,
9566 "Invalid arguments to kext info request.");
9567 goto finish;
9568 }
9569
9570 if (infoKeys) {
9571 infoKeysCount = infoKeys->getCount();
9572 for (uint32_t i = 0; i < infoKeysCount; i++) {
9573 if (!OSDynamicCast(OSString, infoKeys->getObject(i))) {
9574 OSKextLog(/* kext */ NULL,
9575 kOSKextLogErrorLevel |
9576 kOSKextLogIPCFlag,
9577 "Invalid arguments to kext info request.");
9578 goto finish;
9579 }
9580 }
9581 }
9582
9583 if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
9584 responseObject = OSKext::copyLoadedKextInfo(kextIdentifiers, infoKeys);
9585 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
9586 responseObject = OSKext::copyLoadedKextInfoByUUID(kextIdentifiers, infoKeys);
f427ee49
A
9587 } else if (predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
9588 responseObject = OSKext::copyKextCollectionInfo(requestDict, infoKeys);
0a7de745 9589 }
f427ee49 9590
0a7de745
A
9591 if (!responseObject) {
9592 result = kOSKextReturnInternalError;
9593 } else {
9594 OSKextLog(/* kext */ NULL,
9595 kOSKextLogDebugLevel |
9596 kOSKextLogIPCFlag,
9597 "Returning loaded kext info.");
9598 result = kOSReturnSuccess;
9599 }
9600 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
9601 /* Hand the current sKernelRequests array to the caller
9602 * (who must release it), and make a new one.
9603 */
f427ee49 9604 responseObject = os::move(sKernelRequests);
0a7de745
A
9605 sKernelRequests = OSArray::withCapacity(0);
9606 sPostedKextLoadIdentifiers->flushCollection();
9607 OSKextLog(/* kext */ NULL,
9608 kOSKextLogDebugLevel |
9609 kOSKextLogIPCFlag,
9610 "Returning kernel requests.");
9611 result = kOSReturnSuccess;
9612 } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
9613 /* Return the set of all requested bundle identifiers */
9614 responseObject = sAllKextLoadIdentifiers;
0a7de745
A
9615 OSKextLog(/* kext */ NULL,
9616 kOSKextLogDebugLevel |
9617 kOSKextLogIPCFlag,
9618 "Returning load requests.");
9619 result = kOSReturnSuccess;
f427ee49
A
9620 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC)) {
9621 printf("KextLog: Loading FileSet KC(s)\n");
9622 result = OSKext::loadFileSetKexts(requestDict);
9623 } else if (predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
9624 printf("KextLog: " kIOKitDaemonName " is %s\n", sIOKitDaemonActive ? "active" : "not active");
9625 result = (sIOKitDaemonActive && !sOSKextWasResetAfterUserspaceReboot) ? kOSReturnSuccess : kIOReturnNotReady;
0a7de745
A
9626 } else {
9627 OSKextLog(/* kext */ NULL,
9628 kOSKextLogDebugLevel |
9629 kOSKextLogIPCFlag,
9630 "Received '%s' invalid request from user space.",
9631 predicate->getCStringNoCopy());
9632 goto finish;
9633 }
9634
9635 /**********
9636 * Now we have handle the request, or not. Gather up the response & logging
9637 * info to ship to user space.
9638 *********/
9639
9640 /* Note: Nothing in OSKext is supposed to retain requestDict,
9641 * but you never know....
9642 */
9643 if (requestDict->getRetainCount() > 1) {
9644 OSKextLog(/* kext */ NULL,
9645 kOSKextLogWarningLevel |
9646 kOSKextLogIPCFlag,
9647 "Request from user space still retained by a kext; "
9648 "probable memory leak.");
9649 }
9650
9651 if (responseOut && responseObject) {
9652 serializer = OSSerialize::withCapacity(0);
9653 if (!serializer) {
9654 result = kOSKextReturnNoMemory;
9655 goto finish;
9656 }
f427ee49
A
9657 /*
9658 * Before serializing the kernel requests, patch the dext launch requests so
9659 * that the value for kKextRequestArgumentCheckInToken is a mach port name for the
9660 * IOUserServerCheckInToken kernel object.
9661 */
9662 if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
9663 OSArray * requests = OSDynamicCast(OSArray, responseObject.get());
9664 task_t calling_task = current_task();
9665 if (!requests) {
9666 OSKextLog(/* kext */ NULL,
9667 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9668 "responseObject should be an OSArray if predicate is " kKextRequestPredicateGetKernelRequests);
9669 result = kOSKextReturnInternalError;
9670 goto finish;
9671 }
9672 result = patchDextLaunchRequests(calling_task, requests);
9673 if (result != kOSReturnSuccess) {
9674 OSKextLog(/* kext */ NULL,
9675 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9676 "Failed to patch dext launch requests.");
9677 goto finish;
9678 }
9679 }
0a7de745 9680
f427ee49 9681 if (!responseObject->serialize(serializer.get())) {
0a7de745
A
9682 OSKextLog(/* kext */ NULL,
9683 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9684 "Failed to serialize response to request from user space.");
9685 result = kOSKextReturnSerialization;
9686 goto finish;
9687 }
b0d623f7 9688
0a7de745
A
9689 response = (char *)serializer->text();
9690 responseLength = serializer->getLength();
9691 }
b0d623f7 9692
0a7de745
A
9693 if (responseOut && response) {
9694 char * buffer;
b0d623f7 9695
0a7de745
A
9696 /* This kmem_alloc sets the return value of the function.
9697 */
9698 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer,
9699 round_page(responseLength), VM_KERN_MEMORY_OSKEXT);
9700 if (kmem_result != KERN_SUCCESS) {
9701 OSKextLog(/* kext */ NULL,
9702 kOSKextLogErrorLevel |
9703 kOSKextLogIPCFlag,
9704 "Failed to copy response to request from user space.");
9705 result = kmem_result;
9706 goto finish;
9707 } else {
9708 /* 11981737 - clear uninitialized data in last page */
9709 bzero((void *)(buffer + responseLength),
9710 (round_page(responseLength) - responseLength));
9711 memcpy(buffer, response, responseLength);
9712 *responseOut = buffer;
9713 *responseLengthOut = responseLength;
9714 }
9715 }
b0d623f7 9716
0a7de745 9717finish:
b0d623f7 9718
0a7de745
A
9719 /* Gather up the collected log messages for user space. Any messages
9720 * messages past this call will not make it up as log messages but
9721 * will be in the system log. Note that we ignore the return of the
9722 * serialize; it has no bearing on the operation at hand even if we
9723 * fail to get the log messages.
9724 */
9725 logInfoArray = OSKext::clearUserSpaceLogFilter();
9726
9727 if (logInfoArray && logInfoOut && logInfoLengthOut) {
f427ee49 9728 (void)OSKext::serializeLogInfo(logInfoArray.get(),
0a7de745
A
9729 logInfoOut, logInfoLengthOut);
9730 }
9731
9732 IORecursiveLockUnlock(sKextLock);
9733
0a7de745 9734 return result;
b0d623f7
A
9735}
9736
f427ee49
A
9737#if PRAGMA_MARK
9738#pragma mark Linked Kext Collection Support
9739#endif
3e170ce0 9740
f427ee49
A
9741static int
9742__whereIsAddr(vm_offset_t theAddr, unsigned long *segSizes, vm_offset_t *segAddrs, int segCount)
9743{
9744 for (int i = 0; i < segCount; i++) {
9745 vm_offset_t segStart = segAddrs[i];
9746 vm_offset_t segEnd = segStart + (vm_offset_t)segSizes[i];
9747
9748 if (theAddr >= segStart && theAddr < segEnd) {
9749 return i;
9750 }
9751 }
9752 return -1;
3e170ce0
A
9753}
9754
f427ee49
A
9755static void
9756__slideOldKaslrOffsets(kernel_mach_header_t *mh,
9757 kernel_segment_command_t *kextTextSeg,
9758 OSData *kaslrOffsets)
9759{
9760 static const char *plk_segNames[] = {
9761 "__TEXT",
9762 "__TEXT_EXEC",
9763 "__DATA",
9764 "__DATA_CONST",
9765 "__LINKEDIT",
9766 "__PRELINK_TEXT",
9767 "__PLK_TEXT_EXEC",
9768 "__PRELINK_DATA",
9769 "__PLK_DATA_CONST",
9770 "__PLK_LLVM_COV",
9771 "__PLK_LINKEDIT",
9772 "__PRELINK_INFO"
9773 };
9774 static const size_t num_plk_seg = (size_t)(sizeof(plk_segNames) / sizeof(plk_segNames[0]));
9775
9776 unsigned long plk_segSizes[num_plk_seg];
9777 vm_offset_t plk_segAddrs[num_plk_seg];
9778
9779 for (size_t i = 0; i < num_plk_seg; i++) {
9780 plk_segSizes[i] = 0;
9781 plk_segAddrs[i] = (vm_offset_t)getsegdatafromheader(mh, plk_segNames[i], &plk_segSizes[i]);
9782 }
9783
9784 uint64_t kextTextStart = (uint64_t)kextTextSeg->vmaddr;
9785
9786 int slidKextAddrCount = 0;
9787 int badSlideAddr = 0;
9788 int badSlideTarget = 0;
9789
9790 struct kaslrPackedOffsets {
9791 uint32_t count; /* number of offsets */
9792 uint32_t offsetsArray[]; /* offsets to slide */
9793 };
9794 const struct kaslrPackedOffsets *myOffsets = NULL;
9795 myOffsets = (const struct kaslrPackedOffsets *)kaslrOffsets->getBytesNoCopy();
9796
9797 for (uint32_t j = 0; j < myOffsets->count; j++) {
9798 uint64_t slideOffset = (uint64_t)myOffsets->offsetsArray[j];
9799 vm_offset_t *slideAddr = (vm_offset_t *)((uint64_t)kextTextStart + slideOffset);
9800 int slideAddrSegIndex = -1;
9801 int addrToSlideSegIndex = -1;
9802
9803 slideAddrSegIndex = __whereIsAddr((vm_offset_t)slideAddr, &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
9804 if (slideAddrSegIndex >= 0) {
9805 addrToSlideSegIndex = __whereIsAddr(ml_static_slide(*slideAddr), &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
9806 if (addrToSlideSegIndex < 0) {
9807 badSlideTarget++;
9808 continue;
9809 }
9810 } else {
9811 badSlideAddr++;
9812 continue;
9813 }
3e170ce0 9814
f427ee49
A
9815 slidKextAddrCount++;
9816 *slideAddr = ml_static_slide(*slideAddr);
9817 } // for ...
9818}
9819
9820
9821
9822/********************************************************************
9823* addKextsFromKextCollection
9824*
9825* Input: MachO header of kext collection. The MachO is assumed to
9826* have a section named 'info_seg_name,info_sect_name' that
9827* contains a serialized XML info dictionary. This dictionary
9828* contains a UUID, possibly a set of relocations (for older
9829* kxld-built binaries), and an array of kext personalities.
9830*
9831********************************************************************/
9832bool
9833OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
9834 OSDictionary *infoDict, const char *text_seg_name,
9835 OSData **kcUUID, kc_kind_t type)
9836{
9837 bool result = false;
9838
9839 OSArray *kextArray = NULL; // do not release
9840 OSData *infoDictKCUUID = NULL; // do not release
9841 OSData *kaslrOffsets = NULL; // do not release
9842
9843 IORegistryEntry *registryRoot = NULL; // do not release
9844 OSSharedPtr<OSNumber> kcKextCount;
9845
9846 /* extract the KC UUID from the dictionary */
9847 infoDictKCUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
9848 if (infoDictKCUUID) {
9849 if (infoDictKCUUID->getLength() != sizeof(uuid_t)) {
9850 panic("kcUUID length is %d, expected %lu",
9851 infoDictKCUUID->getLength(), sizeof(uuid_t));
9852 }
9853 }
9854
9855 /* locate the array of kext dictionaries */
9856 kextArray = OSDynamicCast(OSArray, infoDict->getObject(kPrelinkInfoDictionaryKey));
9857 if (!kextArray) {
9858 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9859 "The given KC has no kext info dictionaries");
9860 goto finish;
9861 }
9862
9863 /*
9864 * old-style KASLR offsets may be present in the info dictionary. If
9865 * we find them, use them and eventually slide them.
9866 */
9867 kaslrOffsets = OSDynamicCast(OSData, infoDict->getObject(kPrelinkLinkKASLROffsetsKey));
9868
9869 /*
9870 * Before processing any kexts, locate the special kext bundle which
9871 * contains a list of kexts that we are to prevent from loading.
9872 */
9873 createExcludeListFromPrelinkInfo(kextArray);
9874
9875 /*
9876 * Create OSKext objects for each kext we find in the array of kext
9877 * info plist dictionaries.
9878 */
9879 for (int i = 0; i < (int)kextArray->getCount(); ++i) {
9880 OSDictionary *kextDict = NULL;
9881 kextDict = OSDynamicCast(OSDictionary, kextArray->getObject(i));
9882 if (!kextDict) {
9883 OSKextLog(/* kext */ NULL,
9884 kOSKextLogErrorLevel |
9885 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
9886 "Kext info dictionary for kext #%d isn't a dictionary?", i);
9887 continue;
9888 }
9889
9890 /*
9891 * Create the kext for the entry, then release it, because the
9892 * kext system keeps a reference around until the kext is
9893 * explicitly removed. Any creation/registration failures are
9894 * already logged for us.
9895 */
9896 withPrelinkedInfoDict(kextDict, (kaslrOffsets ? TRUE : FALSE), type);
9897 }
9898
9899 /*
9900 * slide old-style kxld relocations
9901 * NOTE: this is still used on embedded KCs built with kcgen
9902 * TODO: Remove this once we use the new kext linker everywhere!
9903 */
9904 if (kaslrOffsets && vm_kernel_slide > 0) {
9905 kernel_segment_command_t *text_segment = NULL;
9906 text_segment = getsegbynamefromheader(mh, text_seg_name);
9907 if (!text_segment) {
9908 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9909 "Can't find a TEXT segment named '%s' in macho header", text_seg_name);
9910 goto finish;
9911 }
9912
9913 __slideOldKaslrOffsets(mh, text_segment, kaslrOffsets);
9914 /* All kexts covered by the old-style kaslr relocation list are now slid, set VM protections for them */
9915 setAllVMAttributes();
9916 }
9917
9918 /* Store the number of prelinked kexts in the registry so we can tell
9919 * when the system has been started from a prelinked kernel.
9920 */
9921 registryRoot = IORegistryEntry::getRegistryRoot();
9922 assert(registryRoot);
9923
9924 kcKextCount = OSNumber::withNumber((unsigned long long)infoDict->getCount(), 8 * sizeof(uint32_t));
9925 assert(kcKextCount);
9926 if (kcKextCount) {
9927 OSSharedPtr<OSObject> prop = registryRoot->copyProperty(kOSPrelinkKextCountKey);
9928 OSNumber *num;
9929 num = OSDynamicCast(OSNumber, prop.get());
9930 if (num) {
9931 kcKextCount->addValue(num->unsigned64BitValue());
9932 }
9933 registryRoot->setProperty(kOSPrelinkKextCountKey, kcKextCount.get());
9934 }
9935
9936 OSKextLog(/* kext */ NULL,
9937 kOSKextLogProgressLevel |
9938 kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
9939 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
9940 "%u prelinked kexts", infoDict->getCount());
9941
9942
9943 if (kcUUID && infoDictKCUUID) {
9944 *kcUUID = OSData::withData(infoDictKCUUID).detach();
9945 }
9946
9947 result = true;
9948
9949finish:
9950 return result;
9951}
9952
9953bool
9954OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
9955 OSDictionary *infoDict, const char *text_seg_name,
9956 OSSharedPtr<OSData> &kcUUID, kc_kind_t type)
9957{
9958 OSData *result = NULL;
9959 bool success = addKextsFromKextCollection(mh,
9960 infoDict,
9961 text_seg_name,
9962 &result,
9963 type);
9964 if (success) {
9965 kcUUID.reset(result, OSNoRetain);
9966 }
9967 return success;
9968}
9969
9970static OSSharedPtr<OSObject> deferredAuxKCXML;
9971bool
9972OSKext::registerDeferredKextCollection(kernel_mach_header_t *mh,
9973 OSSharedPtr<OSObject> &parsedXML, kc_kind_t type)
9974{
9975 if (type != KCKindAuxiliary) {
9976 return false;
9977 }
9978
9979 kernel_mach_header_t *_mh;
9980 _mh = (kernel_mach_header_t*)PE_get_kc_header(type);
9981 if (!_mh || _mh != mh) {
9982 return false;
9983 }
9984
9985 if (deferredAuxKCXML) {
9986 /* only allow this to be called once */
9987 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9988 "An Aux KC has already been registered for deferred processing.");
9989 return false;
9990 }
9991
9992 OSDictionary *infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
9993 if (!infoDict) {
9994 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9995 "The Aux KC has info dictionary");
9996 return false;
9997 }
9998
9999 OSData *kcUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
10000 if (!kcUUID || kcUUID->getLength() != sizeof(uuid_t)) {
10001 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10002 "The Aux KC has no UUID in %s", kPrelinkInfoKCIDKey);
10003 return false;
10004 }
10005
10006 /*
10007 * Copy the AuxKC UUID to make sure that the kern.auxiliaryfilesetuuid
10008 * sysctl can return the UUID to user space which will check this
10009 * value for errors.
10010 */
10011 memcpy((void *)&auxkc_uuid, (const void *)kcUUID->getBytesNoCopy(),
10012 kcUUID->getLength());
10013 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
10014 auxkc_uuid_valid = TRUE;
10015
10016 deferredAuxKCXML = parsedXML;
10017
10018 return true;
10019}
10020
10021OSSharedPtr<OSObject>
10022OSKext::consumeDeferredKextCollection(kc_kind_t type)
10023{
10024 if (type != KCKindAuxiliary || !deferredAuxKCXML) {
10025 return NULL;
10026 }
10027
10028 return os::move(deferredAuxKCXML);
10029}
10030
10031#if PRAGMA_MARK
10032#pragma mark Profile-Guided-Optimization Support
10033#endif
10034
10035// #include <InstrProfiling.h>
10036extern "C" {
10037uint64_t __llvm_profile_get_size_for_buffer_internal(const char *DataBegin,
10038 const char *DataEnd,
10039 const char *CountersBegin,
10040 const char *CountersEnd,
10041 const char *NamesBegin,
10042 const char *NamesEnd);
10043int __llvm_profile_write_buffer_internal(char *Buffer,
10044 const char *DataBegin,
10045 const char *DataEnd,
10046 const char *CountersBegin,
10047 const char *CountersEnd,
10048 const char *NamesBegin,
10049 const char *NamesEnd);
10050}
10051
10052
10053static
10054void
10055OSKextPgoMetadataPut(char *pBuffer,
10056 size_t *position,
10057 size_t bufferSize,
10058 uint32_t *num_pairs,
10059 const char *key,
0a7de745
A
10060 const char *value)
10061{
10062 size_t strlen_key = strlen(key);
10063 size_t strlen_value = strlen(value);
10064 size_t len = strlen(key) + 1 + strlen(value) + 1;
10065 char *pos = pBuffer + *position;
10066 *position += len;
10067 if (pBuffer && bufferSize && *position <= bufferSize) {
10068 memcpy(pos, key, strlen_key); pos += strlen_key;
10069 *(pos++) = '=';
10070 memcpy(pos, value, strlen_value); pos += strlen_value;
10071 *(pos++) = 0;
10072 if (num_pairs) {
10073 (*num_pairs)++;
10074 }
10075 }
3e170ce0
A
10076}
10077
10078
10079static
0a7de745
A
10080void
10081OSKextPgoMetadataPutMax(size_t *position, const char *key, size_t value_max)
3e170ce0 10082{
0a7de745 10083 *position += strlen(key) + 1 + value_max + 1;
3e170ce0
A
10084}
10085
10086
10087static
0a7de745
A
10088void
10089OSKextPgoMetadataPutAll(OSKext *kext,
10090 uuid_t instance_uuid,
10091 char *pBuffer,
10092 size_t *position,
10093 size_t bufferSize,
10094 uint32_t *num_pairs)
10095{
10096 _static_assert_1_arg(sizeof(clock_sec_t) % 2 == 0);
10097 //log_10 2^16 ≈ 4.82
10098 const size_t max_secs_string_size = 5 * sizeof(clock_sec_t) / 2;
10099 const size_t max_timestamp_string_size = max_secs_string_size + 1 + 6;
10100
10101 if (!pBuffer) {
10102 OSKextPgoMetadataPutMax(position, "INSTANCE", 36);
10103 OSKextPgoMetadataPutMax(position, "UUID", 36);
10104 OSKextPgoMetadataPutMax(position, "TIMESTAMP", max_timestamp_string_size);
10105 } else {
10106 uuid_string_t instance_uuid_string;
10107 uuid_unparse(instance_uuid, instance_uuid_string);
10108 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10109 "INSTANCE", instance_uuid_string);
10110
f427ee49 10111 OSSharedPtr<OSData> uuid_data;
0a7de745
A
10112 uuid_t uuid;
10113 uuid_string_t uuid_string;
10114 uuid_data = kext->copyUUID();
10115 if (uuid_data) {
10116 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
0a7de745
A
10117 uuid_unparse(uuid, uuid_string);
10118 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10119 "UUID", uuid_string);
10120 }
3e170ce0 10121
0a7de745
A
10122 clock_sec_t secs;
10123 clock_usec_t usecs;
10124 clock_get_calendar_microtime(&secs, &usecs);
10125 assert(usecs < 1000000);
10126 char timestamp[max_timestamp_string_size + 1];
10127 _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t));
10128 snprintf(timestamp, sizeof(timestamp), "%lu.%06d", (unsigned long)secs, (int)usecs);
10129 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10130 "TIMESTAMP", timestamp);
10131 }
10132
10133 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10134 "NAME", kext->getIdentifierCString());
10135
10136 char versionCString[kOSKextVersionMaxLength];
10137 OSKextVersionGetString(kext->getVersion(), versionCString, kOSKextVersionMaxLength);
10138 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10139 "VERSION", versionCString);
3e170ce0
A
10140}
10141
10142static
0a7de745
A
10143size_t
10144OSKextPgoMetadataSize(OSKext *kext)
10145{
10146 size_t position = 0;
10147 uuid_t fakeuuid = {};
10148 OSKextPgoMetadataPutAll(kext, fakeuuid, NULL, &position, 0, NULL);
10149 return position;
10150}
10151
10152int
10153OSKextGrabPgoDataLocked(OSKext *kext,
10154 bool metadata,
10155 uuid_t instance_uuid,
10156 uint64_t *pSize,
10157 char *pBuffer,
10158 uint64_t bufferSize)
10159{
10160 int err = 0;
10161
10162 kernel_section_t *sect_prf_data = NULL;
10163 kernel_section_t *sect_prf_name = NULL;
10164 kernel_section_t *sect_prf_cnts = NULL;
10165 uint64_t size;
10166 size_t metadata_size = 0;
f427ee49 10167 size_t offset_to_pairs = 0;
0a7de745
A
10168
10169 sect_prf_data = kext->lookupSection("__DATA", "__llvm_prf_data");
cb323159
A
10170 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_names");
10171 if (!sect_prf_name) {
10172 // kextcache sometimes truncates the section name to 15 chars
10173 // <rdar://problem/52080551> 16 character section name is truncated to 15 characters by kextcache
10174 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_name");
10175 }
0a7de745
A
10176 sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
10177
10178 if (!sect_prf_data || !sect_prf_name || !sect_prf_cnts) {
10179 err = ENOTSUP;
10180 goto out;
10181 }
10182
10183 size = __llvm_profile_get_size_for_buffer_internal(
10184 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
10185 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
10186 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
10187
10188 if (metadata) {
10189 metadata_size = OSKextPgoMetadataSize(kext);
10190 size += metadata_size;
10191 size += sizeof(pgo_metadata_footer);
10192 }
10193
10194
10195 if (pSize) {
10196 *pSize = size;
10197 }
10198
10199 if (pBuffer && bufferSize) {
10200 if (bufferSize < size) {
10201 err = ERANGE;
10202 goto out;
10203 }
10204
10205 err = __llvm_profile_write_buffer_internal(
10206 pBuffer,
10207 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
10208 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
10209 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
10210
10211 if (err) {
10212 err = EIO;
10213 goto out;
10214 }
10215
10216 if (metadata) {
f427ee49
A
10217 offset_to_pairs = sizeof(struct pgo_metadata_footer) + metadata_size;
10218 if (offset_to_pairs > UINT32_MAX) {
10219 err = E2BIG;
10220 goto out;
10221 }
10222
0a7de745
A
10223 char *end_of_buffer = pBuffer + size;
10224 struct pgo_metadata_footer *footerp = (struct pgo_metadata_footer *) (end_of_buffer - sizeof(struct pgo_metadata_footer));
10225 char *metadata_buffer = end_of_buffer - (sizeof(struct pgo_metadata_footer) + metadata_size);
10226
10227 size_t metadata_position = 0;
10228 uint32_t num_pairs = 0;
10229 OSKextPgoMetadataPutAll(kext, instance_uuid, metadata_buffer, &metadata_position, metadata_size, &num_pairs);
10230 while (metadata_position < metadata_size) {
10231 metadata_buffer[metadata_position++] = 0;
10232 }
10233
10234 struct pgo_metadata_footer footer;
10235 footer.magic = htonl(0x6d657461);
10236 footer.number_of_pairs = htonl( num_pairs );
f427ee49 10237 footer.offset_to_pairs = htonl((uint32_t)offset_to_pairs );
0a7de745
A
10238 memcpy(footerp, &footer, sizeof(footer));
10239 }
10240 }
3e170ce0
A
10241
10242out:
0a7de745 10243 return err;
3e170ce0
A
10244}
10245
10246
10247int
10248OSKextGrabPgoData(uuid_t uuid,
0a7de745
A
10249 uint64_t *pSize,
10250 char *pBuffer,
10251 uint64_t bufferSize,
10252 int wait_for_unload,
10253 int metadata)
3e170ce0 10254{
0a7de745 10255 int err = 0;
f427ee49 10256 OSSharedPtr<OSKext> kext;
3e170ce0 10257
3e170ce0 10258
0a7de745 10259 IORecursiveLockLock(sKextLock);
3e170ce0 10260
0a7de745
A
10261 kext = OSKext::lookupKextWithUUID(uuid);
10262 if (!kext) {
10263 err = ENOENT;
10264 goto out;
10265 }
3e170ce0 10266
0a7de745
A
10267 if (wait_for_unload) {
10268 OSKextGrabPgoStruct s;
3e170ce0 10269
0a7de745
A
10270 s.metadata = metadata;
10271 s.pSize = pSize;
10272 s.pBuffer = pBuffer;
10273 s.bufferSize = bufferSize;
10274 s.err = EINTR;
3e170ce0 10275
0a7de745
A
10276 struct list_head *prev = &kext->pendingPgoHead;
10277 struct list_head *next = kext->pendingPgoHead.next;
3e170ce0 10278
0a7de745
A
10279 s.list_head.prev = prev;
10280 s.list_head.next = next;
3e170ce0 10281
0a7de745
A
10282 prev->next = &s.list_head;
10283 next->prev = &s.list_head;
3e170ce0 10284
f427ee49 10285 kext.reset();
3e170ce0 10286
0a7de745 10287 IORecursiveLockSleep(sKextLock, &s, THREAD_ABORTSAFE);
3e170ce0 10288
0a7de745
A
10289 prev = s.list_head.prev;
10290 next = s.list_head.next;
3e170ce0 10291
0a7de745
A
10292 prev->next = next;
10293 next->prev = prev;
3e170ce0 10294
0a7de745
A
10295 err = s.err;
10296 } else {
f427ee49 10297 err = OSKextGrabPgoDataLocked(kext.get(), metadata, kext->instance_uuid, pSize, pBuffer, bufferSize);
0a7de745 10298 }
3e170ce0 10299
0a7de745 10300out:
3e170ce0 10301
0a7de745 10302 IORecursiveLockUnlock(sKextLock);
3e170ce0 10303
0a7de745 10304 return err;
3e170ce0
A
10305}
10306
39037602
A
10307void
10308OSKextResetPgoCountersLock()
10309{
0a7de745 10310 IORecursiveLockLock(sKextLock);
39037602
A
10311}
10312
10313void
10314OSKextResetPgoCountersUnlock()
10315{
0a7de745 10316 IORecursiveLockUnlock(sKextLock);
39037602
A
10317}
10318
10319
10320extern unsigned int not_in_kdp;
10321
0a7de745
A
10322void
10323OSKextResetPgoCounters()
10324{
10325 assert(!not_in_kdp);
10326 uint32_t count = sLoadedKexts->getCount();
10327 for (uint32_t i = 0; i < count; i++) {
10328 OSKext *kext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
10329 kernel_section_t *sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
10330 if (!sect_prf_cnts) {
10331 continue;
10332 }
10333 memset((void*)sect_prf_cnts->addr, 0, sect_prf_cnts->size);
10334 }
10335}
10336
f427ee49 10337OSSharedPtr<OSDictionary>
0a7de745
A
10338OSKext::copyLoadedKextInfoByUUID(
10339 OSArray * kextIdentifiers,
10340 OSArray * infoKeys)
10341{
f427ee49
A
10342 OSSharedPtr<OSDictionary> result;
10343 OSSharedPtr<OSDictionary> kextInfo;
cb323159 10344 uint32_t max_count, i, j;
0a7de745
A
10345 uint32_t idCount = 0;
10346 uint32_t idIndex = 0;
0a7de745 10347 IORecursiveLockLock(sKextLock);
f427ee49 10348 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
cb323159 10349 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
0a7de745
A
10350
10351#if CONFIG_MACF
10352 /* Is the calling process allowed to query kext info? */
10353 if (current_task() != kernel_task) {
10354 int macCheckResult = 0;
10355 kauth_cred_t cred = NULL;
10356
10357 cred = kauth_cred_get_with_ref();
10358 macCheckResult = mac_kext_check_query(cred);
10359 kauth_cred_unref(&cred);
10360
10361 if (macCheckResult != 0) {
10362 OSKextLog(/* kext */ NULL,
10363 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10364 "Failed to query kext info (MAC policy error 0x%x).",
10365 macCheckResult);
10366 goto finish;
10367 }
10368 }
10369#endif
10370
10371 /* Empty list of UUIDs is equivalent to no list (get all).
10372 */
10373 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10374 kextIdentifiers = NULL;
10375 } else if (kextIdentifiers) {
10376 idCount = kextIdentifiers->getCount();
10377 }
10378
10379 /* Same for keys.
10380 */
10381 if (infoKeys && !infoKeys->getCount()) {
10382 infoKeys = NULL;
10383 }
10384
cb323159
A
10385 max_count = count[0] + count[1];
10386 result = OSDictionary::withCapacity(max_count);
0a7de745
A
10387 if (!result) {
10388 goto finish;
10389 }
10390
cb323159
A
10391 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
10392 for (i = 0; i < count[j]; i++) {
f427ee49 10393 OSKext *thisKext = NULL; // do not release
cb323159
A
10394 Boolean includeThis = true;
10395 uuid_t thisKextUUID;
10396 uuid_t thisKextTextUUID;
f427ee49 10397 OSSharedPtr<OSData> uuid_data;
cb323159 10398 uuid_string_t uuid_key;
0a7de745 10399
cb323159
A
10400 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
10401 if (!thisKext) {
10402 continue;
10403 }
0a7de745 10404
cb323159
A
10405 uuid_data = thisKext->copyUUID();
10406 if (!uuid_data) {
10407 continue;
10408 }
0a7de745 10409
cb323159 10410 memcpy(&thisKextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextUUID));
0a7de745 10411
cb323159 10412 uuid_unparse(thisKextUUID, uuid_key);
0a7de745 10413
cb323159
A
10414 uuid_data = thisKext->copyTextUUID();
10415 if (!uuid_data) {
10416 continue;
10417 }
10418 memcpy(&thisKextTextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextTextUUID));
0a7de745 10419
cb323159
A
10420 /* Skip current kext if we have a list of UUIDs and
10421 * it isn't in the list.
10422 */
10423 if (kextIdentifiers) {
10424 includeThis = false;
10425
10426 for (idIndex = 0; idIndex < idCount; idIndex++) {
10427 const OSString* wantedUUID = OSDynamicCast(OSString,
10428 kextIdentifiers->getObject(idIndex));
10429
10430 uuid_t uuid;
10431 uuid_parse(wantedUUID->getCStringNoCopy(), uuid);
10432
10433 if ((0 == uuid_compare(uuid, thisKextUUID))
10434 || (0 == uuid_compare(uuid, thisKextTextUUID))) {
10435 includeThis = true;
10436 /* Only need to find the first kext if multiple match,
10437 * ie. asking for the kernel uuid does not need to find
10438 * interface kexts or builtin static kexts.
10439 */
10440 kextIdentifiers->removeObject(idIndex);
10441 uuid_unparse(uuid, uuid_key);
10442 break;
10443 }
0a7de745
A
10444 }
10445 }
0a7de745 10446
cb323159
A
10447 if (!includeThis) {
10448 continue;
10449 }
0a7de745 10450
cb323159
A
10451 kextInfo = thisKext->copyInfo(infoKeys);
10452 if (kextInfo) {
f427ee49 10453 result->setObject(uuid_key, kextInfo.get());
cb323159 10454 }
0a7de745 10455
cb323159
A
10456 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10457 goto finish;
10458 }
0a7de745
A
10459 }
10460 }
10461
10462finish:
10463 IORecursiveLockUnlock(sKextLock);
10464
10465 return result;
10466}
10467
10468/*********************************************************************
10469*********************************************************************/
10470/* static */
f427ee49
A
10471OSSharedPtr<OSDictionary>
10472OSKext::copyKextCollectionInfo(
10473 OSDictionary *requestDict,
10474 OSArray *infoKeys)
10475{
10476 OSSharedPtr<OSDictionary> result;
10477 OSString *collectionType = NULL;
10478 OSObject *rawLoadedState = NULL;
10479 OSString *loadedState = NULL;
10480
10481 kc_kind_t kc_request_kind = KCKindUnknown;
10482 bool onlyLoaded = false;
10483 bool onlyUnloaded = false;
10484
10485#if CONFIG_MACF
10486 /* Is the calling process allowed to query kext info? */
10487 if (current_task() != kernel_task) {
10488 int macCheckResult = 0;
10489 kauth_cred_t cred = NULL;
10490
10491 cred = kauth_cred_get_with_ref();
10492 macCheckResult = mac_kext_check_query(cred);
10493 kauth_cred_unref(&cred);
10494
10495 if (macCheckResult != 0) {
10496 OSKextLog(/* kext */ NULL,
10497 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10498 "Failed to query kext info (MAC policy error 0x%x).",
10499 macCheckResult);
10500 goto finish;
10501 }
10502 }
10503#endif
10504
10505 if (infoKeys && !infoKeys->getCount()) {
10506 infoKeys = NULL;
10507 }
10508
10509 collectionType = OSDynamicCast(OSString,
10510 _OSKextGetRequestArgument(requestDict,
10511 kKextRequestArgumentCollectionTypeKey));
10512 if (!collectionType) {
10513 OSKextLog(/* kext */ NULL,
10514 kOSKextLogErrorLevel |
10515 kOSKextLogIPCFlag,
10516 "Invalid '%s' argument to kext collection info request.",
10517 kKextRequestArgumentCollectionTypeKey);
10518 goto finish;
10519 }
10520 if (collectionType->isEqualTo(kKCTypePrimary)) {
10521 kc_request_kind = KCKindPrimary;
10522 } else if (collectionType->isEqualTo(kKCTypeSystem)) {
10523 kc_request_kind = KCKindPageable;
10524 } else if (collectionType->isEqualTo(kKCTypeAuxiliary)) {
10525 kc_request_kind = KCKindAuxiliary;
10526 } else if (collectionType->isEqualTo(kKCTypeCodeless)) {
10527 kc_request_kind = KCKindNone;
10528 } else if (!collectionType->isEqualTo(kKCTypeAny)) {
10529 OSKextLog(/* kext */ NULL,
10530 kOSKextLogErrorLevel |
10531 kOSKextLogIPCFlag,
10532 "Invalid '%s' argument value '%s' to kext collection info request.",
10533 kKextRequestArgumentCollectionTypeKey,
10534 collectionType->getCStringNoCopy());
10535 goto finish;
10536 }
10537
10538 rawLoadedState = _OSKextGetRequestArgument(requestDict,
10539 kKextRequestArgumentLoadedStateKey);
10540 if (rawLoadedState) {
10541 loadedState = OSDynamicCast(OSString, rawLoadedState);
10542 if (!loadedState) {
10543 OSKextLog(/* kext */ NULL,
10544 kOSKextLogErrorLevel |
10545 kOSKextLogIPCFlag,
10546 "Invalid '%s' argument to kext collection info request.",
10547 kKextRequestArgumentLoadedStateKey);
10548 goto finish;
10549 }
10550 }
10551 if (loadedState) {
10552 if (loadedState->isEqualTo("Loaded")) {
10553 onlyLoaded = true;
10554 } else if (loadedState->isEqualTo("Unloaded")) {
10555 onlyUnloaded = true;
10556 } else if (!loadedState->isEqualTo("Any")) {
10557 OSKextLog(/* kext */ NULL,
10558 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10559 "Invalid '%s' argument value '%s' for '%s' collection info",
10560 kKextRequestArgumentLoadedStateKey,
10561 loadedState->getCStringNoCopy(),
10562 collectionType->getCStringNoCopy());
10563 goto finish;
10564 }
10565 }
10566
10567 result = OSDictionary::withCapacity(sKextsByID->getCount());
10568 if (!result) {
10569 goto finish;
10570 }
10571
10572 IORecursiveLockLock(sKextLock);
10573 { // start block scope
10574 sKextsByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
10575 {
10576 OSKext *thisKext = NULL; // do not release
10577 OSSharedPtr<OSDictionary> kextInfo;
10578
10579 (void)thisKextID;
10580
10581 thisKext = OSDynamicCast(OSKext, obj);
10582 if (!thisKext) {
10583 return false;;
10584 }
10585
10586 /*
10587 * skip the kext if it came from the wrong collection type
10588 * (and the caller requested a specific type)
10589 */
10590 if ((kc_request_kind != KCKindUnknown) && (thisKext->kc_type != kc_request_kind)) {
10591 return false;
10592 }
10593
10594 /*
10595 * respect the caller's desire to find only loaded or
10596 * unloaded kexts
10597 */
10598 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10599 return false;
10600 }
10601 if (onlyUnloaded && (-1U != sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10602 return false;
10603 }
10604
10605 kextInfo = thisKext->copyInfo(infoKeys);
10606 if (kextInfo) {
10607 result->setObject(thisKext->getIdentifier(), kextInfo.get());
10608 }
10609 return false;
10610 });
10611 } // end block scope
10612 IORecursiveLockUnlock(sKextLock);
10613
10614finish:
10615 return result;
10616}
10617
10618/*********************************************************************
10619*********************************************************************/
10620/* static */
10621OSSharedPtr<OSDictionary>
0a7de745
A
10622OSKext::copyLoadedKextInfo(
10623 OSArray * kextIdentifiers,
10624 OSArray * infoKeys)
10625{
f427ee49 10626 OSSharedPtr<OSDictionary> result;
0a7de745
A
10627 uint32_t idCount = 0;
10628 bool onlyLoaded;
10629
10630 IORecursiveLockLock(sKextLock);
10631
10632#if CONFIG_MACF
10633 /* Is the calling process allowed to query kext info? */
10634 if (current_task() != kernel_task) {
10635 int macCheckResult = 0;
10636 kauth_cred_t cred = NULL;
10637
10638 cred = kauth_cred_get_with_ref();
10639 macCheckResult = mac_kext_check_query(cred);
10640 kauth_cred_unref(&cred);
10641
10642 if (macCheckResult != 0) {
10643 OSKextLog(/* kext */ NULL,
10644 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10645 "Failed to query kext info (MAC policy error 0x%x).",
10646 macCheckResult);
10647 goto finish;
10648 }
10649 }
10650#endif
10651
10652 /* Empty list of bundle ids is equivalent to no list (get all).
10653 */
10654 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10655 kextIdentifiers = NULL;
10656 } else if (kextIdentifiers) {
10657 idCount = kextIdentifiers->getCount();
10658 }
10659
10660 /* Same for keys.
10661 */
10662 if (infoKeys && !infoKeys->getCount()) {
10663 infoKeys = NULL;
10664 }
10665
10666 onlyLoaded = (!infoKeys || !_OSArrayContainsCString(infoKeys, kOSBundleAllPrelinkedKey));
10667
10668 result = OSDictionary::withCapacity(128);
10669 if (!result) {
10670 goto finish;
10671 }
10672
10673#if 0
10674 OSKextLog(/* kext */ NULL,
10675 kOSKextLogErrorLevel |
10676 kOSKextLogGeneralFlag,
10677 "kaslr: vm_kernel_slide 0x%lx \n",
10678 vm_kernel_slide);
10679 OSKextLog(/* kext */ NULL,
10680 kOSKextLogErrorLevel |
10681 kOSKextLogGeneralFlag,
10682 "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
10683 vm_kernel_stext, vm_kernel_etext);
10684 OSKextLog(/* kext */ NULL,
10685 kOSKextLogErrorLevel |
10686 kOSKextLogGeneralFlag,
10687 "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
10688 vm_kernel_base, vm_kernel_top);
10689 OSKextLog(/* kext */ NULL,
10690 kOSKextLogErrorLevel |
10691 kOSKextLogGeneralFlag,
10692 "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
10693 vm_kext_base, vm_kext_top);
10694 OSKextLog(/* kext */ NULL,
10695 kOSKextLogErrorLevel |
10696 kOSKextLogGeneralFlag,
10697 "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
10698 vm_prelink_stext, vm_prelink_etext);
10699 OSKextLog(/* kext */ NULL,
10700 kOSKextLogErrorLevel |
10701 kOSKextLogGeneralFlag,
10702 "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
10703 vm_prelink_sinfo, vm_prelink_einfo);
10704 OSKextLog(/* kext */ NULL,
10705 kOSKextLogErrorLevel |
10706 kOSKextLogGeneralFlag,
10707 "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
10708 vm_slinkedit, vm_elinkedit);
10709#endif
f427ee49
A
10710 { // start block scope
10711 sKextsByID->iterateObjects(^bool (const OSSymbol * thisKextID, OSObject * obj)
10712 {
10713 OSKext * thisKext = NULL; // do not release
10714 Boolean includeThis = true;
10715 OSSharedPtr<OSDictionary> kextInfo;
0a7de745 10716
f427ee49
A
10717 thisKext = OSDynamicCast(OSKext, obj);
10718 if (!thisKext) {
10719 return false;;
10720 }
0a7de745 10721
f427ee49
A
10722 /* Skip current kext if not yet started and caller didn't request all.
10723 */
10724 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10725 return false;;
10726 }
0a7de745 10727
f427ee49
A
10728 /* Skip current kext if we have a list of bundle IDs and
10729 * it isn't in the list.
10730 */
10731 if (kextIdentifiers) {
10732 includeThis = false;
10733
10734 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
10735 const OSString * thisRequestID = OSDynamicCast(OSString,
10736 kextIdentifiers->getObject(idIndex));
10737 if (thisKextID->isEqualTo(thisRequestID)) {
10738 includeThis = true;
10739 break;
10740 }
0a7de745
A
10741 }
10742 }
0a7de745 10743
f427ee49
A
10744 if (!includeThis) {
10745 return false;
10746 }
0a7de745 10747
f427ee49
A
10748 kextInfo = thisKext->copyInfo(infoKeys);
10749 if (kextInfo) {
10750 result->setObject(thisKext->getIdentifier(), kextInfo.get());
10751 }
10752 return false;
10753 });
10754 } // end block scope
0a7de745
A
10755
10756finish:
10757 IORecursiveLockUnlock(sKextLock);
10758
10759 return result;
10760}
10761
10762/*********************************************************************
10763* Any info that needs to do allocations must goto finish on alloc
10764* failure. Info that is just a lookup should just not set the object
10765* if the info does not exist.
10766*********************************************************************/
10767#define _OSKextLoadInfoDictCapacity (12)
10768
f427ee49 10769OSSharedPtr<OSDictionary>
0a7de745
A
10770OSKext::copyInfo(OSArray * infoKeys)
10771{
f427ee49
A
10772 OSSharedPtr<OSDictionary> result;
10773 bool success = false;
10774 OSSharedPtr<OSData> headerData;
10775 OSSharedPtr<OSData> logData;
10776 OSSharedPtr<OSNumber> cpuTypeNumber;
10777 OSSharedPtr<OSNumber> cpuSubtypeNumber;
10778 OSString * versionString = NULL; // do not release
10779 OSString * bundleType = NULL; // do not release
10780 uint32_t executablePathCStringSize = 0;
10781 char * executablePathCString = NULL; // must kfree
10782 OSSharedPtr<OSString> executablePathString;
10783 OSSharedPtr<OSData> uuid;
10784 OSSharedPtr<OSArray> dependencyLoadTags;
10785 OSSharedPtr<OSCollectionIterator> metaClassIterator;
10786 OSSharedPtr<OSArray> metaClassInfo;
10787 OSSharedPtr<OSDictionary> metaClassDict;
10788 OSMetaClass * thisMetaClass = NULL; // do not release
10789 OSSharedPtr<OSString> metaClassName;
10790 OSSharedPtr<OSString> superclassName;
10791 kc_format_t kcformat;
10792 uint32_t count, i;
0a7de745
A
10793
10794 result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
10795 if (!result) {
10796 goto finish;
10797 }
10798
10799
10800 /* Empty keys means no keys, but NULL is quicker to check.
10801 */
10802 if (infoKeys && !infoKeys->getCount()) {
10803 infoKeys = NULL;
10804 }
10805
f427ee49
A
10806 if (!PE_get_primary_kc_format(&kcformat)) {
10807 goto finish;
10808 }
10809
0a7de745
A
10810 /* Headers, CPU type, and CPU subtype.
10811 */
10812 if (!infoKeys ||
10813 _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey) ||
10814 _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey) ||
10815 _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey) ||
10816 _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
10817 if (linkedExecutable && !isInterface()) {
10818 kernel_mach_header_t *kext_mach_hdr = (kernel_mach_header_t *)
10819 linkedExecutable->getBytesNoCopy();
10820
f427ee49
A
10821#if !SECURE_KERNEL || XNU_TARGET_OS_OSX
10822 // do not return macho header info on shipping embedded - 19095897
0a7de745
A
10823 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey)) {
10824 kernel_mach_header_t * temp_kext_mach_hdr;
10825 struct load_command * lcp;
10826
10827 headerData = OSData::withBytes(kext_mach_hdr,
10828 (u_int) (sizeof(*kext_mach_hdr) + kext_mach_hdr->sizeofcmds));
10829 if (!headerData) {
10830 goto finish;
10831 }
10832
10833 // unslide any vmaddrs we return to userspace - 10726716
10834 temp_kext_mach_hdr = (kernel_mach_header_t *)
10835 headerData->getBytesNoCopy();
10836 if (temp_kext_mach_hdr == NULL) {
10837 goto finish;
10838 }
10839
10840 lcp = (struct load_command *) (temp_kext_mach_hdr + 1);
10841 for (i = 0; i < temp_kext_mach_hdr->ncmds; i++) {
10842 if (lcp->cmd == LC_SEGMENT_KERNEL) {
10843 kernel_segment_command_t * segp;
10844 kernel_section_t * secp;
10845
10846 segp = (kernel_segment_command_t *) lcp;
10847 // 10543468 - if we jettisoned __LINKEDIT clear size info
10848 if (flags.jettisonLinkeditSeg) {
10849 if (strncmp(segp->segname, SEG_LINKEDIT, sizeof(segp->segname)) == 0) {
10850 segp->vmsize = 0;
10851 segp->fileoff = 0;
10852 segp->filesize = 0;
10853 }
10854 }
10855
f427ee49
A
10856#if __arm__ || __arm64__
10857 // iBoot disregards zero-size segments, just set their addresses to gVirtBase
10858 // and unslide them to avoid vm assertion failures / kernel logging breakage.
10859 if (segp->vmsize == 0 && segp->vmaddr < gVirtBase) {
10860 segp->vmaddr = gVirtBase;
10861 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
10862 secp->size = 0; // paranoia :)
10863 secp->addr = gVirtBase;
10864 }
10865 }
10866#endif
10867
0a7de745
A
10868#if 0
10869 OSKextLog(/* kext */ NULL,
10870 kOSKextLogErrorLevel |
10871 kOSKextLogGeneralFlag,
10872 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
10873 __FUNCTION__, segp->segname, segp->vmaddr,
10874 VM_KERNEL_UNSLIDE(segp->vmaddr),
10875 segp->vmsize, segp->nsects);
10876 if ((VM_KERNEL_IS_SLID(segp->vmaddr) == false) &&
10877 (VM_KERNEL_IS_KEXT(segp->vmaddr) == false) &&
10878 (VM_KERNEL_IS_PRELINKTEXT(segp->vmaddr) == false) &&
10879 (VM_KERNEL_IS_PRELINKINFO(segp->vmaddr) == false) &&
10880 (VM_KERNEL_IS_KEXT_LINKEDIT(segp->vmaddr) == false)) {
10881 OSKextLog(/* kext */ NULL,
10882 kOSKextLogErrorLevel |
10883 kOSKextLogGeneralFlag,
10884 "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
10885 __FUNCTION__, segp->vmaddr, vm_kext_base, vm_kext_top);
10886 }
10887#endif
10888 segp->vmaddr = ml_static_unslide(segp->vmaddr);
10889
10890 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
10891 secp->addr = ml_static_unslide(secp->addr);
10892 }
10893 }
10894 lcp = (struct load_command *)((caddr_t)lcp + lcp->cmdsize);
10895 }
f427ee49 10896 result->setObject(kOSBundleMachOHeadersKey, headerData.get());
0a7de745 10897 }
f427ee49 10898#endif // !SECURE_KERNEL || XNU_TARGET_OS_OSX
0a7de745
A
10899
10900 if (_OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
10901 osLogDataHeaderRef *header;
10902 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
10903
10904 void *os_log_data = NULL;
10905 void *cstring_data = NULL;
10906 unsigned long os_log_size = 0;
10907 unsigned long cstring_size = 0;
10908 uint32_t os_log_offset = 0;
10909 uint32_t cstring_offset = 0;
10910 bool res;
10911
10912 os_log_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__os_log", &os_log_size);
f427ee49 10913 os_log_offset = (uintptr_t)os_log_data - (uintptr_t)kext_mach_hdr;
0a7de745 10914 cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__cstring", &cstring_size);
f427ee49 10915 cstring_offset = (uintptr_t)cstring_data - (uintptr_t)kext_mach_hdr;
0a7de745
A
10916
10917 header = (osLogDataHeaderRef *) headerBytes;
10918 header->version = OS_LOG_HDR_VERSION;
10919 header->sect_count = NUM_OS_LOG_SECTIONS;
10920 header->sections[OS_LOG_SECT_IDX].sect_offset = os_log_offset;
10921 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) os_log_size;
10922 header->sections[CSTRING_SECT_IDX].sect_offset = cstring_offset;
10923 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) cstring_size;
10924
10925
10926 logData = OSData::withBytes(header, (u_int) (sizeof(osLogDataHeaderRef)));
10927 if (!logData) {
10928 goto finish;
10929 }
10930 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
10931 if (!res) {
10932 goto finish;
10933 }
10934 if (os_log_data) {
10935 res = logData->appendBytes(os_log_data, (u_int)header->sections[OS_LOG_SECT_IDX].sect_size);
10936 if (!res) {
10937 goto finish;
10938 }
10939 }
10940 if (cstring_data) {
10941 res = logData->appendBytes(cstring_data, (u_int)header->sections[CSTRING_SECT_IDX].sect_size);
10942 if (!res) {
10943 goto finish;
10944 }
10945 }
f427ee49 10946 result->setObject(kOSBundleLogStringsKey, logData.get());
0a7de745
A
10947 }
10948
10949 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey)) {
10950 cpuTypeNumber = OSNumber::withNumber(
10951 (uint64_t) kext_mach_hdr->cputype,
10952 8 * sizeof(kext_mach_hdr->cputype));
10953 if (!cpuTypeNumber) {
10954 goto finish;
10955 }
f427ee49 10956 result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber.get());
0a7de745
A
10957 }
10958
10959 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
10960 cpuSubtypeNumber = OSNumber::withNumber(
10961 (uint64_t) kext_mach_hdr->cpusubtype,
10962 8 * sizeof(kext_mach_hdr->cpusubtype));
10963 if (!cpuSubtypeNumber) {
10964 goto finish;
10965 }
f427ee49 10966 result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber.get());
0a7de745 10967 }
cb323159
A
10968 } else {
10969 if (isDriverKit() && _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
10970 osLogDataHeaderRef *header;
10971 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
10972 bool res;
10973
10974 header = (osLogDataHeaderRef *) headerBytes;
10975 header->version = OS_LOG_HDR_VERSION;
10976 header->sect_count = NUM_OS_LOG_SECTIONS;
10977 header->sections[OS_LOG_SECT_IDX].sect_offset = 0;
10978 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) 0;
10979 header->sections[CSTRING_SECT_IDX].sect_offset = 0;
10980 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
10981
10982 logData = OSData::withBytes(header, (u_int) (sizeof(osLogDataHeaderRef)));
10983 if (!logData) {
10984 goto finish;
10985 }
10986 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
10987 if (!res) {
10988 goto finish;
10989 }
f427ee49 10990 result->setObject(kOSBundleLogStringsKey, logData.get());
cb323159 10991 }
0a7de745
A
10992 }
10993 }
10994
10995 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
10996 */
f427ee49
A
10997 result->setObject(kCFBundleIdentifierKey, bundleID.get());
10998
10999 /* CFBundlePackageType
11000 */
11001 bundleType = infoDict ? OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey)): NULL;
11002 if (bundleType) {
11003 result->setObject(kCFBundlePackageTypeKey, bundleType);
11004 }
0a7de745
A
11005
11006 /* CFBundleVersion.
11007 */
11008 if (!infoKeys || _OSArrayContainsCString(infoKeys, kCFBundleVersionKey)) {
11009 versionString = OSDynamicCast(OSString,
11010 getPropertyForHostArch(kCFBundleVersionKey));
11011 if (versionString) {
11012 result->setObject(kCFBundleVersionKey, versionString);
11013 }
11014 }
11015
11016 /* OSBundleCompatibleVersion.
11017 */
11018 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCompatibleVersionKey)) {
11019 versionString = OSDynamicCast(OSString,
11020 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
11021 if (versionString) {
11022 result->setObject(kOSBundleCompatibleVersionKey, versionString);
11023 }
11024 }
11025
11026 /* Path.
11027 */
11028 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePathKey)) {
11029 if (path) {
f427ee49 11030 result->setObject(kOSBundlePathKey, path.get());
0a7de745
A
11031 }
11032 }
11033
11034
11035 /* OSBundleExecutablePath.
11036 */
11037 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecutablePathKey)) {
11038 if (path && executableRelPath) {
f427ee49 11039 uint32_t pathLength = path->getLength(); // gets incremented below
0a7de745
A
11040
11041 // +1 for slash, +1 for \0
11042 executablePathCStringSize = pathLength + executableRelPath->getLength() + 2;
11043
f427ee49
A
11044 executablePathCString = (char *)kheap_alloc_tag(KHEAP_TEMP,
11045 executablePathCStringSize, Z_WAITOK, VM_KERN_MEMORY_OSKEXT); // +1 for \0
0a7de745
A
11046 if (!executablePathCString) {
11047 goto finish;
11048 }
11049 strlcpy(executablePathCString, path->getCStringNoCopy(),
11050 executablePathCStringSize);
11051 executablePathCString[pathLength++] = '/';
11052 executablePathCString[pathLength++] = '\0';
11053 strlcat(executablePathCString, executableRelPath->getCStringNoCopy(),
11054 executablePathCStringSize);
11055
11056 executablePathString = OSString::withCString(executablePathCString);
11057
11058 if (!executablePathString) {
11059 goto finish;
11060 }
11061
f427ee49 11062 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
0a7de745 11063 } else if (flags.builtin) {
f427ee49 11064 result->setObject(kOSBundleExecutablePathKey, bundleID.get());
cb323159
A
11065 } else if (isDriverKit()) {
11066 if (path) {
11067 // +1 for slash, +1 for \0
11068 uint32_t pathLength = path->getLength();
11069 executablePathCStringSize = pathLength + 2;
11070
f427ee49
A
11071 executablePathCString = (char *)kheap_alloc_tag(KHEAP_TEMP,
11072 executablePathCStringSize, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
cb323159
A
11073 if (!executablePathCString) {
11074 goto finish;
11075 }
11076 strlcpy(executablePathCString, path->getCStringNoCopy(), executablePathCStringSize);
11077 executablePathCString[pathLength++] = '/';
11078 executablePathCString[pathLength++] = '\0';
11079
11080 executablePathString = OSString::withCString(executablePathCString);
11081
11082 if (!executablePathString) {
11083 goto finish;
11084 }
11085
f427ee49 11086 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
cb323159 11087 }
0a7de745
A
11088 }
11089 }
11090
11091 /* UUID, if the kext has one.
11092 */
11093 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleUUIDKey)) {
11094 uuid = copyUUID();
11095 if (uuid) {
f427ee49 11096 result->setObject(kOSBundleUUIDKey, uuid.get());
0a7de745
A
11097 }
11098 }
11099 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleTextUUIDKey)) {
11100 uuid = copyTextUUID();
11101 if (uuid) {
f427ee49 11102 result->setObject(kOSBundleTextUUIDKey, uuid.get());
0a7de745
A
11103 }
11104 }
11105
f427ee49
A
11106 /*
11107 * Info.plist digest
0a7de745 11108 */
f427ee49
A
11109 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextInfoPlistDigestKey)) {
11110 OSData *digest;
11111 digest = infoDict ? OSDynamicCast(OSData, infoDict->getObject(kOSKextInfoPlistDigestKey)) : NULL;
11112 if (digest) {
11113 result->setObject(kOSKextInfoPlistDigestKey, digest);
11114 }
0a7de745
A
11115 }
11116
f427ee49
A
11117 /*
11118 * Collection type
11119 */
11120 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextBundleCollectionTypeKey)) {
11121 result->setObject(kOSKextBundleCollectionTypeKey, OSString::withCString(getKCTypeString()));
0a7de745
A
11122 }
11123
f427ee49
A
11124 /*
11125 * Collection availability
11126 */
11127 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextAuxKCAvailabilityKey)) {
11128 result->setObject(kOSKextAuxKCAvailabilityKey,
11129 isLoadable() ? kOSBooleanTrue : kOSBooleanFalse);
11130 }
11131
11132 /*
11133 * Allows user load
11134 */
11135 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleAllowUserLoadKey)) {
11136 OSBoolean *allowUserLoad = OSDynamicCast(OSBoolean, getPropertyForHostArch(kOSBundleAllowUserLoadKey));
11137 if (allowUserLoad) {
11138 result->setObject(kOSBundleAllowUserLoadKey, allowUserLoad);
11139 }
11140 }
11141
11142 /*
11143 * Bundle Dependencies (OSBundleLibraries)
11144 */
11145 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLibrariesKey)) {
11146 OSDictionary *libraries = OSDynamicCast(OSDictionary, getPropertyForHostArch(kOSBundleLibrariesKey));
11147 if (libraries) {
11148 result->setObject(kOSBundleLibrariesKey, libraries);
11149 }
11150 }
11151
11152 /*****
11153 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
11154 */
11155 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKernelResourceKey)) {
11156 result->setObject(kOSKernelResourceKey,
11157 isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
11158 }
11159
11160 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleIsInterfaceKey)) {
11161 result->setObject(kOSBundleIsInterfaceKey,
11162 isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
11163 }
11164
11165 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePrelinkedKey)) {
11166 result->setObject(kOSBundlePrelinkedKey,
11167 isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
0a7de745
A
11168 }
11169
11170 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleStartedKey)) {
11171 result->setObject(kOSBundleStartedKey,
11172 isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
11173 }
11174
11175 /* LoadTag (Index).
11176 */
11177 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadTagKey)) {
f427ee49 11178 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
0a7de745
A
11179 /* numBits */ 8 * sizeof(loadTag));
11180 if (!scratchNumber) {
11181 goto finish;
11182 }
f427ee49 11183 result->setObject(kOSBundleLoadTagKey, scratchNumber.get());
0a7de745
A
11184 }
11185
11186 /* LoadAddress, LoadSize.
11187 */
11188 if (!infoKeys ||
11189 _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey) ||
11190 _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey) ||
11191 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey) ||
11192 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey) ||
11193 _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
cb323159
A
11194 bool is_dext = isDriverKit();
11195 if (isInterface() || flags.builtin || linkedExecutable || is_dext) {
0a7de745
A
11196 /* These go to userspace via serialization, so we don't want any doubts
11197 * about their size.
11198 */
11199 uint64_t loadAddress = 0;
11200 uint32_t loadSize = 0;
11201 uint32_t wiredSize = 0;
11202 uint64_t execLoadAddress = 0;
11203 uint32_t execLoadSize = 0;
11204
11205 /* Interfaces always report 0 load address & size.
11206 * Just the way they roll.
11207 *
11208 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
11209 * xxx - shouldn't have one!
11210 */
11211
11212 if (flags.builtin || linkedExecutable) {
11213 kernel_mach_header_t *mh = NULL;
11214 kernel_segment_command_t *seg = NULL;
11215
11216 if (flags.builtin) {
11217 loadAddress = kmod_info->address;
f427ee49 11218 loadSize = (uint32_t)kmod_info->size;
0a7de745
A
11219 } else {
11220 loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
11221 loadSize = linkedExecutable->getLength();
11222 }
11223 mh = (kernel_mach_header_t *)loadAddress;
11224 loadAddress = ml_static_unslide(loadAddress);
11225
11226 /* Walk through the kext, looking for the first executable
11227 * segment in case we were asked for its size/address.
11228 */
11229 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
11230 if (seg->initprot & VM_PROT_EXECUTE) {
11231 execLoadAddress = ml_static_unslide(seg->vmaddr);
f427ee49 11232 execLoadSize = (uint32_t)seg->vmsize;
0a7de745
A
11233 break;
11234 }
11235 }
11236
11237 /* If we have a kmod_info struct, calculated the wired size
11238 * from that. Otherwise it's the full load size.
11239 */
11240 if (kmod_info) {
f427ee49 11241 wiredSize = loadSize - (uint32_t)kmod_info->hdr_size;
0a7de745
A
11242 } else {
11243 wiredSize = loadSize;
11244 }
cb323159
A
11245 } else if (is_dext) {
11246 /*
11247 * DriverKit userspace executables do not have a kernel linkedExecutable,
11248 * so we "fake" their address range with the LoadTag.
11249 */
11250 if (loadTag) {
11251 loadAddress = execLoadAddress = loadTag;
11252 loadSize = execLoadSize = 1;
11253 }
0a7de745
A
11254 }
11255
11256 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey)) {
f427ee49 11257 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
0a7de745
A
11258 (unsigned long long)(loadAddress),
11259 /* numBits */ 8 * sizeof(loadAddress));
11260 if (!scratchNumber) {
11261 goto finish;
11262 }
f427ee49 11263 result->setObject(kOSBundleLoadAddressKey, scratchNumber.get());
0a7de745 11264 }
f427ee49
A
11265 if (kcformat == KCFormatStatic || kcformat == KCFormatKCGEN) {
11266 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCacheLoadAddressKey))
11267 && loadAddress && loadSize) {
11268 void *baseAddress = PE_get_kc_baseaddress(KCKindPrimary);
11269 if (!baseAddress) {
11270 goto finish;
11271 }
11272
11273 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11274 (unsigned long long)ml_static_unslide((vm_offset_t)baseAddress),
11275 /* numBits */ 8 * sizeof(loadAddress));
11276 if (!scratchNumber) {
11277 goto finish;
11278 }
11279 result->setObject(kOSBundleCacheLoadAddressKey, scratchNumber.get());
11280 }
11281 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleKextsInKernelTextKey))
11282 && (this == sKernelKext) && gBuiltinKmodsCount) {
11283 result->setObject(kOSBundleKextsInKernelTextKey, kOSBooleanTrue);
0a7de745 11284 }
0a7de745 11285 }
f427ee49 11286
0a7de745 11287 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey)) {
f427ee49 11288 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
0a7de745
A
11289 (unsigned long long)(execLoadAddress),
11290 /* numBits */ 8 * sizeof(execLoadAddress));
11291 if (!scratchNumber) {
11292 goto finish;
11293 }
f427ee49 11294 result->setObject(kOSBundleExecLoadAddressKey, scratchNumber.get());
0a7de745
A
11295 }
11296 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey)) {
f427ee49 11297 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
0a7de745
A
11298 (unsigned long long)(loadSize),
11299 /* numBits */ 8 * sizeof(loadSize));
11300 if (!scratchNumber) {
11301 goto finish;
11302 }
f427ee49 11303 result->setObject(kOSBundleLoadSizeKey, scratchNumber.get());
0a7de745
A
11304 }
11305 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey)) {
f427ee49 11306 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
0a7de745
A
11307 (unsigned long long)(execLoadSize),
11308 /* numBits */ 8 * sizeof(execLoadSize));
11309 if (!scratchNumber) {
11310 goto finish;
11311 }
f427ee49 11312 result->setObject(kOSBundleExecLoadSizeKey, scratchNumber.get());
0a7de745
A
11313 }
11314 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
f427ee49 11315 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
0a7de745
A
11316 (unsigned long long)(wiredSize),
11317 /* numBits */ 8 * sizeof(wiredSize));
11318 if (!scratchNumber) {
11319 goto finish;
11320 }
f427ee49 11321 result->setObject(kOSBundleWiredSizeKey, scratchNumber.get());
0a7de745
A
11322 }
11323 }
11324 }
11325
11326 /* OSBundleDependencies. In descending order for
11327 * easy compatibility with kextstat(8).
11328 */
11329 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleDependenciesKey)) {
11330 if ((count = getNumDependencies())) {
11331 dependencyLoadTags = OSArray::withCapacity(count);
f427ee49 11332 result->setObject(kOSBundleDependenciesKey, dependencyLoadTags.get());
0a7de745
A
11333
11334 i = count - 1;
11335 do {
11336 OSKext * dependency = OSDynamicCast(OSKext,
11337 dependencies->getObject(i));
11338
0a7de745
A
11339 if (!dependency) {
11340 continue;
11341 }
f427ee49 11342 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
0a7de745
A
11343 (unsigned long long)dependency->getLoadTag(),
11344 /* numBits*/ 8 * sizeof(loadTag));
11345 if (!scratchNumber) {
11346 goto finish;
11347 }
f427ee49 11348 dependencyLoadTags->setObject(scratchNumber.get());
0a7de745
A
11349 } while (i--);
11350 }
11351 }
39037602 11352
0a7de745
A
11353 /* OSBundleMetaClasses.
11354 */
11355 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleClassesKey)) {
11356 if (metaClasses && metaClasses->getCount()) {
f427ee49 11357 metaClassIterator = OSCollectionIterator::withCollection(metaClasses.get());
0a7de745
A
11358 metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
11359 if (!metaClassIterator || !metaClassInfo) {
11360 goto finish;
11361 }
f427ee49 11362 result->setObject(kOSBundleClassesKey, metaClassInfo.get());
0a7de745
A
11363
11364 while ((thisMetaClass = OSDynamicCast(OSMetaClass,
11365 metaClassIterator->getNextObject()))) {
0a7de745
A
11366 metaClassDict = OSDictionary::withCapacity(3);
11367 if (!metaClassDict) {
11368 goto finish;
11369 }
11370
11371 metaClassName = OSString::withCString(thisMetaClass->getClassName());
11372 if (thisMetaClass->getSuperClass()) {
11373 superclassName = OSString::withCString(
11374 thisMetaClass->getSuperClass()->getClassName());
11375 }
f427ee49 11376 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
0a7de745
A
11377 8 * sizeof(unsigned int));
11378
11379 /* Bail if any of the essentials is missing. The root class lacks a superclass,
11380 * of course.
11381 */
11382 if (!metaClassDict || !metaClassName || !scratchNumber) {
11383 goto finish;
11384 }
11385
f427ee49
A
11386 metaClassInfo->setObject(metaClassDict.get());
11387 metaClassDict->setObject(kOSMetaClassNameKey, metaClassName.get());
0a7de745 11388 if (superclassName) {
f427ee49 11389 metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName.get());
0a7de745 11390 }
f427ee49 11391 metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber.get());
0a7de745
A
11392 }
11393 }
11394 }
39037602 11395
0a7de745
A
11396 /* OSBundleRetainCount.
11397 */
11398 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleRetainCountKey)) {
0a7de745
A
11399 {
11400 int kextRetainCount = getRetainCount() - 1;
11401 if (isLoaded()) {
11402 kextRetainCount--;
11403 }
f427ee49 11404 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
0a7de745
A
11405 (int)kextRetainCount,
11406 /* numBits*/ 8 * sizeof(int));
11407 if (scratchNumber) {
f427ee49 11408 result->setObject(kOSBundleRetainCountKey, scratchNumber.get());
0a7de745
A
11409 }
11410 }
11411 }
39037602 11412
0a7de745 11413 success = true;
39037602
A
11414
11415finish:
0a7de745 11416 if (executablePathCString) {
f427ee49
A
11417 kheap_free(KHEAP_TEMP, executablePathCString, executablePathCStringSize);
11418 }
0a7de745 11419 if (!success) {
f427ee49 11420 result.reset();
0a7de745
A
11421 }
11422 return result;
39037602
A
11423}
11424
cb323159
A
11425/*********************************************************************
11426*********************************************************************/
11427/* static */
11428bool
11429OSKext::copyUserExecutablePath(const OSSymbol * bundleID, char * pathResult, size_t pathSize)
11430{
11431 bool ok;
f427ee49 11432 OSSharedPtr<OSKext> kext;
cb323159
A
11433
11434 IORecursiveLockLock(sKextLock);
f427ee49 11435 kext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(bundleID)), OSRetain);
cb323159
A
11436 IORecursiveLockUnlock(sKextLock);
11437
11438 if (!kext || !kext->path || !kext->userExecutableRelPath) {
cb323159
A
11439 return false;
11440 }
11441 snprintf(pathResult, pathSize, "%s/Contents/MacOS/%s",
11442 kext->path->getCStringNoCopy(),
11443 kext->userExecutableRelPath->getCStringNoCopy());
11444 ok = true;
cb323159
A
11445
11446 return ok;
11447}
11448
b0d623f7
A
11449/*********************************************************************
11450*********************************************************************/
11451/* static */
0a7de745
A
11452OSReturn
11453OSKext::requestResource(
11454 const char * kextIdentifierCString,
11455 const char * resourceNameCString,
11456 OSKextRequestResourceCallback callback,
11457 void * context,
11458 OSKextRequestTag * requestTagOut)
b0d623f7 11459{
f427ee49
A
11460 OSReturn result = kOSReturnError;
11461 OSSharedPtr<OSKext> callbackKext; // looked up
b0d623f7 11462
0a7de745 11463 OSKextRequestTag requestTag = -1;
f427ee49
A
11464 OSSharedPtr<OSNumber> requestTagNum;
11465 OSSharedPtr<OSDictionary> requestDict;
11466 OSSharedPtr<OSString> kextIdentifier;
11467 OSSharedPtr<OSString> resourceName;
3e170ce0 11468
f427ee49
A
11469 OSSharedPtr<OSDictionary> callbackRecord;
11470 OSSharedPtr<OSData> callbackWrapper;
b0d623f7 11471
f427ee49 11472 OSSharedPtr<OSData> contextWrapper;
6d2010ae 11473
0a7de745 11474 IORecursiveLockLock(sKextLock);
d9a64523 11475
0a7de745
A
11476 if (requestTagOut) {
11477 *requestTagOut = kOSKextRequestTagInvalid;
11478 }
3e170ce0 11479
0a7de745
A
11480 /* If requests to user space are disabled, don't go any further */
11481 if (!sKernelRequestsEnabled) {
11482 OSKextLog(/* kext */ NULL,
11483 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11484 "Can't request resource %s for %s - requests to user space are disabled.",
11485 resourceNameCString,
11486 kextIdentifierCString);
11487 result = kOSKextReturnDisabled;
11488 goto finish;
11489 }
3e170ce0 11490
0a7de745
A
11491 if (!kextIdentifierCString || !resourceNameCString || !callback) {
11492 result = kOSKextReturnInvalidArgument;
11493 goto finish;
11494 }
b0d623f7 11495
0a7de745
A
11496 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
11497 if (!callbackKext) {
11498 OSKextLog(/* kext */ NULL,
11499 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11500 "Resource request has bad callback address.");
11501 result = kOSKextReturnInvalidArgument;
11502 goto finish;
11503 }
11504 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
11505 OSKextLog(/* kext */ NULL,
11506 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11507 "Resource request callback is in a kext that is not started.");
11508 result = kOSKextReturnInvalidArgument;
11509 goto finish;
11510 }
b0d623f7 11511
0a7de745
A
11512 /* Do not allow any new requests to be made on a kext that is unloading.
11513 */
11514 if (callbackKext->flags.stopping) {
11515 result = kOSKextReturnStopping;
11516 goto finish;
11517 }
b0d623f7 11518
0a7de745
A
11519 /* If we're wrapped the next available request tag around to the negative
11520 * numbers, we can't service any more requests.
11521 */
11522 if (sNextRequestTag == kOSKextRequestTagInvalid) {
11523 OSKextLog(/* kext */ NULL,
11524 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11525 "No more request tags available; restart required.");
11526 result = kOSKextReturnNoResources;
11527 goto finish;
11528 }
11529 requestTag = sNextRequestTag++;
6d2010ae 11530
0a7de745 11531 result = _OSKextCreateRequest(kKextRequestPredicateRequestResource,
f427ee49 11532 requestDict);
0a7de745
A
11533 if (result != kOSReturnSuccess) {
11534 goto finish;
11535 }
5ba3f43e 11536
0a7de745
A
11537 kextIdentifier = OSString::withCString(kextIdentifierCString);
11538 resourceName = OSString::withCString(resourceNameCString);
11539 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
11540 8 * sizeof(requestTag));
11541 if (!kextIdentifier ||
11542 !resourceName ||
11543 !requestTagNum ||
f427ee49
A
11544 !_OSKextSetRequestArgument(requestDict.get(),
11545 kKextRequestArgumentBundleIdentifierKey, kextIdentifier.get()) ||
11546 !_OSKextSetRequestArgument(requestDict.get(),
11547 kKextRequestArgumentNameKey, resourceName.get()) ||
11548 !_OSKextSetRequestArgument(requestDict.get(),
11549 kKextRequestArgumentRequestTagKey, requestTagNum.get())) {
0a7de745
A
11550 result = kOSKextReturnNoMemory;
11551 goto finish;
11552 }
6d2010ae 11553
f427ee49 11554 callbackRecord = OSDynamicPtrCast<OSDictionary>(requestDict->copyCollection());
0a7de745
A
11555 if (!callbackRecord) {
11556 result = kOSKextReturnNoMemory;
11557 goto finish;
11558 }
11559 // we validate callback address at call time
11560 callbackWrapper = OSData::withBytes((void *)&callback, sizeof(void *));
11561 if (context) {
11562 contextWrapper = OSData::withBytes((void *)&context, sizeof(void *));
11563 }
f427ee49
A
11564 if (!callbackWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
11565 kKextRequestArgumentCallbackKey, callbackWrapper.get())) {
0a7de745
A
11566 result = kOSKextReturnNoMemory;
11567 goto finish;
11568 }
6d2010ae 11569
0a7de745 11570 if (context) {
f427ee49
A
11571 if (!contextWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
11572 kKextRequestArgumentContextKey, contextWrapper.get())) {
0a7de745
A
11573 result = kOSKextReturnNoMemory;
11574 goto finish;
11575 }
11576 }
b0d623f7 11577
0a7de745
A
11578 /* Only post the requests after all the other potential failure points
11579 * have been passed.
11580 */
f427ee49
A
11581 if (!sKernelRequests->setObject(requestDict.get()) ||
11582 !sRequestCallbackRecords->setObject(callbackRecord.get())) {
0a7de745
A
11583 result = kOSKextReturnNoMemory;
11584 goto finish;
11585 }
11586
f427ee49 11587 OSKext::pingIOKitDaemon();
0a7de745
A
11588
11589 result = kOSReturnSuccess;
11590 if (requestTagOut) {
11591 *requestTagOut = requestTag;
11592 }
b0d623f7
A
11593
11594finish:
11595
0a7de745
A
11596 /* If we didn't succeed, yank the request & callback
11597 * from their holding arrays.
11598 */
11599 if (result != kOSReturnSuccess) {
11600 unsigned int index;
b0d623f7 11601
f427ee49 11602 index = sKernelRequests->getNextIndexOfObject(requestDict.get(), 0);
0a7de745
A
11603 if (index != (unsigned int)-1) {
11604 sKernelRequests->removeObject(index);
11605 }
f427ee49 11606 index = sRequestCallbackRecords->getNextIndexOfObject(callbackRecord.get(), 0);
0a7de745
A
11607 if (index != (unsigned int)-1) {
11608 sRequestCallbackRecords->removeObject(index);
11609 }
11610 }
11611
11612 OSKext::considerUnloads(/* rescheduleOnly? */ true);
b0d623f7 11613
0a7de745 11614 IORecursiveLockUnlock(sKextLock);
b0d623f7 11615
f427ee49
A
11616 return result;
11617}
b0d623f7 11618
f427ee49
A
11619OSReturn
11620OSKext::requestDaemonLaunch(
11621 OSString *kextIdentifier,
11622 OSString *serverName,
11623 OSNumber *serverTag,
11624 OSSharedPtr<IOUserServerCheckInToken> &checkInToken)
11625{
11626 OSReturn result;
11627 IOUserServerCheckInToken * checkInTokenRaw = NULL;
b0d623f7 11628
f427ee49
A
11629 result = requestDaemonLaunch(kextIdentifier, serverName,
11630 serverTag, &checkInTokenRaw);
11631
11632 if (kOSReturnSuccess == result) {
11633 checkInToken.reset(checkInTokenRaw, OSNoRetain);
0a7de745 11634 }
b0d623f7 11635
0a7de745 11636 return result;
b0d623f7
A
11637}
11638
cb323159
A
11639OSReturn
11640OSKext::requestDaemonLaunch(
11641 OSString *kextIdentifier,
11642 OSString *serverName,
f427ee49
A
11643 OSNumber *serverTag,
11644 IOUserServerCheckInToken ** checkInToken)
cb323159
A
11645{
11646 OSReturn result = kOSReturnError;
f427ee49
A
11647 OSSharedPtr<OSDictionary> requestDict;
11648 OSSharedPtr<IOUserServerCheckInToken> token;
cb323159
A
11649
11650 if (!kextIdentifier || !serverName || !serverTag) {
11651 result = kOSKextReturnInvalidArgument;
11652 goto finish;
11653 }
11654
11655 IORecursiveLockLock(sKextLock);
11656
11657 OSKextLog(/* kext */ NULL,
11658 kOSKextLogDebugLevel |
11659 kOSKextLogGeneralFlag,
11660 "Requesting daemon launch for %s with serverName %s and tag %llu",
11661 kextIdentifier->getCStringNoCopy(),
11662 serverName->getCStringNoCopy(),
11663 serverTag->unsigned64BitValue()
11664 );
11665
f427ee49 11666 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonLaunch, requestDict);
cb323159
A
11667 if (result != kOSReturnSuccess) {
11668 goto finish;
11669 }
11670
f427ee49
A
11671 token.reset(IOUserServerCheckInToken::create(), OSNoRetain);
11672 if (!token) {
11673 result = kOSKextReturnNoMemory;
11674 goto finish;
11675 }
11676
11677 if (!_OSKextSetRequestArgument(requestDict.get(),
cb323159 11678 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
f427ee49 11679 !_OSKextSetRequestArgument(requestDict.get(),
cb323159 11680 kKextRequestArgumentDriverExtensionServerName, serverName) ||
f427ee49
A
11681 !_OSKextSetRequestArgument(requestDict.get(),
11682 kKextRequestArgumentDriverExtensionServerTag, serverTag) ||
11683 !_OSKextSetRequestArgument(requestDict.get(),
11684 kKextRequestArgumentCheckInToken, token.get())) {
cb323159
A
11685 result = kOSKextReturnNoMemory;
11686 goto finish;
11687 }
11688
11689 /* Only post the requests after all the other potential failure points
11690 * have been passed.
11691 */
f427ee49 11692 if (!sKernelRequests->setObject(requestDict.get())) {
cb323159
A
11693 result = kOSKextReturnNoMemory;
11694 goto finish;
11695 }
f427ee49
A
11696 *checkInToken = token.detach();
11697 OSKext::pingIOKitDaemon();
cb323159
A
11698
11699 result = kOSReturnSuccess;
11700finish:
11701 IORecursiveLockUnlock(sKextLock);
f427ee49
A
11702 return result;
11703}
11704
11705/*********************************************************************
11706* Assumes sKextLock is held.
11707*********************************************************************/
11708/* static */
11709OSReturn
11710OSKext::dequeueCallbackForRequestTag(
11711 OSKextRequestTag requestTag,
11712 OSSharedPtr<OSDictionary> &callbackRecordOut)
11713{
11714 OSDictionary * callbackRecordOutRaw = NULL;
11715 OSReturn result;
11716
11717 result = dequeueCallbackForRequestTag(requestTag,
11718 &callbackRecordOutRaw);
11719
11720 if (kOSReturnSuccess == result) {
11721 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
11722 }
11723
11724 return result;
11725}
11726OSReturn
11727OSKext::dequeueCallbackForRequestTag(
11728 OSKextRequestTag requestTag,
11729 OSDictionary ** callbackRecordOut)
11730{
11731 OSReturn result = kOSReturnError;
11732 OSSharedPtr<OSNumber> requestTagNum;
11733
11734 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
11735 8 * sizeof(requestTag));
11736 if (!requestTagNum) {
11737 goto finish;
11738 }
11739
11740 result = OSKext::dequeueCallbackForRequestTag(requestTagNum.get(),
11741 callbackRecordOut);
11742
11743finish:
11744 return result;
11745}
11746
11747/*********************************************************************
11748* Assumes sKextLock is held.
11749*********************************************************************/
11750/* static */
11751OSReturn
11752OSKext::dequeueCallbackForRequestTag(
11753 OSNumber * requestTagNum,
11754 OSSharedPtr<OSDictionary> &callbackRecordOut)
11755{
11756 OSDictionary * callbackRecordOutRaw = NULL;
11757 OSReturn result;
11758
11759 result = dequeueCallbackForRequestTag(requestTagNum,
11760 &callbackRecordOutRaw);
11761
11762 if (kOSReturnSuccess == result) {
11763 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
11764 }
11765
11766 return result;
11767}
11768OSReturn
11769OSKext::dequeueCallbackForRequestTag(
11770 OSNumber * requestTagNum,
11771 OSDictionary ** callbackRecordOut)
11772{
11773 OSReturn result = kOSKextReturnInvalidArgument;
11774 OSDictionary * callbackRecord = NULL; // retain if matched!
11775 OSNumber * callbackTagNum = NULL; // do not release
11776 unsigned int count, i;
11777
11778 result = kOSReturnError;
11779 count = sRequestCallbackRecords->getCount();
11780 for (i = 0; i < count; i++) {
11781 callbackRecord = OSDynamicCast(OSDictionary,
11782 sRequestCallbackRecords->getObject(i));
11783 if (!callbackRecord) {
11784 goto finish;
11785 }
11786
11787 /* If we don't find a tag, we basically have a leak here. Maybe
11788 * we should just remove it.
11789 */
11790 callbackTagNum = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(
11791 callbackRecord, kKextRequestArgumentRequestTagKey));
11792 if (!callbackTagNum) {
11793 goto finish;
11794 }
11795
11796 /* We could be even more paranoid and check that all the incoming
11797 * args match what's in the callback record.
11798 */
11799 if (callbackTagNum->isEqualTo(requestTagNum)) {
11800 if (callbackRecordOut) {
11801 *callbackRecordOut = callbackRecord;
11802 callbackRecord->retain();
11803 }
11804 sRequestCallbackRecords->removeObject(i);
11805 result = kOSReturnSuccess;
11806 goto finish;
11807 }
11808 }
11809 result = kOSKextReturnNotFound;
11810
11811finish:
11812 return result;
11813}
11814
11815
11816/*********************************************************************
11817* Busy timeout triage
11818*********************************************************************/
11819/* static */
11820bool
11821OSKext::pendingIOKitDaemonRequests(void)
11822{
11823 return sRequestCallbackRecords && sRequestCallbackRecords->getCount();
11824}
11825
11826/*********************************************************************
11827* Acquires and releases sKextLock
11828*
11829* This function is designed to be called exactly once on boot by
11830* the IOKit management daemon, kernelmanagerd. It gathers all codeless
11831* kext and dext personalities, and then attempts to map a System
11832* (pageable) KC and an Auxiliary (aux) KC.
11833*
11834* Even if the pageable or aux KC fail to load - this function will
11835* not allow a second call. This avoids security issues where
11836* kernelmanagerd has been compromised or the pageable kc has been
11837* tampered with and the attacker attempts to re-load a malicious
11838* variant.
11839*
11840* Return: if a KC fails to load the return value will contain:
11841* kOSKextReturnKCLoadFailure. If the pageable KC fails,
11842* the return value will contain kOSKextReturnKCLoadFailureSystemKC.
11843* Similarly, if the aux kc load fails, the return value will
11844* contain kOSKextReturnKCLoadFailureAuxKC. The two values
11845* compose with each other and with kOSKextReturnKCLoadFailure.
11846*********************************************************************/
11847/* static */
11848OSReturn
11849OSKext::loadFileSetKexts(OSDictionary * requestDict __unused)
11850{
11851 static bool daemon_ready = false;
11852
11853 OSReturn ret = kOSKextReturnInvalidArgument;
11854 OSReturn kcerr = 0;
11855 bool start_matching = false;
11856
11857 bool allow_fileset_load = !daemon_ready;
11858#if !(defined(__x86_64__) || defined(__i386__))
11859 /* never allow KCs full of kexts on non-x86 machines */
11860 allow_fileset_load = false;
11861#endif
11862
c3c9b80d
A
11863 /*
11864 * Change with 70582300
11865 */
11866#if 0 || !defined(VM_MAPPED_KEXTS)
11867 /*
11868 * On platforms that don't support the SystemKC or a file-backed
11869 * AuxKC, the kext receipt for 3rd party kexts loaded by the booter
11870 * needs to be queried before we load any codeless kexts or release
11871 * any 3rd party kexts to run. On platforms that support a file-backed
11872 * AuxKC, this process is done via the kext audit mechanism.
11873 */
11874
11875 printf("KextLog: waiting for kext receipt to be queried.\n");
11876 while (!IOServiceWaitForMatchingResource(kOSKextReceiptQueried, UINT64_MAX)) {
11877 IOSleep(30);
11878 }
11879#endif /* !VM_MAPPED_KEXTS */
11880
f427ee49
A
11881 /*
11882 * Get the args from the request. Right now we need the file
11883 * name for the pageable and the aux kext collection file sets.
11884 */
11885 OSDictionary * requestArgs = NULL; // do not release
11886 OSString * pageable_filepath = NULL; // do not release
11887 OSString * aux_filepath = NULL; // do not release
11888 OSArray * codeless_kexts = NULL; // do not release
11889
11890 kernel_mach_header_t *akc_mh = NULL;
11891
11892 requestArgs = OSDynamicCast(OSDictionary,
11893 requestDict->getObject(kKextRequestArgumentsKey));
11894
11895 if (requestArgs == NULL) {
11896 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
11897 "KextLog: No arguments in plist for loading fileset kext\n");
11898 printf("KextLog: No arguments in plist for loading fileset kext\n");
11899 return ret;
11900 }
11901
11902 ret = kOSKextReturnDisabled;
11903
11904 IORecursiveLockLock(sKextLock);
11905
2a1bd2d3
A
11906 if (!sLoadEnabled) {
11907 OSKextLog(NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11908 "KextLog: Kext loading is disabled (attempt to load KCs).");
11909 IORecursiveLockUnlock(sKextLock);
11910 return ret;
11911 }
11912
f427ee49
A
11913 pageable_filepath = OSDynamicCast(OSString,
11914 requestArgs->getObject(kKextRequestArgumentPageableKCFilename));
11915
11916 if (allow_fileset_load && pageable_filepath != NULL) {
11917 printf("KextLog: Loading Pageable KC from file %s\n", pageable_filepath->getCStringNoCopy());
11918
11919 ret = OSKext::loadKCFileSet(pageable_filepath->getCStringNoCopy(), KCKindPageable);
11920 if (ret) {
11921 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
11922 "KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
11923
11924 printf("KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
11925 ret = kOSKextReturnKCLoadFailure;
11926 kcerr |= kOSKextReturnKCLoadFailureSystemKC;
11927 goto try_auxkc;
11928 }
11929 /*
11930 * Even if the AuxKC fails to load, we still want to send
11931 * the System KC personalities to the catalog for matching
11932 */
11933 start_matching = true;
11934 } else if (pageable_filepath != NULL) {
11935 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
11936 "KextLog: ignoring Pageable KC load from %s\n", pageable_filepath->getCStringNoCopy());
11937 ret = kOSKextReturnUnsupported;
11938 }
11939
11940try_auxkc:
11941 akc_mh = (kernel_mach_header_t*)PE_get_kc_header(KCKindAuxiliary);
11942 if (akc_mh) {
11943 /*
11944 * If we try to load a deferred AuxKC, then don't ever attempt
11945 * a filesystem map of a file
11946 */
11947 allow_fileset_load = false;
11948
11949 /*
11950 * This function is only called once per boot, so we haven't
11951 * yet loaded an AuxKC. If we have registered the AuxKC mach
11952 * header, that means that the kext collection has been placed
11953 * in memory for us by the booter, and is waiting for us to
11954 * process it. Grab the deferred XML plist of info
11955 * dictionaries and add all the kexts.
11956 */
11957 OSSharedPtr<OSObject> parsedXML;
11958 OSSharedPtr<OSData> loaded_kcUUID;
11959 OSDictionary *infoDict;
11960 parsedXML = consumeDeferredKextCollection(KCKindAuxiliary);
11961 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
c3c9b80d
A
11962#if !defined(VM_MAPPED_KEXTS)
11963 /*
11964 * On platforms where we don't dynamically wire-down / page-in
11965 * kext memory, we need to maintain the invariant that if the
11966 * AuxKC in memory does not contain a kext receipt, then we
11967 * should not load any of the kexts.
11968 */
11969 size_t receipt_sz = 0;
11970 if (getsectdatafromheader(akc_mh, kReceiptInfoSegment, kAuxKCReceiptSection, &receipt_sz) == NULL || receipt_sz == 0) {
11971 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11972 "KextLog: WARNING: Failed to load AuxKC from memory: missing receipt");
11973 ret = kOSKextReturnKCLoadFailure;
11974 goto try_codeless;
11975 }
11976#endif
f427ee49
A
11977 if (infoDict) {
11978 bool added;
11979 printf("KextLog: Adding kexts from in-memory AuxKC\n");
11980 added = OSKext::addKextsFromKextCollection(akc_mh, infoDict,
11981 kPrelinkTextSegment, loaded_kcUUID, KCKindAuxiliary);
11982 if (!loaded_kcUUID) {
11983 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11984 "KextLog: WARNING: did not find UUID in deferred Aux KC!");
11985 } else if (!added) {
11986 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11987 "KextLog: WARNING: Failed to load AuxKC from memory.");
11988 }
11989 /* only return success if the pageable load (above) was successful */
11990 if (ret != kOSKextReturnKCLoadFailure) {
11991 ret = kOSReturnSuccess;
11992 }
11993 /* the registration of the AuxKC parsed out the KC's UUID already */
11994 } else {
11995 if (daemon_ready) {
11996 /*
11997 * Complain, but don't return an error if this isn't the first time the
11998 * IOKit daemon is checking in. If the daemon ever restarts, we will
11999 * hit this case because we've already consumed the deferred personalities.
12000 * We return success here so that a call to this function from a restarted
12001 * daemon with no codeless kexts will succeed.
12002 */
12003 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
12004 "KextLog: can't re-parse deferred AuxKC personalities on IOKit daemon restart");
12005 if (ret != kOSKextReturnKCLoadFailure) {
12006 ret = kOSReturnSuccess;
12007 }
12008 } else {
12009 /* this is a real error case */
12010 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12011 "KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary");
12012 printf("KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary\n");
12013 ret = kOSKextReturnKCLoadFailure;
12014 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
12015 }
12016 }
12017 }
12018
12019 aux_filepath = OSDynamicCast(OSString,
12020 requestArgs->getObject(kKextRequestArgumentAuxKCFilename));
12021 if (allow_fileset_load && aux_filepath != NULL) {
12022 printf("KextLog: Loading Aux KC from file %s\n", aux_filepath->getCStringNoCopy());
12023
12024 ret = OSKext::loadKCFileSet(aux_filepath->getCStringNoCopy(), KCKindAuxiliary);
12025 if (ret) {
12026 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12027 "KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
12028
12029 printf("KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
12030 ret = kOSKextReturnKCLoadFailure;
12031 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
12032 goto try_codeless;
12033 }
12034 start_matching = true;
12035 } else if (aux_filepath != NULL) {
12036 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
12037 "KextLog: Ignoring AuxKC load from %s\n", aux_filepath->getCStringNoCopy());
12038 if (ret != kOSKextReturnKCLoadFailure) {
12039 ret = kOSKextReturnUnsupported;
12040 }
12041 }
12042
12043try_codeless:
12044 /*
12045 * Load codeless kexts last so that there is no possibilty of a
12046 * codeless kext bundle ID preventing a kext in the system KC from
12047 * loading
12048 */
12049 codeless_kexts = OSDynamicCast(OSArray,
12050 requestArgs->getObject(kKextRequestArgumentCodelessPersonalities));
12051 if (codeless_kexts != NULL) {
12052 uint32_t count = codeless_kexts->getCount();
12053 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12054 "KextLog: loading %d codeless kexts/dexts", count);
12055 for (uint32_t i = 0; i < count; i++) {
12056 OSDictionary *infoDict;
12057 infoDict = OSDynamicCast(OSDictionary,
12058 codeless_kexts->getObject(i));
12059 if (!infoDict) {
12060 continue;
12061 }
12062 // instantiate a new kext, and don't hold a reference
12063 // (the kext subsystem will hold one implicitly)
12064 OSKext::withCodelessInfo(infoDict);
12065 }
12066 /* ignore errors that are not KC load failures */
12067 if (ret != kOSKextReturnKCLoadFailure) {
12068 ret = kOSReturnSuccess;
12069 }
12070 start_matching = true;
12071 }
12072
12073 /* send personalities to the IOCatalog once */
12074 if (ret == kOSReturnSuccess || start_matching || sOSKextWasResetAfterUserspaceReboot) {
12075 OSKext::sendAllKextPersonalitiesToCatalog(true);
12076 /*
12077 * This request necessarily came from the IOKit daemon (kernelmanagerd), so mark
12078 * things as active and start all the delayed matching: the
12079 * dext and codeless kext personalities should have all been
12080 * delivered via this one call.
12081 */
12082 if (!daemon_ready) {
12083 OSKext::setIOKitDaemonActive();
12084 OSKext::setDeferredLoadSucceeded(TRUE);
12085 IOService::iokitDaemonLaunched();
12086 }
12087 if (sOSKextWasResetAfterUserspaceReboot) {
12088 sOSKextWasResetAfterUserspaceReboot = false;
12089 OSKext::setIOKitDaemonActive();
12090 IOService::startDeferredMatches();
12091 }
12092 }
12093
12094 if (ret == kOSKextReturnKCLoadFailure) {
12095 ret |= kcerr;
12096 }
12097
12098 /*
12099 * Only allow this function to attempt to load the pageable and
12100 * aux KCs once per boot.
12101 */
12102 daemon_ready = true;
12103
12104 IORecursiveLockUnlock(sKextLock);
12105
12106 return ret;
12107}
12108
12109OSReturn
12110OSKext::resetMutableSegments(void)
12111{
12112 kernel_segment_command_t *seg = NULL;
12113 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
12114 u_int index = 0;
12115 OSKextSavedMutableSegment *savedSegment = NULL;
12116 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
12117 OSReturn err;
12118
12119 if (!savedMutableSegments) {
12120 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
12121 "Kext %s cannot be reset, mutable segments were not saved.", getIdentifierCString());
12122 err = kOSKextReturnInternalError;
12123 goto finish;
12124 }
12125
12126 for (seg = firstsegfromheader(k_mh), index = 0; seg; seg = nextsegfromheader(k_mh, seg)) {
12127 if (!segmentIsMutable(seg)) {
12128 continue;
12129 }
12130 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
12131 uint64_t vmsize = seg->vmsize;
12132 err = kOSKextReturnInternalError;
12133 for (index = 0; index < savedMutableSegments->getCount(); index++) {
12134 savedSegment = OSDynamicCast(OSKextSavedMutableSegment, savedMutableSegments->getObject(index));
12135 assert(savedSegment);
12136 if (savedSegment->getVMAddr() == seg->vmaddr && savedSegment->getVMSize() == seg->vmsize) {
12137 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
12138 "Resetting kext %s, mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12139 err = savedSegment->restoreContents(seg);
12140 if (err != kOSReturnSuccess) {
12141 panic("Kext %s cannot be reset, mutable segment %llx->%llx could not be restored.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12142 }
12143 }
12144 }
12145 if (err != kOSReturnSuccess) {
12146 panic("Kext %s cannot be reset, could not find saved mutable segment for %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12147 }
12148 }
12149 err = kOSReturnSuccess;
12150finish:
12151 return err;
12152}
12153
12154
12155/*********************************************************************
12156* Assumes sKextLock is held.
12157*********************************************************************/
12158/* static */
12159OSReturn
12160OSKext::loadKCFileSet(
12161 const char *filepath,
12162 kc_kind_t type)
12163{
12164#if VM_MAPPED_KEXTS
12165 /* we only need to load filesets on systems that support VM_MAPPED kexts */
12166 OSReturn err;
12167 struct vnode *vp = NULL;
12168 void *fileset_control;
12169 off_t fsize;
12170 bool pageable = (type == KCKindPageable);
12171
12172 if ((pageable && pageableKCloaded) ||
12173 (!pageable && auxKCloaded)) {
12174 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12175 "KC FileSet of type %s is already loaded", (pageable ? "Pageable" : "Aux"));
12176
12177 return kOSKextReturnInvalidArgument;
12178 }
12179
12180 /* Do not allow AuxKC to load if Pageable KC is not loaded */
12181 if (!pageable && !pageableKCloaded) {
12182 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12183 "Trying to load the Aux KC without loading the Pageable KC");
12184 return kOSKextReturnInvalidArgument;
12185 }
12186
12187 fileset_control = ubc_getobject_from_filename(filepath, &vp, &fsize);
12188
12189 if (fileset_control == NULL) {
12190 printf("Could not get memory control object for file %s", filepath);
12191
12192 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12193 "Could not get memory control object for file %s", filepath);
12194 return kOSKextReturnInvalidArgument;
12195 }
12196 if (vp == NULL) {
12197 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12198 "Could not find vnode for file %s", filepath);
12199 return kOSKextReturnInvalidArgument;
12200 }
12201
12202 kernel_mach_header_t *mh = NULL;
12203 uintptr_t slide = 0;
12204
12205#if CONFIG_CSR
12206 /*
12207 * When SIP is enabled, the KC we map must be SIP-protected
12208 */
12209 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS) != 0) {
12210 struct vnode_attr va;
12211 int error;
12212 VATTR_INIT(&va);
12213 VATTR_WANTED(&va, va_flags);
12214 error = vnode_getattr(vp, &va, vfs_context_current());
12215 if (error) {
12216 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12217 "vnode_getattr(%s) failed (error=%d)", filepath, error);
12218 err = kOSKextReturnInternalError;
12219 goto finish;
12220 }
12221 if (!(va.va_flags & SF_RESTRICTED)) {
12222 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12223 "Path to KC '%s' is not SIP-protected", filepath);
12224 err = kOSKextReturnInvalidArgument;
12225 goto finish;
12226 }
12227 }
12228#endif
12229
12230 err = OSKext::mapKCFileSet(fileset_control, (vm_size_t)fsize, &mh, 0, &slide, pageable, NULL);
12231 if (err) {
12232 printf("KextLog: mapKCFileSet returned %d\n", err);
12233
12234 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12235 "mapKCFileSet returned %d\n", err);
12236
12237 err = kOSKextReturnInvalidArgument;
12238 }
12239
12240#if CONFIG_CSR
12241finish:
12242#endif
12243 /* Drop the vnode ref returned by ubc_getobject_from_filename if mapKCFileSet failed */
12244 assert(vp != NULL);
12245 if (err == kOSReturnSuccess) {
12246 PE_set_kc_vp(type, vp);
12247 if (pageable) {
12248 pageableKCloaded = true;
12249 } else {
12250 auxKCloaded = true;
12251 }
12252 } else {
12253 vnode_put(vp);
12254 }
12255
12256 return err;
12257#else
12258 (void)filepath;
12259 (void)type;
12260 return kOSKextReturnUnsupported;
12261#endif // VM_MAPPED_KEXTS
12262}
12263
12264#if defined(__x86_64__) || defined(__i386__)
12265/*********************************************************************
12266* Assumes sKextLock is held.
12267*********************************************************************/
12268/* static */
12269OSReturn
12270OSKext::mapKCFileSet(
12271 void *control,
12272 vm_size_t fsize,
12273 kernel_mach_header_t **mhp,
12274 off_t file_offset,
12275 uintptr_t *slidep,
12276 bool pageable,
12277 void *map_entry_list)
12278{
12279 bool fileset_load = false;
12280 kern_return_t ret;
12281 OSReturn err;
12282 kernel_section_t *infoPlistSection = NULL;
12283 OSDictionary *infoDict = NULL;
12284
12285 OSSharedPtr<OSObject> parsedXML;
12286 OSSharedPtr<OSString> errorString;
12287 OSSharedPtr<OSData> loaded_kcUUID;
12288
12289 /* Check if initial load for file set */
12290 if (*mhp == NULL) {
12291 fileset_load = true;
12292
12293 /* Get a page aligned address from kext map to map the file */
12294 vm_map_offset_t pagealigned_addr = get_address_from_kext_map(fsize);
12295 if (pagealigned_addr == 0) {
12296 return kOSKextReturnNoMemory;
12297 }
12298
12299 *mhp = (kernel_mach_header_t *)pagealigned_addr;
12300
12301 /* Allocate memory for bailout mechanism */
12302 map_entry_list = allocate_kcfileset_map_entry_list();
12303 if (map_entry_list == NULL) {
12304 return kOSKextReturnNoMemory;
12305 }
12306 }
12307
12308 uintptr_t *slideptr = fileset_load ? slidep : NULL;
12309 err = mapKCTextSegment(control, mhp, file_offset, slideptr, map_entry_list);
12310 /* mhp and slideptr are updated by mapKCTextSegment */
12311 if (err) {
12312 if (fileset_load) {
12313 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12314 }
12315 return err;
12316 }
12317
12318 /* Initialize the kc header globals */
12319 if (fileset_load) {
12320 if (pageable) {
12321 PE_set_kc_header(KCKindPageable, *mhp, *slidep);
12322 } else {
12323 PE_set_kc_header(KCKindAuxiliary, *mhp, *slidep);
12324 }
12325 }
12326
12327 /* Iterate through all the segments and map necessary segments */
12328 struct load_command *lcp = (struct load_command *) (*mhp + 1);
12329 for (unsigned int i = 0; i < (*mhp)->ncmds; i++, lcp = (struct load_command *)((uintptr_t)lcp + lcp->cmdsize)) {
12330 vm_map_offset_t start;
12331 kernel_mach_header_t *k_mh = NULL;
12332 kernel_segment_command_t * seg = NULL;
12333 struct fileset_entry_command *fse = NULL;
12334
12335 if (lcp->cmd == LC_SEGMENT_KERNEL) {
12336 seg = (kernel_segment_command_t *)lcp;
12337 start = ((uintptr_t)(seg->vmaddr)) + *slidep;
12338 } else if (lcp->cmd == LC_FILESET_ENTRY) {
12339 fse = (struct fileset_entry_command *)lcp;
12340 k_mh = (kernel_mach_header_t *)(((uintptr_t)(fse->vmaddr)) + *slidep);
12341
12342 /* Map the segments of the mach-o binary */
12343 err = OSKext::mapKCFileSet(control, 0, &k_mh, fse->fileoff, slidep, pageable, map_entry_list);
12344 if (err) {
12345 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12346 return kOSKextReturnInvalidArgument;
12347 }
12348 continue;
12349 } else if (lcp->cmd == LC_DYLD_CHAINED_FIXUPS) {
12350 /* Check if the Aux KC is built pageable style */
12351 if (!pageable && !fileset_load && !auxKCloaded) {
12352 resetAuxKCSegmentOnUnload = true;
12353 }
12354 continue;
12355 } else {
12356 continue;
12357 }
12358
12359 if (fileset_load) {
12360 if (seg->vmsize == 0) {
12361 continue;
12362 }
12363
12364 /* Only map __PRELINK_INFO, __BRANCH_STUBS, __BRANCH_GOTS and __LINKEDIT sections */
12365 if (strncmp(seg->segname, kPrelinkInfoSegment, sizeof(seg->segname)) != 0 &&
12366 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) != 0 &&
12367 strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) != 0 &&
12368 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0) {
12369 continue;
12370 }
12371 } else {
12372 if (seg->vmsize == 0) {
12373 continue;
12374 }
12375
12376 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
12377 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
12378 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
12379 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
12380 continue;
12381 }
12382 }
12383
12384 ret = vm_map_kcfileset_segment(
12385 &start, seg->vmsize,
12386 (memory_object_control_t)control, seg->fileoff, seg->maxprot);
12387
12388 if (ret != KERN_SUCCESS) {
12389 if (fileset_load) {
12390 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12391 }
12392 return kOSKextReturnInvalidArgument;
12393 }
12394 add_kcfileset_map_entry(map_entry_list, start, seg->vmsize);
12395 }
12396
12397 /* Return if regular mach-o */
12398 if (!fileset_load) {
12399 return 0;
12400 }
12401
12402 /*
12403 * Fixup for the Pageable KC and the Aux KC is done by
12404 * i386_slide_kext_collection_mh_addrs, but it differs in
12405 * following ways:
12406 *
12407 * PageableKC: Fixup only __BRANCH_STUBS segment and top level load commands.
12408 * The fixup of kext segments and kext load commands are done at kext
12409 * load time by calling i386_slide_individual_kext.
12410 *
12411 * AuxKC old style: Fixup all the segments and all the load commands.
12412 *
12413 * AuxKC pageable style: Same as the Pageable KC.
12414 */
12415 bool adjust_mach_header = (pageable ? true : ((resetAuxKCSegmentOnUnload) ? true : false));
12416 ret = i386_slide_kext_collection_mh_addrs(*mhp, *slidep, adjust_mach_header);
12417 if (ret != KERN_SUCCESS) {
12418 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12419 return kOSKextReturnInvalidArgument;
12420 }
12421
12422 /* Get the prelink info dictionary */
12423 infoPlistSection = getsectbynamefromheader(*mhp, kPrelinkInfoSegment, kPrelinkInfoSection);
12424 parsedXML = OSUnserializeXML((const char *)infoPlistSection->addr, errorString);
12425 if (parsedXML) {
12426 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
12427 }
12428
12429 if (!infoDict) {
12430 const char *errorCString = "(unknown error)";
12431
12432 if (errorString && errorString->getCStringNoCopy()) {
12433 errorCString = errorString->getCStringNoCopy();
12434 } else if (parsedXML) {
12435 errorCString = "not a dictionary";
12436 }
12437 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12438 "Error unserializing kext info plist section: %s.", errorCString);
12439 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12440 return kOSKextReturnInvalidArgument;
12441 }
12442
12443 /* Validate that the Kext Collection is prelinked to the loaded KC */
12444 err = OSKext::validateKCFileSetUUID(infoDict, pageable ? KCKindPageable : KCKindAuxiliary);
12445 if (err) {
12446 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12447 return kOSKextReturnInvalidArgument;
12448 }
12449
12450 /* Set Protection of Segments */
12451 OSKext::protectKCFileSet(*mhp, pageable ? KCKindPageable : KCKindAuxiliary);
12452
12453 OSKext::addKextsFromKextCollection(*mhp,
12454 infoDict, kPrelinkTextSegment,
12455 loaded_kcUUID, pageable ? KCKindPageable : KCKindAuxiliary);
12456
12457 /* Copy in the KC UUID */
12458 if (!loaded_kcUUID) {
12459 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12460 "WARNING: did not find UUID in prelinked %s KC!", pageable ? "Pageable" : "Aux");
12461 } else if (pageable) {
12462 pageablekc_uuid_valid = TRUE;
12463 memcpy((void *)&pageablekc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
12464 uuid_unparse_upper(pageablekc_uuid, pageablekc_uuid_string);
12465 } else {
12466 auxkc_uuid_valid = TRUE;
12467 memcpy((void *)&auxkc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
12468 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
12469 }
12470
12471 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, FALSE, pageable);
12472
12473 return 0;
12474}
12475
12476/*********************************************************************
12477* Assumes sKextLock is held.
12478*********************************************************************/
12479/* static */
12480OSReturn
12481OSKext::mapKCTextSegment(
12482 void *control,
12483 kernel_mach_header_t **mhp,
12484 off_t file_offset,
12485 uintptr_t *slidep,
12486 void *map_entry_list)
12487{
12488 kern_return_t ret;
12489 vm_map_offset_t mach_header_map_size = vm_map_round_page(sizeof(kernel_mach_header_t),
12490 PAGE_MASK);
12491 vm_map_offset_t load_command_map_size = 0;
12492 kernel_mach_header_t *base_mh = *mhp;
12493
12494 /* Map the mach header at start of fileset for now (vmaddr = 0) */
12495 ret = vm_map_kcfileset_segment(
12496 (vm_map_offset_t *)&base_mh, mach_header_map_size,
12497 (memory_object_control_t)control, file_offset, (VM_PROT_READ | VM_PROT_WRITE));
12498
12499 if (ret != KERN_SUCCESS) {
12500 printf("Kext Log: mapKCTextSegment failed to map mach header of fileset %x", ret);
12501
12502 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12503 "Failed to map mach header of kc fileset with error %d", ret);
12504 return kOSKextReturnInvalidArgument;
12505 }
12506
12507 if (slidep) {
12508 /* Verify that it's an MH_FILESET */
12509 if (base_mh->filetype != MH_FILESET) {
12510 printf("Kext Log: mapKCTextSegment mach header filetype"
12511 " is not an MH_FILESET, it is %x", base_mh->filetype);
12512
12513 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12514 "mapKCTextSegment mach header filetype is not an MH_FILESET, it is %x", base_mh->filetype);
12515
12516 /* Unmap the mach header */
12517 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12518 return kOSKextReturnInvalidArgument;
12519 }
12520 }
12521
12522 /* Map the remaining pages of load commands */
12523 if (base_mh->sizeofcmds > mach_header_map_size) {
12524 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
12525 load_command_map_size = base_mh->sizeofcmds - mach_header_map_size;
12526
12527 /* Map the load commands */
12528 ret = vm_map_kcfileset_segment(
12529 &load_command_addr, load_command_map_size,
12530 (memory_object_control_t)control, file_offset + mach_header_map_size,
12531 (VM_PROT_READ | VM_PROT_WRITE));
12532
12533 if (ret != KERN_SUCCESS) {
12534 printf("KextLog: mapKCTextSegment failed to map load commands of fileset %x", ret);
12535 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12536 "Failed to map load commands of kc fileset with error %d", ret);
12537
12538 /* Unmap the mach header */
12539 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12540 return kOSKextReturnInvalidArgument;
12541 }
12542 }
12543
12544 kernel_segment_command_t *text_seg;
12545 text_seg = getsegbynamefromheader((kernel_mach_header_t *)base_mh, SEG_TEXT);
12546
12547 /* Calculate the slide and vm addr of mach header */
12548 if (slidep) {
12549 *mhp = (kernel_mach_header_t *)((uintptr_t)base_mh + text_seg->vmaddr);
12550 *slidep = ((uintptr_t)*mhp) - text_seg->vmaddr;
12551 }
12552
12553 /* Cache the text segment size and file offset before unmapping */
12554 vm_map_offset_t text_segment_size = text_seg->vmsize;
12555 vm_object_offset_t text_segment_fileoff = text_seg->fileoff;
12556 vm_prot_t text_maxprot = text_seg->maxprot;
12557
12558 /* Unmap the first page and loadcommands and map the text segment */
12559 ret = vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12560 assert(ret == KERN_SUCCESS);
12561
12562 if (load_command_map_size) {
12563 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
12564 ret = vm_unmap_kcfileset_segment(&load_command_addr, load_command_map_size);
12565 assert(ret == KERN_SUCCESS);
12566 }
12567
12568 /* Map the text segment at actual vm addr specified in fileset */
12569 ret = vm_map_kcfileset_segment((vm_map_offset_t *)mhp, text_segment_size,
12570 (memory_object_control_t)control, text_segment_fileoff, text_maxprot);
12571 if (ret != KERN_SUCCESS) {
12572 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12573 "Failed to map Text segment of kc fileset with error %d", ret);
12574 return kOSKextReturnInvalidArgument;
12575 }
12576
12577 add_kcfileset_map_entry(map_entry_list, (vm_map_offset_t)*mhp, text_segment_size);
12578 return 0;
12579}
12580
12581/*********************************************************************
12582* Assumes sKextLock is held.
12583*********************************************************************/
12584/* static */
12585OSReturn
12586OSKext::protectKCFileSet(
12587 kernel_mach_header_t *mh,
12588 kc_kind_t type)
12589{
12590 vm_map_t kext_map = g_kext_map;
12591 kernel_segment_command_t * seg = NULL;
12592 vm_map_offset_t start = 0;
12593 vm_map_offset_t end = 0;
12594 OSReturn ret = 0;
12595
12596 /* Set VM permissions */
12597 seg = firstsegfromheader((kernel_mach_header_t *)mh);
12598 while (seg) {
12599 start = round_page(seg->vmaddr);
12600 end = trunc_page(seg->vmaddr + seg->vmsize);
12601
12602 /*
12603 * Wire down and protect __TEXT, __BRANCH_STUBS and __BRANCH_GOTS
12604 * for the Pageable KC and the Aux KC, wire down and protect __LINKEDIT
12605 * for the Aux KC as well.
12606 */
12607 if (strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) == 0 ||
12608 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) == 0 ||
12609 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0 ||
12610 (type == KCKindAuxiliary && !resetAuxKCSegmentOnUnload &&
12611 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0)) {
12612 ret = OSKext_protect((kernel_mach_header_t *)mh,
12613 kext_map, start, end, seg->maxprot, TRUE, type);
12614 if (ret != KERN_SUCCESS) {
12615 printf("OSKext protect failed with error %d", ret);
12616 return kOSKextReturnInvalidArgument;
12617 }
12618
12619 ret = OSKext_protect((kernel_mach_header_t *)mh,
12620 kext_map, start, end, seg->initprot, FALSE, type);
12621 if (ret != KERN_SUCCESS) {
12622 printf("OSKext protect failed with error %d", ret);
12623 return kOSKextReturnInvalidArgument;
12624 }
12625
12626 ret = OSKext_wire((kernel_mach_header_t *)mh,
12627 kext_map, start, end, seg->initprot, FALSE, type);
12628 if (ret != KERN_SUCCESS) {
12629 printf("OSKext wire failed with error %d", ret);
12630 return kOSKextReturnInvalidArgument;
12631 }
12632 }
12633
12634 seg = nextsegfromheader((kernel_mach_header_t *) mh, seg);
12635 }
12636
12637 return 0;
12638}
12639
12640/*********************************************************************
12641* Assumes sKextLock is held.
12642*********************************************************************/
12643/* static */
12644void
12645OSKext::freeKCFileSetcontrol(void)
12646{
12647 PE_reset_all_kc_vp();
12648}
12649
12650/*********************************************************************
12651* Assumes sKextLock is held.
12652*
12653* resetKCFileSetSegments: Kext start function expects data segment to
12654* be pristine on every load, unmap the dirty segments on unload and
12655* remap them from FileSet on disk. Remap all segments of kext since
12656* fixups are done per kext and not per segment.
12657*********************************************************************/
12658OSReturn
12659OSKext::resetKCFileSetSegments(void)
12660{
12661 kernel_segment_command_t *seg = NULL;
12662 kernel_segment_command_t *text_seg;
12663 uint32_t text_fileoff;
12664 kernel_mach_header_t *k_mh = NULL;
12665 uintptr_t slide;
12666 struct vnode *vp = NULL;
12667 void *fileset_control = NULL;
12668 bool pageable = (kc_type == KCKindPageable);
12669 OSReturn err;
12670 kern_return_t kr;
12671
12672 /* Check the vnode reference is still available */
12673 vp = (struct vnode *)PE_get_kc_vp(kc_type);
12674 if (vp == NULL) {
12675 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
12676 "Kext %s could not be reset, since reboot released the vnode ref", getIdentifierCString());
12677 return kOSKextReturnInternalError;
12678 }
12679
12680 fileset_control = ubc_getobject(vp, 0);
12681 assert(fileset_control != NULL);
12682
12683 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
12684 "Kext %s resetting all segments", getIdentifierCString());
12685
12686 k_mh = (kernel_mach_header_t *)kmod_info->address;
12687 text_seg = getsegbynamefromheader((kernel_mach_header_t *)kmod_info->address, SEG_TEXT);
12688 text_fileoff = text_seg->fileoff;
12689 slide = PE_get_kc_slide(kc_type);
12690
12691 seg = firstsegfromheader((kernel_mach_header_t *)k_mh);
12692 while (seg) {
12693 if (seg->vmsize == 0) {
12694 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12695 continue;
12696 }
12697
12698 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
12699 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
12700 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
12701 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
12702 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12703 continue;
12704 }
12705
12706 kr = vm_unmap_kcfileset_segment(&seg->vmaddr, seg->vmsize);
12707 assert(kr == KERN_SUCCESS);
12708 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12709 }
12710
12711 /* Unmap the text segment */
12712 kr = vm_unmap_kcfileset_segment(&text_seg->vmaddr, text_seg->vmsize);
12713 assert(kr == KERN_SUCCESS);
12714
12715 /* Map all the segments of the kext */
12716 err = OSKext::mapKCFileSet(fileset_control, 0, &k_mh, text_fileoff, &slide, pageable, NULL);
12717 if (err) {
12718 panic("Could not reset segments of a mapped kext, error %x", err);
12719 }
12720
12721 /* Update address in kmod_info, since it has been reset */
12722 if (kmod_info->address) {
12723 kmod_info->address = (((uintptr_t)(kmod_info->address)) + slide);
12724 }
12725
12726 return 0;
12727}
12728
12729/*********************************************************************
12730* Mechanism to track all segment mapping while mapping KC fileset.
12731*********************************************************************/
12732
12733struct kcfileset_map_entry {
12734 vm_map_offset_t me_start;
12735 vm_map_offset_t me_size;
12736};
12737
12738struct kcfileset_map_entry_list {
12739 int kme_list_count;
12740 int kme_list_index;
12741 struct kcfileset_map_entry kme_list[];
12742};
12743
12744#define KCFILESET_MAP_ENTRY_MAX (16380)
12745
12746static void *
12747allocate_kcfileset_map_entry_list(void)
12748{
12749 struct kcfileset_map_entry_list *entry_list;
12750
12751 entry_list = (struct kcfileset_map_entry_list *)kalloc(sizeof(struct kcfileset_map_entry_list) +
12752 (sizeof(struct kcfileset_map_entry) * KCFILESET_MAP_ENTRY_MAX));
12753
12754 entry_list->kme_list_count = KCFILESET_MAP_ENTRY_MAX;
12755 entry_list->kme_list_index = 0;
12756 return entry_list;
12757}
12758
12759static void
12760add_kcfileset_map_entry(
12761 void *map_entry_list,
12762 vm_map_offset_t start,
12763 vm_map_offset_t size)
12764{
12765 if (map_entry_list == NULL) {
12766 return;
12767 }
12768
12769 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
12770
12771 if (entry_list->kme_list_index >= entry_list->kme_list_count) {
12772 panic("Ran out of map kc fileset list\n");
12773 }
12774
12775 entry_list->kme_list[entry_list->kme_list_index].me_start = start;
12776 entry_list->kme_list[entry_list->kme_list_index].me_size = size;
12777
12778 entry_list->kme_list_index++;
12779}
12780
12781static void
12782deallocate_kcfileset_map_entry_list_and_unmap_entries(
12783 void *map_entry_list,
12784 boolean_t unmap_entries,
12785 bool pageable)
12786{
12787 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
12788
12789 if (unmap_entries) {
12790 for (int i = 0; i < entry_list->kme_list_index; i++) {
12791 kern_return_t ret;
12792 ret = vm_unmap_kcfileset_segment(
12793 &(entry_list->kme_list[i].me_start),
12794 entry_list->kme_list[i].me_size);
12795 assert(ret == KERN_SUCCESS);
12796 }
12797
12798 PE_reset_kc_header(pageable ? KCKindPageable : KCKindAuxiliary);
cb323159 12799 }
f427ee49
A
12800
12801 kfree(entry_list, sizeof(struct kcfileset_map_entry_list) +
12802 (sizeof(struct kcfileset_map_entry) * KCFILESET_MAP_ENTRY_MAX));
cb323159
A
12803}
12804
b0d623f7 12805/*********************************************************************
f427ee49 12806* Mechanism to map kext segment.
b0d623f7 12807*********************************************************************/
f427ee49
A
12808
12809kern_return_t
12810vm_map_kcfileset_segment(
12811 vm_map_offset_t *start,
12812 vm_map_offset_t size,
12813 void *control,
12814 vm_object_offset_t fileoffset,
12815 vm_prot_t max_prot)
b0d623f7 12816{
f427ee49
A
12817 vm_map_kernel_flags_t vmk_flags;
12818 vmk_flags.vmkf_no_copy_on_read = 1;
12819 vmk_flags.vmkf_cs_enforcement = 0;
12820 vmk_flags.vmkf_cs_enforcement_override = 1;
12821 kern_return_t ret;
b0d623f7 12822
f427ee49
A
12823 /* Add Write to max prot to allow fixups */
12824 max_prot = max_prot | VM_PROT_WRITE;
b0d623f7 12825
f427ee49
A
12826 /*
12827 * Map the segments from file as COPY mappings to
12828 * make sure changes on disk to the file does not affect
12829 * mapped segments.
12830 */
12831 ret = vm_map_enter_mem_object_control(
12832 g_kext_map,
12833 start,
12834 size,
12835 (mach_vm_offset_t)0,
12836 VM_FLAGS_FIXED,
12837 vmk_flags,
12838 VM_KERN_MEMORY_OSKEXT,
12839 (memory_object_control_t)control,
12840 fileoffset,
12841 TRUE, /* copy */
12842 (VM_PROT_READ | VM_PROT_WRITE), max_prot,
12843 VM_INHERIT_NONE);
b0d623f7 12844
f427ee49
A
12845 return ret;
12846}
b0d623f7 12847
f427ee49
A
12848kern_return_t
12849vm_unmap_kcfileset_segment(
12850 vm_map_offset_t *start,
12851 vm_map_offset_t size)
12852{
12853 return mach_vm_deallocate(g_kext_map, *start, size);
b0d623f7
A
12854}
12855
f427ee49
A
12856#endif //(__x86_64__) || defined(__i386__)
12857
b0d623f7 12858/*********************************************************************
6d2010ae 12859* Assumes sKextLock is held.
b0d623f7
A
12860*********************************************************************/
12861/* static */
12862OSReturn
f427ee49
A
12863OSKext::validateKCFileSetUUID(
12864 OSDictionary *infoDict,
12865 kc_kind_t type)
0a7de745 12866{
f427ee49 12867 OSReturn ret = kOSReturnSuccess;
0a7de745 12868
f427ee49
A
12869 if (!kernelcache_uuid_valid) {
12870 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12871 "validateKCFileSetUUID Boot KC UUID was not set at boot.");
12872 ret = kOSKextReturnInvalidArgument;
12873 goto finish;
12874 }
12875 ret = OSKext::validateKCUUIDfromPrelinkInfo(&kernelcache_uuid, type, infoDict, kPrelinkInfoBootKCIDKey);
12876 if (ret != 0) {
12877 goto finish;
12878 }
0a7de745 12879
f427ee49
A
12880#if defined(__x86_64__) || defined(__i386__)
12881 /* Check if the Aux KC is prelinked to correct Pageable KC */
12882 if (type == KCKindAuxiliary) {
12883 if (!pageablekc_uuid_valid) {
12884 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12885 "validateKCFileSetUUID Pageable KC UUID was not set while loading Pageable KC.");
12886 ret = kOSKextReturnInvalidArgument;
0a7de745
A
12887 goto finish;
12888 }
f427ee49
A
12889 ret = OSKext::validateKCUUIDfromPrelinkInfo(&pageablekc_uuid, type, infoDict, kPrelinkInfoPageableKCIDKey);
12890 if (ret != 0) {
0a7de745
A
12891 goto finish;
12892 }
12893 }
f427ee49 12894#endif //(__x86_64__) || defined(__i386__)
b0d623f7 12895
f427ee49 12896 printf("KextLog: Collection UUID matches with loaded KCs.\n");
b0d623f7 12897finish:
f427ee49 12898 return ret;
b0d623f7
A
12899}
12900
5ba3f43e 12901/*********************************************************************
f427ee49 12902* Assumes sKextLock is held.
5ba3f43e
A
12903*********************************************************************/
12904/* static */
f427ee49
A
12905OSReturn
12906OSKext::validateKCUUIDfromPrelinkInfo(
12907 uuid_t *loaded_kcuuid,
12908 kc_kind_t type,
12909 OSDictionary *infoDict,
12910 const char *uuid_key)
12911{
12912 /* extract the UUID from the dictionary */
12913 OSData *prelinkinfoKCUUID = OSDynamicCast(OSData, infoDict->getObject(uuid_key));
12914 if (!prelinkinfoKCUUID) {
12915 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12916 "validateKCUUID Info plist does not contain %s KC UUID key.", uuid_key);
12917 return kOSKextReturnInvalidArgument;
12918 }
12919
12920 if (prelinkinfoKCUUID->getLength() != sizeof(uuid_t)) {
12921 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12922 "validateKCUUID %s KC UUID has wrong length: %d.", uuid_key, prelinkinfoKCUUID->getLength());
12923 return kOSKextReturnInvalidArgument;
12924 }
12925
12926 if (memcmp((void *)loaded_kcuuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(),
12927 prelinkinfoKCUUID->getLength())) {
12928 OSData *info_dict_uuid;
12929 uuid_string_t info_dict_uuid_str = {};
12930 uuid_string_t expected_uuid_str = {};
12931 uuid_string_t given_uuid_str = {};
12932 uuid_t given_uuid;
12933
12934 /* extract the KC UUID from the dictionary */
12935 info_dict_uuid = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
12936 if (info_dict_uuid && info_dict_uuid->getLength() == sizeof(uuid_t)) {
12937 uuid_t tmp_uuid;
12938 memcpy(tmp_uuid, (const void *)info_dict_uuid->getBytesNoCopy(), sizeof(tmp_uuid));
12939 uuid_unparse(tmp_uuid, info_dict_uuid_str);
12940 }
12941
12942 uuid_unparse(*loaded_kcuuid, expected_uuid_str);
12943 memcpy(given_uuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(), sizeof(given_uuid));
12944 uuid_unparse(given_uuid, given_uuid_str);
12945
12946 printf("KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
12947 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
12948 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12949 "KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
12950 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
12951 if (type == KCKindPageable && sPanicOnKCMismatch) {
12952 panic("System KC UUID %s linked against %s, but %s is loaded",
12953 info_dict_uuid_str, given_uuid_str, expected_uuid_str);
12954 }
12955 return kOSKextReturnInvalidArgument;
12956 }
12957
12958 return 0;
5ba3f43e
A
12959}
12960
b0d623f7 12961/*********************************************************************
6d2010ae 12962* Assumes sKextLock is held.
b0d623f7
A
12963*********************************************************************/
12964/* static */
12965OSReturn
12966OSKext::dispatchResource(OSDictionary * requestDict)
12967{
0a7de745 12968 OSReturn result = kOSReturnError;
f427ee49
A
12969 OSSharedPtr<OSDictionary> callbackRecord;
12970 OSNumber * requestTag = NULL; // do not release
12971 OSNumber * requestResult = NULL; // do not release
12972 OSData * dataObj = NULL; // do not release
0a7de745 12973 uint32_t dataLength = 0;
f427ee49
A
12974 const void * dataPtr = NULL; // do not free
12975 OSData * callbackWrapper = NULL; // do not release
0a7de745 12976 OSKextRequestResourceCallback callback = NULL;
f427ee49
A
12977 OSData * contextWrapper = NULL; // do not release
12978 void * context = NULL; // do not free
12979 OSSharedPtr<OSKext> callbackKext;
0a7de745
A
12980
12981 /* Get the args from the request. Right now we need the tag
12982 * to look up the callback record, and the result for invoking the callback.
12983 */
12984 requestTag = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
12985 kKextRequestArgumentRequestTagKey));
12986 requestResult = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
12987 kKextRequestArgumentResultKey));
12988 if (!requestTag || !requestResult) {
12989 result = kOSKextReturnInvalidArgument;
12990 goto finish;
12991 }
12992
12993 /* Look for a callback record matching this request's tag.
12994 */
f427ee49 12995 result = dequeueCallbackForRequestTag(requestTag, callbackRecord);
0a7de745
A
12996 if (result != kOSReturnSuccess) {
12997 goto finish;
12998 }
12999
13000 /*****
13001 * Get the context pointer of the callback record (if there is one).
13002 */
f427ee49 13003 contextWrapper = OSDynamicCast(OSData, _OSKextGetRequestArgument(callbackRecord.get(),
0a7de745
A
13004 kKextRequestArgumentContextKey));
13005 context = _OSKextExtractPointer(contextWrapper);
13006 if (contextWrapper && !context) {
13007 goto finish;
13008 }
13009
13010 callbackWrapper = OSDynamicCast(OSData,
f427ee49 13011 _OSKextGetRequestArgument(callbackRecord.get(),
0a7de745 13012 kKextRequestArgumentCallbackKey));
f427ee49 13013 callback = _OSKextExtractCallbackPointer(callbackWrapper);
0a7de745
A
13014 if (!callback) {
13015 goto finish;
13016 }
13017
13018 /* Check for a data obj. We might not have one and that's ok, that means
13019 * we didn't find the requested resource, and we still have to tell the
13020 * caller that via the callback.
13021 */
13022 dataObj = OSDynamicCast(OSData, _OSKextGetRequestArgument(requestDict,
13023 kKextRequestArgumentValueKey));
13024 if (dataObj) {
13025 dataPtr = dataObj->getBytesNoCopy();
13026 dataLength = dataObj->getLength();
13027 }
13028
13029 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
13030 if (!callbackKext) {
13031 OSKextLog(/* kext */ NULL,
13032 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13033 "Can't invoke callback for resource request; ");
13034 goto finish;
13035 }
13036 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
13037 OSKextLog(/* kext */ NULL,
13038 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13039 "Can't invoke kext resource callback; ");
13040 goto finish;
13041 }
13042
13043 (void)callback(requestTag->unsigned32BitValue(),
13044 (OSReturn)requestResult->unsigned32BitValue(),
13045 dataPtr, dataLength, context);
13046
13047 result = kOSReturnSuccess;
b0d623f7
A
13048
13049finish:
f427ee49
A
13050 return result;
13051}
13052
13053/*********************************************************************
13054* Assumes sKextLock is held.
13055*********************************************************************/
13056/* static */
13057OSReturn
13058OSKext::setMissingAuxKCBundles(OSDictionary * requestDict)
13059{
13060 OSSharedPtr<OSDictionary> missingIDs;
13061 OSArray *bundleIDList = NULL; // do not release
13062
13063 bundleIDList = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
13064 requestDict, kKextRequestArgumentMissingBundleIDs));
13065 if (!bundleIDList) {
13066 return kOSKextReturnInvalidArgument;
13067 }
13068
13069 missingIDs = OSDictionary::withCapacity(bundleIDList->getCount());
13070 if (!missingIDs) {
13071 return kOSKextReturnNoMemory;
0a7de745 13072 }
f427ee49
A
13073
13074 uint32_t count, i;
13075 count = bundleIDList->getCount();
13076 for (i = 0; i < count; i++) {
13077 OSString *thisID = OSDynamicCast(OSString, bundleIDList->getObject(i));
13078 if (thisID) {
13079 missingIDs->setObject(thisID, kOSBooleanFalse);
13080 }
0a7de745 13081 }
b0d623f7 13082
f427ee49
A
13083 sNonLoadableKextsByID.reset(missingIDs.get(), OSRetain);
13084
13085 return kOSReturnSuccess;
13086}
13087
13088/*********************************************************************
13089* Assumes sKextLock is held.
13090*********************************************************************/
13091/* static */
13092OSReturn
13093OSKext::setAuxKCBundleAvailable(OSString *kextIdentifier, OSDictionary *requestDict)
13094{
13095 bool loadable = true;
13096 if (!kextIdentifier) {
13097 return kOSKextReturnInvalidArgument;
13098 }
13099
13100 if (requestDict) {
13101 OSBoolean *loadableArg;
13102 loadableArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
13103 requestDict, kKextRequestArgumentBundleAvailability));
13104 /* If we find the "Bundle Available" arg, and it's false, then
13105 * mark the bundle ID as _not_ loadable
13106 */
13107 if (loadableArg && !loadableArg->getValue()) {
13108 loadable = false;
13109 }
13110 }
13111
13112 if (!sNonLoadableKextsByID) {
13113 sNonLoadableKextsByID = OSDictionary::withCapacity(1);
13114 }
13115
13116 sNonLoadableKextsByID->setObject(kextIdentifier, OSBoolean::withBoolean(loadable));
13117
13118 OSKextLog(/* kext */ NULL,
13119 kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13120 "KextLog: AuxKC bundle %s marked as %s",
13121 kextIdentifier->getCStringNoCopy(),
13122 (loadable ? "loadable" : "NOT loadable"));
13123
13124 return kOSReturnSuccess;
b0d623f7
A
13125}
13126
13127/*********************************************************************
13128*********************************************************************/
13129/* static */
13130void
13131OSKext::invokeRequestCallback(
0a7de745
A
13132 OSDictionary * callbackRecord,
13133 OSReturn callbackResult)
13134{
13135 OSString * predicate = _OSKextGetRequestPredicate(callbackRecord);
f427ee49 13136 OSSharedPtr<OSNumber> resultNum;
0a7de745
A
13137
13138 if (!predicate) {
13139 goto finish;
13140 }
13141
13142 resultNum = OSNumber::withNumber((long long unsigned int)callbackResult,
13143 8 * sizeof(callbackResult));
13144 if (!resultNum) {
13145 goto finish;
13146 }
13147
13148 /* Insert the result into the callback record and dispatch it as if it
13149 * were the reply coming down from user space.
13150 */
13151 _OSKextSetRequestArgument(callbackRecord, kKextRequestArgumentResultKey,
f427ee49 13152 resultNum.get());
0a7de745
A
13153
13154 if (predicate->isEqualTo(kKextRequestPredicateRequestResource)) {
13155 /* This removes the pending callback record.
13156 */
13157 OSKext::dispatchResource(callbackRecord);
13158 }
b0d623f7
A
13159
13160finish:
0a7de745 13161 return;
b0d623f7
A
13162}
13163
13164/*********************************************************************
6d2010ae 13165* Assumes sKextLock is held.
b0d623f7
A
13166*********************************************************************/
13167/* static */
13168OSReturn
13169OSKext::cancelRequest(
0a7de745
A
13170 OSKextRequestTag requestTag,
13171 void ** contextOut)
13172{
13173 OSReturn result = kOSKextReturnNoMemory;
f427ee49
A
13174 OSSharedPtr<OSDictionary> callbackRecord;
13175 OSData * contextWrapper = NULL; // do not release
0a7de745
A
13176
13177 IORecursiveLockLock(sKextLock);
13178 result = OSKext::dequeueCallbackForRequestTag(requestTag,
f427ee49 13179 callbackRecord);
0a7de745
A
13180 IORecursiveLockUnlock(sKextLock);
13181
13182 if (result == kOSReturnSuccess && contextOut) {
13183 contextWrapper = OSDynamicCast(OSData,
f427ee49 13184 _OSKextGetRequestArgument(callbackRecord.get(),
0a7de745
A
13185 kKextRequestArgumentContextKey));
13186 *contextOut = _OSKextExtractPointer(contextWrapper);
13187 }
6d2010ae 13188
0a7de745 13189 return result;
b0d623f7
A
13190}
13191
13192/*********************************************************************
6d2010ae 13193* Assumes sKextLock is held.
b0d623f7
A
13194*********************************************************************/
13195void
13196OSKext::invokeOrCancelRequestCallbacks(
0a7de745
A
13197 OSReturn callbackResult,
13198 bool invokeFlag)
13199{
13200 unsigned int count, i;
13201
13202 count = sRequestCallbackRecords->getCount();
13203 if (!count) {
13204 goto finish;
13205 }
13206
13207 i = count - 1;
13208 do {
13209 OSDictionary * request = OSDynamicCast(OSDictionary,
13210 sRequestCallbackRecords->getObject(i));
13211
13212 if (!request) {
13213 continue;
13214 }
13215 OSData * callbackWrapper = OSDynamicCast(OSData,
13216 _OSKextGetRequestArgument(request,
13217 kKextRequestArgumentCallbackKey));
13218
13219 if (!callbackWrapper) {
13220 sRequestCallbackRecords->removeObject(i);
13221 continue;
13222 }
13223
13224 vm_address_t callbackAddress = (vm_address_t)
f427ee49 13225 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
0a7de745
A
13226
13227 if ((kmod_info->address <= callbackAddress) &&
13228 (callbackAddress < (kmod_info->address + kmod_info->size))) {
13229 if (invokeFlag) {
13230 /* This removes the callback record.
13231 */
13232 invokeRequestCallback(request, callbackResult);
13233 } else {
13234 sRequestCallbackRecords->removeObject(i);
13235 }
13236 }
13237 } while (i--);
b0d623f7
A
13238
13239finish:
0a7de745 13240 return;
b0d623f7
A
13241}
13242
13243/*********************************************************************
6d2010ae 13244* Assumes sKextLock is held.
b0d623f7
A
13245*********************************************************************/
13246uint32_t
13247OSKext::countRequestCallbacks(void)
13248{
0a7de745
A
13249 uint32_t result = 0;
13250 unsigned int count, i;
13251
13252 count = sRequestCallbackRecords->getCount();
13253 if (!count) {
13254 goto finish;
13255 }
13256
13257 i = count - 1;
13258 do {
13259 OSDictionary * request = OSDynamicCast(OSDictionary,
13260 sRequestCallbackRecords->getObject(i));
13261
13262 if (!request) {
13263 continue;
13264 }
13265 OSData * callbackWrapper = OSDynamicCast(OSData,
13266 _OSKextGetRequestArgument(request,
13267 kKextRequestArgumentCallbackKey));
13268
13269 if (!callbackWrapper) {
13270 continue;
13271 }
13272
13273 vm_address_t callbackAddress = (vm_address_t)
f427ee49 13274 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
0a7de745
A
13275
13276 if ((kmod_info->address <= callbackAddress) &&
13277 (callbackAddress < (kmod_info->address + kmod_info->size))) {
13278 result++;
13279 }
13280 } while (i--);
b0d623f7
A
13281
13282finish:
0a7de745 13283 return result;
b0d623f7
A
13284}
13285
13286/*********************************************************************
13287*********************************************************************/
0a7de745
A
13288static OSReturn
13289_OSKextCreateRequest(
13290 const char * predicate,
f427ee49 13291 OSSharedPtr<OSDictionary> & requestR)
0a7de745
A
13292{
13293 OSReturn result = kOSKextReturnNoMemory;
f427ee49 13294 OSSharedPtr<OSDictionary> request;
0a7de745
A
13295
13296 request = OSDictionary::withCapacity(2);
13297 if (!request) {
13298 goto finish;
13299 }
f427ee49 13300 result = _OSDictionarySetCStringValue(request.get(),
0a7de745
A
13301 kKextRequestPredicateKey, predicate);
13302 if (result != kOSReturnSuccess) {
13303 goto finish;
13304 }
13305 result = kOSReturnSuccess;
b0d623f7
A
13306
13307finish:
f427ee49
A
13308 if (result == kOSReturnSuccess) {
13309 requestR = os::move(request);
0a7de745 13310 }
b0d623f7 13311
0a7de745 13312 return result;
b0d623f7 13313}
0a7de745 13314
b0d623f7
A
13315/*********************************************************************
13316*********************************************************************/
0a7de745
A
13317static OSString *
13318_OSKextGetRequestPredicate(OSDictionary * requestDict)
b0d623f7 13319{
0a7de745
A
13320 return OSDynamicCast(OSString,
13321 requestDict->getObject(kKextRequestPredicateKey));
b0d623f7
A
13322}
13323
13324/*********************************************************************
13325*********************************************************************/
0a7de745
A
13326static OSObject *
13327_OSKextGetRequestArgument(
13328 OSDictionary * requestDict,
13329 const char * argName)
b0d623f7 13330{
0a7de745
A
13331 OSDictionary * args = OSDynamicCast(OSDictionary,
13332 requestDict->getObject(kKextRequestArgumentsKey));
13333 if (args) {
13334 return args->getObject(argName);
13335 }
13336 return NULL;
b0d623f7
A
13337}
13338
13339/*********************************************************************
13340*********************************************************************/
0a7de745
A
13341static bool
13342_OSKextSetRequestArgument(
13343 OSDictionary * requestDict,
13344 const char * argName,
13345 OSObject * value)
13346{
13347 OSDictionary * args = OSDynamicCast(OSDictionary,
13348 requestDict->getObject(kKextRequestArgumentsKey));
f427ee49 13349 OSSharedPtr<OSDictionary> newArgs;
0a7de745 13350 if (!args) {
f427ee49
A
13351 newArgs = OSDictionary::withCapacity(2);
13352 args = newArgs.get();
0a7de745
A
13353 if (!args) {
13354 goto finish;
13355 }
13356 requestDict->setObject(kKextRequestArgumentsKey, args);
0a7de745
A
13357 }
13358 if (args) {
13359 return args->setObject(argName, value);
13360 }
b0d623f7 13361finish:
0a7de745 13362 return false;
b0d623f7
A
13363}
13364
13365/*********************************************************************
13366*********************************************************************/
0a7de745
A
13367static void *
13368_OSKextExtractPointer(OSData * wrapper)
b0d623f7 13369{
0a7de745
A
13370 void * result = NULL;
13371 const void * resultPtr = NULL;
13372
13373 if (!wrapper) {
13374 goto finish;
13375 }
13376 resultPtr = wrapper->getBytesNoCopy();
13377 result = *(void **)resultPtr;
b0d623f7 13378finish:
0a7de745 13379 return result;
b0d623f7
A
13380}
13381
f427ee49
A
13382/*********************************************************************
13383*********************************************************************/
13384static OSKextRequestResourceCallback
13385_OSKextExtractCallbackPointer(OSData * wrapper)
13386{
13387 OSKextRequestResourceCallback result = NULL;
13388 const void * resultPtr = NULL;
13389
13390 if (!wrapper) {
13391 goto finish;
13392 }
13393 resultPtr = wrapper->getBytesNoCopy();
13394 result = *(OSKextRequestResourceCallback *)resultPtr;
13395finish:
13396 return result;
13397}
13398
13399
b0d623f7
A
13400/*********************************************************************
13401*********************************************************************/
0a7de745
A
13402static OSReturn
13403_OSDictionarySetCStringValue(
13404 OSDictionary * dict,
13405 const char * cKey,
13406 const char * cValue)
13407{
13408 OSReturn result = kOSKextReturnNoMemory;
f427ee49
A
13409 OSSharedPtr<const OSSymbol> key;
13410 OSSharedPtr<OSString> value;
0a7de745
A
13411
13412 key = OSSymbol::withCString(cKey);
13413 value = OSString::withCString(cValue);
13414 if (!key || !value) {
13415 goto finish;
13416 }
f427ee49 13417 if (dict->setObject(key.get(), value.get())) {
0a7de745
A
13418 result = kOSReturnSuccess;
13419 }
b0d623f7
A
13420
13421finish:
0a7de745 13422 return result;
b0d623f7
A
13423}
13424
6d2010ae
A
13425/*********************************************************************
13426*********************************************************************/
0a7de745
A
13427static bool
13428_OSArrayContainsCString(
13429 OSArray * array,
13430 const char * cString)
6d2010ae 13431{
0a7de745 13432 bool result = false;
f427ee49 13433 OSSharedPtr<const OSSymbol> symbol;
0a7de745
A
13434 uint32_t count, i;
13435
13436 if (!array || !cString) {
13437 goto finish;
13438 }
6d2010ae 13439
0a7de745
A
13440 symbol = OSSymbol::withCStringNoCopy(cString);
13441 if (!symbol) {
13442 goto finish;
13443 }
6d2010ae 13444
0a7de745
A
13445 count = array->getCount();
13446 for (i = 0; i < count; i++) {
13447 OSObject * thisObject = array->getObject(i);
13448 if (symbol->isEqualTo(thisObject)) {
13449 result = true;
13450 goto finish;
13451 }
13452 }
6d2010ae
A
13453
13454finish:
0a7de745 13455 return result;
6d2010ae
A
13456}
13457
f427ee49 13458#if CONFIG_KXLD
316670eb 13459/*********************************************************************
0a7de745
A
13460* We really only care about boot / system start up related kexts.
13461* We return true if we're less than REBUILD_MAX_TIME since start up,
13462* otherwise return false.
13463*********************************************************************/
13464bool
13465_OSKextInPrelinkRebuildWindow(void)
13466{
13467 static bool outside_the_window = false;
13468 AbsoluteTime my_abstime;
13469 UInt64 my_ns;
13470 SInt32 my_secs;
13471
13472 if (outside_the_window) {
13473 return false;
13474 }
13475 clock_get_uptime(&my_abstime);
13476 absolutetime_to_nanoseconds(my_abstime, &my_ns);
13477 my_secs = (SInt32)(my_ns / NSEC_PER_SEC);
13478 if (my_secs > REBUILD_MAX_TIME) {
13479 outside_the_window = true;
13480 return false;
13481 }
13482 return true;
316670eb 13483}
f427ee49 13484#endif /* CONFIG_KXLD */
316670eb
A
13485
13486/*********************************************************************
0a7de745
A
13487*********************************************************************/
13488bool
13489_OSKextInUnloadedPrelinkedKexts( const OSSymbol * theBundleID )
13490{
13491 int unLoadedCount, i;
13492 bool result = false;
13493
13494 IORecursiveLockLock(sKextLock);
13495
13496 if (sUnloadedPrelinkedKexts == NULL) {
13497 goto finish;
13498 }
13499 unLoadedCount = sUnloadedPrelinkedKexts->getCount();
13500 if (unLoadedCount == 0) {
13501 goto finish;
13502 }
13503
13504 for (i = 0; i < unLoadedCount; i++) {
f427ee49 13505 const OSSymbol * myBundleID; // do not release
0a7de745
A
13506
13507 myBundleID = OSDynamicCast(OSSymbol, sUnloadedPrelinkedKexts->getObject(i));
13508 if (!myBundleID) {
13509 continue;
13510 }
13511 if (theBundleID->isEqualTo(myBundleID->getCStringNoCopy())) {
13512 result = true;
13513 break;
13514 }
13515 }
316670eb 13516finish:
0a7de745
A
13517 IORecursiveLockUnlock(sKextLock);
13518 return result;
316670eb
A
13519}
13520
b0d623f7
A
13521#if PRAGMA_MARK
13522#pragma mark Personalities (IOKit Drivers)
13523#endif
13524/*********************************************************************
13525*********************************************************************/
13526/* static */
f427ee49 13527OSSharedPtr<OSArray>
b0d623f7
A
13528OSKext::copyAllKextPersonalities(bool filterSafeBootFlag)
13529{
f427ee49
A
13530 OSSharedPtr<OSArray> result;
13531 OSSharedPtr<OSCollectionIterator> kextIterator;
13532 OSSharedPtr<OSArray> personalities;
0a7de745 13533
f427ee49
A
13534 OSString * kextID = NULL; // do not release
13535 OSKext * theKext = NULL; // do not release
0a7de745
A
13536
13537 IORecursiveLockLock(sKextLock);
13538
13539 /* Let's conservatively guess that any given kext has around 3
13540 * personalities for now.
13541 */
13542 result = OSArray::withCapacity(sKextsByID->getCount() * 3);
13543 if (!result) {
13544 goto finish;
13545 }
13546
f427ee49 13547 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
0a7de745
A
13548 if (!kextIterator) {
13549 goto finish;
13550 }
13551
13552 while ((kextID = OSDynamicCast(OSString, kextIterator->getNextObject()))) {
0a7de745 13553 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextID));
f427ee49
A
13554 if (theKext->flags.requireExplicitLoad) {
13555 OSKextLog(theKext,
13556 kOSKextLogDebugLevel |
13557 kOSKextLogLoadFlag,
13558 "Kext %s requires an explicit kextload; "
13559 "omitting its personalities.",
13560 theKext->getIdentifierCString());
13561 } else if (!sSafeBoot || !filterSafeBootFlag || theKext->isLoadableInSafeBoot()) {
0a7de745
A
13562 personalities = theKext->copyPersonalitiesArray();
13563 if (!personalities) {
13564 continue;
13565 }
f427ee49 13566 result->merge(personalities.get());
0a7de745
A
13567 } else {
13568 // xxx - check for better place to put this log msg
13569 OSKextLog(theKext,
13570 kOSKextLogWarningLevel |
13571 kOSKextLogLoadFlag,
13572 "Kext %s is not loadable during safe boot; "
13573 "omitting its personalities.",
13574 theKext->getIdentifierCString());
13575 }
13576 }
b0d623f7
A
13577
13578finish:
0a7de745 13579 IORecursiveLockUnlock(sKextLock);
b0d623f7 13580
0a7de745 13581 return result;
b0d623f7
A
13582}
13583
b0d623f7
A
13584/*********************************************************************
13585*********************************************************************/
13586/* static */
13587void
13588OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching)
13589{
0a7de745 13590 int numPersonalities = 0;
b0d623f7 13591
0a7de745
A
13592 OSKextLog(/* kext */ NULL,
13593 kOSKextLogStepLevel |
13594 kOSKextLogLoadFlag,
13595 "Sending all eligible registered kexts' personalities "
13596 "to the IOCatalogue %s.",
13597 startMatching ? "and starting matching" : "but not starting matching");
b0d623f7 13598
f427ee49 13599 OSSharedPtr<OSArray> personalities = OSKext::copyAllKextPersonalities(
0a7de745 13600 /* filterSafeBootFlag */ true);
b0d623f7 13601
0a7de745 13602 if (personalities) {
f427ee49 13603 gIOCatalogue->addDrivers(personalities.get(), startMatching);
0a7de745 13604 numPersonalities = personalities->getCount();
0a7de745 13605 }
b0d623f7 13606
0a7de745
A
13607 OSKextLog(/* kext */ NULL,
13608 kOSKextLogStepLevel |
13609 kOSKextLogLoadFlag,
13610 "%d kext personalit%s sent to the IOCatalogue; %s.",
13611 numPersonalities, numPersonalities > 0 ? "ies" : "y",
13612 startMatching ? "matching started" : "matching not started");
13613 return;
b0d623f7
A
13614}
13615
13616/*********************************************************************
13617* Do not make a deep copy, just convert the IOKitPersonalities dict
13618* to an array for sending to the IOCatalogue.
13619*********************************************************************/
f427ee49 13620OSSharedPtr<OSArray>
b0d623f7
A
13621OSKext::copyPersonalitiesArray(void)
13622{
f427ee49
A
13623 OSSharedPtr<OSArray> result;
13624 OSDictionary * personalities = NULL; // do not release
13625 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
0a7de745 13626
f427ee49
A
13627 OSString * personalityName = NULL; // do not release
13628 OSString * personalityBundleIdentifier = NULL; // do not release
0a7de745
A
13629
13630 personalities = OSDynamicCast(OSDictionary,
13631 getPropertyForHostArch(kIOKitPersonalitiesKey));
13632 if (!personalities) {
13633 goto finish;
13634 }
13635
13636 result = OSArray::withCapacity(personalities->getCount());
13637 if (!result) {
13638 goto finish;
13639 }
13640
13641 personalitiesIterator =
13642 OSCollectionIterator::withCollection(personalities);
13643 if (!personalitiesIterator) {
13644 goto finish;
13645 }
13646 while ((personalityName = OSDynamicCast(OSString,
13647 personalitiesIterator->getNextObject()))) {
13648 OSDictionary * personality = OSDynamicCast(OSDictionary,
13649 personalities->getObject(personalityName));
13650
13651 /******
13652 * If the personality doesn't have a CFBundleIdentifier, or if it
13653 * differs from the kext's, insert the kext's ID so we can find it.
13654 * The publisher ID is used to remove personalities from bundles
13655 * correctly.
13656 */
13657 personalityBundleIdentifier = OSDynamicCast(OSString,
13658 personality->getObject(kCFBundleIdentifierKey));
13659
13660 if (!personalityBundleIdentifier) {
f427ee49
A
13661 personality->setObject(kCFBundleIdentifierKey, bundleID.get());
13662 } else if (!personalityBundleIdentifier->isEqualTo(bundleID.get())) {
13663 personality->setObject(kIOPersonalityPublisherKey, bundleID.get());
0a7de745
A
13664 }
13665
13666 result->setObject(personality);
13667 }
b0d623f7
A
13668
13669finish:
0a7de745 13670 return result;
b0d623f7
A
13671}
13672
13673/*********************************************************************
0a7de745 13674* Might want to change this to a bool return?
b0d623f7 13675*********************************************************************/
b7266188 13676OSReturn
b0d623f7 13677OSKext::sendPersonalitiesToCatalog(
0a7de745
A
13678 bool startMatching,
13679 OSArray * personalityNames)
13680{
13681 OSReturn result = kOSReturnSuccess;
f427ee49
A
13682 OSSharedPtr<OSArray> personalitiesToSend;
13683 OSDictionary * kextPersonalities = NULL; // do not release
0a7de745
A
13684 int count, i;
13685
13686 if (!sLoadEnabled) {
13687 OSKextLog(this,
13688 kOSKextLogErrorLevel |
13689 kOSKextLogLoadFlag,
13690 "Kext loading is disabled (attempt to start matching for kext %s).",
13691 getIdentifierCString());
13692 result = kOSKextReturnDisabled;
13693 goto finish;
13694 }
13695
13696 if (sSafeBoot && !isLoadableInSafeBoot()) {
13697 OSKextLog(this,
13698 kOSKextLogErrorLevel |
13699 kOSKextLogLoadFlag,
13700 "Kext %s is not loadable during safe boot; "
13701 "not sending personalities to the IOCatalogue.",
13702 getIdentifierCString());
13703 result = kOSKextReturnNotLoadable;
13704 goto finish;
13705 }
13706
13707 if (!personalityNames || !personalityNames->getCount()) {
13708 personalitiesToSend = copyPersonalitiesArray();
13709 } else {
13710 kextPersonalities = OSDynamicCast(OSDictionary,
13711 getPropertyForHostArch(kIOKitPersonalitiesKey));
13712 if (!kextPersonalities || !kextPersonalities->getCount()) {
13713 // not an error
13714 goto finish;
13715 }
13716 personalitiesToSend = OSArray::withCapacity(0);
13717 if (!personalitiesToSend) {
13718 result = kOSKextReturnNoMemory;
13719 goto finish;
13720 }
13721 count = personalityNames->getCount();
13722 for (i = 0; i < count; i++) {
13723 OSString * name = OSDynamicCast(OSString,
13724 personalityNames->getObject(i));
13725 if (!name) {
13726 continue;
13727 }
13728 OSDictionary * personality = OSDynamicCast(OSDictionary,
13729 kextPersonalities->getObject(name));
13730 if (personality) {
13731 personalitiesToSend->setObject(personality);
13732 }
13733 }
13734 }
13735 if (personalitiesToSend) {
13736 unsigned numPersonalities = personalitiesToSend->getCount();
13737 OSKextLog(this,
13738 kOSKextLogStepLevel |
13739 kOSKextLogLoadFlag,
13740 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
13741 getIdentifierCString(),
13742 numPersonalities,
13743 numPersonalities > 1 ? "ies" : "y",
13744 startMatching ? " and starting matching" : " but not starting matching");
f427ee49 13745 gIOCatalogue->addDrivers(personalitiesToSend.get(), startMatching);
0a7de745 13746 }
b0d623f7 13747finish:
0a7de745 13748 return result;
b0d623f7
A
13749}
13750
13751/*********************************************************************
b7266188
A
13752* xxx - We should allow removing the kext's declared personalities,
13753* xxx - even with other bundle identifiers.
b0d623f7
A
13754*********************************************************************/
13755void
13756OSKext::removePersonalitiesFromCatalog(void)
13757{
f427ee49 13758 OSSharedPtr<OSDictionary> personality;
b0d623f7 13759
0a7de745
A
13760 personality = OSDictionary::withCapacity(1);
13761 if (!personality) {
13762 goto finish;
13763 }
13764 personality->setObject(kCFBundleIdentifierKey, getIdentifier());
b0d623f7 13765
0a7de745
A
13766 OSKextLog(this,
13767 kOSKextLogStepLevel |
13768 kOSKextLogLoadFlag,
13769 "Kext %s removing all personalities naming it from the IOCatalogue.",
13770 getIdentifierCString());
b0d623f7 13771
0a7de745
A
13772 /* Have the IOCatalog remove all personalities matching this kext's
13773 * bundle ID and trigger matching anew.
13774 */
f427ee49 13775 gIOCatalogue->removeDrivers(personality.get(), /* startMatching */ true);
b0d623f7 13776
0a7de745 13777finish:
0a7de745 13778 return;
b0d623f7
A
13779}
13780
13781
13782#if PRAGMA_MARK
13783#pragma mark Logging
13784#endif
13785/*********************************************************************
13786* Do not call any function that takes sKextLock here!
13787*********************************************************************/
13788/* static */
13789OSKextLogSpec
13790OSKext::setUserSpaceLogFilter(
0a7de745
A
13791 OSKextLogSpec newUserLogFilter,
13792 bool captureFlag)
13793{
13794 OSKextLogSpec result;
13795 bool allocError = false;
13796
13797 /* Do not call any function that takes sKextLoggingLock during
13798 * this critical block. That means do logging after.
13799 */
13800 IOLockLock(sKextLoggingLock);
13801
13802 result = sUserSpaceKextLogFilter;
13803 sUserSpaceKextLogFilter = newUserLogFilter;
13804
13805 if (newUserLogFilter && captureFlag &&
13806 !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
13807 // xxx - do some measurements for a good initial capacity?
13808 sUserSpaceLogSpecArray = OSArray::withCapacity(0);
13809 sUserSpaceLogMessageArray = OSArray::withCapacity(0);
13810
13811 if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
0a7de745
A
13812 allocError = true;
13813 }
13814 }
13815
13816 IOLockUnlock(sKextLoggingLock);
13817
13818 /* If the config flag itself is changing, log the state change
13819 * going both ways, before setting up the user-space log arrays,
13820 * so that this is only logged in the kernel.
13821 */
13822 if (result != newUserLogFilter) {
13823 OSKextLog(/* kext */ NULL,
13824 kOSKextLogDebugLevel |
13825 kOSKextLogGeneralFlag,
13826 "User-space log flags changed from 0x%x to 0x%x.",
13827 result, newUserLogFilter);
13828 }
13829 if (allocError) {
13830 OSKextLog(/* kext */ NULL,
13831 kOSKextLogErrorLevel |
13832 kOSKextLogGeneralFlag,
13833 "Failed to allocate user-space log message arrays.");
13834 }
13835
13836 return result;
b0d623f7
A
13837}
13838
13839/*********************************************************************
13840* Do not call any function that takes sKextLock here!
13841*********************************************************************/
13842/* static */
f427ee49 13843OSSharedPtr<OSArray>
b0d623f7
A
13844OSKext::clearUserSpaceLogFilter(void)
13845{
f427ee49 13846 OSSharedPtr<OSArray> result;
0a7de745
A
13847 OSKextLogSpec oldLogFilter;
13848 OSKextLogSpec newLogFilter = kOSKextLogSilentFilter;
b0d623f7 13849
0a7de745
A
13850 /* Do not call any function that takes sKextLoggingLock during
13851 * this critical block. That means do logging after.
13852 */
13853 IOLockLock(sKextLoggingLock);
b0d623f7 13854
0a7de745
A
13855 result = OSArray::withCapacity(2);
13856 if (result) {
f427ee49
A
13857 result->setObject(sUserSpaceLogSpecArray.get());
13858 result->setObject(sUserSpaceLogMessageArray.get());
0a7de745 13859 }
f427ee49
A
13860 sUserSpaceLogSpecArray.reset();
13861 sUserSpaceLogMessageArray.reset();
0a7de745
A
13862
13863 oldLogFilter = sUserSpaceKextLogFilter;
13864 sUserSpaceKextLogFilter = newLogFilter;
13865
13866 IOLockUnlock(sKextLoggingLock);
13867
13868 /* If the config flag itself is changing, log the state change
13869 * going both ways, after tearing down the user-space log
13870 * arrays, so this is only logged within the kernel.
13871 */
13872 if (oldLogFilter != newLogFilter) {
13873 OSKextLog(/* kext */ NULL,
13874 kOSKextLogDebugLevel |
13875 kOSKextLogGeneralFlag,
13876 "User-space log flags changed from 0x%x to 0x%x.",
13877 oldLogFilter, newLogFilter);
13878 }
b0d623f7 13879
0a7de745 13880 return result;
b0d623f7
A
13881}
13882
6d2010ae 13883
b0d623f7
A
13884/*********************************************************************
13885* Do not call any function that takes sKextLock here!
13886*********************************************************************/
13887/* static */
13888OSKextLogSpec
13889OSKext::getUserSpaceLogFilter(void)
13890{
0a7de745 13891 OSKextLogSpec result;
b0d623f7 13892
0a7de745
A
13893 IOLockLock(sKextLoggingLock);
13894 result = sUserSpaceKextLogFilter;
13895 IOLockUnlock(sKextLoggingLock);
b0d623f7 13896
0a7de745 13897 return result;
b0d623f7
A
13898}
13899
13900/*********************************************************************
13901* This function is called by OSMetaClass during kernel C++ setup.
13902* Be careful what you access here; assume only OSKext::initialize()
13903* has been called.
13904*
13905* Do not call any function that takes sKextLock here!
13906*********************************************************************/
13907#define VTRESET "\033[0m"
13908
13909#define VTBOLD "\033[1m"
13910#define VTUNDER "\033[4m"
13911
13912#define VTRED "\033[31m"
13913#define VTGREEN "\033[32m"
13914#define VTYELLOW "\033[33m"
13915#define VTBLUE "\033[34m"
13916#define VTMAGENTA "\033[35m"
13917#define VTCYAN "\033[36m"
13918
0a7de745
A
13919inline const char *
13920colorForFlags(OSKextLogSpec flags)
13921{
13922 OSKextLogSpec logLevel = flags & kOSKextLogLevelMask;
13923
13924 switch (logLevel) {
13925 case kOSKextLogErrorLevel:
13926 return VTRED VTBOLD;
13927 case kOSKextLogWarningLevel:
13928 return VTRED;
13929 case kOSKextLogBasicLevel:
13930 return VTYELLOW VTUNDER;
13931 case kOSKextLogProgressLevel:
13932 return VTYELLOW;
13933 case kOSKextLogStepLevel:
13934 return VTGREEN;
13935 case kOSKextLogDetailLevel:
13936 return VTCYAN;
13937 case kOSKextLogDebugLevel:
13938 return VTMAGENTA;
13939 default:
f427ee49 13940 return ""; // white
0a7de745 13941 }
b0d623f7
A
13942}
13943
0a7de745
A
13944inline bool
13945logSpecMatch(
13946 OSKextLogSpec msgLogSpec,
13947 OSKextLogSpec logFilter)
13948{
13949 OSKextLogSpec filterKextGlobal = logFilter & kOSKextLogKextOrGlobalMask;
13950 OSKextLogSpec filterLevel = logFilter & kOSKextLogLevelMask;
13951 OSKextLogSpec filterFlags = logFilter & kOSKextLogFlagsMask;
13952
13953 OSKextLogSpec msgKextGlobal = msgLogSpec & kOSKextLogKextOrGlobalMask;
13954 OSKextLogSpec msgLevel = msgLogSpec & kOSKextLogLevelMask;
13955 OSKextLogSpec msgFlags = msgLogSpec & kOSKextLogFlagsMask;
13956
13957 /* Explicit messages always get logged.
13958 */
13959 if (msgLevel == kOSKextLogExplicitLevel) {
13960 return true;
13961 }
13962
13963 /* Warnings and errors are logged regardless of the flags.
13964 */
13965 if (msgLevel <= kOSKextLogBasicLevel && (msgLevel <= filterLevel)) {
13966 return true;
13967 }
13968
13969 /* A verbose message that isn't for a logging-enabled kext and isn't global
13970 * does *not* get logged.
13971 */
13972 if (!msgKextGlobal && !filterKextGlobal) {
13973 return false;
13974 }
13975
13976 /* Warnings and errors are logged regardless of the flags.
13977 * All other messages must fit the flags and
13978 * have a level at or below the filter.
13979 *
13980 */
13981 if ((msgFlags & filterFlags) && (msgLevel <= filterLevel)) {
13982 return true;
13983 }
13984 return false;
13985}
b0d623f7 13986
0a7de745 13987extern "C" {
b0d623f7
A
13988void
13989OSKextLog(
0a7de745
A
13990 OSKext * aKext,
13991 OSKextLogSpec msgLogSpec,
13992 const char * format, ...)
b0d623f7 13993{
0a7de745 13994 va_list argList;
b0d623f7 13995
0a7de745
A
13996 va_start(argList, format);
13997 OSKextVLog(aKext, msgLogSpec, format, argList);
13998 va_end(argList);
b0d623f7
A
13999}
14000
14001void
14002OSKextVLog(
0a7de745
A
14003 OSKext * aKext,
14004 OSKextLogSpec msgLogSpec,
14005 const char * format,
14006 va_list srcArgList)
14007{
14008 extern int disableConsoleOutput;
14009
14010 bool logForKernel = false;
14011 bool logForUser = false;
14012 va_list argList;
14013 char stackBuffer[120];
14014 uint32_t length = 0;
f427ee49
A
14015 char * allocBuffer = NULL; // must kfree
14016 OSSharedPtr<OSNumber> logSpecNum;
14017 OSSharedPtr<OSString> logString;
14018 char * buffer = stackBuffer; // do not free
0a7de745
A
14019
14020 IOLockLock(sKextLoggingLock);
14021
14022 /* Set the kext/global bit in the message spec if we have no
14023 * kext or if the kext requests logging.
14024 */
14025 if (!aKext || aKext->flags.loggingEnabled) {
14026 msgLogSpec = msgLogSpec | kOSKextLogKextOrGlobalMask;
14027 }
14028
14029 logForKernel = logSpecMatch(msgLogSpec, sKernelLogFilter);
14030 if (sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
14031 logForUser = logSpecMatch(msgLogSpec, sUserSpaceKextLogFilter);
14032 }
14033
14034 if (!(logForKernel || logForUser)) {
14035 goto finish;
14036 }
14037
14038 /* No goto from here until past va_end()!
14039 */
14040 va_copy(argList, srcArgList);
14041 length = vsnprintf(stackBuffer, sizeof(stackBuffer), format, argList);
14042 va_end(argList);
14043
14044 if (length + 1 >= sizeof(stackBuffer)) {
f427ee49
A
14045 allocBuffer = (char *)kheap_alloc_tag(KHEAP_TEMP,
14046 length + 1, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
0a7de745
A
14047 if (!allocBuffer) {
14048 goto finish;
14049 }
14050
14051 /* No goto from here until past va_end()!
14052 */
14053 va_copy(argList, srcArgList);
14054 vsnprintf(allocBuffer, length + 1, format, argList);
14055 va_end(argList);
14056
14057 buffer = allocBuffer;
14058 }
14059
14060 /* If user space wants the log message, queue it up.
14061 */
14062 if (logForUser && sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
14063 logSpecNum = OSNumber::withNumber(msgLogSpec, 8 * sizeof(msgLogSpec));
14064 logString = OSString::withCString(buffer);
14065 if (logSpecNum && logString) {
f427ee49
A
14066 sUserSpaceLogSpecArray->setObject(logSpecNum.get());
14067 sUserSpaceLogMessageArray->setObject(logString.get());
0a7de745
A
14068 }
14069 }
14070
14071 /* Always log messages from the kernel according to the kernel's
14072 * log flags.
14073 */
14074 if (logForKernel) {
14075 /* If we are in console mode and have a custom log filter,
14076 * colorize the log message.
14077 */
14078 if (!disableConsoleOutput && sBootArgLogFilterFound) {
f427ee49 14079 const char * color = ""; // do not free
0a7de745
A
14080 color = colorForFlags(msgLogSpec);
14081 printf("%s%s%s\n", colorForFlags(msgLogSpec),
14082 buffer, color[0] ? VTRESET : "");
14083 } else {
14084 printf("%s\n", buffer);
14085 }
14086 }
b0d623f7
A
14087
14088finish:
0a7de745 14089 IOLockUnlock(sKextLoggingLock);
6d2010ae 14090
0a7de745 14091 if (allocBuffer) {
f427ee49 14092 kheap_free(KHEAP_TEMP, allocBuffer, (length + 1) * sizeof(char));
0a7de745 14093 }
0a7de745 14094 return;
b0d623f7
A
14095}
14096
316670eb 14097#if KASLR_IOREG_DEBUG
0a7de745 14098
316670eb
A
14099#define IOLOG_INDENT( the_indention ) \
14100{ \
14101 int i; \
14102 for ( i = 0; i < (the_indention); i++ ) { \
0a7de745 14103 IOLog(" "); \
316670eb
A
14104 } \
14105}
0a7de745
A
14106
14107extern vm_offset_t vm_kernel_stext;
14108extern vm_offset_t vm_kernel_etext;
14109extern mach_vm_offset_t kext_alloc_base;
316670eb 14110extern mach_vm_offset_t kext_alloc_max;
0a7de745
A
14111
14112bool ScanForAddrInObject(OSObject * theObject,
14113 int indent );
14114
14115bool
14116ScanForAddrInObject(OSObject * theObject,
14117 int indent)
14118{
14119 const OSMetaClass * myTypeID;
f427ee49 14120 OSSharedPtr<OSCollectionIterator> myIter;
0a7de745
A
14121 OSSymbol * myKey;
14122 OSObject * myValue;
14123 bool myResult = false;
14124
14125 if (theObject == NULL) {
14126 IOLog("%s: theObject is NULL \n",
14127 __FUNCTION__);
14128 return myResult;
14129 }
14130
14131 myTypeID = OSTypeIDInst(theObject);
14132
14133 if (myTypeID == OSTypeID(OSDictionary)) {
14134 OSDictionary * myDictionary;
14135
14136 myDictionary = OSDynamicCast(OSDictionary, theObject);
14137 myIter = OSCollectionIterator::withCollection( myDictionary );
14138 if (myIter == NULL) {
14139 return myResult;
14140 }
f427ee49
A
14141
14142 // !! reset the iterator
0a7de745
A
14143 myIter->reset();
14144
14145 while ((myKey = OSDynamicCast(OSSymbol, myIter->getNextObject()))) {
14146 bool myTempResult;
14147
14148 myValue = myDictionary->getObject(myKey);
14149 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
14150 if (myTempResult) {
14151 // if we ever get a true result return true
14152 myResult = true;
14153 IOLOG_INDENT(indent);
14154 IOLog("OSDictionary key \"%s\" \n", myKey->getCStringNoCopy());
14155 }
14156 }
f427ee49
A
14157
14158 // !! release the iterator
14159 myIter.reset();
0a7de745
A
14160 } else if (myTypeID == OSTypeID(OSArray)) {
14161 OSArray * myArray;
14162
14163 myArray = OSDynamicCast(OSArray, theObject);
14164 myIter = OSCollectionIterator::withCollection(myArray);
14165 if (myIter == NULL) {
14166 return myResult;
14167 }
f427ee49 14168 // !! reset the iterator
0a7de745
A
14169 myIter->reset();
14170
14171 while ((myValue = myIter->getNextObject())) {
14172 bool myTempResult;
14173 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
14174 if (myTempResult) {
14175 // if we ever get a true result return true
14176 myResult = true;
14177 IOLOG_INDENT(indent);
14178 IOLog("OSArray: \n");
14179 }
14180 }
f427ee49
A
14181 // !! release the iterator
14182 myIter.reset();
0a7de745
A
14183 } else if (myTypeID == OSTypeID(OSString) || myTypeID == OSTypeID(OSSymbol)) {
14184 // should we look for addresses in strings?
14185 } else if (myTypeID == OSTypeID(OSData)) {
14186 void * * myPtrPtr;
14187 unsigned int myLen;
14188 OSData * myDataObj;
14189
14190 myDataObj = OSDynamicCast(OSData, theObject);
14191 myPtrPtr = (void * *) myDataObj->getBytesNoCopy();
14192 myLen = myDataObj->getLength();
14193
14194 if (myPtrPtr && myLen && myLen > 7) {
14195 int i;
14196 int myPtrCount = (myLen / sizeof(void *));
14197
14198 for (i = 0; i < myPtrCount; i++) {
14199 UInt64 numberValue = (UInt64) * (myPtrPtr);
14200
14201 if (kext_alloc_max != 0 &&
14202 numberValue >= kext_alloc_base &&
14203 numberValue < kext_alloc_max) {
f427ee49
A
14204 OSSharedPtr<OSKext> myKext;
14205 // IOLog("found OSData %p in kext map %p to %p \n",
14206 // *(myPtrPtr),
14207 // (void *) kext_alloc_base,
14208 // (void *) kext_alloc_max);
0a7de745
A
14209
14210 myKext = OSKext::lookupKextWithAddress((vm_address_t) *(myPtrPtr));
14211 if (myKext) {
14212 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
14213 *(myPtrPtr),
14214 myKext->getIdentifierCString());
0a7de745
A
14215 }
14216 myResult = true;
14217 }
14218 if (vm_kernel_etext != 0 &&
14219 numberValue >= vm_kernel_stext &&
14220 numberValue < vm_kernel_etext) {
14221 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
14222 *(myPtrPtr),
14223 (void *) vm_kernel_stext,
14224 (void *) vm_kernel_etext);
14225 myResult = true;
14226 }
14227 myPtrPtr++;
14228 }
14229 }
14230 } else if (myTypeID == OSTypeID(OSBoolean)) {
14231 // do nothing here...
14232 } else if (myTypeID == OSTypeID(OSNumber)) {
14233 OSNumber * number = OSDynamicCast(OSNumber, theObject);
14234
14235 UInt64 numberValue = number->unsigned64BitValue();
14236
14237 if (kext_alloc_max != 0 &&
14238 numberValue >= kext_alloc_base &&
14239 numberValue < kext_alloc_max) {
f427ee49 14240 OSSharedPtr<OSKext> myKext;
0a7de745
A
14241 IOLog("found OSNumber in kext map %p to %p \n",
14242 (void *) kext_alloc_base,
14243 (void *) kext_alloc_max);
14244 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
14245
14246 myKext = OSKext::lookupKextWithAddress((vm_address_t) numberValue );
14247 if (myKext) {
14248 IOLog("found in kext \"%s\" \n",
14249 myKext->getIdentifierCString());
0a7de745
A
14250 }
14251
14252 myResult = true;
14253 }
14254 if (vm_kernel_etext != 0 &&
14255 numberValue >= vm_kernel_stext &&
14256 numberValue < vm_kernel_etext) {
14257 IOLog("found OSNumber in kernel text segment %p to %p \n",
14258 (void *) vm_kernel_stext,
14259 (void *) vm_kernel_etext);
14260 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
14261 myResult = true;
14262 }
14263 }
316670eb 14264#if 0
0a7de745
A
14265 else {
14266 const OSMetaClass* myMetaClass = NULL;
14267
14268 myMetaClass = theObject->getMetaClass();
14269 if (myMetaClass) {
14270 IOLog("class %s \n", myMetaClass->getClassName());
14271 } else {
14272 IOLog("Unknown object \n" );
14273 }
14274 }
316670eb 14275#endif
316670eb 14276
0a7de745
A
14277 return myResult;
14278}
14279#endif // KASLR_KEXT_DEBUG
f427ee49 14280}; /* extern "C" */
b0d623f7
A
14281
14282#if PRAGMA_MARK
14283#pragma mark Backtrace Dump & kmod_get_info() support
14284#endif
14285/*********************************************************************
6d2010ae 14286* This function must be safe to call in panic context.
b0d623f7
A
14287*********************************************************************/
14288/* static */
14289void
14290OSKext::printKextsInBacktrace(
0a7de745
A
14291 vm_offset_t * addr __unused,
14292 unsigned int cnt __unused,
14293 int (* printf_func)(const char *fmt, ...) __unused,
14294 uint32_t flags __unused)
14295{
14296 addr64_t summary_page = 0;
14297 addr64_t last_summary_page = 0;
14298 bool found_kmod = false;
14299 u_int i = 0;
14300
14301 if (kPrintKextsLock & flags) {
14302 if (!sKextSummariesLock) {
14303 return;
14304 }
14305 IOLockLock(sKextSummariesLock);
14306 }
14307
14308 if (!gLoadedKextSummaries) {
14309 (*printf_func)(" can't perform kext scan: no kext summary");
14310 goto finish;
14311 }
14312
14313 summary_page = trunc_page((addr64_t)(uintptr_t)gLoadedKextSummaries);
14314 last_summary_page = round_page(summary_page + sLoadedKextSummariesAllocSize);
14315 for (; summary_page < last_summary_page; summary_page += PAGE_SIZE) {
14316 if (pmap_find_phys(kernel_pmap, summary_page) == 0) {
14317 (*printf_func)(" can't perform kext scan: "
14318 "missing kext summary page %p", summary_page);
14319 goto finish;
14320 }
14321 }
14322
14323 for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
14324 OSKextLoadedKextSummary * summary;
14325
14326 summary = gLoadedKextSummaries->summaries + i;
14327 if (!summary->address) {
14328 continue;
14329 }
14330
14331 if (!summaryIsInBacktrace(summary, addr, cnt)) {
14332 continue;
14333 }
14334
14335 if (!found_kmod) {
14336 if (!(kPrintKextsTerse & flags)) {
14337 (*printf_func)(" Kernel Extensions in backtrace:\n");
14338 }
14339 found_kmod = true;
14340 }
14341
14342 printSummary(summary, printf_func, flags);
14343 }
b0d623f7 14344
6d2010ae 14345finish:
0a7de745
A
14346 if (kPrintKextsLock & flags) {
14347 IOLockUnlock(sKextSummariesLock);
14348 }
b0d623f7 14349
0a7de745 14350 return;
6d2010ae 14351}
b0d623f7 14352
6d2010ae
A
14353/*********************************************************************
14354* This function must be safe to call in panic context.
14355*********************************************************************/
14356/* static */
14357boolean_t
14358OSKext::summaryIsInBacktrace(
0a7de745
A
14359 OSKextLoadedKextSummary * summary,
14360 vm_offset_t * addr,
14361 unsigned int cnt)
6d2010ae 14362{
0a7de745 14363 u_int i = 0;
6d2010ae 14364
0a7de745
A
14365 for (i = 0; i < cnt; i++) {
14366 vm_offset_t kscan_addr = addr[i];
f427ee49
A
14367#if __has_feature(ptrauth_calls)
14368 kscan_addr = (vm_offset_t)VM_KERNEL_STRIP_PTR(kscan_addr);
14369#endif /* __has_feature(ptrauth_calls) */
14370 if ((kscan_addr >= summary->text_exec_address) &&
14371 (kscan_addr < (summary->text_exec_address + summary->text_exec_size))) {
0a7de745
A
14372 return TRUE;
14373 }
14374 }
b0d623f7 14375
0a7de745 14376 return FALSE;
6d2010ae 14377}
b0d623f7 14378
813fb2f6
A
14379/*
14380 * Get the kext summary object for the kext where 'addr' lies. Must be called with
14381 * sKextSummariesLock held.
14382 */
14383OSKextLoadedKextSummary *
f427ee49 14384OSKext::summaryForAddress(uintptr_t addr)
39037602 14385{
f427ee49
A
14386#if __has_feature(ptrauth_calls)
14387 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
14388#endif /* __has_feature(ptrauth_calls) */
813fb2f6 14389 for (unsigned i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
813fb2f6
A
14390 OSKextLoadedKextSummary *summary = &gLoadedKextSummaries->summaries[i];
14391 if (!summary->address) {
14392 continue;
14393 }
39037602 14394
813fb2f6
A
14395#if VM_MAPPED_KEXTS
14396 /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
14397 * support split kexts, but we also may unmap the kexts, which can
14398 * race with the above codepath (see OSKext::unload). As such,
14399 * use a simple range lookup if we are using VM_MAPPED_KEXTS.
14400 */
14401 if ((addr >= summary->address) && (addr < (summary->address + summary->size))) {
14402 return summary;
14403 }
14404#else
14405 kernel_mach_header_t *mh = (kernel_mach_header_t *)summary->address;
14406 kernel_segment_command_t *seg;
14407
14408 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
14409 if ((addr >= seg->vmaddr) && (addr < (seg->vmaddr + seg->vmsize))) {
14410 return summary;
14411 }
14412 }
14413#endif
14414 }
39037602 14415
813fb2f6
A
14416 /* addr did not map to any kext */
14417 return NULL;
14418}
39037602 14419
813fb2f6
A
14420/* static */
14421void *
d9a64523 14422OSKext::kextForAddress(const void *address)
813fb2f6 14423{
0a7de745
A
14424 void * image = NULL;
14425 OSKextActiveAccount * active;
14426 OSKext * kext = NULL;
14427 uint32_t baseIdx;
14428 uint32_t lim;
14429 uintptr_t addr = (uintptr_t) address;
f427ee49 14430 size_t i;
39037602 14431
d9a64523 14432 if (!addr) {
813fb2f6
A
14433 return NULL;
14434 }
f427ee49
A
14435#if __has_feature(ptrauth_calls)
14436 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
14437#endif /* __has_feature(ptrauth_calls) */
d9a64523 14438
0a7de745
A
14439 if (sKextAccountsCount) {
14440 IOSimpleLockLock(sKextAccountsLock);
14441 // bsearch sKextAccounts list
14442 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
14443 active = &sKextAccounts[baseIdx + (lim >> 1)];
14444 if ((addr >= active->address) && (addr < active->address_end)) {
14445 kext = active->account->kext;
14446 if (kext && kext->kmod_info) {
14447 image = (void *) kext->kmod_info->address;
14448 }
14449 break;
14450 } else if (addr > active->address) {
14451 // move right
14452 baseIdx += (lim >> 1) + 1;
14453 lim--;
14454 }
14455 // else move left
14456 }
14457 IOSimpleLockUnlock(sKextAccountsLock);
14458 }
14459 if (!image && (addr >= vm_kernel_stext) && (addr < vm_kernel_etext)) {
14460 image = (void *) &_mh_execute_header;
14461 }
f427ee49
A
14462 if (!image && gLoadedKextSummaries) {
14463 IOLockLock(sKextSummariesLock);
14464 for (i = 0; i < gLoadedKextSummaries->numSummaries; i++) {
14465 OSKextLoadedKextSummary *summary = gLoadedKextSummaries->summaries + i;
14466 if (addr >= summary->address && addr < summary->address + summary->size) {
14467 image = (void *)summary->address;
14468 }
14469 }
14470 IOLockUnlock(sKextSummariesLock);
14471 }
39037602 14472
813fb2f6 14473 return image;
39037602
A
14474}
14475
f427ee49
A
14476/*
14477 * Find a OSKextLoadedKextSummary given the ID from a kmod_info_t *
14478 * Safe to call in panic context.
14479 */
14480static OSKextLoadedKextSummary *
14481findSummary(uint32_t tagID)
0a7de745 14482{
f427ee49
A
14483 OSKextLoadedKextSummary * summary;
14484 for (size_t i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
0a7de745 14485 summary = gLoadedKextSummaries->summaries + i;
f427ee49
A
14486 if (summary->loadTag == tagID) {
14487 return summary;
0a7de745
A
14488 }
14489 }
f427ee49 14490 return NULL;
6d2010ae 14491}
b0d623f7 14492
6d2010ae
A
14493/*********************************************************************
14494* This function must be safe to call in panic context.
14495*********************************************************************/
0a7de745
A
14496void
14497OSKext::printSummary(
14498 OSKextLoadedKextSummary * summary,
14499 int (* printf_func)(const char *fmt, ...),
14500 uint32_t flags)
14501{
14502 kmod_reference_t * kmod_ref = NULL;
14503 uuid_string_t uuid;
14504 char version[kOSKextVersionMaxLength];
14505 uint64_t tmpAddr;
f427ee49
A
14506 uint64_t tmpSize;
14507 OSKextLoadedKextSummary *dependencySummary;
0a7de745
A
14508
14509 if (!OSKextVersionGetString(summary->version, version, sizeof(version))) {
14510 strlcpy(version, "unknown version", sizeof(version));
14511 }
14512 (void) uuid_unparse(summary->uuid, uuid);
14513
f427ee49
A
14514#if defined(__arm__) || defined(__arm64__)
14515 tmpAddr = summary->text_exec_address;
14516 tmpSize = summary->text_exec_size;
14517#else
14518 tmpAddr = summary->address;
14519 tmpSize = summary->size;
14520#endif
0a7de745 14521 if (kPrintKextsUnslide & flags) {
f427ee49 14522 tmpAddr = ml_static_unslide(tmpAddr);
0a7de745
A
14523 }
14524 (*printf_func)("%s%s(%s)[%s]@0x%llx->0x%llx\n",
14525 (kPrintKextsTerse & flags) ? "" : " ",
14526 summary->name, version, uuid,
f427ee49 14527 tmpAddr, tmpAddr + tmpSize - 1);
0a7de745
A
14528
14529 if (kPrintKextsTerse & flags) {
14530 return;
14531 }
14532
14533 /* print dependency info */
14534 for (kmod_ref = (kmod_reference_t *) summary->reference_list;
14535 kmod_ref;
14536 kmod_ref = kmod_ref->next) {
14537 kmod_info_t * rinfo;
14538
14539 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_ref)) == 0) {
14540 (*printf_func)(" kmod dependency scan stopped "
14541 "due to missing dependency page: %p\n",
14542 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)kmod_ref) : kmod_ref);
14543 break;
14544 }
14545 rinfo = kmod_ref->info;
14546
14547 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
14548 (*printf_func)(" kmod dependency scan stopped "
14549 "due to missing kmod page: %p\n",
14550 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)rinfo) : rinfo);
14551 break;
14552 }
14553
14554 if (!rinfo->address) {
f427ee49 14555 continue; // skip fake entries for built-ins
0a7de745
A
14556 }
14557
f427ee49
A
14558 dependencySummary = findSummary(rinfo->id);
14559 uuid[0] = 0x00;
14560 tmpAddr = rinfo->address;
14561 tmpSize = rinfo->size;
14562 if (dependencySummary) {
14563 (void) uuid_unparse(dependencySummary->uuid, uuid);
14564#if defined(__arm__) || defined(__arm64__)
14565 tmpAddr = dependencySummary->text_exec_address;
14566 tmpSize = dependencySummary->text_exec_size;
14567#endif
14568 }
0a7de745
A
14569
14570 if (kPrintKextsUnslide & flags) {
f427ee49 14571 tmpAddr = ml_static_unslide(tmpAddr);
0a7de745 14572 }
f427ee49
A
14573 (*printf_func)(" dependency: %s(%s)[%s]@%p->%p\n",
14574 rinfo->name, rinfo->version, uuid, tmpAddr, tmpAddr + tmpSize - 1);
0a7de745
A
14575 }
14576 return;
b0d623f7
A
14577}
14578
6d2010ae 14579
f427ee49 14580#if !defined(__arm__) && !defined(__arm64__)
b0d623f7
A
14581/*******************************************************************************
14582* substitute() looks at an input string (a pointer within a larger buffer)
14583* for a match to a substring, and on match it writes the marker & substitution
14584* character to an output string, updating the scan (from) and
14585* output (to) indexes as appropriate.
14586*******************************************************************************/
14587static int substitute(
0a7de745
A
14588 const char * scan_string,
14589 char * string_out,
14590 uint32_t * to_index,
14591 uint32_t * from_index,
14592 const char * substring,
14593 char marker,
14594 char substitution);
b0d623f7
A
14595
14596/* string_out must be at least KMOD_MAX_NAME bytes.
14597 */
14598static int
14599substitute(
0a7de745
A
14600 const char * scan_string,
14601 char * string_out,
14602 uint32_t * to_index,
14603 uint32_t * from_index,
14604 const char * substring,
14605 char marker,
14606 char substitution)
14607{
f427ee49 14608 size_t substring_length = strnlen(substring, KMOD_MAX_NAME - 1);
0a7de745
A
14609
14610 /* On a substring match, append the marker (if there is one) and then
14611 * the substitution character, updating the output (to) index accordingly.
14612 * Then update the input (from) length by the length of the substring
14613 * that got replaced.
14614 */
14615 if (!strncmp(scan_string, substring, substring_length)) {
14616 if (marker) {
14617 string_out[(*to_index)++] = marker;
14618 }
14619 string_out[(*to_index)++] = substitution;
14620 (*from_index) += substring_length;
14621 return 1;
14622 }
14623 return 0;
b0d623f7
A
14624}
14625
14626/*******************************************************************************
14627* compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
14628* KMOD_MAX_NAME characters and performs various substitutions of common
14629* prefixes & substrings as defined by tables in kext_panic_report.h.
14630*******************************************************************************/
14631static void compactIdentifier(
0a7de745
A
14632 const char * identifier,
14633 char * identifier_out,
14634 char ** identifier_out_end);
b0d623f7
A
14635
14636static void
14637compactIdentifier(
0a7de745
A
14638 const char * identifier,
14639 char * identifier_out,
14640 char ** identifier_out_end)
14641{
14642 uint32_t from_index, to_index;
14643 uint32_t scan_from_index = 0;
14644 uint32_t scan_to_index = 0;
14645 subs_entry_t * subs_entry = NULL;
14646 int did_sub = 0;
14647
14648 from_index = to_index = 0;
14649 identifier_out[0] = '\0';
14650
14651 /* Replace certain identifier prefixes with shorter @+character sequences.
14652 * Check the return value of substitute() so we only replace the prefix.
14653 */
14654 for (subs_entry = &kext_identifier_prefix_subs[0];
14655 subs_entry->substring && !did_sub;
14656 subs_entry++) {
14657 did_sub = substitute(identifier, identifier_out,
14658 &scan_to_index, &scan_from_index,
14659 subs_entry->substring, /* marker */ '\0', subs_entry->substitute);
14660 }
14661 did_sub = 0;
14662
14663 /* Now scan through the identifier looking for the common substrings
14664 * and replacing them with shorter !+character sequences via substitute().
14665 */
14666 for (/* see above */;
14667 scan_from_index < KMOD_MAX_NAME - 1 && identifier[scan_from_index];
14668 /* see loop */) {
14669 const char * scan_string = &identifier[scan_from_index];
14670
14671 did_sub = 0;
14672
14673 if (scan_from_index) {
14674 for (subs_entry = &kext_identifier_substring_subs[0];
14675 subs_entry->substring && !did_sub;
14676 subs_entry++) {
14677 did_sub = substitute(scan_string, identifier_out,
14678 &scan_to_index, &scan_from_index,
14679 subs_entry->substring, '!', subs_entry->substitute);
14680 }
14681 }
14682
14683 /* If we didn't substitute, copy the input character to the output.
14684 */
14685 if (!did_sub) {
14686 identifier_out[scan_to_index++] = identifier[scan_from_index++];
14687 }
14688 }
14689
14690 identifier_out[scan_to_index] = '\0';
14691 if (identifier_out_end) {
14692 *identifier_out_end = &identifier_out[scan_to_index];
14693 }
14694
14695 return;
b0d623f7 14696}
f427ee49 14697#endif /* !defined(__arm__) && !defined(__arm64__) */
b0d623f7
A
14698
14699/*******************************************************************************
14700* assemble_identifier_and_version() adds to a string buffer a compacted
14701* bundle identifier followed by a version string.
14702*******************************************************************************/
14703
14704/* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
14705 */
f427ee49 14706static size_t assemble_identifier_and_version(
0a7de745
A
14707 kmod_info_t * kmod_info,
14708 char * identPlusVers,
f427ee49 14709 size_t bufSize);
fe8ab488 14710
f427ee49 14711static size_t
b0d623f7 14712assemble_identifier_and_version(
0a7de745
A
14713 kmod_info_t * kmod_info,
14714 char * identPlusVers,
f427ee49 14715 size_t bufSize)
0a7de745 14716{
f427ee49 14717 size_t result = 0;
0a7de745 14718
f427ee49
A
14719#if defined(__arm__) || defined(__arm64__)
14720 result = strlcpy(identPlusVers, kmod_info->name, KMOD_MAX_NAME);
14721#else
0a7de745
A
14722 compactIdentifier(kmod_info->name, identPlusVers, NULL);
14723 result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
f427ee49
A
14724#endif
14725 identPlusVers[result++] = '\t'; // increment for real char
14726 identPlusVers[result] = '\0'; // don't increment for nul char
0a7de745
A
14727 result = strlcat(identPlusVers, kmod_info->version, bufSize);
14728 if (result >= bufSize) {
14729 identPlusVers[bufSize - 1] = '\0';
14730 result = bufSize - 1;
14731 }
b0d623f7 14732
0a7de745 14733 return result;
b0d623f7
A
14734}
14735
14736/*******************************************************************************
6d2010ae 14737* Assumes sKextLock is held.
b0d623f7 14738*******************************************************************************/
b0d623f7 14739/* static */
fe8ab488 14740int
b0d623f7 14741OSKext::saveLoadedKextPanicListTyped(
0a7de745
A
14742 const char * prefix,
14743 int invertFlag,
14744 int libsFlag,
14745 char * paniclist,
14746 uint32_t list_size)
14747{
14748 int result = -1;
14749 unsigned int count, i;
14750
14751 count = sLoadedKexts->getCount();
14752 if (!count) {
14753 goto finish;
14754 }
14755
14756 i = count - 1;
14757 do {
14758 OSObject * rawKext = sLoadedKexts->getObject(i);
14759 OSKext * theKext = OSDynamicCast(OSKext, rawKext);
14760 int match;
f427ee49
A
14761 size_t identPlusVersLength;
14762 size_t tempLen;
0a7de745
A
14763 char identPlusVers[2 * KMOD_MAX_NAME];
14764
14765 if (!rawKext) {
14766 printf("OSKext::saveLoadedKextPanicListTyped - "
14767 "NULL kext in loaded kext list; continuing\n");
14768 continue;
14769 }
14770
14771 if (!theKext) {
14772 printf("OSKext::saveLoadedKextPanicListTyped - "
14773 "Kext type cast failed in loaded kext list; continuing\n");
14774 continue;
14775 }
14776
14777 /* Skip all built-in kexts.
14778 */
14779 if (theKext->isKernelComponent()) {
14780 continue;
14781 }
14782
14783 kmod_info_t * kmod_info = theKext->kmod_info;
14784
14785 /* Filter for kmod name (bundle identifier).
14786 */
14787 match = !strncmp(kmod_info->name, prefix, strnlen(prefix, KMOD_MAX_NAME));
14788 if ((match && invertFlag) || (!match && !invertFlag)) {
14789 continue;
14790 }
14791
14792 /* Filter for libraries (kexts that have a compatible version).
14793 */
14794 if ((libsFlag == 0 && theKext->getCompatibleVersion() > 1) ||
14795 (libsFlag == 1 && theKext->getCompatibleVersion() < 1)) {
14796 continue;
14797 }
14798
14799 if (!kmod_info ||
14800 !pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_info))) {
14801 printf("kext scan stopped due to missing kmod_info page: %p\n",
14802 kmod_info);
14803 goto finish;
14804 }
14805
14806 identPlusVersLength = assemble_identifier_and_version(kmod_info,
14807 identPlusVers,
14808 sizeof(identPlusVers));
14809 if (!identPlusVersLength) {
14810 printf("error saving loaded kext info\n");
14811 goto finish;
14812 }
14813
14814 /* make sure everything fits and we null terminate.
14815 */
14816 tempLen = strlcat(paniclist, identPlusVers, list_size);
14817 if (tempLen >= list_size) {
14818 // panic list is full, keep it and null terminate
14819 paniclist[list_size - 1] = 0x00;
14820 result = 0;
14821 goto finish;
14822 }
14823 tempLen = strlcat(paniclist, "\n", list_size);
14824 if (tempLen >= list_size) {
14825 // panic list is full, keep it and null terminate
14826 paniclist[list_size - 1] = 0x00;
14827 result = 0;
14828 goto finish;
14829 }
14830 } while (i--);
14831
14832 result = 0;
b0d623f7 14833finish:
0a7de745
A
14834
14835 return result;
b0d623f7
A
14836}
14837
14838/*********************************************************************
14839*********************************************************************/
14840/* static */
14841void
14842OSKext::saveLoadedKextPanicList(void)
14843{
0a7de745
A
14844 char * newlist = NULL;
14845 uint32_t newlist_size = 0;
14846
14847 newlist_size = KEXT_PANICLIST_SIZE;
f427ee49
A
14848 newlist = (char *)kheap_alloc_tag(KHEAP_DATA_BUFFERS, newlist_size,
14849 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
0a7de745
A
14850
14851 if (!newlist) {
14852 OSKextLog(/* kext */ NULL,
14853 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
14854 "Couldn't allocate kext panic log buffer.");
14855 goto finish;
14856 }
14857
14858 newlist[0] = '\0';
14859
14860 // non-"com.apple." kexts
14861 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
14862 /* libs? */ -1, newlist, newlist_size) != 0) {
14863 goto finish;
14864 }
14865 // "com.apple." nonlibrary kexts
14866 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
14867 /* libs? */ 0, newlist, newlist_size) != 0) {
14868 goto finish;
14869 }
14870 // "com.apple." library kexts
14871 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
14872 /* libs? */ 1, newlist, newlist_size) != 0) {
14873 goto finish;
14874 }
14875
14876 if (loaded_kext_paniclist) {
f427ee49
A
14877 kheap_free(KHEAP_DATA_BUFFERS, loaded_kext_paniclist,
14878 loaded_kext_paniclist_size);
0a7de745
A
14879 }
14880 loaded_kext_paniclist = newlist;
14881 newlist = NULL;
14882 loaded_kext_paniclist_size = newlist_size;
14883
b0d623f7 14884finish:
0a7de745 14885 if (newlist) {
f427ee49 14886 kheap_free(KHEAP_TEMP, newlist, newlist_size);
0a7de745
A
14887 }
14888 return;
b0d623f7 14889}
0a7de745 14890
b0d623f7 14891/*********************************************************************
6d2010ae 14892* Assumes sKextLock is held.
b0d623f7 14893*********************************************************************/
b0d623f7 14894void
6d2010ae 14895OSKext::savePanicString(bool isLoading)
b0d623f7 14896{
0a7de745
A
14897 u_long len;
14898
14899 if (!kmod_info) {
f427ee49 14900 return; // do not goto finish here b/c of lock
0a7de745
A
14901 }
14902
14903 len = assemble_identifier_and_version( kmod_info,
14904 (isLoading) ? last_loaded_str_buf : last_unloaded_str_buf,
14905 (isLoading) ? sizeof(last_loaded_str_buf) : sizeof(last_unloaded_str_buf));
14906 if (!len) {
14907 printf("error saving unloaded kext info\n");
14908 goto finish;
14909 }
14910
14911 if (isLoading) {
14912 last_loaded_strlen = len;
14913 last_loaded_address = (void *)kmod_info->address;
14914 last_loaded_size = kmod_info->size;
14915 clock_get_uptime(&last_loaded_timestamp);
14916 } else {
14917 last_unloaded_strlen = len;
14918 last_unloaded_address = (void *)kmod_info->address;
14919 last_unloaded_size = kmod_info->size;
14920 clock_get_uptime(&last_unloaded_timestamp);
14921 }
b0d623f7
A
14922
14923finish:
0a7de745 14924 return;
b0d623f7
A
14925}
14926
14927/*********************************************************************
14928*********************************************************************/
b0d623f7
A
14929/* static */
14930void
14931OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
14932{
0a7de745 14933 if (last_loaded_strlen) {
f427ee49 14934 printf_func("last started kext at %llu: %.*s (addr %p, size %lu)\n",
0a7de745
A
14935 AbsoluteTime_to_scalar(&last_loaded_timestamp),
14936 last_loaded_strlen, last_loaded_str_buf,
14937 last_loaded_address, last_loaded_size);
14938 }
6d2010ae 14939
0a7de745 14940 if (last_unloaded_strlen) {
f427ee49 14941 printf_func("last stopped kext at %llu: %.*s (addr %p, size %lu)\n",
0a7de745
A
14942 AbsoluteTime_to_scalar(&last_unloaded_timestamp),
14943 last_unloaded_strlen, last_unloaded_str_buf,
14944 last_unloaded_address, last_unloaded_size);
14945 }
b0d623f7 14946
0a7de745
A
14947 printf_func("loaded kexts:\n");
14948 if (loaded_kext_paniclist &&
14949 pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
14950 loaded_kext_paniclist[0]) {
14951 printf_func("%.*s",
14952 strnlen(loaded_kext_paniclist, loaded_kext_paniclist_size),
14953 loaded_kext_paniclist);
14954 } else {
14955 printf_func("(none)\n");
14956 }
14957 return;
b0d623f7
A
14958}
14959
6d2010ae
A
14960/*********************************************************************
14961* Assumes sKextLock is held.
14962*********************************************************************/
14963/* static */
14964void
14965OSKext::updateLoadedKextSummaries(void)
14966{
0a7de745
A
14967 kern_return_t result = KERN_FAILURE;
14968 OSKextLoadedKextSummaryHeader *summaryHeader = NULL;
14969 OSKextLoadedKextSummaryHeader *summaryHeaderAlloc = NULL;
14970 OSKext *aKext;
14971 vm_map_offset_t start, end;
14972 size_t summarySize = 0;
14973 size_t size;
14974 u_int count;
14975 u_int maxKexts;
14976 u_int i, j;
14977 OSKextActiveAccount * accountingList;
14978 OSKextActiveAccount * prevAccountingList;
14979 uint32_t idx, accountingListAlloc, accountingListCount, prevAccountingListCount;
14980
14981 prevAccountingList = NULL;
14982 prevAccountingListCount = 0;
3e170ce0 14983
fe8ab488 14984#if DEVELOPMENT || DEBUG
0a7de745
A
14985 if (IORecursiveLockHaveLock(sKextLock) == false) {
14986 panic("sKextLock must be held");
14987 }
fe8ab488 14988#endif
0a7de745
A
14989
14990 IOLockLock(sKextSummariesLock);
14991
14992 count = sLoadedKexts->getCount();
14993 for (i = 0, maxKexts = 0; i < count; ++i) {
14994 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
14995 maxKexts += (aKext && aKext->isExecutable());
14996 }
14997
14998 if (!maxKexts) {
14999 goto finish;
15000 }
15001 if (maxKexts < kOSKextTypicalLoadCount) {
15002 maxKexts = kOSKextTypicalLoadCount;
15003 }
15004
15005 /* Calculate the size needed for the new summary headers.
15006 */
15007
15008 size = sizeof(*gLoadedKextSummaries);
15009 size += maxKexts * sizeof(*gLoadedKextSummaries->summaries);
15010 size = round_page(size);
15011
15012 if (gLoadedKextSummaries == NULL || sLoadedKextSummariesAllocSize < size) {
15013 if (gLoadedKextSummaries) {
15014 kmem_free(kernel_map, (vm_offset_t)gLoadedKextSummaries, sLoadedKextSummariesAllocSize);
15015 gLoadedKextSummaries = NULL;
15016 gLoadedKextSummariesTimestamp = mach_absolute_time();
15017 sLoadedKextSummariesAllocSize = 0;
15018 }
15019 result = kmem_alloc(kernel_map, (vm_offset_t *)&summaryHeaderAlloc, size, VM_KERN_MEMORY_OSKEXT);
15020 if (result != KERN_SUCCESS) {
15021 goto finish;
15022 }
15023 summaryHeader = summaryHeaderAlloc;
15024 summarySize = size;
15025 } else {
15026 summaryHeader = gLoadedKextSummaries;
15027 summarySize = sLoadedKextSummariesAllocSize;
15028
15029 start = (vm_map_offset_t) summaryHeader;
15030 end = start + summarySize;
15031 result = vm_map_protect(kernel_map,
15032 start,
15033 end,
15034 VM_PROT_DEFAULT,
15035 FALSE);
15036 if (result != KERN_SUCCESS) {
15037 goto finish;
15038 }
15039 }
15040
15041 /* Populate the summary header.
15042 */
15043
15044 bzero(summaryHeader, summarySize);
15045 summaryHeader->version = kOSKextLoadedKextSummaryVersion;
15046 summaryHeader->entry_size = sizeof(OSKextLoadedKextSummary);
15047
15048 /* Populate each kext summary.
15049 */
15050
15051 count = sLoadedKexts->getCount();
15052 accountingListAlloc = 0;
15053 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
15054 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
15055 if (!aKext || !aKext->isExecutable()) {
15056 continue;
15057 }
15058
15059 aKext->updateLoadedKextSummary(&summaryHeader->summaries[j++]);
15060 summaryHeader->numSummaries++;
15061 accountingListAlloc++;
15062 }
15063
15064 accountingList = IONew(typeof(accountingList[0]), accountingListAlloc);
15065 accountingListCount = 0;
15066 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
15067 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
15068 if (!aKext || !aKext->isExecutable()) {
15069 continue;
15070 }
15071
15072 OSKextActiveAccount activeAccount;
15073 aKext->updateActiveAccount(&activeAccount);
15074 // order by address
15075 for (idx = 0; idx < accountingListCount; idx++) {
15076 if (activeAccount.address < accountingList[idx].address) {
15077 break;
15078 }
15079 }
15080 bcopy(&accountingList[idx], &accountingList[idx + 1], (accountingListCount - idx) * sizeof(accountingList[0]));
15081 accountingList[idx] = activeAccount;
15082 accountingListCount++;
15083 }
15084 assert(accountingListCount == accountingListAlloc);
15085 /* Write protect the buffer and move it into place.
15086 */
15087
15088 start = (vm_map_offset_t) summaryHeader;
15089 end = start + summarySize;
15090
15091 result = vm_map_protect(kernel_map, start, end, VM_PROT_READ, FALSE);
15092 if (result != KERN_SUCCESS) {
15093 goto finish;
15094 }
15095
15096 gLoadedKextSummaries = summaryHeader;
15097 gLoadedKextSummariesTimestamp = mach_absolute_time();
15098 sLoadedKextSummariesAllocSize = summarySize;
15099 summaryHeaderAlloc = NULL;
15100
15101 /* Call the magic breakpoint function through a static function pointer so
15102 * the compiler can't optimize the function away.
15103 */
15104 if (sLoadedKextSummariesUpdated) {
15105 (*sLoadedKextSummariesUpdated)();
15106 }
15107
15108 IOSimpleLockLock(sKextAccountsLock);
15109 prevAccountingList = sKextAccounts;
15110 prevAccountingListCount = sKextAccountsCount;
15111 sKextAccounts = accountingList;
15112 sKextAccountsCount = accountingListCount;
15113 IOSimpleLockUnlock(sKextAccountsLock);
3e170ce0 15114
6d2010ae 15115finish:
0a7de745 15116 IOLockUnlock(sKextSummariesLock);
6d2010ae 15117
0a7de745
A
15118 /* If we had to allocate a new buffer but failed to generate the summaries,
15119 * free that now.
15120 */
15121 if (summaryHeaderAlloc) {
15122 kmem_free(kernel_map, (vm_offset_t)summaryHeaderAlloc, summarySize);
15123 }
15124 if (prevAccountingList) {
15125 IODelete(prevAccountingList, typeof(accountingList[0]), prevAccountingListCount);
15126 }
6d2010ae 15127
0a7de745 15128 return;
6d2010ae
A
15129}
15130
15131/*********************************************************************
15132*********************************************************************/
15133void
15134OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary *summary)
15135{
f427ee49 15136 OSSharedPtr<OSData> uuid;
6d2010ae 15137
0a7de745
A
15138 strlcpy(summary->name, getIdentifierCString(),
15139 sizeof(summary->name));
6d2010ae 15140
0a7de745
A
15141 uuid = copyUUID();
15142 if (uuid) {
15143 memcpy(summary->uuid, uuid->getBytesNoCopy(), sizeof(summary->uuid));
0a7de745 15144 }
6d2010ae 15145
0a7de745 15146 if (flags.builtin) {
d9a64523
A
15147// this value will stop lldb from parsing the mach-o header
15148// summary->address = UINT64_MAX;
15149// summary->size = 0;
0a7de745
A
15150 summary->address = kmod_info->address;
15151 summary->size = kmod_info->size;
15152 } else {
15153 summary->address = kmod_info->address;
15154 summary->size = kmod_info->size;
15155 }
15156 summary->version = getVersion();
15157 summary->loadTag = kmod_info->id;
15158 summary->flags = 0;
15159 summary->reference_list = (uint64_t) kmod_info->reference_list;
6d2010ae 15160
f427ee49
A
15161 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT_EXEC", &summary->text_exec_size);
15162 if (summary->text_exec_address == 0) {
15163 // Fallback to __TEXT
15164 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT", &summary->text_exec_size);
15165 }
0a7de745 15166 return;
6d2010ae
A
15167}
15168
3e170ce0
A
15169/*********************************************************************
15170*********************************************************************/
15171
15172void
39037602 15173OSKext::updateActiveAccount(OSKextActiveAccount *accountp)
3e170ce0 15174{
0a7de745
A
15175 kernel_mach_header_t *hdr = NULL;
15176 kernel_segment_command_t *seg = NULL;
15177
15178 bzero(accountp, sizeof(*accountp));
15179
15180 hdr = (kernel_mach_header_t *)kmod_info->address;
f427ee49
A
15181 if (getcommandfromheader(hdr, LC_SEGMENT_SPLIT_INFO) || isInFileset()) {
15182 /*
15183 * If this kext supports split segments (or is in a new
15184 * MH_FILESET kext collection), use the first
0a7de745
A
15185 * executable segment as the range for instructions
15186 * (and thus for backtracing.
15187 */
15188 for (seg = firstsegfromheader(hdr); seg != NULL; seg = nextsegfromheader(hdr, seg)) {
15189 if (seg->initprot & VM_PROT_EXECUTE) {
15190 break;
15191 }
15192 }
15193 }
15194 if (seg) {
15195 accountp->address = seg->vmaddr;
15196 if (accountp->address) {
15197 accountp->address_end = seg->vmaddr + seg->vmsize;
15198 }
15199 } else {
15200 /* For non-split kexts and for kexts without executable
15201 * segments, just use the kmod_info range (as the kext
15202 * is either all in one range or should not show up in
15203 * instruction backtraces).
15204 */
15205 accountp->address = kmod_info->address;
15206 if (accountp->address) {
15207 accountp->address_end = kmod_info->address + kmod_info->size;
15208 }
15209 }
15210
15211 accountp->account = this->account;
15212}
15213
cb323159
A
15214bool
15215OSKext::isDriverKit(void)
15216{
15217 OSString *bundleType;
15218
15219 if (infoDict) {
15220 bundleType = OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey));
15221 if (bundleType && bundleType->isEqualTo(kOSKextBundlePackageTypeDriverKit)) {
15222 return TRUE;
15223 }
15224 }
15225 return FALSE;
15226}
15227
f427ee49
A
15228bool
15229OSKext::isInFileset(void)
15230{
15231 if (!kmod_info) {
15232 goto check_prelinked;
15233 }
15234
15235 if (kmod_info->address && kernel_mach_header_is_in_fileset((kernel_mach_header_t *)kmod_info->address)) {
15236 return true;
15237 }
15238
15239check_prelinked:
15240 if (isPrelinked()) {
15241 /*
15242 * If we haven't setup kmod_info yet, but we know
15243 * we're loading a prelinked kext in an MH_FILESET KC,
15244 * then return true
15245 */
15246 kc_format_t kc_format;
15247 if (PE_get_primary_kc_format(&kc_format) && kc_format == KCFormatFileset) {
15248 return true;
15249 }
15250 }
15251 return false;
15252}
15253
15254bool
15255OSKextSavedMutableSegment::initWithSegment(kernel_segment_command_t *seg)
15256{
15257 kern_return_t result;
15258 if (!super::init()) {
15259 return false;
15260 }
15261 if (seg == nullptr) {
15262 return false;
15263 }
15264 result = kmem_alloc_pageable(kernel_map, (vm_offset_t *)&data, seg->vmsize, VM_KERN_MEMORY_KEXT);
15265 if (result != KERN_SUCCESS) {
15266 return false;
15267 }
15268 memcpy((void *)data, (const void *)seg->vmaddr, seg->vmsize);
15269 savedSegment = seg;
15270 vmsize = seg->vmsize;
15271 vmaddr = seg->vmaddr;
15272 return true;
15273}
15274
15275OSSharedPtr<OSKextSavedMutableSegment>
15276OSKextSavedMutableSegment::withSegment(kernel_segment_command_t *seg)
15277{
15278 OSSharedPtr<OSKextSavedMutableSegment> me = OSMakeShared<OSKextSavedMutableSegment>();
15279 if (me && !me->initWithSegment(seg)) {
15280 return nullptr;
15281 }
15282 return me;
15283}
15284
15285void
15286OSKextSavedMutableSegment::free(void)
15287{
15288 if (data) {
15289 kmem_free(kernel_map, (vm_offset_t)data, vmsize);
15290 }
15291}
15292
15293vm_offset_t
15294OSKextSavedMutableSegment::getVMAddr() const
15295{
15296 return vmaddr;
15297}
15298
15299vm_offset_t
15300OSKextSavedMutableSegment::getVMSize() const
15301{
15302 return vmsize;
15303}
15304
15305OSReturn
15306OSKextSavedMutableSegment::restoreContents(kernel_segment_command_t *seg)
15307{
15308 if (seg != savedSegment) {
15309 return kOSKextReturnInvalidArgument;
15310 }
15311 if (seg->vmaddr != vmaddr || seg->vmsize != vmsize) {
15312 return kOSKextReturnInvalidArgument;
15313 }
15314 memcpy((void *)seg->vmaddr, data, vmsize);
15315 return kOSReturnSuccess;
15316}
15317
c3c9b80d
A
15318extern "C" kern_return_t
15319OSKextSetReceiptQueried(void)
15320{
15321 OSKextLog(/* kext */ NULL,
15322 kOSKextLogStepLevel | kOSKextLogGeneralFlag,
15323 "Setting kext receipt as queried");
15324
15325 IOService::publishResource(kOSKextReceiptQueried, kOSBooleanTrue);
15326 return KERN_SUCCESS;
15327}
15328
0a7de745 15329extern "C" const vm_allocation_site_t *
3e170ce0
A
15330OSKextGetAllocationSiteForCaller(uintptr_t address)
15331{
0a7de745
A
15332 OSKextActiveAccount * active;
15333 vm_allocation_site_t * site;
15334 vm_allocation_site_t * releasesite;
15335
15336 uint32_t baseIdx;
15337 uint32_t lim;
f427ee49
A
15338#if __has_feature(ptrauth_calls)
15339 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
15340#endif /* __has_feature(ptrauth_calls) */
0a7de745
A
15341
15342 IOSimpleLockLock(sKextAccountsLock);
15343 site = releasesite = NULL;
15344
15345 // bsearch sKextAccounts list
15346 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
15347 active = &sKextAccounts[baseIdx + (lim >> 1)];
15348 if ((address >= active->address) && (address < active->address_end)) {
15349 site = &active->account->site;
15350 if (!site->tag) {
15351 vm_tag_alloc_locked(site, &releasesite);
15352 }
15353 break;
15354 } else if (address > active->address) {
15355 // move right
15356 baseIdx += (lim >> 1) + 1;
15357 lim--;
15358 }
15359 // else move left
3e170ce0 15360 }
0a7de745
A
15361 IOSimpleLockUnlock(sKextAccountsLock);
15362 if (releasesite) {
15363 kern_allocation_name_release(releasesite);
3e170ce0 15364 }
3e170ce0 15365
0a7de745 15366 return site;
3e170ce0
A
15367}
15368
0a7de745 15369extern "C" uint32_t
5ba3f43e 15370OSKextGetKmodIDForSite(const vm_allocation_site_t * site, char * name, vm_size_t namelen)
3e170ce0 15371{
0a7de745
A
15372 OSKextAccount * account = (typeof(account))site;
15373 const char * kname;
39037602 15374
0a7de745
A
15375 if (name) {
15376 if (account->kext) {
15377 kname = account->kext->getIdentifierCString();
15378 } else {
15379 kname = "<>";
15380 }
15381 strlcpy(name, kname, namelen);
15382 }
39037602 15383
0a7de745 15384 return account->loadTag;
3e170ce0
A
15385}
15386
0a7de745 15387extern "C" void
3e170ce0
A
15388OSKextFreeSite(vm_allocation_site_t * site)
15389{
0a7de745
A
15390 OSKextAccount * freeAccount = (typeof(freeAccount))site;
15391 IODelete(freeAccount, OSKextAccount, 1);
3e170ce0
A
15392}
15393
b0d623f7
A
15394/*********************************************************************
15395*********************************************************************/
b0d623f7 15396
813fb2f6 15397#if CONFIG_IMAGEBOOT
0a7de745
A
15398int
15399OSKextGetUUIDForName(const char *name, uuid_t uuid)
813fb2f6 15400{
f427ee49 15401 OSSharedPtr<OSKext> kext = OSKext::lookupKextWithIdentifier(name);
813fb2f6
A
15402 if (!kext) {
15403 return 1;
15404 }
15405
f427ee49 15406 OSSharedPtr<OSData> uuid_data = kext->copyUUID();
813fb2f6
A
15407 if (uuid_data) {
15408 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_t));
813fb2f6
A
15409 return 0;
15410 }
15411
15412 return 1;
15413}
15414#endif
f427ee49
A
15415
15416static int
15417sysctl_willuserspacereboot
15418(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
15419{
15420 int new_value = 0, old_value = 0, changed = 0;
15421 int error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed);
15422 if (error) {
15423 return error;
15424 }
15425 if (changed) {
15426 OSKext::willUserspaceReboot();
15427 }
15428 return 0;
15429}
15430
15431static SYSCTL_PROC(_kern, OID_AUTO, willuserspacereboot,
15432 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
15433 NULL, 0, sysctl_willuserspacereboot, "I", "");