1/*
2 * Copyright (c) 2008-2016 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29extern "C" {
30#include <string.h>
31#include <kern/clock.h>
32#include <kern/host.h>
33#include <kern/kext_alloc.h>
34#include <firehose/tracepoint_private.h>
35#include <firehose/chunk_private.h>
36#include <os/firehose_buffer_private.h>
37#include <vm/vm_kern.h>
38#include <kextd/kextd_mach.h>
39#include <libkern/kernel_mach_header.h>
40#include <libkern/kext_panic_report.h>
41#include <libkern/kext_request_keys.h>
42#include <libkern/mkext.h>
43#include <libkern/prelink.h>
44#include <libkern/version.h>
45#include <libkern/zlib.h>
46#include <mach/host_special_ports.h>
47#include <mach/mach_vm.h>
48#include <mach/mach_time.h>
49#include <sys/sysctl.h>
50#include <uuid/uuid.h>
51#include <sys/random.h>
52
53#include <sys/pgo.h>
54
55#if CONFIG_MACF
56#include <sys/kauth.h>
57#include <security/mac_framework.h>
58#endif
59};
60
61#include <libkern/OSKextLibPrivate.h>
62#include <libkern/c++/OSKext.h>
63#include <libkern/c++/OSLib.h>
64
65#include <IOKit/IOLib.h>
66#include <IOKit/IOCatalogue.h>
67#include <IOKit/IORegistryEntry.h>
68#include <IOKit/IOService.h>
69
70#include <IOKit/IOStatisticsPrivate.h>
71#include <IOKit/IOBSD.h>
72
73#include <san/kasan.h>
74
75#if PRAGMA_MARK
76#pragma mark External & Internal Function Protos
77#endif
78/*********************************************************************
79*********************************************************************/
80extern "C" {
81extern int IODTGetLoaderInfo(const char * key, void ** infoAddr, int * infoSize);
82extern void IODTFreeLoaderInfo(const char * key, void * infoAddr, int infoSize);
83
84extern ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va); /* osfmk/machine/pmap.h */
85extern int dtrace_keep_kernel_symbols(void);
86}
87
88extern unsigned long gVirtBase;
89extern unsigned long gPhysBase;
90#if CONFIG_EMBEDDED
91extern vm_offset_t segLOWESTTEXT;
92#endif /* CONFIG_EMBEDDED */
93
94static OSReturn _OSKextCreateRequest(
95 const char * predicate,
96 OSDictionary ** requestP);
97static OSString * _OSKextGetRequestPredicate(OSDictionary * requestDict);
98static OSObject * _OSKextGetRequestArgument(
99 OSDictionary * requestDict,
100 const char * argName);
101static bool _OSKextSetRequestArgument(
102 OSDictionary * requestDict,
103 const char * argName,
104 OSObject * value);
105static void * _OSKextExtractPointer(OSData * wrapper);
106static OSReturn _OSDictionarySetCStringValue(
107 OSDictionary * dict,
108 const char * key,
109 const char * value);
110static bool _OSKextInPrelinkRebuildWindow(void);
111static bool _OSKextInUnloadedPrelinkedKexts(const OSSymbol * theBundleID);
112
113// We really should add containsObject() & containsCString to OSCollection & subclasses.
114// So few pad slots, though....
115static bool _OSArrayContainsCString(OSArray * array, const char * cString);
116
117/* Prelinked arm kexts do not have VM entries because the method we use to
118 * fake an entry (see libsa/bootstrap.cpp:readPrelinkedExtensions()) does
119 * not work on ARM. To get around that, we must free prelinked kext
120 * executables with ml_static_mfree() instead of kext_free().
121 */
122#if __i386__ || __x86_64__
123#define VM_MAPPED_KEXTS 1
124#define KASLR_KEXT_DEBUG 0
125#define KASLR_IOREG_DEBUG 0
126#elif __arm__ || __arm64__
127#define VM_MAPPED_KEXTS 0
128#define KASLR_KEXT_DEBUG 0
129#else
130#error Unsupported architecture
131#endif
132
133#if PRAGMA_MARK
134#pragma mark Constants & Macros
135#endif
136/*********************************************************************
137* Constants & Macros
138*********************************************************************/
139
140/* Use this number to create containers.
141 */
142#define kOSKextTypicalLoadCount (150)
143
144/* Any kext will have at least 1 retain for the internal lookup-by-ID dict.
145 * A loaded kext will no dependents or external retains will have 2 retains.
146 */
147#define kOSKextMinRetainCount (1)
148#define kOSKextMinLoadedRetainCount (2)
149
150/**********
151 * Strings and substrings used in dependency resolution.
152 */
153#define APPLE_KEXT_PREFIX "com.apple."
154#define KERNEL_LIB "com.apple.kernel"
155
156#define PRIVATE_KPI "com.apple.kpi.private"
157
158/* Version for compatbility pseudokexts (com.apple.kernel.*),
159 * compatible back to v6.0.
160 */
161#define KERNEL6_LIB "com.apple.kernel.6.0"
162#define KERNEL6_VERSION "7.9.9"
163
164#define KERNEL_LIB_PREFIX "com.apple.kernel."
165#define KPI_LIB_PREFIX "com.apple.kpi."
166
167#define STRING_HAS_PREFIX(s, p) (strncmp((s), (p), strlen(p)) == 0)
168
169#define REBUILD_MAX_TIME (60 * 5) // 5 minutes
170#define MINIMUM_WAKEUP_SECONDS (30)
171
172/*********************************************************************
173* infoDict keys for internally-stored data. Saves on ivar slots for
174* objects we don't keep around past boot time or during active load.
175*********************************************************************/
176
177/* A usable, uncompressed file is stored under this key.
178 */
179#define _kOSKextExecutableKey "_OSKextExecutable"
180
181/* An indirect reference to the executable file from an mkext
182 * is stored under this key.
183 */
184#define _kOSKextMkextExecutableReferenceKey "_OSKextMkextExecutableReference"
185
186/* If the file is contained in a larger buffer laid down by the booter or
187 * sent from user space, the OSKext stores that OSData under this key so that
188 * references are properly tracked. This is always an mkext, right now.
189 */
190#define _kOSKextExecutableExternalDataKey "_OSKextExecutableExternalData"
191
192#define OS_LOG_HDR_VERSION 1
193#define NUM_OS_LOG_SECTIONS 2
194
195#define OS_LOG_SECT_IDX 0
196#define CSTRING_SECT_IDX 1
197
198#if PRAGMA_MARK
199#pragma mark Typedefs
200#endif
201/*********************************************************************
202* Typedefs
203*********************************************************************/
204
205/*********************************************************************
206* osLogDataHeaderRef describes the header information of an OSData
207* object that is returned when querying for kOSBundleLogStringsKey.
208* We currently return information regarding 2 sections - os_log and
209* cstring. In the case that the os_log section doesn't exist, we just
210* return an offset and length of 0 for that section.
211*********************************************************************/
212typedef struct osLogDataHeader {
213 uint32_t version;
214 uint32_t sect_count;
215 struct {
216 uint32_t sect_offset;
217 uint32_t sect_size;
218 } sections[0];
219} osLogDataHeaderRef;
220
221/*********************************************************************
222* MkextEntryRef describes the contents of an OSData object
223* referencing a file entry from an mkext so that we can uncompress
224* (if necessary) and extract it on demand.
225*
226* It contains the mkextVersion in case we ever wind up supporting
227* multiple mkext formats. Mkext format 1 is officially retired as of
228* Snow Leopard.
229*********************************************************************/
230typedef struct MkextEntryRef {
231 mkext_basic_header * mkext; // beginning of whole mkext file
232 void * fileinfo; // mkext2_file_entry or equiv; see mkext.h
233} MkextEntryRef;
234
235#if PRAGMA_MARK
236#pragma mark Global and static Module Variables
237#endif
238/*********************************************************************
239* Global & static variables, used to keep track of kexts.
240*********************************************************************/
241
242static bool sPrelinkBoot = false;
243static bool sSafeBoot = false;
244static bool sKeepSymbols = false;
245
246/*********************************************************************
247* sKextLock is the principal lock for OSKext, and guards all static
248* and global variables not owned by other locks (declared further
249* below). It must be taken by any entry-point method or function,
250* including internal functions called on scheduled threads.
251*
252* sKextLock and sKextInnerLock are recursive due to multiple functions
253* that are called both externally and internally. The other locks are
254* nonrecursive.
255*
256* Which locks are taken depends on what they protect, but if more than
257* one must be taken, they must always be locked in this order
258* (and unlocked in reverse order) to prevent deadlocks:
259*
260* 1. sKextLock
261* 2. sKextInnerLock
262* 3. sKextSummariesLock
263* 4. sKextLoggingLock
264*/
265static IORecursiveLock * sKextLock = NULL;
266
267static OSDictionary * sKextsByID = NULL;
268static OSDictionary * sExcludeListByID = NULL;
269static OSKextVersion sExcludeListVersion = 0;
270static OSArray * sLoadedKexts = NULL;
271static OSArray * sUnloadedPrelinkedKexts = NULL;
272
273// Requests to kextd waiting to be picked up.
274static OSArray * sKernelRequests = NULL;
275// Identifier of kext load requests in sKernelRequests
276static OSSet * sPostedKextLoadIdentifiers = NULL;
277static OSArray * sRequestCallbackRecords = NULL;
278
279// Identifiers of all kexts ever requested in kernel; used for prelinked kernel
280static OSSet * sAllKextLoadIdentifiers = NULL;
281static KXLDContext * sKxldContext = NULL;
282static uint32_t sNextLoadTag = 0;
283static uint32_t sNextRequestTag = 0;
284
285static bool sUserLoadsActive = false;
286static bool sKextdActive = false;
287static bool sDeferredLoadSucceeded = false;
288static bool sConsiderUnloadsExecuted = false;
289
290#if NO_KEXTD
291static bool sKernelRequestsEnabled = false;
292#else
293static bool sKernelRequestsEnabled = true;
294#endif
295static bool sLoadEnabled = true;
296static bool sUnloadEnabled = true;
297
298/*********************************************************************
299* Stuff for the OSKext representing the kernel itself.
300**********/
301static OSKext * sKernelKext = NULL;
302
303/* Set up a fake kmod_info struct for the kernel.
304 * It's used in OSRuntime.cpp to call OSRuntimeInitializeCPP()
305 * before OSKext is initialized; that call only needs the name
306 * and address to be set correctly.
307 *
308 * We don't do much else with the kerne's kmod_info; we never
309 * put it into the kmod list, never adjust the reference count,
310 * and never have kernel components reference it.
311 * For that matter, we don't do much with kmod_info structs
312 * at all anymore! We just keep them filled in for gdb and
313 * binary compability.
314 */
315kmod_info_t g_kernel_kmod_info = {
316 /* next */ 0,
317 /* info_version */ KMOD_INFO_VERSION,
318 /* id */ 0, // loadTag: kernel is always 0
319 /* name */ kOSKextKernelIdentifier, // bundle identifier
320 /* version */ "0", // filled in in OSKext::initialize()
321 /* reference_count */ -1, // never adjusted; kernel never unloads
322 /* reference_list */ NULL,
323 /* address */ 0,
324 /* size */ 0, // filled in in OSKext::initialize()
325 /* hdr_size */ 0,
326 /* start */ 0,
327 /* stop */ 0
328};
329
330/* Set up a fake kmod_info struct for statically linked kexts that don't have one. */
331
332kmod_info_t invalid_kmod_info = {
333 /* next */ 0,
334 /* info_version */ KMOD_INFO_VERSION,
335 /* id */ UINT32_MAX,
336 /* name */ "invalid",
337 /* version */ "0",
338 /* reference_count */ -1,
339 /* reference_list */ NULL,
340 /* address */ 0,
341 /* size */ 0,
342 /* hdr_size */ 0,
343 /* start */ 0,
344 /* stop */ 0
345};
346
347extern "C" {
348// symbol 'kmod' referenced in: model_dep.c, db_trace.c, symbols.c, db_low_trace.c,
349// dtrace.c, dtrace_glue.h, OSKext.cpp, locore.s, lowmem_vectors.s,
350// misc_protos.h, db_low_trace.c, kgmacros
351// 'kmod' is a holdover from the old kmod system, we can't rename it.
352kmod_info_t * kmod = NULL;
353
354#define KEXT_PANICLIST_SIZE (2 * PAGE_SIZE)
355
356
357static char * loaded_kext_paniclist = NULL;
358static uint32_t loaded_kext_paniclist_size = 0;
359
360AbsoluteTime last_loaded_timestamp;
361static char last_loaded_str_buf[2*KMOD_MAX_NAME];
362static u_long last_loaded_strlen = 0;
363static void * last_loaded_address = NULL;
364static u_long last_loaded_size = 0;
365
366AbsoluteTime last_unloaded_timestamp;
367static char last_unloaded_str_buf[2*KMOD_MAX_NAME];
368static u_long last_unloaded_strlen = 0;
369static void * last_unloaded_address = NULL;
370static u_long last_unloaded_size = 0;
371
372// Statically linked kmods described by several mach-o sections:
373//
374// kPrelinkInfoSegment:kBuiltinInfoSection
375// Array of pointers to kmod_info_t structs.
376//
377// kPrelinkInfoSegment:kBuiltinInfoSection
378// Array of pointers to an embedded mach-o header.
379//
380// __DATA:kBuiltinInitSection, kBuiltinTermSection
381// Structors for all kmods. Has to be filtered by proc address.
382//
383
384static uint32_t gBuiltinKmodsCount;
385static kernel_section_t * gBuiltinKmodsSectionInfo;
386static kernel_section_t * gBuiltinKmodsSectionStart;
387
388static const OSSymbol * gIOSurfaceIdentifier;
389vm_tag_t gIOSurfaceTag;
390
391/*********************************************************************
392* sKextInnerLock protects against cross-calls with IOService and
393* IOCatalogue, and owns the variables declared immediately below.
394*
395* Note that sConsiderUnloadsExecuted above belongs to sKextLock!
396*
397* When both sKextLock and sKextInnerLock need to be taken,
398* always lock sKextLock first and unlock it second. Never take both
399* locks in an entry point to OSKext; if you need to do so, you must
400* spawn an independent thread to avoid potential deadlocks for threads
401* calling into OSKext.
402**********/
403static IORecursiveLock * sKextInnerLock = NULL;
404
405static bool sAutounloadEnabled = true;
406static bool sConsiderUnloadsCalled = false;
407static bool sConsiderUnloadsPending = false;
408
409static unsigned int sConsiderUnloadDelay = 60; // seconds
410static thread_call_t sUnloadCallout = 0;
411static thread_call_t sDestroyLinkContextThread = 0; // one-shot, one-at-a-time thread
412static bool sSystemSleep = false; // true when system going to sleep
413static AbsoluteTime sLastWakeTime; // last time we woke up
414
415/*********************************************************************
416* Backtraces can be printed at various times so we need a tight lock
417* on data used for that. sKextSummariesLock protects the variables
418* declared immediately below.
419*
420* gLoadedKextSummaries is accessed by other modules, but only during
421* a panic so the lock isn't needed then.
422*
423* gLoadedKextSummaries has the "used" attribute in order to ensure
424* that it remains visible even when we are performing extremely
425* aggressive optimizations, as it is needed to allow the debugger
426* to automatically parse the list of loaded kexts.
427**********/
428static IOLock * sKextSummariesLock = NULL;
429extern "C" lck_spin_t vm_allocation_sites_lock;
430static IOSimpleLock * sKextAccountsLock = &vm_allocation_sites_lock;
431
432void (*sLoadedKextSummariesUpdated)(void) = OSKextLoadedKextSummariesUpdated;
433OSKextLoadedKextSummaryHeader * gLoadedKextSummaries __attribute__((used)) = NULL;
434uint64_t gLoadedKextSummariesTimestamp __attribute__((used)) = 0;
435static size_t sLoadedKextSummariesAllocSize = 0;
436
437static OSKextActiveAccount * sKextAccounts;
438static uint32_t sKextAccountsCount;
439};
440
441/*********************************************************************
442* sKextLoggingLock protects the logging variables declared immediately below.
443**********/
444static IOLock * sKextLoggingLock = NULL;
445
446static const OSKextLogSpec kDefaultKernelLogFilter = kOSKextLogBasicLevel |
447 kOSKextLogVerboseFlagsMask;
448static OSKextLogSpec sKernelLogFilter = kDefaultKernelLogFilter;
449static bool sBootArgLogFilterFound = false;
450SYSCTL_UINT(_debug, OID_AUTO, kextlog, CTLFLAG_RW | CTLFLAG_LOCKED, &sKernelLogFilter,
451 0, "kernel kext logging");
452
453static OSKextLogSpec sUserSpaceKextLogFilter = kOSKextLogSilentFilter;
454static OSArray * sUserSpaceLogSpecArray = NULL;
455static OSArray * sUserSpaceLogMessageArray = NULL;
456
457/*********
458* End scope for sKextInnerLock-protected variables.
459*********************************************************************/
460
461
462/*********************************************************************
463 helper function used for collecting PGO data upon unload of a kext
464 */
465
466static int OSKextGrabPgoDataLocked(OSKext *kext,
467 bool metadata,
468 uuid_t instance_uuid,
469 uint64_t *pSize,
470 char *pBuffer,
471 uint64_t bufferSize);
472
473/**********************************************************************/
474
475
476
477#if PRAGMA_MARK
478#pragma mark OSData callbacks (need to move to OSData)
479#endif
480/*********************************************************************
481* C functions used for callbacks.
482*********************************************************************/
483extern "C" {
484void osdata_kmem_free(void * ptr, unsigned int length) {
485 kmem_free(kernel_map, (vm_address_t)ptr, length);
486 return;
487}
488
489void osdata_phys_free(void * ptr, unsigned int length) {
490 ml_static_mfree((vm_offset_t)ptr, length);
491 return;
492}
493
494void osdata_vm_deallocate(void * ptr, unsigned int length)
495{
496 (void)vm_deallocate(kernel_map, (vm_offset_t)ptr, length);
497 return;
498}
499
500void osdata_kext_free(void * ptr, unsigned int length)
501{
502 (void)kext_free((vm_offset_t)ptr, length);
503}
504
505};
506
507#if PRAGMA_MARK
508#pragma mark KXLD Allocation Callback
509#endif
510/*********************************************************************
511* KXLD Allocation Callback
512*********************************************************************/
513kxld_addr_t
514kern_allocate(
515 u_long size,
516 KXLDAllocateFlags * flags,
517 void * user_data)
518{
519 vm_address_t result = 0; // returned
520 kern_return_t mach_result = KERN_FAILURE;
521 bool success = false;
522 OSKext * theKext = (OSKext *)user_data;
523 u_long roundSize = round_page(size);
524 OSData * linkBuffer = NULL; // must release
525
526 mach_result = kext_alloc(&result, roundSize, /* fixed */ FALSE);
527 if (mach_result != KERN_SUCCESS) {
528 OSKextLog(theKext,
529 kOSKextLogErrorLevel |
530 kOSKextLogGeneralFlag,
531 "Can't allocate kernel memory to link %s.",
532 theKext->getIdentifierCString());
533 goto finish;
534 }
535
536 /* Create an OSData wrapper for the allocated buffer.
537 */
538 linkBuffer = OSData::withBytesNoCopy((void *)result, roundSize);
539 if (!linkBuffer) {
540 OSKextLog(theKext,
541 kOSKextLogErrorLevel |
542 kOSKextLogGeneralFlag,
543 "Can't allocate linked executable wrapper for %s.",
544 theKext->getIdentifierCString());
545 goto finish;
546 }
547 linkBuffer->setDeallocFunction(osdata_kext_free);
548 OSKextLog(theKext,
549 kOSKextLogProgressLevel |
550 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
551 "Allocated link buffer for kext %s at %p (%lu bytes).",
552 theKext->getIdentifierCString(),
553 (void *)result, (unsigned long)roundSize);
554
555 theKext->setLinkedExecutable(linkBuffer);
556
557 *flags = kKxldAllocateWritable;
558 success = true;
559
560finish:
561 if (!success && result) {
562 kext_free(result, roundSize);
563 result = 0;
564 }
565
566 OSSafeReleaseNULL(linkBuffer);
567
568 return (kxld_addr_t)result;
569}
570
571/*********************************************************************
572*********************************************************************/
573void
574kxld_log_callback(
575 KXLDLogSubsystem subsystem,
576 KXLDLogLevel level,
577 const char * format,
578 va_list argList,
579 void * user_data)
580{
581 OSKext *theKext = (OSKext *) user_data;
582 OSKextLogSpec logSpec = 0;
583
584 switch (subsystem) {
585 case kKxldLogLinking:
586 logSpec |= kOSKextLogLinkFlag;
587 break;
588 case kKxldLogPatching:
589 logSpec |= kOSKextLogPatchFlag;
590 break;
591 }
592
593 switch (level) {
594 case kKxldLogExplicit:
595 logSpec |= kOSKextLogExplicitLevel;
596 break;
597 case kKxldLogErr:
598 logSpec |= kOSKextLogErrorLevel;
599 break;
600 case kKxldLogWarn:
601 logSpec |= kOSKextLogWarningLevel;
602 break;
603 case kKxldLogBasic:
604 logSpec |= kOSKextLogProgressLevel;
605 break;
606 case kKxldLogDetail:
607 logSpec |= kOSKextLogDetailLevel;
608 break;
609 case kKxldLogDebug:
610 logSpec |= kOSKextLogDebugLevel;
611 break;
612 }
613
614 OSKextVLog(theKext, logSpec, format, argList);
615}
616
617#if PRAGMA_MARK
618#pragma mark IOStatistics defines
619#endif
620
621#if IOKITSTATS
622
623#define notifyKextLoadObservers(kext, kmod_info) \
624do { \
625 IOStatistics::onKextLoad(kext, kmod_info); \
626} while (0)
627
628#define notifyKextUnloadObservers(kext) \
629do { \
630 IOStatistics::onKextUnload(kext); \
631} while (0)
632
633#define notifyAddClassObservers(kext, addedClass, flags) \
634do { \
635 IOStatistics::onClassAdded(kext, addedClass); \
636} while (0)
637
638#define notifyRemoveClassObservers(kext, removedClass, flags) \
639do { \
640 IOStatistics::onClassRemoved(kext, removedClass); \
641} while (0)
642
643#else
644
645#define notifyKextLoadObservers(kext, kmod_info)
646#define notifyKextUnloadObservers(kext)
647#define notifyAddClassObservers(kext, addedClass, flags)
648#define notifyRemoveClassObservers(kext, removedClass, flags)
649
650#endif /* IOKITSTATS */
651
652#if PRAGMA_MARK
653#pragma mark Module Config (Startup & Shutdown)
654#endif
655/*********************************************************************
656* Module Config (Class Definition & Class Methods)
657*********************************************************************/
658#define super OSObject
659OSDefineMetaClassAndStructors(OSKext, OSObject)
660
661/*********************************************************************
662*********************************************************************/
663/* static */
664void
665OSKext::initialize(void)
666{
667 OSData * kernelExecutable = NULL; // do not release
668 u_char * kernelStart = NULL; // do not free
669 size_t kernelLength = 0;
670 OSString * scratchString = NULL; // must release
671 IORegistryEntry * registryRoot = NULL; // do not release
672 OSNumber * kernelCPUType = NULL; // must release
673 OSNumber * kernelCPUSubtype = NULL; // must release
674 OSKextLogSpec bootLogFilter = kOSKextLogSilentFilter;
675 bool setResult = false;
676 uint64_t * timestamp = 0;
677 char bootArgBuffer[16]; // for PE_parse_boot_argn w/strings
678
679 /* This must be the first thing allocated. Everything else grabs this lock.
680 */
681 sKextLock = IORecursiveLockAlloc();
682 sKextInnerLock = IORecursiveLockAlloc();
683 sKextSummariesLock = IOLockAlloc();
684 sKextLoggingLock = IOLockAlloc();
685 assert(sKextLock);
686 assert(sKextInnerLock);
687 assert(sKextSummariesLock);
688 assert(sKextLoggingLock);
689
690 sKextsByID = OSDictionary::withCapacity(kOSKextTypicalLoadCount);
691 sLoadedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
692 sUnloadedPrelinkedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount / 10);
693 sKernelRequests = OSArray::withCapacity(0);
694 sPostedKextLoadIdentifiers = OSSet::withCapacity(0);
695 sAllKextLoadIdentifiers = OSSet::withCapacity(kOSKextTypicalLoadCount);
696 sRequestCallbackRecords = OSArray::withCapacity(0);
697 assert(sKextsByID && sLoadedKexts && sKernelRequests &&
698 sPostedKextLoadIdentifiers && sAllKextLoadIdentifiers &&
699 sRequestCallbackRecords && sUnloadedPrelinkedKexts);
700
701 /* Read the log flag boot-args and set the log flags.
702 */
703 if (PE_parse_boot_argn("kextlog", &bootLogFilter, sizeof(bootLogFilter))) {
704 sBootArgLogFilterFound = true;
705 sKernelLogFilter = bootLogFilter;
706 // log this if any flags are set
707 OSKextLog(/* kext */ NULL,
708 kOSKextLogBasicLevel |
709 kOSKextLogFlagsMask,
710 "Kernel kext log filter 0x%x per kextlog boot arg.",
711 (unsigned)sKernelLogFilter);
712 }
713
714 sSafeBoot = PE_parse_boot_argn("-x", bootArgBuffer,
715 sizeof(bootArgBuffer)) ? true : false;
716
717 if (sSafeBoot) {
718 OSKextLog(/* kext */ NULL,
719 kOSKextLogWarningLevel |
720 kOSKextLogGeneralFlag,
721 "SAFE BOOT DETECTED - "
722 "only valid OSBundleRequired kexts will be loaded.");
723 }
724
725 PE_parse_boot_argn("keepsyms", &sKeepSymbols, sizeof(sKeepSymbols));
726#if CONFIG_DTRACE
727 if (dtrace_keep_kernel_symbols())
728 sKeepSymbols = true;
729#endif /* CONFIG_DTRACE */
730#if KASAN_DYNAMIC_BLACKLIST
731 /* needed for function lookup */
732 sKeepSymbols = true;
733#endif
734
735 /* Set up an OSKext instance to represent the kernel itself.
736 */
737 sKernelKext = new OSKext;
738 assert(sKernelKext);
739
740 kernelStart = (u_char *)&_mh_execute_header;
741 kernelLength = getlastaddr() - (vm_offset_t)kernelStart;
742 kernelExecutable = OSData::withBytesNoCopy(
743 kernelStart, kernelLength);
744 assert(kernelExecutable);
745
746#if KASLR_KEXT_DEBUG
747 IOLog("kaslr: kernel start 0x%lx end 0x%lx length %lu vm_kernel_slide %llu (0x%016lx) \n",
748 (unsigned long)kernelStart,
749 (unsigned long)getlastaddr(),
750 kernelLength,
751 vm_kernel_slide, vm_kernel_slide);
752#endif
753
754 sKernelKext->loadTag = sNextLoadTag++; // the kernel is load tag 0
755 sKernelKext->bundleID = OSSymbol::withCString(kOSKextKernelIdentifier);
756
757 sKernelKext->version = OSKextParseVersionString(osrelease);
758 sKernelKext->compatibleVersion = sKernelKext->version;
759 sKernelKext->linkedExecutable = kernelExecutable;
760 sKernelKext->interfaceUUID = sKernelKext->copyUUID();
761
762 sKernelKext->flags.hasAllDependencies = 1;
763 sKernelKext->flags.kernelComponent = 1;
764 sKernelKext->flags.prelinked = 0;
765 sKernelKext->flags.loaded = 1;
766 sKernelKext->flags.started = 1;
767 sKernelKext->flags.CPPInitialized = 0;
768 sKernelKext->flags.jettisonLinkeditSeg = 0;
769
770 sKernelKext->kmod_info = &g_kernel_kmod_info;
771 strlcpy(g_kernel_kmod_info.version, osrelease,
772 sizeof(g_kernel_kmod_info.version));
773 g_kernel_kmod_info.size = kernelLength;
774 g_kernel_kmod_info.id = sKernelKext->loadTag;
775
776 /* Cons up an info dict, so we don't have to have special-case
777 * checking all over.
778 */
779 sKernelKext->infoDict = OSDictionary::withCapacity(5);
780 assert(sKernelKext->infoDict);
781 setResult = sKernelKext->infoDict->setObject(kCFBundleIdentifierKey,
782 sKernelKext->bundleID);
783 assert(setResult);
784 setResult = sKernelKext->infoDict->setObject(kOSKernelResourceKey,
785 kOSBooleanTrue);
786 assert(setResult);
787
788 scratchString = OSString::withCStringNoCopy(osrelease);
789 assert(scratchString);
790 setResult = sKernelKext->infoDict->setObject(kCFBundleVersionKey,
791 scratchString);
792 assert(setResult);
793 OSSafeReleaseNULL(scratchString);
794
795 scratchString = OSString::withCStringNoCopy("mach_kernel");
796 assert(scratchString);
797 setResult = sKernelKext->infoDict->setObject(kCFBundleNameKey,
798 scratchString);
799 assert(setResult);
800 OSSafeReleaseNULL(scratchString);
801
802 /* Add the kernel kext to the bookkeeping dictionaries. Note that
803 * the kernel kext doesn't have a kmod_info struct. copyInfo()
804 * gathers info from other places anyhow.
805 */
806 setResult = sKextsByID->setObject(sKernelKext->bundleID, sKernelKext);
807 assert(setResult);
808 setResult = sLoadedKexts->setObject(sKernelKext);
809 assert(setResult);
810 sKernelKext->release();
811
812 registryRoot = IORegistryEntry::getRegistryRoot();
813 kernelCPUType = OSNumber::withNumber(
814 (long long unsigned int)_mh_execute_header.cputype,
815 8 * sizeof(_mh_execute_header.cputype));
816 kernelCPUSubtype = OSNumber::withNumber(
817 (long long unsigned int)_mh_execute_header.cpusubtype,
818 8 * sizeof(_mh_execute_header.cpusubtype));
819 assert(registryRoot && kernelCPUSubtype && kernelCPUType);
820
821 registryRoot->setProperty(kOSKernelCPUTypeKey, kernelCPUType);
822 registryRoot->setProperty(kOSKernelCPUSubtypeKey, kernelCPUSubtype);
823
824 OSSafeReleaseNULL(kernelCPUType);
825 OSSafeReleaseNULL(kernelCPUSubtype);
826
827 gBuiltinKmodsSectionInfo = getsectbyname(kPrelinkInfoSegment, kBuiltinInfoSection);
828 if (gBuiltinKmodsSectionInfo) {
829 uint32_t count;
830
831 assert(gBuiltinKmodsSectionInfo->addr);
832 assert(gBuiltinKmodsSectionInfo->size);
833 gBuiltinKmodsCount = (gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *));
834
835 gBuiltinKmodsSectionStart = getsectbyname(kPrelinkInfoSegment, kBuiltinStartSection);
836 assert(gBuiltinKmodsSectionStart);
837 assert(gBuiltinKmodsSectionStart->addr);
838 assert(gBuiltinKmodsSectionStart->size);
839 count = (gBuiltinKmodsSectionStart->size / sizeof(uintptr_t));
840 // one extra pointer for the end of last kmod
841 assert(count == (gBuiltinKmodsCount + 1));
842
843 vm_kernel_builtinkmod_text = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[0];
844 vm_kernel_builtinkmod_text_end = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[count - 1];
845 }
846 gIOSurfaceIdentifier = OSSymbol::withCStringNoCopy("com.apple.iokit.IOSurface");
847
848 timestamp = __OSAbsoluteTimePtr(&last_loaded_timestamp);
849 *timestamp = 0;
850 timestamp = __OSAbsoluteTimePtr(&last_unloaded_timestamp);
851 *timestamp = 0;
852 timestamp = __OSAbsoluteTimePtr(&sLastWakeTime);
853 *timestamp = 0;
854
855 OSKextLog(/* kext */ NULL,
856 kOSKextLogProgressLevel |
857 kOSKextLogGeneralFlag,
858 "Kext system initialized.");
859
860 notifyKextLoadObservers(sKernelKext, sKernelKext->kmod_info);
861
862 return;
863}
864
865/*********************************************************************
866* This is expected to be called exactly once, from exactly one thread
867* context, during kernel bootstrap.
868*********************************************************************/
869/* static */
870OSReturn
871OSKext::removeKextBootstrap(void)
872{
873 OSReturn result = kOSReturnError;
874
875 const char * dt_kernel_header_name = "Kernel-__HEADER";
876 const char * dt_kernel_symtab_name = "Kernel-__SYMTAB";
877 kernel_mach_header_t * dt_mach_header = NULL;
878 int dt_mach_header_size = 0;
879 struct symtab_command * dt_symtab = NULL;
880 int dt_symtab_size = 0;
881 int dt_result = 0;
882
883 kernel_segment_command_t * seg_to_remove = NULL;
884
885#if __arm__ || __arm64__
886 const char * dt_segment_name = NULL;
887 void * segment_paddress = NULL;
888 int segment_size = 0;
889#endif
890
891 OSKextLog(/* kext */ NULL,
892 kOSKextLogProgressLevel |
893 kOSKextLogGeneralFlag,
894 "Jettisoning kext bootstrap segments.");
895
896 /*****
897 * Dispose of unnecessary stuff that the booter didn't need to load.
898 */
899 dt_result = IODTGetLoaderInfo(dt_kernel_header_name,
900 (void **)&dt_mach_header, &dt_mach_header_size);
901 if (dt_result == 0 && dt_mach_header) {
902 IODTFreeLoaderInfo(dt_kernel_header_name, (void *)dt_mach_header,
903 round_page_32(dt_mach_header_size));
904 }
905 dt_result = IODTGetLoaderInfo(dt_kernel_symtab_name,
906 (void **)&dt_symtab, &dt_symtab_size);
907 if (dt_result == 0 && dt_symtab) {
908 IODTFreeLoaderInfo(dt_kernel_symtab_name, (void *)dt_symtab,
909 round_page_32(dt_symtab_size));
910 }
911
912 /*****
913 * KLD bootstrap segment.
914 */
915 // xxx - should rename KLD segment
916 seg_to_remove = getsegbyname("__KLD");
917 if (seg_to_remove) {
918 OSRuntimeUnloadCPPForSegment(seg_to_remove);
919 }
920
921#if __arm__ || __arm64__
922 /* Free the memory that was set up by bootx.
923 */
924 dt_segment_name = "Kernel-__KLD";
925 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
926 /* We cannot free this with KTRR enabled, as we cannot
927 * update the permissions on the KLD range this late
928 * in the boot process.
929 */
930 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
931 (int)segment_size);
932 }
933#elif __i386__ || __x86_64__
934 /* On x86, use the mapping data from the segment load command to
935 * unload KLD directly.
936 * This may invalidate any assumptions about "avail_start"
937 * defining the lower bound for valid physical addresses.
938 */
939 if (seg_to_remove && seg_to_remove->vmaddr && seg_to_remove->vmsize) {
940 // 04/18/11 - gab: <rdar://problem/9236163>
941 // overwrite memory occupied by KLD segment with random data before
942 // releasing it.
943 read_frandom((void *) seg_to_remove->vmaddr, seg_to_remove->vmsize);
944 ml_static_mfree(seg_to_remove->vmaddr, seg_to_remove->vmsize);
945 }
946#else
947#error arch
948#endif
949
950 seg_to_remove = NULL;
951
952 /*****
953 * Prelinked kernel's symtab (if there is one).
954 */
955 kernel_section_t * sect;
956 sect = getsectbyname("__PRELINK", "__symtab");
957 if (sect && sect->addr && sect->size) {
958 ml_static_mfree(sect->addr, sect->size);
959 }
960
961 seg_to_remove = (kernel_segment_command_t *)getsegbyname("__LINKEDIT");
962
963 /* kxld always needs the kernel's __LINKEDIT segment, but we can make it
964 * pageable, unless keepsyms is set. To do that, we have to copy it from
965 * its booter-allocated memory, free the booter memory, reallocate proper
966 * managed memory, then copy the segment back in.
967 */
968#if CONFIG_KXLD
969#if (__arm__ || __arm64__)
970#error CONFIG_KXLD not expected for this arch
971#endif
972 if (!sKeepSymbols) {
973 kern_return_t mem_result;
974 void *seg_copy = NULL;
975 void *seg_data = NULL;
976 vm_map_offset_t seg_offset = 0;
977 vm_map_offset_t seg_copy_offset = 0;
978 vm_map_size_t seg_length = 0;
979
980 seg_data = (void *) seg_to_remove->vmaddr;
981 seg_offset = (vm_map_offset_t) seg_to_remove->vmaddr;
982 seg_length = (vm_map_size_t) seg_to_remove->vmsize;
983
984 /* Allocate space for the LINKEDIT copy.
985 */
986 mem_result = kmem_alloc(kernel_map, (vm_offset_t *) &seg_copy,
987 seg_length, VM_KERN_MEMORY_KEXT);
988 if (mem_result != KERN_SUCCESS) {
989 OSKextLog(/* kext */ NULL,
990 kOSKextLogErrorLevel |
991 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
992 "Can't copy __LINKEDIT segment for VM reassign.");
993 return result;
994 }
995 seg_copy_offset = (vm_map_offset_t) seg_copy;
996
997 /* Copy it out.
998 */
999 memcpy(seg_copy, seg_data, seg_length);
1000
1001 /* Dump the booter memory.
1002 */
1003 ml_static_mfree(seg_offset, seg_length);
1004
1005 /* Set up the VM region.
1006 */
1007 mem_result = vm_map_enter_mem_object(
1008 kernel_map,
1009 &seg_offset,
1010 seg_length, /* mask */ 0,
1011 VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
1012 VM_MAP_KERNEL_FLAGS_NONE,
1013 VM_KERN_MEMORY_NONE,
1014 (ipc_port_t)NULL,
1015 (vm_object_offset_t) 0,
1016 /* copy */ FALSE,
1017 /* cur_protection */ VM_PROT_READ | VM_PROT_WRITE,
1018 /* max_protection */ VM_PROT_ALL,
1019 /* inheritance */ VM_INHERIT_DEFAULT);
1020 if ((mem_result != KERN_SUCCESS) ||
1021 (seg_offset != (vm_map_offset_t) seg_data))
1022 {
1023 OSKextLog(/* kext */ NULL,
1024 kOSKextLogErrorLevel |
1025 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1026 "Can't create __LINKEDIT VM entry at %p, length 0x%llx (error 0x%x).",
1027 seg_data, seg_length, mem_result);
1028 return result;
1029 }
1030
1031 /* And copy it back.
1032 */
1033 memcpy(seg_data, seg_copy, seg_length);
1034
1035 /* Free the copy.
1036 */
1037 kmem_free(kernel_map, seg_copy_offset, seg_length);
1038 }
1039#else /* we are not CONFIG_KXLD */
1040#if !(__arm__ || __arm64__)
1041#error CONFIG_KXLD is expected for this arch
1042#endif
1043
1044 /*****
1045 * Dump the LINKEDIT segment, unless keepsyms is set.
1046 */
1047 if (!sKeepSymbols) {
1048 dt_segment_name = "Kernel-__LINKEDIT";
1049 if (0 == IODTGetLoaderInfo(dt_segment_name,
1050 &segment_paddress, &segment_size)) {
1051#ifdef SECURE_KERNEL
1052 vm_offset_t vmaddr = ml_static_ptovirt((vm_offset_t)segment_paddress);
1053 bzero((void*)vmaddr, segment_size);
1054#endif
1055 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1056 (int)segment_size);
1057 }
1058 } else {
1059 OSKextLog(/* kext */ NULL,
1060 kOSKextLogBasicLevel |
1061 kOSKextLogGeneralFlag,
1062 "keepsyms boot arg specified; keeping linkedit segment for symbols.");
1063 }
1064#endif /* CONFIG_KXLD */
1065
1066 seg_to_remove = NULL;
1067
1068 result = kOSReturnSuccess;
1069
1070 return result;
1071}
1072
1073/*********************************************************************
1074*********************************************************************/
1075void
1076OSKext::flushNonloadedKexts(
1077 Boolean flushPrelinkedKexts)
1078{
1079 OSSet * prelinkedKexts = NULL; // must release
1080 OSCollectionIterator * kextIterator = NULL; // must release
1081 OSCollectionIterator * prelinkIterator = NULL; // must release
1082 const OSSymbol * thisID = NULL; // do not release
1083 OSKext * thisKext = NULL; // do not release
1084 uint32_t count, i;
1085
1086 IORecursiveLockLock(sKextLock);
1087
1088 OSKextLog(/* kext */ NULL,
1089 kOSKextLogProgressLevel |
1090 kOSKextLogKextBookkeepingFlag,
1091 "Flushing nonloaded kexts and other unused data.");
1092
1093 OSKext::considerDestroyingLinkContext();
1094
1095 /* If we aren't flushing unused prelinked kexts, we have to put them
1096 * aside while we flush everything else so make a container for them.
1097 */
1098 if (!flushPrelinkedKexts) {
1099 prelinkedKexts = OSSet::withCapacity(0);
1100 if (!prelinkedKexts) {
1101 goto finish;
1102 }
1103 }
1104
1105 /* Set aside prelinked kexts (in-use or not) and break
1106 * any lingering inter-kext references for nonloaded kexts
1107 * so they have min. retain counts.
1108 */
1109 kextIterator = OSCollectionIterator::withCollection(sKextsByID);
1110 if (!kextIterator) {
1111 goto finish;
1112 }
1113
1114 while ((thisID = OSDynamicCast(OSSymbol,
1115 kextIterator->getNextObject()))) {
1116
1117 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
1118
1119 if (thisKext) {
1120 if (prelinkedKexts && thisKext->isPrelinked()) {
1121 prelinkedKexts->setObject(thisKext);
1122 }
1123 thisKext->flushDependencies(/* forceIfLoaded */ false);
1124 }
1125 }
1126
1127 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
1128 */
1129 sKextsByID->flushCollection();
1130
1131 /* Now put the loaded kexts back into the ID dictionary.
1132 */
1133 count = sLoadedKexts->getCount();
1134 for (i = 0; i < count; i++) {
1135 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
1136 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1137 }
1138
1139 /* Finally, put back the prelinked kexts if we saved any.
1140 */
1141 if (prelinkedKexts) {
1142 prelinkIterator = OSCollectionIterator::withCollection(prelinkedKexts);
1143 if (!prelinkIterator) {
1144 goto finish;
1145 }
1146
1147 while ((thisKext = OSDynamicCast(OSKext,
1148 prelinkIterator->getNextObject()))) {
1149
1150 sKextsByID->setObject(thisKext->getIdentifierCString(),
1151 thisKext);
1152 }
1153 }
1154
1155finish:
1156 IORecursiveLockUnlock(sKextLock);
1157
1158 OSSafeReleaseNULL(prelinkedKexts);
1159 OSSafeReleaseNULL(kextIterator);
1160 OSSafeReleaseNULL(prelinkIterator);
1161
1162 return;
1163}
1164
1165/*********************************************************************
1166*********************************************************************/
1167/* static */
1168void
1169OSKext::setKextdActive(Boolean active)
1170{
1171 IORecursiveLockLock(sKextLock);
1172 sKextdActive = active;
1173 if (sKernelRequests->getCount()) {
1174 OSKext::pingKextd();
1175 }
1176 IORecursiveLockUnlock(sKextLock);
1177
1178 return;
1179}
1180
1181/*********************************************************************
1182* OSKextLib.cpp might need access to this someday but for now it's
1183* private.
1184*********************************************************************/
1185extern "C" {
1186extern void ipc_port_release_send(ipc_port_t);
1187};
1188
1189/* static */
1190OSReturn
1191OSKext::pingKextd(void)
1192{
1193 OSReturn result = kOSReturnError;
1194#if !NO_KEXTD
1195 mach_port_t kextd_port = IPC_PORT_NULL;
1196
1197 if (!sKextdActive) {
1198 result = kOSKextReturnDisabled; // basically unavailable
1199 goto finish;
1200 }
1201
1202 result = host_get_kextd_port(host_priv_self(), &kextd_port);
1203 if (result != KERN_SUCCESS || !IPC_PORT_VALID(kextd_port)) {
1204 OSKextLog(/* kext */ NULL,
1205 kOSKextLogErrorLevel |
1206 kOSKextLogIPCFlag,
1207 "Can't get kextd port.");
1208 goto finish;
1209 }
1210
1211 result = kextd_ping(kextd_port);
1212 if (result != KERN_SUCCESS) {
1213 OSKextLog(/* kext */ NULL,
1214 kOSKextLogErrorLevel |
1215 kOSKextLogIPCFlag,
1216 "kextd ping failed (0x%x).", (int)result);
1217 goto finish;
1218 }
1219
1220finish:
1221 if (IPC_PORT_VALID(kextd_port)) {
1222 ipc_port_release_send(kextd_port);
1223 }
1224#endif
1225
1226 return result;
1227}
1228
1229/*********************************************************************
1230*********************************************************************/
1231/* static */
1232void
1233OSKext::setDeferredLoadSucceeded(Boolean succeeded)
1234{
1235 IORecursiveLockLock(sKextLock);
1236 sDeferredLoadSucceeded = succeeded;
1237 IORecursiveLockUnlock(sKextLock);
1238
1239 return;
1240}
1241
1242/*********************************************************************
1243* Called from IOSystemShutdownNotification.
1244*********************************************************************/
1245/* static */
1246void
1247OSKext::willShutdown(void)
1248{
1249#if !NO_KEXTD
1250 OSReturn checkResult = kOSReturnError;
1251#endif
1252 OSDictionary * exitRequest = NULL; // must release
1253
1254 IORecursiveLockLock(sKextLock);
1255
1256 OSKext::setLoadEnabled(false);
1257 OSKext::setUnloadEnabled(false);
1258 OSKext::setAutounloadsEnabled(false);
1259 OSKext::setKernelRequestsEnabled(false);
1260
1261#if !NO_KEXTD
1262 OSKextLog(/* kext */ NULL,
1263 kOSKextLogProgressLevel |
1264 kOSKextLogGeneralFlag,
1265 "System shutdown; requesting immediate kextd exit.");
1266
1267 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestKextdExit,
1268 &exitRequest);
1269 if (checkResult != kOSReturnSuccess) {
1270 goto finish;
1271 }
1272 if (!sKernelRequests->setObject(exitRequest)) {
1273 goto finish;
1274 }
1275
1276 OSKext::pingKextd();
1277
1278finish:
1279#endif
1280
1281 IORecursiveLockUnlock(sKextLock);
1282
1283 OSSafeReleaseNULL(exitRequest);
1284 return;
1285}
1286
1287/*********************************************************************
1288*********************************************************************/
1289/* static */
1290bool
1291OSKext::getLoadEnabled(void)
1292{
1293 bool result;
1294
1295 IORecursiveLockLock(sKextLock);
1296 result = sLoadEnabled;
1297 IORecursiveLockUnlock(sKextLock);
1298 return result;
1299}
1300
1301/*********************************************************************
1302*********************************************************************/
1303/* static */
1304bool
1305OSKext::setLoadEnabled(bool flag)
1306{
1307 bool result;
1308
1309 IORecursiveLockLock(sKextLock);
1310 result = sLoadEnabled;
1311 sLoadEnabled = (flag ? true : false);
1312
1313 if (sLoadEnabled != result) {
1314 OSKextLog(/* kext */ NULL,
1315 kOSKextLogBasicLevel |
1316 kOSKextLogLoadFlag,
1317 "Kext loading now %sabled.", sLoadEnabled ? "en" : "dis");
1318 }
1319
1320 IORecursiveLockUnlock(sKextLock);
1321
1322 return result;
1323}
1324
1325/*********************************************************************
1326*********************************************************************/
1327/* static */
1328bool
1329OSKext::getUnloadEnabled(void)
1330{
1331 bool result;
1332
1333 IORecursiveLockLock(sKextLock);
1334 result = sUnloadEnabled;
1335 IORecursiveLockUnlock(sKextLock);
1336 return result;
1337}
1338
1339/*********************************************************************
1340*********************************************************************/
1341/* static */
1342bool
1343OSKext::setUnloadEnabled(bool flag)
1344{
1345 bool result;
1346
1347 IORecursiveLockLock(sKextLock);
1348 result = sUnloadEnabled;
1349 sUnloadEnabled = (flag ? true : false);
1350 IORecursiveLockUnlock(sKextLock);
1351
1352 if (sUnloadEnabled != result) {
1353 OSKextLog(/* kext */ NULL,
1354 kOSKextLogBasicLevel |
1355 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1356 "Kext unloading now %sabled.", sUnloadEnabled ? "en" : "dis");
1357 }
1358
1359 return result;
1360}
1361
1362/*********************************************************************
1363* Do not call any function that takes sKextLock here!
1364*********************************************************************/
1365/* static */
1366bool
1367OSKext::getAutounloadEnabled(void)
1368{
1369 bool result;
1370
1371 IORecursiveLockLock(sKextInnerLock);
1372 result = sAutounloadEnabled ? true : false;
1373 IORecursiveLockUnlock(sKextInnerLock);
1374 return result;
1375}
1376
1377/*********************************************************************
1378* Do not call any function that takes sKextLock here!
1379*********************************************************************/
1380/* static */
1381bool
1382OSKext::setAutounloadsEnabled(bool flag)
1383{
1384 bool result;
1385
1386 IORecursiveLockLock(sKextInnerLock);
1387
1388 result = sAutounloadEnabled;
1389 sAutounloadEnabled = (flag ? true : false);
1390 if (!sAutounloadEnabled && sUnloadCallout) {
1391 thread_call_cancel(sUnloadCallout);
1392 }
1393
1394 if (sAutounloadEnabled != result) {
1395 OSKextLog(/* kext */ NULL,
1396 kOSKextLogBasicLevel |
1397 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1398 "Kext autounloading now %sabled.",
1399 sAutounloadEnabled ? "en" : "dis");
1400 }
1401
1402 IORecursiveLockUnlock(sKextInnerLock);
1403
1404 return result;
1405}
1406
1407/*********************************************************************
1408*********************************************************************/
1409/* instance method operating on OSKext field */
1410bool
1411OSKext::setAutounloadEnabled(bool flag)
1412{
1413 bool result = flags.autounloadEnabled ? true : false;
1414 flags.autounloadEnabled = flag ? 1 : 0;
1415
1416 if (result != (flag ? true : false)) {
1417 OSKextLog(this,
1418 kOSKextLogProgressLevel |
1419 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
1420 "Autounloading for kext %s now %sabled.",
1421 getIdentifierCString(),
1422 flags.autounloadEnabled ? "en" : "dis");
1423 }
1424 return result;
1425}
1426
1427/*********************************************************************
1428*********************************************************************/
1429/* static */
1430bool
1431OSKext::setKernelRequestsEnabled(bool flag)
1432{
1433 bool result;
1434
1435 IORecursiveLockLock(sKextLock);
1436 result = sKernelRequestsEnabled;
1437 sKernelRequestsEnabled = flag ? true : false;
1438
1439 if (sKernelRequestsEnabled != result) {
1440 OSKextLog(/* kext */ NULL,
1441 kOSKextLogBasicLevel |
1442 kOSKextLogGeneralFlag,
1443 "Kernel requests now %sabled.",
1444 sKernelRequestsEnabled ? "en" : "dis");
1445 }
1446 IORecursiveLockUnlock(sKextLock);
1447 return result;
1448}
1449
1450/*********************************************************************
1451*********************************************************************/
1452/* static */
1453bool
1454OSKext::getKernelRequestsEnabled(void)
1455{
1456 bool result;
1457
1458 IORecursiveLockLock(sKextLock);
1459 result = sKernelRequestsEnabled;
1460 IORecursiveLockUnlock(sKextLock);
1461 return result;
1462}
1463
1464#if PRAGMA_MARK
1465#pragma mark Kext Life Cycle
1466#endif
1467/*********************************************************************
1468*********************************************************************/
1469OSKext *
1470OSKext::withPrelinkedInfoDict(
1471 OSDictionary * anInfoDict,
1472 bool doCoalesedSlides)
1473{
1474 OSKext * newKext = new OSKext;
1475
1476 if (newKext && !newKext->initWithPrelinkedInfoDict(anInfoDict, doCoalesedSlides)) {
1477 newKext->release();
1478 return NULL;
1479 }
1480
1481 return newKext;
1482}
1483
1484/*********************************************************************
1485*********************************************************************/
1486bool
1487OSKext::initWithPrelinkedInfoDict(
1488 OSDictionary * anInfoDict,
1489 bool doCoalesedSlides)
1490{
1491 bool result = false;
1492 OSString * kextPath = NULL; // do not release
1493 OSNumber * addressNum = NULL; // reused; do not release
1494 OSNumber * lengthNum = NULL; // reused; do not release
1495 void * data = NULL; // do not free
1496 void * srcData = NULL; // do not free
1497 OSData * prelinkedExecutable = NULL; // must release
1498 uint32_t length = 0; // reused
1499
1500 if (!super::init()) {
1501 goto finish;
1502 }
1503
1504 /* Get the path. Don't look for an arch-specific path property.
1505 */
1506 kextPath = OSDynamicCast(OSString,
1507 anInfoDict->getObject(kPrelinkBundlePathKey));
1508
1509 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
1510 goto finish;
1511 }
1512#if KASLR_KEXT_DEBUG
1513 IOLog("kaslr: doCoalesedSlides %d kext %s \n", doCoalesedSlides, getIdentifierCString());
1514#endif
1515
1516 /* Also get the executable's bundle-relative path if present.
1517 * Don't look for an arch-specific path property.
1518 */
1519 executableRelPath = OSDynamicCast(OSString,
1520 anInfoDict->getObject(kPrelinkExecutableRelativePathKey));
1521 if (executableRelPath) {
1522 executableRelPath->retain();
1523 }
1524
1525 /* Don't need the paths to be in the info dictionary any more.
1526 */
1527 anInfoDict->removeObject(kPrelinkBundlePathKey);
1528 anInfoDict->removeObject(kPrelinkExecutableRelativePathKey);
1529
1530 /* Create an OSData wrapper around the linked executable.
1531 */
1532 addressNum = OSDynamicCast(OSNumber,
1533 anInfoDict->getObject(kPrelinkExecutableLoadKey));
1534 if (addressNum) {
1535 lengthNum = OSDynamicCast(OSNumber,
1536 anInfoDict->getObject(kPrelinkExecutableSizeKey));
1537 if (!lengthNum) {
1538 OSKextLog(this,
1539 kOSKextLogErrorLevel |
1540 kOSKextLogArchiveFlag,
1541 "Kext %s can't find prelinked kext executable size.",
1542 getIdentifierCString());
1543 goto finish;
1544 }
1545
1546 data = (void *) ml_static_slide((intptr_t) (addressNum->unsigned64BitValue()));
1547 length = (uint32_t) (lengthNum->unsigned32BitValue());
1548
1549#if KASLR_KEXT_DEBUG
1550 IOLog("kaslr: unslid 0x%lx slid 0x%lx length %u - prelink executable \n",
1551 (unsigned long)ml_static_unslide(data),
1552 (unsigned long)data,
1553 length);
1554#endif
1555
1556 anInfoDict->removeObject(kPrelinkExecutableLoadKey);
1557 anInfoDict->removeObject(kPrelinkExecutableSizeKey);
1558
1559 /* If the kext's load address differs from its source address, allocate
1560 * space in the kext map at the load address and copy the kext over.
1561 */
1562 addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject(kPrelinkExecutableSourceKey));
1563 if (addressNum) {
1564 srcData = (void *) ml_static_slide((intptr_t) (addressNum->unsigned64BitValue()));
1565
1566#if KASLR_KEXT_DEBUG
1567 IOLog("kaslr: unslid 0x%lx slid 0x%lx - prelink executable source \n",
1568 (unsigned long)ml_static_unslide(srcData),
1569 (unsigned long)srcData);
1570#endif
1571
1572 if (data != srcData) {
1573#if __LP64__
1574 kern_return_t alloc_result;
1575
1576 alloc_result = kext_alloc((vm_offset_t *)&data, length, /* fixed */ TRUE);
1577 if (alloc_result != KERN_SUCCESS) {
1578 OSKextLog(this,
1579 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1580 "Failed to allocate space for prelinked kext %s.",
1581 getIdentifierCString());
1582 goto finish;
1583 }
1584 memcpy(data, srcData, length);
1585#else
1586 OSKextLog(this,
1587 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1588 "Error: prelinked kext %s - source and load addresses "
1589 "differ on ILP32 architecture.",
1590 getIdentifierCString());
1591 goto finish;
1592#endif /* __LP64__ */
1593 }
1594
1595 anInfoDict->removeObject(kPrelinkExecutableSourceKey);
1596 }
1597
1598 prelinkedExecutable = OSData::withBytesNoCopy(data, length);
1599 if (!prelinkedExecutable) {
1600 OSKextLog(this,
1601 kOSKextLogErrorLevel |
1602 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1603 "Kext %s failed to create executable wrapper.",
1604 getIdentifierCString());
1605 goto finish;
1606 }
1607
1608#if VM_MAPPED_KEXTS
1609 prelinkedExecutable->setDeallocFunction(osdata_kext_free);
1610#else
1611 prelinkedExecutable->setDeallocFunction(osdata_phys_free);
1612#endif
1613 setLinkedExecutable(prelinkedExecutable);
1614 addressNum = OSDynamicCast(OSNumber,
1615 anInfoDict->getObject(kPrelinkKmodInfoKey));
1616 if (!addressNum) {
1617 OSKextLog(this,
1618 kOSKextLogErrorLevel |
1619 kOSKextLogArchiveFlag,
1620 "Kext %s can't find prelinked kext kmod_info address.",
1621 getIdentifierCString());
1622 goto finish;
1623 }
1624
1625 if (addressNum->unsigned64BitValue() != 0) {
1626 kmod_info = (kmod_info_t *) ml_static_slide((intptr_t) (addressNum->unsigned64BitValue()));
1627 kmod_info->address = ml_static_slide(kmod_info->address);
1628#if KASLR_KEXT_DEBUG
1629 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info \n",
1630 (unsigned long)ml_static_unslide(kmod_info),
1631 (unsigned long)kmod_info);
1632 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info->address \n",
1633 (unsigned long)ml_static_unslide(kmod_info->address),
1634 (unsigned long)kmod_info->address);
1635 #endif
1636 }
1637
1638 anInfoDict->removeObject(kPrelinkKmodInfoKey);
1639 }
1640
1641 if ((addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject("ModuleIndex"))))
1642 {
1643 uintptr_t builtinTextStart;
1644 uintptr_t builtinTextEnd;
1645
1646 flags.builtin = true;
1647 builtinKmodIdx = addressNum->unsigned32BitValue();
1648 assert(builtinKmodIdx < gBuiltinKmodsCount);
1649
1650 builtinTextStart = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx];
1651 builtinTextEnd = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx + 1];
1652
1653 kmod_info = ((kmod_info_t **)gBuiltinKmodsSectionInfo->addr)[builtinKmodIdx];
1654 kmod_info->address = builtinTextStart;
1655 kmod_info->size = builtinTextEnd - builtinTextStart;
1656 }
1657
1658 /* If the plist has a UUID for an interface, save that off.
1659 */
1660 if (isInterface()) {
1661 interfaceUUID = OSDynamicCast(OSData,
1662 anInfoDict->getObject(kPrelinkInterfaceUUIDKey));
1663 if (interfaceUUID) {
1664 interfaceUUID->retain();
1665 anInfoDict->removeObject(kPrelinkInterfaceUUIDKey);
1666 }
1667 }
1668
1669 result = slidePrelinkedExecutable(doCoalesedSlides);
1670 if (result != kOSReturnSuccess) {
1671 goto finish;
1672 }
1673
1674 if (doCoalesedSlides == false) {
1675 /* set VM protections now, wire later at kext load */
1676 result = setVMAttributes(true, false);
1677 if (result != KERN_SUCCESS) {
1678 goto finish;
1679 }
1680 }
1681
1682 flags.prelinked = true;
1683
1684 /* If we created a kext from prelink info,
1685 * we must be booting from a prelinked kernel.
1686 */
1687 sPrelinkBoot = true;
1688
1689 result = registerIdentifier();
1690
1691finish:
1692 OSSafeReleaseNULL(prelinkedExecutable);
1693
1694 return result;
1695}
1696
1697/*********************************************************************
1698 *********************************************************************/
1699/* static */
1700void OSKext::setAllVMAttributes(void)
1701{
1702 OSCollectionIterator * kextIterator = NULL; // must release
1703 const OSSymbol * thisID = NULL; // do not release
1704
1705 IORecursiveLockLock(sKextLock);
1706
1707 kextIterator = OSCollectionIterator::withCollection(sKextsByID);
1708 if (!kextIterator) {
1709 goto finish;
1710 }
1711
1712 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
1713 OSKext * thisKext; // do not release
1714
1715 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
1716 if (!thisKext || thisKext->isInterface() || !thisKext->declaresExecutable()) {
1717 continue;
1718 }
1719
1720 /* set VM protections now, wire later at kext load */
1721 thisKext->setVMAttributes(true, false);
1722 }
1723
1724finish:
1725 IORecursiveLockUnlock(sKextLock);
1726 OSSafeReleaseNULL(kextIterator);
1727
1728 return;
1729}
1730
1731/*********************************************************************
1732*********************************************************************/
1733OSKext *
1734OSKext::withBooterData(
1735 OSString * deviceTreeName,
1736 OSData * booterData)
1737{
1738 OSKext * newKext = new OSKext;
1739
1740 if (newKext && !newKext->initWithBooterData(deviceTreeName, booterData)) {
1741 newKext->release();
1742 return NULL;
1743 }
1744
1745 return newKext;
1746}
1747
1748/*********************************************************************
1749*********************************************************************/
1750typedef struct _BooterKextFileInfo {
1751 uint32_t infoDictPhysAddr;
1752 uint32_t infoDictLength;
1753 uint32_t executablePhysAddr;
1754 uint32_t executableLength;
1755 uint32_t bundlePathPhysAddr;
1756 uint32_t bundlePathLength;
1757} _BooterKextFileInfo;
1758
1759bool
1760OSKext::initWithBooterData(
1761 OSString * deviceTreeName,
1762 OSData * booterData)
1763{
1764 bool result = false;
1765 _BooterKextFileInfo * kextFileInfo = NULL; // do not free
1766 char * infoDictAddr = NULL; // do not free
1767 void * executableAddr = NULL; // do not free
1768 char * bundlePathAddr = NULL; // do not free
1769
1770 OSObject * parsedXML = NULL; // must release
1771 OSDictionary * theInfoDict = NULL; // do not release
1772 OSString * kextPath = NULL; // must release
1773 OSString * errorString = NULL; // must release
1774 OSData * executable = NULL; // must release
1775
1776 if (!super::init()) {
1777 goto finish;
1778 }
1779
1780 kextFileInfo = (_BooterKextFileInfo *)booterData->getBytesNoCopy();
1781 if (!kextFileInfo) {
1782 OSKextLog(this,
1783 kOSKextLogErrorLevel |
1784 kOSKextLogGeneralFlag,
1785 "No booter-provided data for kext device tree entry %s.",
1786 deviceTreeName->getCStringNoCopy());
1787 goto finish;
1788 }
1789
1790 /* The info plist must exist or we can't read the kext.
1791 */
1792 if (!kextFileInfo->infoDictPhysAddr || !kextFileInfo->infoDictLength) {
1793 OSKextLog(this,
1794 kOSKextLogErrorLevel |
1795 kOSKextLogGeneralFlag,
1796 "No kext info dictionary for booter device tree entry %s.",
1797 deviceTreeName->getCStringNoCopy());
1798 goto finish;
1799 }
1800
1801 infoDictAddr = (char *)ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
1802 if (!infoDictAddr) {
1803 OSKextLog(this,
1804 kOSKextLogErrorLevel |
1805 kOSKextLogGeneralFlag,
1806 "Can't translate physical address 0x%x of kext info dictionary "
1807 "for device tree entry %s.",
1808 (int)kextFileInfo->infoDictPhysAddr,
1809 deviceTreeName->getCStringNoCopy());
1810 goto finish;
1811 }
1812
1813 parsedXML = OSUnserializeXML(infoDictAddr, &errorString);
1814 if (parsedXML) {
1815 theInfoDict = OSDynamicCast(OSDictionary, parsedXML);
1816 }
1817 if (!theInfoDict) {
1818 const char * errorCString = "(unknown error)";
1819
1820 if (errorString && errorString->getCStringNoCopy()) {
1821 errorCString = errorString->getCStringNoCopy();
1822 } else if (parsedXML) {
1823 errorCString = "not a dictionary";
1824 }
1825 OSKextLog(this,
1826 kOSKextLogErrorLevel |
1827 kOSKextLogGeneralFlag,
1828 "Error unserializing info dictionary for device tree entry %s: %s.",
1829 deviceTreeName->getCStringNoCopy(), errorCString);
1830 goto finish;
1831 }
1832
1833 /* A bundle path is not mandatory.
1834 */
1835 if (kextFileInfo->bundlePathPhysAddr && kextFileInfo->bundlePathLength) {
1836 bundlePathAddr = (char *)ml_static_ptovirt(kextFileInfo->bundlePathPhysAddr);
1837 if (!bundlePathAddr) {
1838 OSKextLog(this,
1839 kOSKextLogErrorLevel |
1840 kOSKextLogGeneralFlag,
1841 "Can't translate physical address 0x%x of kext bundle path "
1842 "for device tree entry %s.",
1843 (int)kextFileInfo->bundlePathPhysAddr,
1844 deviceTreeName->getCStringNoCopy());
1845 goto finish;
1846 }
1847 bundlePathAddr[kextFileInfo->bundlePathLength-1] = '\0'; // just in case!
1848
1849 kextPath = OSString::withCString(bundlePathAddr);
1850 if (!kextPath) {
1851 OSKextLog(this,
1852 kOSKextLogErrorLevel |
1853 kOSKextLogGeneralFlag,
1854 "Failed to create wrapper for device tree entry %s kext path %s.",
1855 deviceTreeName->getCStringNoCopy(), bundlePathAddr);
1856 goto finish;
1857 }
1858 }
1859
1860 if (!setInfoDictionaryAndPath(theInfoDict, kextPath)) {
1861 goto finish;
1862 }
1863
1864 /* An executable is not mandatory.
1865 */
1866 if (kextFileInfo->executablePhysAddr && kextFileInfo->executableLength) {
1867 executableAddr = (void *)ml_static_ptovirt(kextFileInfo->executablePhysAddr);
1868 if (!executableAddr) {
1869 OSKextLog(this,
1870 kOSKextLogErrorLevel |
1871 kOSKextLogGeneralFlag,
1872 "Can't translate physical address 0x%x of kext executable "
1873 "for device tree entry %s.",
1874 (int)kextFileInfo->executablePhysAddr,
1875 deviceTreeName->getCStringNoCopy());
1876 goto finish;
1877 }
1878
1879 executable = OSData::withBytesNoCopy(executableAddr,
1880 kextFileInfo->executableLength);
1881 if (!executable) {
1882 OSKextLog(this,
1883 kOSKextLogErrorLevel |
1884 kOSKextLogGeneralFlag,
1885 "Failed to create executable wrapper for device tree entry %s.",
1886 deviceTreeName->getCStringNoCopy());
1887 goto finish;
1888 }
1889
1890 /* A kext with an executable needs to retain the whole booterData
1891 * object to keep the executable in memory.
1892 */
1893 if (!setExecutable(executable, booterData)) {
1894 OSKextLog(this,
1895 kOSKextLogErrorLevel |
1896 kOSKextLogGeneralFlag,
1897 "Failed to set kext executable for device tree entry %s.",
1898 deviceTreeName->getCStringNoCopy());
1899 goto finish;
1900 }
1901 }
1902
1903 result = registerIdentifier();
1904
1905finish:
1906 OSSafeReleaseNULL(parsedXML);
1907 OSSafeReleaseNULL(kextPath);
1908 OSSafeReleaseNULL(errorString);
1909 OSSafeReleaseNULL(executable);
1910
1911 return result;
1912}
1913
1914/*********************************************************************
1915*********************************************************************/
1916bool
1917OSKext::registerIdentifier(void)
1918{
1919 bool result = false;
1920 OSKext * existingKext = NULL; // do not release
1921 bool existingIsLoaded = false;
1922 bool existingIsPrelinked = false;
1923 OSKextVersion newVersion = -1;
1924 OSKextVersion existingVersion = -1;
1925 char newVersionCString[kOSKextVersionMaxLength];
1926 char existingVersionCString[kOSKextVersionMaxLength];
1927 OSData * newUUID = NULL; // must release
1928 OSData * existingUUID = NULL; // must release
1929
1930 IORecursiveLockLock(sKextLock);
1931
1932 /* Get the new kext's version for checks & log messages.
1933 */
1934 newVersion = getVersion();
1935 OSKextVersionGetString(newVersion, newVersionCString,
1936 kOSKextVersionMaxLength);
1937
1938 /* If we don't have an existing kext with this identifier,
1939 * just record the new kext and we're done!
1940 */
1941 existingKext = OSDynamicCast(OSKext, sKextsByID->getObject(bundleID));
1942 if (!existingKext) {
1943 sKextsByID->setObject(bundleID, this);
1944 result = true;
1945 goto finish;
1946 }
1947
1948 /* Get the existing kext's version for checks & log messages.
1949 */
1950 existingVersion = existingKext->getVersion();
1951 OSKextVersionGetString(existingVersion,
1952 existingVersionCString, kOSKextVersionMaxLength);
1953
1954 existingIsLoaded = existingKext->isLoaded();
1955 existingIsPrelinked = existingKext->isPrelinked();
1956
1957 /* If we have a kext with this identifier that's already loaded/prelinked,
1958 * we can't use the new one, but let's be really thorough and check how
1959 * the two are related for a precise diagnostic log message.
1960 *
1961 * Note that user space can't find out about nonloaded prelinked kexts,
1962 * so in this case we log a message when new & existing are equivalent
1963 * at the step rather than warning level, because we are always going
1964 * be getting a copy of the kext in the user load request mkext.
1965 */
1966 if (existingIsLoaded || existingIsPrelinked) {
1967 bool sameVersion = (newVersion == existingVersion);
1968 bool sameExecutable = true; // assume true unless we have UUIDs
1969
1970 /* Only get the UUID if the existing kext is loaded. Doing so
1971 * might have to uncompress an mkext executable and we shouldn't
1972 * take that hit when neither kext is loaded.
1973 */
1974 newUUID = copyUUID();
1975 existingUUID = existingKext->copyUUID();
1976
1977 /* I'm entirely too paranoid about checking equivalence of executables,
1978 * but I remember nasty problems with it in the past.
1979 *
1980 * - If we have UUIDs for both kexts, compare them.
1981 * - If only one kext has a UUID, they're definitely different.
1982 */
1983 if (newUUID && existingUUID) {
1984 sameExecutable = newUUID->isEqualTo(existingUUID);
1985 } else if (newUUID || existingUUID) {
1986 sameExecutable = false;
1987 }
1988
1989 if (!newUUID && !existingUUID) {
1990
1991 /* If there are no UUIDs, we can't really tell that the executables
1992 * are *different* without a lot of work; the loaded kext's
1993 * unrelocated executable is no longer around (and we never had it
1994 * in-kernel for a prelinked kext). We certainly don't want to do
1995 * a whole fake link for the new kext just to compare, either.
1996 */
1997
1998 OSKextVersionGetString(version, newVersionCString,
1999 sizeof(newVersionCString));
2000 OSKextLog(this,
2001 kOSKextLogWarningLevel |
2002 kOSKextLogKextBookkeepingFlag,
2003 "Notice - new kext %s, v%s matches %s kext "
2004 "but can't determine if executables are the same (no UUIDs).",
2005 getIdentifierCString(),
2006 newVersionCString,
2007 (existingIsLoaded ? "loaded" : "prelinked"));
2008 }
2009
2010 if (sameVersion && sameExecutable) {
2011 OSKextLog(this,
2012 (existingIsLoaded ? kOSKextLogWarningLevel : kOSKextLogStepLevel) |
2013 kOSKextLogKextBookkeepingFlag,
2014 "Refusing new kext %s, v%s: a %s copy is already present "
2015 "(same version and executable).",
2016 getIdentifierCString(), newVersionCString,
2017 (existingIsLoaded ? "loaded" : "prelinked"));
2018 } else {
2019 if (!sameVersion) {
2020 /* This condition is significant so log it under warnings.
2021 */
2022 OSKextLog(this,
2023 kOSKextLogWarningLevel |
2024 kOSKextLogKextBookkeepingFlag,
2025 "Refusing new kext %s, v%s: already have %s v%s.",
2026 getIdentifierCString(),
2027 newVersionCString,
2028 (existingIsLoaded ? "loaded" : "prelinked"),
2029 existingVersionCString);
2030 } else {
2031 /* This condition is significant so log it under warnings.
2032 */
2033 OSKextLog(this,
2034 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2035 "Refusing new kext %s, v%s: a %s copy with a different "
2036 "executable UUID is already present.",
2037 getIdentifierCString(), newVersionCString,
2038 (existingIsLoaded ? "loaded" : "prelinked"));
2039 }
2040 }
2041 goto finish;
2042 } /* if (existingIsLoaded || existingIsPrelinked) */
2043
2044 /* We have two nonloaded/nonprelinked kexts, so our decision depends on whether
2045 * user loads are happening or if we're still in early boot. User agents are
2046 * supposed to resolve dependencies topside and include only the exact
2047 * kexts needed; so we always accept the new kext (in fact we should never
2048 * see an older unloaded copy hanging around).
2049 */
2050 if (sUserLoadsActive) {
2051 sKextsByID->setObject(bundleID, this);
2052 result = true;
2053
2054 OSKextLog(this,
2055 kOSKextLogStepLevel |
2056 kOSKextLogKextBookkeepingFlag,
2057 "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
2058 getIdentifierCString(),
2059 existingVersionCString,
2060 newVersionCString);
2061
2062 goto finish;
2063 }
2064
2065 /* During early boot, the kext with the highest version always wins out.
2066 * Prelinked kernels will never hit this, but mkexts and booter-read
2067 * kexts might have duplicates.
2068 */
2069 if (newVersion > existingVersion) {
2070 sKextsByID->setObject(bundleID, this);
2071 result = true;
2072
2073 OSKextLog(this,
2074 kOSKextLogStepLevel |
2075 kOSKextLogKextBookkeepingFlag,
2076 "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
2077 existingVersionCString,
2078 getIdentifierCString(),
2079 newVersionCString);
2080
2081 } else {
2082 OSKextLog(this,
2083 kOSKextLogStepLevel |
2084 kOSKextLogKextBookkeepingFlag,
2085 "Kext %s is already registered with a higher/same version (v%s); "
2086 "dropping newly-added (v%s).",
2087 getIdentifierCString(),
2088 existingVersionCString,
2089 newVersionCString);
2090 }
2091
2092 /* result has been set appropriately by now. */
2093
2094finish:
2095
2096 IORecursiveLockUnlock(sKextLock);
2097
2098 if (result) {
2099 OSKextLog(this,
2100 kOSKextLogStepLevel |
2101 kOSKextLogKextBookkeepingFlag,
2102 "Kext %s, v%s registered and available for loading.",
2103 getIdentifierCString(), newVersionCString);
2104 }
2105
2106 OSSafeReleaseNULL(newUUID);
2107 OSSafeReleaseNULL(existingUUID);
2108
2109 return result;
2110}
2111
2112/*********************************************************************
2113* Does the bare minimum validation to look up a kext.
2114* All other validation is done on the spot as needed.
2115**********************************************************************/
2116bool
2117OSKext::setInfoDictionaryAndPath(
2118 OSDictionary * aDictionary,
2119 OSString * aPath)
2120{
2121 bool result = false;
2122 OSString * bundleIDString = NULL; // do not release
2123 OSString * versionString = NULL; // do not release
2124 OSString * compatibleVersionString = NULL; // do not release
2125 const char * versionCString = NULL; // do not free
2126 const char * compatibleVersionCString = NULL; // do not free
2127 OSBoolean * scratchBool = NULL; // do not release
2128 OSDictionary * scratchDict = NULL; // do not release
2129
2130 if (infoDict) {
2131 panic("Attempt to set info dictionary on a kext "
2132 "that already has one (%s).",
2133 getIdentifierCString());
2134 }
2135
2136 if (!aDictionary || !OSDynamicCast(OSDictionary, aDictionary)) {
2137 goto finish;
2138 }
2139
2140 infoDict = aDictionary;
2141 infoDict->retain();
2142
2143 /* Check right away if the info dictionary has any log flags.
2144 */
2145 scratchBool = OSDynamicCast(OSBoolean,
2146 getPropertyForHostArch(kOSBundleEnableKextLoggingKey));
2147 if (scratchBool == kOSBooleanTrue) {
2148 flags.loggingEnabled = 1;
2149 }
2150
2151 /* The very next thing to get is the bundle identifier. Unlike
2152 * in user space, a kext with no bundle identifier gets axed
2153 * immediately.
2154 */
2155 bundleIDString = OSDynamicCast(OSString,
2156 getPropertyForHostArch(kCFBundleIdentifierKey));
2157 if (!bundleIDString) {
2158 OSKextLog(this,
2159 kOSKextLogErrorLevel |
2160 kOSKextLogValidationFlag,
2161 "CFBundleIdentifier missing/invalid type in kext %s.",
2162 aPath ? aPath->getCStringNoCopy() : "(unknown)");
2163 goto finish;
2164 }
2165 bundleID = OSSymbol::withString(bundleIDString);
2166 if (!bundleID) {
2167 OSKextLog(this,
2168 kOSKextLogErrorLevel |
2169 kOSKextLogValidationFlag,
2170 "Can't copy bundle identifier as symbol for kext %s.",
2171 bundleIDString->getCStringNoCopy());
2172 goto finish;
2173 }
2174
2175 /* Save the path if we got one (it should always be available but it's
2176 * just something nice to have for bookkeeping).
2177 */
2178 if (aPath) {
2179 path = aPath;
2180 path->retain();
2181 }
2182
2183 /*****
2184 * Minimal validation to initialize. We'll do other validation on the spot.
2185 */
2186 if (bundleID->getLength() >= KMOD_MAX_NAME) {
2187 OSKextLog(this,
2188 kOSKextLogErrorLevel |
2189 kOSKextLogValidationFlag,
2190 "Kext %s error - CFBundleIdentifier over max length %d.",
2191 getIdentifierCString(), KMOD_MAX_NAME - 1);
2192 goto finish;
2193 }
2194
2195 version = compatibleVersion = -1;
2196
2197 versionString = OSDynamicCast(OSString,
2198 getPropertyForHostArch(kCFBundleVersionKey));
2199 if (!versionString) {
2200 OSKextLog(this,
2201 kOSKextLogErrorLevel |
2202 kOSKextLogValidationFlag,
2203 "Kext %s error - CFBundleVersion missing/invalid type.",
2204 getIdentifierCString());
2205 goto finish;
2206 }
2207 versionCString = versionString->getCStringNoCopy();
2208 version = OSKextParseVersionString(versionCString);
2209 if (version < 0) {
2210 OSKextLog(this,
2211 kOSKextLogErrorLevel |
2212 kOSKextLogValidationFlag,
2213 "Kext %s error - CFBundleVersion bad value '%s'.",
2214 getIdentifierCString(), versionCString);
2215 goto finish;
2216 }
2217
2218 compatibleVersion = -1; // set to illegal value for kexts that don't have
2219
2220 compatibleVersionString = OSDynamicCast(OSString,
2221 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
2222 if (compatibleVersionString) {
2223 compatibleVersionCString = compatibleVersionString->getCStringNoCopy();
2224 compatibleVersion = OSKextParseVersionString(compatibleVersionCString);
2225 if (compatibleVersion < 0) {
2226 OSKextLog(this,
2227 kOSKextLogErrorLevel |
2228 kOSKextLogValidationFlag,
2229 "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
2230 getIdentifierCString(), compatibleVersionCString);
2231 goto finish;
2232 }
2233
2234 if (compatibleVersion > version) {
2235 OSKextLog(this,
2236 kOSKextLogErrorLevel |
2237 kOSKextLogValidationFlag,
2238 "Kext %s error - %s %s > %s %s (must be <=).",
2239 getIdentifierCString(),
2240 kOSBundleCompatibleVersionKey, compatibleVersionCString,
2241 kCFBundleVersionKey, versionCString);
2242 goto finish;
2243 }
2244 }
2245
2246 /* Check to see if this kext is in exclude list */
2247 if ( isInExcludeList() ) {
2248 OSKextLog(this,
2249 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2250 "Kext %s is in exclude list, not loadable",
2251 getIdentifierCString());
2252 goto finish;
2253 }
2254
2255 /* Set flags for later use if the infoDict gets flushed. We only
2256 * check for true values, not false ones(!)
2257 */
2258 scratchBool = OSDynamicCast(OSBoolean,
2259 getPropertyForHostArch(kOSBundleIsInterfaceKey));
2260 if (scratchBool == kOSBooleanTrue) {
2261 flags.interface = 1;
2262 }
2263
2264 scratchBool = OSDynamicCast(OSBoolean,
2265 getPropertyForHostArch(kOSKernelResourceKey));
2266 if (scratchBool == kOSBooleanTrue) {
2267 flags.kernelComponent = 1;
2268 flags.interface = 1; // xxx - hm. the kernel itself isn't an interface...
2269 flags.started = 1;
2270
2271 /* A kernel component has one implicit dependency on the kernel.
2272 */
2273 flags.hasAllDependencies = 1;
2274 }
2275
2276 /* Make sure common string values in personalities are uniqued to OSSymbols.
2277 */
2278 scratchDict = OSDynamicCast(OSDictionary,
2279 getPropertyForHostArch(kIOKitPersonalitiesKey));
2280 if (scratchDict) {
2281 uniquePersonalityProperties(scratchDict);
2282 }
2283
2284 result = true;
2285
2286finish:
2287
2288 return result;
2289}
2290
2291/*********************************************************************
2292* Not used for prelinked kernel boot as there is no unrelocated
2293* executable.
2294*********************************************************************/
2295bool
2296OSKext::setExecutable(
2297 OSData * anExecutable,
2298 OSData * externalData,
2299 bool externalDataIsMkext)
2300{
2301 bool result = false;
2302 const char * executableKey = NULL; // do not free
2303
2304 if (!anExecutable) {
2305 infoDict->removeObject(_kOSKextExecutableKey);
2306 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
2307 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
2308 result = true;
2309 goto finish;
2310 }
2311
2312 if (infoDict->getObject(_kOSKextExecutableKey) ||
2313 infoDict->getObject(_kOSKextMkextExecutableReferenceKey)) {
2314
2315 panic("Attempt to set an executable on a kext "
2316 "that already has one (%s).",
2317 getIdentifierCString());
2318 goto finish;
2319 }
2320
2321 if (externalDataIsMkext) {
2322 executableKey = _kOSKextMkextExecutableReferenceKey;
2323 } else {
2324 executableKey = _kOSKextExecutableKey;
2325 }
2326
2327 if (anExecutable) {
2328 infoDict->setObject(executableKey, anExecutable);
2329 if (externalData) {
2330 infoDict->setObject(_kOSKextExecutableExternalDataKey, externalData);
2331 }
2332 }
2333
2334 result = true;
2335
2336finish:
2337 return result;
2338}
2339
2340/*********************************************************************
2341*********************************************************************/
2342static void
2343uniqueStringPlistProperty(OSDictionary * dict, const char * key)
2344{
2345 OSString * stringValue = NULL; // do not release
2346 const OSSymbol * symbolValue = NULL; // must release
2347
2348 stringValue = OSDynamicCast(OSString, dict->getObject(key));
2349 if (!stringValue) {
2350 goto finish;
2351 }
2352
2353 symbolValue = OSSymbol::withString(stringValue);
2354 if (!symbolValue) {
2355 goto finish;
2356 }
2357
2358 dict->setObject(key, symbolValue);
2359
2360finish:
2361 if (symbolValue) symbolValue->release();
2362
2363 return;
2364}
2365
2366/*********************************************************************
2367*********************************************************************/
2368static void
2369uniqueStringPlistProperty(OSDictionary * dict, const OSString * key)
2370{
2371 OSString * stringValue = NULL; // do not release
2372 const OSSymbol * symbolValue = NULL; // must release
2373
2374 stringValue = OSDynamicCast(OSString, dict->getObject(key));
2375 if (!stringValue) {
2376 goto finish;
2377 }
2378
2379 symbolValue = OSSymbol::withString(stringValue);
2380 if (!symbolValue) {
2381 goto finish;
2382 }
2383
2384 dict->setObject(key, symbolValue);
2385
2386finish:
2387 if (symbolValue) symbolValue->release();
2388
2389 return;
2390}
2391
2392/*********************************************************************
2393* Replace common personality property values with uniqued instances
2394* to save on wired memory.
2395*********************************************************************/
2396/* static */
2397void
2398OSKext::uniquePersonalityProperties(OSDictionary * personalityDict)
2399{
2400 /* Properties every personality has.
2401 */
2402 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKey);
2403 uniqueStringPlistProperty(personalityDict, kIOProviderClassKey);
2404 uniqueStringPlistProperty(personalityDict, gIOClassKey);
2405
2406 /* Other commonly used properties.
2407 */
2408 uniqueStringPlistProperty(personalityDict, gIOMatchCategoryKey);
2409 uniqueStringPlistProperty(personalityDict, gIOResourceMatchKey);
2410 uniqueStringPlistProperty(personalityDict, gIOUserClientClassKey);
2411
2412 uniqueStringPlistProperty(personalityDict, "HIDDefaultBehavior");
2413 uniqueStringPlistProperty(personalityDict, "HIDPointerAccelerationType");
2414 uniqueStringPlistProperty(personalityDict, "HIDRemoteControlType");
2415 uniqueStringPlistProperty(personalityDict, "HIDScrollAccelerationType");
2416 uniqueStringPlistProperty(personalityDict, "IOPersonalityPublisher");
2417 uniqueStringPlistProperty(personalityDict, "Physical Interconnect");
2418 uniqueStringPlistProperty(personalityDict, "Physical Interconnect Location");
2419 uniqueStringPlistProperty(personalityDict, "Vendor");
2420 uniqueStringPlistProperty(personalityDict, "Vendor Identification");
2421 uniqueStringPlistProperty(personalityDict, "Vendor Name");
2422 uniqueStringPlistProperty(personalityDict, "bConfigurationValue");
2423 uniqueStringPlistProperty(personalityDict, "bInterfaceNumber");
2424 uniqueStringPlistProperty(personalityDict, "idProduct");
2425
2426 return;
2427}
2428
2429/*********************************************************************
2430*********************************************************************/
2431void
2432OSKext::free(void)
2433{
2434 if (isLoaded()) {
2435 panic("Attempt to free loaded kext %s.", getIdentifierCString());
2436 }
2437
2438 OSSafeReleaseNULL(infoDict);
2439 OSSafeReleaseNULL(bundleID);
2440 OSSafeReleaseNULL(path);
2441 OSSafeReleaseNULL(executableRelPath);
2442 OSSafeReleaseNULL(dependencies);
2443 OSSafeReleaseNULL(linkedExecutable);
2444 OSSafeReleaseNULL(metaClasses);
2445 OSSafeReleaseNULL(interfaceUUID);
2446
2447 if (isInterface() && kmod_info) {
2448 kfree(kmod_info, sizeof(kmod_info_t));
2449 }
2450
2451 super::free();
2452 return;
2453}
2454
2455#if PRAGMA_MARK
2456#pragma mark Mkext files
2457#endif
2458/*********************************************************************
2459*********************************************************************/
2460OSReturn
2461OSKext::readMkextArchive(OSData * mkextData,
2462 uint32_t * checksumPtr)
2463{
2464 OSReturn result = kOSKextReturnBadData;
2465 uint32_t mkextLength = 0;
2466 mkext_header * mkextHeader = 0; // do not free
2467 uint32_t mkextVersion = 0;
2468
2469 /* Note default return of kOSKextReturnBadData above.
2470 */
2471 mkextLength = mkextData->getLength();
2472 if (mkextLength < sizeof(mkext_basic_header)) {
2473 OSKextLog(/* kext */ NULL,
2474 kOSKextLogErrorLevel |
2475 kOSKextLogArchiveFlag,
2476 "Mkext archive too small to be valid.");
2477 goto finish;
2478 }
2479
2480 mkextHeader = (mkext_header *)mkextData->getBytesNoCopy();
2481
2482 if (MKEXT_GET_MAGIC(mkextHeader) != MKEXT_MAGIC ||
2483 MKEXT_GET_SIGNATURE(mkextHeader) != MKEXT_SIGN) {
2484 OSKextLog(/* kext */ NULL,
2485 kOSKextLogErrorLevel |
2486 kOSKextLogArchiveFlag,
2487 "Mkext archive has invalid magic or signature.");
2488 goto finish;
2489 }
2490
2491 if (MKEXT_GET_LENGTH(mkextHeader) != mkextLength) {
2492 OSKextLog(/* kext */ NULL,
2493 kOSKextLogErrorLevel |
2494 kOSKextLogArchiveFlag,
2495 "Mkext archive recorded length doesn't match actual file length.");
2496 goto finish;
2497 }
2498
2499 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
2500
2501 if (mkextVersion == MKEXT_VERS_2) {
2502 result = OSKext::readMkext2Archive(mkextData, NULL, checksumPtr);
2503 } else {
2504 OSKextLog(/* kext */ NULL,
2505 kOSKextLogErrorLevel |
2506 kOSKextLogArchiveFlag,
2507 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion);
2508 result = kOSKextReturnUnsupported;
2509 }
2510
2511finish:
2512 return result;
2513}
2514
2515/*********************************************************************
2516* Assumes magic, signature, version, length have been checked.
2517* xxx - need to add further bounds checking for each file entry
2518*
2519* Should keep track of all kexts created so far, and if we hit a
2520* fatal error halfway through, remove those kexts. If we've dropped
2521* an older version that had already been read, whoops! Might want to
2522* add a level of buffering?
2523*********************************************************************/
2524/* static */
2525OSReturn
2526OSKext::readMkext2Archive(
2527 OSData * mkextData,
2528 OSDictionary ** mkextPlistOut,
2529 uint32_t * checksumPtr)
2530{
2531 OSReturn result = kOSReturnError;
2532 uint32_t mkextLength;
2533 mkext2_header * mkextHeader = NULL; // do not free
2534 void * mkextEnd = NULL; // do not free
2535 uint32_t mkextVersion;
2536 uint8_t * crc_address = NULL;
2537 uint32_t checksum;
2538 uint32_t mkextPlistOffset;
2539 uint32_t mkextPlistCompressedSize;
2540 char * mkextPlistEnd = NULL; // do not free
2541 uint32_t mkextPlistFullSize;
2542 OSString * errorString = NULL; // must release
2543 OSData * mkextPlistUncompressedData = NULL; // must release
2544 const char * mkextPlistDataBuffer = NULL; // do not free
2545 OSObject * parsedXML = NULL; // must release
2546 OSDictionary * mkextPlist = NULL; // do not release
2547 OSArray * mkextInfoDictArray = NULL; // do not release
2548 uint32_t count, i;
2549
2550 mkextLength = mkextData->getLength();
2551 mkextHeader = (mkext2_header *)mkextData->getBytesNoCopy();
2552 mkextEnd = (char *)mkextHeader + mkextLength;
2553 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
2554
2555 crc_address = (u_int8_t *)&mkextHeader->version;
2556 checksum = mkext_adler32(crc_address,
2557 (uintptr_t)mkextHeader +
2558 MKEXT_GET_LENGTH(mkextHeader) - (uintptr_t)crc_address);
2559
2560 if (MKEXT_GET_CHECKSUM(mkextHeader) != checksum) {
2561 OSKextLog(/* kext */ NULL,
2562 kOSKextLogErrorLevel |
2563 kOSKextLogArchiveFlag,
2564 "Mkext archive has bad checksum.");
2565 result = kOSKextReturnBadData;
2566 goto finish;
2567 }
2568
2569 if (checksumPtr) {
2570 *checksumPtr = checksum;
2571 }
2572
2573 /* Check that the CPU type & subtype match that of the running kernel. */
2574 if (MKEXT_GET_CPUTYPE(mkextHeader) == (UInt32)CPU_TYPE_ANY) {
2575 OSKextLog(/* kext */ NULL,
2576 kOSKextLogErrorLevel |
2577 kOSKextLogArchiveFlag,
2578 "Mkext archive must have a specific CPU type.");
2579 result = kOSKextReturnBadData;
2580 goto finish;
2581 } else {
2582 if ((UInt32)_mh_execute_header.cputype !=
2583 MKEXT_GET_CPUTYPE(mkextHeader)) {
2584
2585 OSKextLog(/* kext */ NULL,
2586 kOSKextLogErrorLevel |
2587 kOSKextLogArchiveFlag,
2588 "Mkext archive does not match the running kernel's CPU type.");
2589 result = kOSKextReturnArchNotFound;
2590 goto finish;
2591 }
2592 }
2593
2594 mkextPlistOffset = MKEXT2_GET_PLIST(mkextHeader);
2595 mkextPlistCompressedSize = MKEXT2_GET_PLIST_COMPSIZE(mkextHeader);
2596 mkextPlistEnd = (char *)mkextHeader + mkextPlistOffset +
2597 mkextPlistCompressedSize;
2598 if (mkextPlistEnd > mkextEnd) {
2599 OSKextLog(/* kext */ NULL,
2600 kOSKextLogErrorLevel |
2601 kOSKextLogArchiveFlag,
2602 "Mkext archive file overrun.");
2603 result = kOSKextReturnBadData;
2604 }
2605
2606 mkextPlistFullSize = MKEXT2_GET_PLIST_FULLSIZE(mkextHeader);
2607 if (mkextPlistCompressedSize) {
2608 mkextPlistUncompressedData = sKernelKext->extractMkext2FileData(
2609 (UInt8 *)mkextHeader + mkextPlistOffset,
2610 "plist",
2611 mkextPlistCompressedSize, mkextPlistFullSize);
2612 if (!mkextPlistUncompressedData) {
2613 goto finish;
2614 }
2615 mkextPlistDataBuffer = (const char *)
2616 mkextPlistUncompressedData->getBytesNoCopy();
2617 } else {
2618 mkextPlistDataBuffer = (const char *)mkextHeader + mkextPlistOffset;
2619 }
2620
2621 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
2622 */
2623 parsedXML = OSUnserializeXML(mkextPlistDataBuffer, &errorString);
2624 if (parsedXML) {
2625 mkextPlist = OSDynamicCast(OSDictionary, parsedXML);
2626 }
2627 if (!mkextPlist) {
2628 const char * errorCString = "(unknown error)";
2629
2630 if (errorString && errorString->getCStringNoCopy()) {
2631 errorCString = errorString->getCStringNoCopy();
2632 } else if (parsedXML) {
2633 errorCString = "not a dictionary";
2634 }
2635 OSKextLog(/* kext */ NULL,
2636 kOSKextLogErrorLevel |
2637 kOSKextLogArchiveFlag,
2638 "Error unserializing mkext plist: %s.", errorCString);
2639 goto finish;
2640 }
2641
2642 /* If the caller needs the plist, hand it back and retain it.
2643 * (This function releases it at the end.)
2644 */
2645 if (mkextPlistOut) {
2646 *mkextPlistOut = mkextPlist;
2647 (*mkextPlistOut)->retain();
2648 }
2649
2650 mkextInfoDictArray = OSDynamicCast(OSArray,
2651 mkextPlist->getObject(kMKEXTInfoDictionariesKey));
2652 if (!mkextInfoDictArray) {
2653 OSKextLog(/* kext */ NULL,
2654 kOSKextLogErrorLevel |
2655 kOSKextLogArchiveFlag,
2656 "Mkext archive contains no kext info dictionaries.");
2657 goto finish;
2658 }
2659
2660 count = mkextInfoDictArray->getCount();
2661 for (i = 0; i < count; i++) {
2662 OSDictionary * infoDict;
2663
2664
2665 infoDict = OSDynamicCast(OSDictionary,
2666 mkextInfoDictArray->getObject(i));
2667
2668 /* Create the kext for the entry, then release it, because the
2669 * kext system keeps them around until explicitly removed.
2670 * Any creation/registration failures are already logged for us.
2671 */
2672 if (infoDict) {
2673 OSKext * newKext = OSKext::withMkext2Info(infoDict, mkextData);
2674 OSSafeReleaseNULL(newKext);
2675 }
2676 }
2677
2678 /* Even if we didn't keep any kexts from the mkext, we may have a load
2679 * request to process, so we are successful (no errors occurred).
2680 */
2681 result = kOSReturnSuccess;
2682
2683finish:
2684
2685 OSSafeReleaseNULL(parsedXML);
2686 OSSafeReleaseNULL(mkextPlistUncompressedData);
2687 OSSafeReleaseNULL(errorString);
2688
2689 return result;
2690}
2691
2692/*********************************************************************
2693*********************************************************************/
2694/* static */
2695OSKext *
2696OSKext::withMkext2Info(
2697 OSDictionary * anInfoDict,
2698 OSData * mkextData)
2699{
2700 OSKext * newKext = new OSKext;
2701
2702 if (newKext && !newKext->initWithMkext2Info(anInfoDict, mkextData)) {
2703 newKext->release();
2704 return NULL;
2705 }
2706
2707 return newKext;
2708}
2709
2710/*********************************************************************
2711*********************************************************************/
2712bool
2713OSKext::initWithMkext2Info(
2714 OSDictionary * anInfoDict,
2715 OSData * mkextData)
2716{
2717 bool result = false;
2718 OSString * kextPath = NULL; // do not release
2719 OSNumber * executableOffsetNum = NULL; // do not release
2720 OSCollectionIterator * iterator = NULL; // must release
2721 OSData * executable = NULL; // must release
2722
2723 if (anInfoDict == NULL || !super::init()) {
2724 goto finish;
2725 }
2726
2727 /* Get the path. Don't look for an arch-specific path property.
2728 */
2729 kextPath = OSDynamicCast(OSString,
2730 anInfoDict->getObject(kMKEXTBundlePathKey));
2731
2732 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
2733 goto finish;
2734 }
2735
2736 /* If we have a path to the executable, save it.
2737 */
2738 executableRelPath = OSDynamicCast(OSString,
2739 anInfoDict->getObject(kMKEXTExecutableRelativePathKey));
2740 if (executableRelPath) {
2741 executableRelPath->retain();
2742 }
2743
2744 /* Don't need the paths to be in the info dictionary any more.
2745 */
2746 anInfoDict->removeObject(kMKEXTBundlePathKey);
2747 anInfoDict->removeObject(kMKEXTExecutableRelativePathKey);
2748
2749 executableOffsetNum = OSDynamicCast(OSNumber,
2750 infoDict->getObject(kMKEXTExecutableKey));
2751 if (executableOffsetNum) {
2752 executable = createMkext2FileEntry(mkextData,
2753 executableOffsetNum, "executable");
2754 infoDict->removeObject(kMKEXTExecutableKey);
2755 if (!executable) {
2756 goto finish;
2757 }
2758 if (!setExecutable(executable, mkextData, true)) {
2759 goto finish;
2760 }
2761 }
2762
2763 result = registerIdentifier();
2764
2765finish:
2766
2767 OSSafeReleaseNULL(executable);
2768 OSSafeReleaseNULL(iterator);
2769 return result;
2770}
2771
2772/*********************************************************************
2773*********************************************************************/
2774OSData *
2775OSKext::createMkext2FileEntry(
2776 OSData * mkextData,
2777 OSNumber * offsetNum,
2778 const char * name)
2779{
2780 OSData * result = NULL;
2781 MkextEntryRef entryRef;
2782 uint8_t * mkextBuffer = (uint8_t *)mkextData->getBytesNoCopy();
2783 uint32_t entryOffset = offsetNum->unsigned32BitValue();
2784
2785 result = OSData::withCapacity(sizeof(entryRef));
2786 if (!result) {
2787 goto finish;
2788 }
2789
2790 entryRef.mkext = (mkext_basic_header *)mkextBuffer;
2791 entryRef.fileinfo = mkextBuffer + entryOffset;
2792 if (!result->appendBytes(&entryRef, sizeof(entryRef))) {
2793 OSSafeReleaseNULL(result);
2794 goto finish;
2795 }
2796
2797finish:
2798 if (!result) {
2799 OSKextLog(this,
2800 kOSKextLogErrorLevel |
2801 kOSKextLogArchiveFlag,
2802 "Can't create wrapper for mkext file entry '%s' of kext %s.",
2803 name, getIdentifierCString());
2804 }
2805 return result;
2806}
2807
2808/*********************************************************************
2809*********************************************************************/
2810extern "C" {
2811static void * z_alloc(void *, u_int items, u_int size);
2812static void z_free(void *, void *ptr);
2813
2814typedef struct z_mem {
2815 uint32_t alloc_size;
2816 uint8_t data[0];
2817} z_mem;
2818
2819/*
2820 * Space allocation and freeing routines for use by zlib routines.
2821 */
2822void *
2823z_alloc(void * notused __unused, u_int num_items, u_int size)
2824{
2825 void * result = NULL;
2826 z_mem * zmem = NULL;
2827
2828 uint64_t total = ((uint64_t)num_items) * ((uint64_t)size);
2829 //Check for overflow due to multiplication
2830 if (total > UINT32_MAX){
2831 panic("z_alloc(%p, %x, %x): overflow caused by %x * %x\n",
2832 notused, num_items, size, num_items, size);
2833 }
2834
2835 uint64_t allocSize64 = total + ((uint64_t)sizeof(zmem));
2836 //Check for overflow due to addition
2837 if (allocSize64 > UINT32_MAX){
2838 panic("z_alloc(%p, %x, %x): overflow caused by %x + %lx\n",
2839 notused, num_items, size, (uint32_t)total, sizeof(zmem));
2840 }
2841 uint32_t allocSize = (uint32_t)allocSize64;
2842
2843 zmem = (z_mem *)kalloc_tag(allocSize, VM_KERN_MEMORY_OSKEXT);
2844 if (!zmem) {
2845 goto finish;
2846 }
2847 zmem->alloc_size = allocSize;
2848 result = (void *)&(zmem->data);
2849finish:
2850 return result;
2851}
2852
2853void
2854z_free(void * notused __unused, void * ptr)
2855{
2856 uint32_t * skipper = (uint32_t *)ptr - 1;
2857 z_mem * zmem = (z_mem *)skipper;
2858 kfree((void *)zmem, zmem->alloc_size);
2859 return;
2860}
2861};
2862
2863OSData *
2864OSKext::extractMkext2FileData(
2865 UInt8 * data,
2866 const char * name,
2867 uint32_t compressedSize,
2868 uint32_t fullSize)
2869{
2870 OSData * result = NULL;
2871
2872 OSData * uncompressedData = NULL; // release on error
2873
2874 uint8_t * uncompressedDataBuffer = 0; // do not free
2875 unsigned long uncompressedSize;
2876 z_stream zstream;
2877 bool zstream_inited = false;
2878 int zlib_result;
2879
2880 /* If the file isn't compressed, we want to make a copy
2881 * so that we don't have the tie to the larger mkext file buffer any more.
2882 */
2883 if (!compressedSize) {
2884 uncompressedData = OSData::withBytes(data, fullSize);
2885 // xxx - no check for failure?
2886 result = uncompressedData;
2887 goto finish;
2888 }
2889
2890 if (KERN_SUCCESS != kmem_alloc(kernel_map,
2891 (vm_offset_t*)&uncompressedDataBuffer, fullSize, VM_KERN_MEMORY_OSKEXT)) {
2892
2893 /* How's this for cheesy? The kernel is only asked to extract
2894 * kext plists so we tailor the log messages.
2895 */
2896 if (isKernel()) {
2897 OSKextLog(this,
2898 kOSKextLogErrorLevel |
2899 kOSKextLogArchiveFlag,
2900 "Allocation failure extracting %s from mkext.", name);
2901 } else {
2902 OSKextLog(this,
2903 kOSKextLogErrorLevel |
2904 kOSKextLogArchiveFlag,
2905 "Allocation failure extracting %s from mkext for kext %s.",
2906 name, getIdentifierCString());
2907 }
2908
2909 goto finish;
2910 }
2911 uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer, fullSize);
2912 if (!uncompressedData) {
2913 if (isKernel()) {
2914 OSKextLog(this,
2915 kOSKextLogErrorLevel |
2916 kOSKextLogArchiveFlag,
2917 "Allocation failure extracting %s from mkext.", name);
2918 } else {
2919 OSKextLog(this,
2920 kOSKextLogErrorLevel |
2921 kOSKextLogArchiveFlag,
2922 "Allocation failure extracting %s from mkext for kext %s.",
2923 name, getIdentifierCString());
2924 }
2925 goto finish;
2926 }
2927 uncompressedData->setDeallocFunction(&osdata_kmem_free);
2928
2929 if (isKernel()) {
2930 OSKextLog(this,
2931 kOSKextLogDetailLevel |
2932 kOSKextLogArchiveFlag,
2933 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
2934 name, compressedSize, fullSize);
2935 } else {
2936 OSKextLog(this,
2937 kOSKextLogDetailLevel |
2938 kOSKextLogArchiveFlag,
2939 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
2940 getIdentifierCString(), name, compressedSize, fullSize);
2941 }
2942
2943 bzero(&zstream, sizeof(zstream));
2944 zstream.next_in = (UInt8 *)data;
2945 zstream.avail_in = compressedSize;
2946
2947 zstream.next_out = uncompressedDataBuffer;
2948 zstream.avail_out = fullSize;
2949
2950 zstream.zalloc = z_alloc;
2951 zstream.zfree = z_free;
2952
2953 zlib_result = inflateInit(&zstream);
2954 if (Z_OK != zlib_result) {
2955 if (isKernel()) {
2956 OSKextLog(this,
2957 kOSKextLogErrorLevel |
2958 kOSKextLogArchiveFlag,
2959 "Mkext error; zlib inflateInit failed (%d) for %s.",
2960 zlib_result, name);
2961 } else {
2962 OSKextLog(this,
2963 kOSKextLogErrorLevel |
2964 kOSKextLogArchiveFlag,
2965 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
2966 getIdentifierCString(), zlib_result, name);
2967 }
2968 goto finish;
2969 } else {
2970 zstream_inited = true;
2971 }
2972
2973 zlib_result = inflate(&zstream, Z_FINISH);
2974
2975 if (zlib_result == Z_STREAM_END || zlib_result == Z_OK) {
2976 uncompressedSize = zstream.total_out;
2977 } else {
2978 if (isKernel()) {
2979 OSKextLog(this,
2980 kOSKextLogErrorLevel |
2981 kOSKextLogArchiveFlag,
2982 "Mkext error; zlib inflate failed (%d) for %s.",
2983 zlib_result, name);
2984 } else {
2985 OSKextLog(this,
2986 kOSKextLogErrorLevel |
2987 kOSKextLogArchiveFlag,
2988 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
2989 getIdentifierCString(), zlib_result, name);
2990 }
2991 if (zstream.msg) {
2992 OSKextLog(this,
2993 kOSKextLogErrorLevel |
2994 kOSKextLogArchiveFlag,
2995 "zlib error: %s.", zstream.msg);
2996 }
2997 goto finish;
2998 }
2999
3000 if (uncompressedSize != fullSize) {
3001 if (isKernel()) {
3002 OSKextLog(this,
3003 kOSKextLogErrorLevel |
3004 kOSKextLogArchiveFlag,
3005 "Mkext error; zlib inflate discrepancy for %s, "
3006 "uncompressed size != original size.", name);
3007 } else {
3008 OSKextLog(this,
3009 kOSKextLogErrorLevel |
3010 kOSKextLogArchiveFlag,
3011 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
3012 "uncompressed size != original size.",
3013 getIdentifierCString(), name);
3014 }
3015 goto finish;
3016 }
3017
3018 result = uncompressedData;
3019
3020finish:
3021 /* Don't bother checking return, nothing we can do on fail.
3022 */
3023 if (zstream_inited) inflateEnd(&zstream);
3024
3025 if (!result) {
3026 OSSafeReleaseNULL(uncompressedData);
3027 }
3028
3029 return result;
3030}
3031
3032/*********************************************************************
3033*********************************************************************/
3034/* static */
3035OSReturn
3036OSKext::loadFromMkext(
3037 OSKextLogSpec clientLogFilter,
3038 char * mkextBuffer,
3039 uint32_t mkextBufferLength,
3040 char ** logInfoOut,
3041 uint32_t * logInfoLengthOut)
3042{
3043 OSReturn result = kOSReturnError;
3044 OSReturn tempResult = kOSReturnError;
3045
3046 OSData * mkextData = NULL; // must release
3047 OSDictionary * mkextPlist = NULL; // must release
3048
3049 OSArray * logInfoArray = NULL; // must release
3050 OSSerialize * serializer = NULL; // must release
3051
3052 OSString * predicate = NULL; // do not release
3053 OSDictionary * requestArgs = NULL; // do not release
3054
3055 OSString * kextIdentifier = NULL; // do not release
3056 OSNumber * startKextExcludeNum = NULL; // do not release
3057 OSNumber * startMatchingExcludeNum = NULL; // do not release
3058 OSBoolean * delayAutounloadBool = NULL; // do not release
3059 OSArray * personalityNames = NULL; // do not release
3060
3061 /* Default values for these two options: regular autounload behavior,
3062 * load all kexts, send no personalities.
3063 */
3064 Boolean delayAutounload = false;
3065 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
3066 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeAll;
3067
3068 IORecursiveLockLock(sKextLock);
3069
3070 if (logInfoOut) {
3071 *logInfoOut = NULL;
3072 *logInfoLengthOut = 0;
3073 }
3074
3075 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
3076
3077 OSKextLog(/* kext */ NULL,
3078 kOSKextLogDebugLevel |
3079 kOSKextLogIPCFlag,
3080 "Received kext load request from user space.");
3081
3082 /* Regardless of processing, the fact that we have gotten here means some
3083 * user-space program is up and talking to us, so we'll switch our kext
3084 * registration to reflect that.
3085 */
3086 if (!sUserLoadsActive) {
3087 OSKextLog(/* kext */ NULL,
3088 kOSKextLogProgressLevel |
3089 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
3090 "Switching to late startup (user-space) kext loading policy.");
3091
3092 sUserLoadsActive = true;
3093 }
3094
3095 if (!sLoadEnabled) {
3096 OSKextLog(/* kext */ NULL,
3097 kOSKextLogErrorLevel |
3098 kOSKextLogLoadFlag,
3099 "Kext loading is disabled.");
3100 result = kOSKextReturnDisabled;
3101 goto finish;
3102 }
3103
3104 /* Note that we do not set a dealloc function on this OSData
3105 * object! No references to it can remain after the loadFromMkext()
3106 * call since we are in a MIG function, and will vm_deallocate()
3107 * the buffer.
3108 */
3109 mkextData = OSData::withBytesNoCopy(mkextBuffer,
3110 mkextBufferLength);
3111 if (!mkextData) {
3112 OSKextLog(/* kext */ NULL,
3113 kOSKextLogErrorLevel |
3114 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3115 "Failed to create wrapper for kext load request.");
3116 result = kOSKextReturnNoMemory;
3117 goto finish;
3118 }
3119
3120 result = readMkext2Archive(mkextData, &mkextPlist, NULL);
3121 if (result != kOSReturnSuccess) {
3122 OSKextLog(/* kext */ NULL,
3123 kOSKextLogErrorLevel |
3124 kOSKextLogLoadFlag,
3125 "Failed to read kext load request.");
3126 goto finish;
3127 }
3128
3129 predicate = _OSKextGetRequestPredicate(mkextPlist);
3130 if (!predicate || !predicate->isEqualTo(kKextRequestPredicateLoad)) {
3131 OSKextLog(/* kext */ NULL,
3132 kOSKextLogErrorLevel |
3133 kOSKextLogLoadFlag,
3134 "Received kext load request with no predicate; skipping.");
3135 result = kOSKextReturnInvalidArgument;
3136 goto finish;
3137 }
3138
3139 requestArgs = OSDynamicCast(OSDictionary,
3140 mkextPlist->getObject(kKextRequestArgumentsKey));
3141 if (!requestArgs || !requestArgs->getCount()) {
3142 OSKextLog(/* kext */ NULL,
3143 kOSKextLogErrorLevel |
3144 kOSKextLogLoadFlag,
3145 "Received kext load request with no arguments.");
3146 result = kOSKextReturnInvalidArgument;
3147 goto finish;
3148 }
3149
3150 kextIdentifier = OSDynamicCast(OSString,
3151 requestArgs->getObject(kKextRequestArgumentBundleIdentifierKey));
3152 if (!kextIdentifier) {
3153 OSKextLog(/* kext */ NULL,
3154 kOSKextLogErrorLevel |
3155 kOSKextLogLoadFlag,
3156 "Received kext load request with no kext identifier.");
3157 result = kOSKextReturnInvalidArgument;
3158 goto finish;
3159 }
3160
3161 startKextExcludeNum = OSDynamicCast(OSNumber,
3162 requestArgs->getObject(kKextRequestArgumentStartExcludeKey));
3163 startMatchingExcludeNum = OSDynamicCast(OSNumber,
3164 requestArgs->getObject(kKextRequestArgumentStartMatchingExcludeKey));
3165 delayAutounloadBool = OSDynamicCast(OSBoolean,
3166 requestArgs->getObject(kKextRequestArgumentDelayAutounloadKey));
3167 personalityNames = OSDynamicCast(OSArray,
3168 requestArgs->getObject(kKextRequestArgumentPersonalityNamesKey));
3169
3170 if (delayAutounloadBool) {
3171 delayAutounload = delayAutounloadBool->getValue();
3172 }
3173 if (startKextExcludeNum) {
3174 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
3175 }
3176 if (startMatchingExcludeNum) {
3177 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
3178 }
3179
3180 OSKextLog(/* kext */ NULL,
3181 kOSKextLogProgressLevel |
3182 kOSKextLogIPCFlag,
3183 "Received request from user space to load kext %s.",
3184 kextIdentifier->getCStringNoCopy());
3185
3186 /* Load the kext, with no deferral, since this is a load from outside
3187 * the kernel.
3188 * xxx - Would like a better way to handle the default values for the
3189 * xxx - start/match opt args.
3190 */
3191 result = OSKext::loadKextWithIdentifier(
3192 kextIdentifier,
3193 /* allowDefer */ false,
3194 delayAutounload,
3195 startKextExcludeLevel,
3196 startMatchingExcludeLevel,
3197 personalityNames);
3198 if (result != kOSReturnSuccess) {
3199 goto finish;
3200 }
3201 /* If the load came down from kextd, it will shortly inform IOCatalogue
3202 * for matching via a separate IOKit calldown.
3203 */
3204
3205finish:
3206
3207 /* Gather up the collected log messages for user space. Any
3208 * error messages past this call will not make it up as log messages
3209 * but will be in the system log.
3210 */
3211 logInfoArray = OSKext::clearUserSpaceLogFilter();
3212
3213 if (logInfoArray && logInfoOut && logInfoLengthOut) {
3214 tempResult = OSKext::serializeLogInfo(logInfoArray,
3215 logInfoOut, logInfoLengthOut);
3216 if (tempResult != kOSReturnSuccess) {
3217 result = tempResult;
3218 }
3219 }
3220
3221 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
3222
3223 /* Note: mkextDataObject will have been retained by every kext w/an
3224 * executable in it. That should all have been flushed out at the
3225 * and of the load operation, but you never know....
3226 */
3227 if (mkextData && mkextData->getRetainCount() > 1) {
3228 OSKextLog(/* kext */ NULL,
3229 kOSKextLogErrorLevel |
3230 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3231 "Kext load request buffer from user space still retained by a kext; "
3232 "probable memory leak.");
3233 }
3234
3235 IORecursiveLockUnlock(sKextLock);
3236
3237 OSSafeReleaseNULL(mkextData);
3238 OSSafeReleaseNULL(mkextPlist);
3239 OSSafeReleaseNULL(serializer);
3240 OSSafeReleaseNULL(logInfoArray);
3241
3242 return result;
3243}
3244
3245/*********************************************************************
3246*********************************************************************/
3247/* static */
3248OSReturn
3249OSKext::serializeLogInfo(
3250 OSArray * logInfoArray,
3251 char ** logInfoOut,
3252 uint32_t * logInfoLengthOut)
3253{
3254 OSReturn result = kOSReturnError;
3255 char * buffer = NULL;
3256 kern_return_t kmem_result = KERN_FAILURE;
3257 OSSerialize * serializer = NULL; // must release; reused
3258 char * logInfo = NULL; // returned by reference
3259 uint32_t logInfoLength = 0;
3260
3261 if (!logInfoArray || !logInfoOut || !logInfoLengthOut) {
3262 OSKextLog(/* kext */ NULL,
3263 kOSKextLogErrorLevel |
3264 kOSKextLogIPCFlag,
3265 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
3266 /* Bad programmer. */
3267 result = kOSKextReturnInvalidArgument;
3268 goto finish;
3269 }
3270
3271 serializer = OSSerialize::withCapacity(0);
3272 if (!serializer) {
3273 OSKextLog(/* kext */ NULL,
3274 kOSKextLogErrorLevel |
3275 kOSKextLogIPCFlag,
3276 "Failed to create serializer on log info for request from user space.");
3277 /* Incidental error; we're going to (try to) allow the request
3278 * itself to succeed. */
3279 }
3280
3281 if (!logInfoArray->serialize(serializer)) {
3282 OSKextLog(/* kext */ NULL,
3283 kOSKextLogErrorLevel |
3284 kOSKextLogIPCFlag,
3285 "Failed to serialize log info for request from user space.");
3286 /* Incidental error; we're going to (try to) allow the request
3287 * itself to succeed. */
3288 } else {
3289 logInfo = serializer->text();
3290 logInfoLength = serializer->getLength();
3291
3292 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer, round_page(logInfoLength), VM_KERN_MEMORY_OSKEXT);
3293 if (kmem_result != KERN_SUCCESS) {
3294 OSKextLog(/* kext */ NULL,
3295 kOSKextLogErrorLevel |
3296 kOSKextLogIPCFlag,
3297 "Failed to copy log info for request from user space.");
3298 /* Incidental error; we're going to (try to) allow the request
3299 * to succeed. */
3300 } else {
3301 /* 11981737 - clear uninitialized data in last page */
3302 bzero((void *)(buffer + logInfoLength),
3303 (round_page(logInfoLength) - logInfoLength));
3304 memcpy(buffer, logInfo, logInfoLength);
3305 *logInfoOut = buffer;
3306 *logInfoLengthOut = logInfoLength;
3307 }
3308 }
3309
3310 result = kOSReturnSuccess;
3311finish:
3312 OSSafeReleaseNULL(serializer);
3313 return result;
3314}
3315
3316#if PRAGMA_MARK
3317#pragma mark Instance Management Methods
3318#endif
3319/*********************************************************************
3320*********************************************************************/
3321OSKext *
3322OSKext::lookupKextWithIdentifier(const char * kextIdentifier)
3323{
3324 OSKext * foundKext = NULL;
3325
3326 IORecursiveLockLock(sKextLock);
3327 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
3328 if (foundKext) {
3329 foundKext->retain();
3330 }
3331 IORecursiveLockUnlock(sKextLock);
3332
3333 return foundKext;
3334}
3335
3336/*********************************************************************
3337*********************************************************************/
3338OSKext *
3339OSKext::lookupKextWithIdentifier(OSString * kextIdentifier)
3340{
3341 return OSKext::lookupKextWithIdentifier(kextIdentifier->getCStringNoCopy());
3342}
3343
3344/*********************************************************************
3345*********************************************************************/
3346OSKext *
3347OSKext::lookupKextWithLoadTag(uint32_t aTag)
3348{
3349 OSKext * foundKext = NULL; // returned
3350 uint32_t count, i;
3351
3352 IORecursiveLockLock(sKextLock);
3353
3354 count = sLoadedKexts->getCount();
3355 for (i = 0; i < count; i++) {
3356 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
3357 if (thisKext->getLoadTag() == aTag) {
3358 foundKext = thisKext;
3359 foundKext->retain();
3360 goto finish;
3361 }
3362 }
3363
3364finish:
3365 IORecursiveLockUnlock(sKextLock);
3366
3367 return foundKext;
3368}
3369
3370/*********************************************************************
3371*********************************************************************/
3372OSKext *
3373OSKext::lookupKextWithAddress(vm_address_t address)
3374{
3375 OSKext * foundKext = NULL; // returned
3376 uint32_t count, i;
3377
3378 IORecursiveLockLock(sKextLock);
3379
3380 count = sLoadedKexts->getCount();
3381 for (i = 0; i < count; i++) {
3382 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
3383 if (thisKext->linkedExecutable) {
3384 vm_address_t kext_start =
3385 (vm_address_t)thisKext->linkedExecutable->getBytesNoCopy();
3386 vm_address_t kext_end = kext_start +
3387 thisKext->linkedExecutable->getLength();
3388 if ((kext_start <= address) && (address < kext_end)) {
3389 foundKext = thisKext;
3390 foundKext->retain();
3391 goto finish;
3392 }
3393 }
3394 }
3395
3396finish:
3397 IORecursiveLockUnlock(sKextLock);
3398
3399 return foundKext;
3400}
3401
3402OSData *
3403OSKext::copyKextUUIDForAddress(OSNumber *address)
3404{
3405 OSData * uuid = NULL;
3406 OSKextActiveAccount * active;
3407 OSKext * kext = NULL;
3408 uint32_t baseIdx;
3409 uint32_t lim;
3410
3411 if (!address) {
3412 return NULL;
3413 }
3414
3415 uintptr_t addr = ml_static_slide((uintptr_t)address->unsigned64BitValue());
3416
3417#if CONFIG_MACF
3418 /* Is the calling process allowed to query kext info? */
3419 if (current_task() != kernel_task) {
3420 int macCheckResult = 0;
3421 kauth_cred_t cred = NULL;
3422
3423 cred = kauth_cred_get_with_ref();
3424 macCheckResult = mac_kext_check_query(cred);
3425 kauth_cred_unref(&cred);
3426
3427 if (macCheckResult != 0) {
3428 OSKextLog(/* kext */ NULL,
3429 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
3430 "Failed to query kext UUID (MAC policy error 0x%x).",
3431 macCheckResult);
3432 return NULL;
3433 }
3434 }
3435#endif
3436
3437 IOSimpleLockLock(sKextAccountsLock);
3438 // bsearch sKextAccounts list
3439 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1)
3440 {
3441 active = &sKextAccounts[baseIdx + (lim >> 1)];
3442 if ((addr >= active->address) && (addr < active->address_end))
3443 {
3444 kext = active->account->kext;
3445 if (kext) kext->retain();
3446 break;
3447 }
3448 else if (addr > active->address)
3449 {
3450 // move right
3451 baseIdx += (lim >> 1) + 1;
3452 lim--;
3453 }
3454 // else move left
3455 }
3456 IOSimpleLockUnlock(sKextAccountsLock);
3457
3458 if (kext)
3459 {
3460 uuid = kext->copyTextUUID();
3461 kext->release();
3462 }
3463 else if (((vm_offset_t)addr >= vm_kernel_stext) && ((vm_offset_t)addr < vm_kernel_etext))
3464 {
3465 uuid = sKernelKext->copyTextUUID();
3466 }
3467
3468 return uuid;
3469}
3470
3471/*********************************************************************
3472*********************************************************************/
3473OSKext *
3474OSKext::lookupKextWithUUID(uuid_t wanted)
3475{
3476 OSKext * foundKext = NULL; // returned
3477 uint32_t count, i;
3478
3479 IORecursiveLockLock(sKextLock);
3480
3481 count = sLoadedKexts->getCount();
3482
3483 for (i = 0; i < count; i++) {
3484 OSKext * thisKext = NULL;
3485
3486 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
3487 if (!thisKext) {
3488 continue;
3489 }
3490
3491 OSData *uuid_data = thisKext->copyUUID();
3492 if (!uuid_data) {
3493 continue;
3494 }
3495
3496 uuid_t uuid;
3497 memcpy(&uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
3498 uuid_data->release();
3499
3500 if (0 == uuid_compare(wanted, uuid)) {
3501 foundKext = thisKext;
3502 foundKext->retain();
3503 goto finish;
3504 }
3505
3506 }
3507
3508finish:
3509 IORecursiveLockUnlock(sKextLock);
3510
3511 return foundKext;
3512}
3513
3514
3515
3516
3517/*********************************************************************
3518*********************************************************************/
3519/* static */
3520bool OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
3521{
3522 bool result = false;
3523 OSKext * foundKext = NULL; // returned
3524
3525 IORecursiveLockLock(sKextLock);
3526
3527 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
3528 if (foundKext && foundKext->isLoaded()) {
3529 result = true;
3530 }
3531
3532 IORecursiveLockUnlock(sKextLock);
3533
3534 return result;
3535}
3536
3537/*********************************************************************
3538* xxx - should spawn a separate thread so a kext can safely have
3539* xxx - itself unloaded.
3540*********************************************************************/
3541/* static */
3542OSReturn
3543OSKext::removeKext(
3544 OSKext * aKext,
3545#if CONFIG_EMBEDDED
3546 __unused
3547#endif
3548 bool terminateServicesAndRemovePersonalitiesFlag)
3549 {
3550#if CONFIG_EMBEDDED
3551 OSKextLog(aKext,
3552 kOSKextLogErrorLevel |
3553 kOSKextLogKextBookkeepingFlag,
3554 "removeKext() called for %s, not supported on embedded",
3555 aKext->getIdentifier() ? aKext->getIdentifierCString() : "unknown kext");
3556
3557 return kOSReturnSuccess;
3558#else /* CONFIG_EMBEDDED */
3559
3560 OSReturn result = kOSKextReturnInUse;
3561 OSKext * checkKext = NULL; // do not release
3562#if CONFIG_MACF
3563 int macCheckResult = 0;
3564 kauth_cred_t cred = NULL;
3565#endif
3566
3567 IORecursiveLockLock(sKextLock);
3568
3569 /* If the kext has no identifier, it failed to init
3570 * so isn't in sKextsByID and it isn't loaded.
3571 */
3572 if (!aKext->getIdentifier()) {
3573 result = kOSReturnSuccess;
3574 goto finish;
3575 }
3576
3577 checkKext = OSDynamicCast(OSKext,
3578 sKextsByID->getObject(aKext->getIdentifier()));
3579 if (checkKext != aKext) {
3580 result = kOSKextReturnNotFound;
3581 goto finish;
3582 }
3583
3584 if (aKext->isLoaded()) {
3585#if CONFIG_MACF
3586 if (current_task() != kernel_task) {
3587 cred = kauth_cred_get_with_ref();
3588 macCheckResult = mac_kext_check_unload(cred, aKext->getIdentifierCString());
3589 kauth_cred_unref(&cred);
3590 }
3591
3592 if (macCheckResult != 0) {
3593 result = kOSReturnError;
3594 OSKextLog(aKext,
3595 kOSKextLogErrorLevel |
3596 kOSKextLogKextBookkeepingFlag,
3597 "Failed to remove kext %s (MAC policy error 0x%x).",
3598 aKext->getIdentifierCString(), macCheckResult);
3599 goto finish;
3600 }
3601#endif
3602
3603 /* make sure there are no resource requests in flight - 17187548 */
3604 if (aKext->countRequestCallbacks()) {
3605 goto finish;
3606 }
3607
3608 /* If we are terminating, send the request to the IOCatalogue
3609 * (which will actually call us right back but that's ok we have
3610 * a recursive lock don't you know) but do not ask the IOCatalogue
3611 * to call back with an unload, we'll do that right here.
3612 */
3613 if (terminateServicesAndRemovePersonalitiesFlag) {
3614 result = gIOCatalogue->terminateDriversForModule(
3615 aKext->getIdentifierCString(), /* unload */ false);
3616 if (result != kOSReturnSuccess) {
3617 OSKextLog(aKext,
3618 kOSKextLogErrorLevel |
3619 kOSKextLogKextBookkeepingFlag,
3620 "Can't remove kext %s; services failed to terminate - 0x%x.",
3621 aKext->getIdentifierCString(), result);
3622 goto finish;
3623 }
3624 }
3625
3626 result = aKext->unload();
3627 if (result != kOSReturnSuccess) {
3628 goto finish;
3629 }
3630 }
3631
3632 /* Remove personalities as requested. This is a bit redundant for a loaded
3633 * kext as IOCatalogue::terminateDriversForModule() removes driver
3634 * personalities, but it doesn't restart matching, which we always want
3635 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
3636 * that happens.
3637 */
3638 if (terminateServicesAndRemovePersonalitiesFlag) {
3639 aKext->removePersonalitiesFromCatalog();
3640 }
3641
3642 OSKextLog(aKext,
3643 kOSKextLogProgressLevel |
3644 kOSKextLogKextBookkeepingFlag,
3645 "Removing kext %s.",
3646 aKext->getIdentifierCString());
3647
3648 sKextsByID->removeObject(aKext->getIdentifier());
3649 result = kOSReturnSuccess;
3650
3651finish:
3652 IORecursiveLockUnlock(sKextLock);
3653 return result;
3654#endif /* CONFIG_EMBEDDED */
3655 }
3656
3657/*********************************************************************
3658*********************************************************************/
3659/* static */
3660OSReturn
3661OSKext::removeKextWithIdentifier(
3662 const char * kextIdentifier,
3663 bool terminateServicesAndRemovePersonalitiesFlag)
3664{
3665 OSReturn result = kOSReturnError;
3666
3667 IORecursiveLockLock(sKextLock);
3668
3669 OSKext * aKext = OSDynamicCast(OSKext,
3670 sKextsByID->getObject(kextIdentifier));
3671 if (!aKext) {
3672 result = kOSKextReturnNotFound;
3673 OSKextLog(/* kext */ NULL,
3674 kOSKextLogErrorLevel |
3675 kOSKextLogKextBookkeepingFlag,
3676 "Can't remove kext %s - not found.",
3677 kextIdentifier);
3678 goto finish;
3679 }
3680
3681 result = OSKext::removeKext(aKext,
3682 terminateServicesAndRemovePersonalitiesFlag);
3683
3684finish:
3685 IORecursiveLockUnlock(sKextLock);
3686
3687 return result;
3688}
3689
3690/*********************************************************************
3691*********************************************************************/
3692/* static */
3693OSReturn
3694OSKext::removeKextWithLoadTag(
3695 OSKextLoadTag loadTag,
3696 bool terminateServicesAndRemovePersonalitiesFlag)
3697{
3698 OSReturn result = kOSReturnError;
3699 OSKext * foundKext = NULL;
3700 uint32_t count, i;
3701
3702 IORecursiveLockLock(sKextLock);
3703
3704 count = sLoadedKexts->getCount();
3705 for (i = 0; i < count; i++) {
3706 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
3707 if (thisKext->loadTag == loadTag) {
3708 foundKext = thisKext;
3709 break;
3710 }
3711 }
3712
3713 if (!foundKext) {
3714 result = kOSKextReturnNotFound;
3715 OSKextLog(/* kext */ NULL,
3716 kOSKextLogErrorLevel |
3717 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
3718 "Can't remove kext with load tag %d - not found.",
3719 loadTag);
3720 goto finish;
3721 }
3722
3723 result = OSKext::removeKext(foundKext,
3724 terminateServicesAndRemovePersonalitiesFlag);
3725
3726finish:
3727 IORecursiveLockUnlock(sKextLock);
3728
3729 return result;
3730 }
3731
3732/*********************************************************************
3733*********************************************************************/
3734OSDictionary *
3735OSKext::copyKexts(void)
3736{
3737 OSDictionary * result;
3738
3739 IORecursiveLockLock(sKextLock);
3740 result = OSDynamicCast(OSDictionary, sKextsByID->copyCollection());
3741 IORecursiveLockUnlock(sKextLock);
3742
3743 return result;
3744}
3745
3746/*********************************************************************
3747 *********************************************************************/
3748#define BOOTER_KEXT_PREFIX "Driver-"
3749
3750typedef struct _DeviceTreeBuffer {
3751 uint32_t paddr;
3752 uint32_t length;
3753} _DeviceTreeBuffer;
3754
3755/*********************************************************************
3756 * Create a dictionary of excluded kexts from the given booter data.
3757 *********************************************************************/
3758/* static */
3759void
3760OSKext::createExcludeListFromBooterData(
3761 OSDictionary * theDictionary,
3762 OSCollectionIterator * theIterator )
3763{
3764 OSString * deviceTreeName = NULL; // do not release
3765 const _DeviceTreeBuffer * deviceTreeBuffer = NULL; // do not release
3766 char * booterDataPtr = NULL; // do not release
3767 _BooterKextFileInfo * kextFileInfo = NULL; // do not release
3768 char * infoDictAddr = NULL; // do not release
3769 OSObject * parsedXML = NULL; // must release
3770 OSDictionary * theInfoDict = NULL; // do not release
3771
3772 theIterator->reset();
3773
3774 /* look for AppleKextExcludeList.kext */
3775 while ( (deviceTreeName =
3776 OSDynamicCast(OSString, theIterator->getNextObject())) ) {
3777
3778 const char * devTreeNameCString;
3779 OSData * deviceTreeEntry;
3780 OSString * myBundleID; // do not release
3781
3782 OSSafeReleaseNULL(parsedXML);
3783
3784 deviceTreeEntry =
3785 OSDynamicCast(OSData, theDictionary->getObject(deviceTreeName));
3786 if (!deviceTreeEntry) {
3787 continue;
3788 }
3789
3790 /* Make sure it is a kext */
3791 devTreeNameCString = deviceTreeName->getCStringNoCopy();
3792 if (strncmp(devTreeNameCString, BOOTER_KEXT_PREFIX,
3793 (sizeof(BOOTER_KEXT_PREFIX) - 1)) != 0) {
3794 OSKextLog(NULL,
3795 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
3796 "\"%s\" not a kext",
3797 devTreeNameCString);
3798 continue;
3799 }
3800
3801 deviceTreeBuffer = (const _DeviceTreeBuffer *)
3802 deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
3803 if (!deviceTreeBuffer) {
3804 continue;
3805 }
3806
3807 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
3808 if (!booterDataPtr) {
3809 continue;
3810 }
3811
3812 kextFileInfo = (_BooterKextFileInfo *) booterDataPtr;
3813 if (!kextFileInfo->infoDictPhysAddr ||
3814 !kextFileInfo->infoDictLength) {
3815 continue;
3816 }
3817
3818 infoDictAddr = (char *)
3819 ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
3820 if (!infoDictAddr) {
3821 continue;
3822 }
3823
3824 parsedXML = OSUnserializeXML(infoDictAddr);
3825 if (!parsedXML) {
3826 continue;
3827 }
3828
3829 theInfoDict = OSDynamicCast(OSDictionary, parsedXML);
3830 if (!theInfoDict) {
3831 continue;
3832 }
3833
3834 myBundleID =
3835 OSDynamicCast(OSString,
3836 theInfoDict->getObject(kCFBundleIdentifierKey));
3837 if ( myBundleID &&
3838 strcmp( myBundleID->getCStringNoCopy(), "com.apple.driver.KextExcludeList" ) == 0 ) {
3839
3840 boolean_t updated = updateExcludeList(theInfoDict);
3841 if (!updated) {
3842 /* 25322874 */
3843 panic("Missing OSKextExcludeList dictionary\n");
3844 }
3845 break;
3846 }
3847
3848 } // while ( (deviceTreeName = ...) )
3849
3850 OSSafeReleaseNULL(parsedXML);
3851 return;
3852}
3853
3854/*********************************************************************
3855 * Create a dictionary of excluded kexts from the given prelink
3856 * info (kernelcache).
3857 *********************************************************************/
3858/* static */
3859void
3860OSKext::createExcludeListFromPrelinkInfo( OSArray * theInfoArray )
3861{
3862 OSDictionary * myInfoDict = NULL; // do not release
3863 OSString * myBundleID; // do not release
3864 u_int i;
3865
3866 /* Find com.apple.driver.KextExcludeList. */
3867 for (i = 0; i < theInfoArray->getCount(); i++) {
3868 myInfoDict = OSDynamicCast(OSDictionary, theInfoArray->getObject(i));
3869 if (!myInfoDict) {
3870 continue;
3871 }
3872 myBundleID =
3873 OSDynamicCast(OSString,
3874 myInfoDict->getObject(kCFBundleIdentifierKey));
3875 if ( myBundleID &&
3876 strcmp( myBundleID->getCStringNoCopy(), "com.apple.driver.KextExcludeList" ) == 0 ) {
3877
3878 boolean_t updated = updateExcludeList(myInfoDict);
3879 if (!updated) {
3880 /* 25322874 */
3881 panic("Missing OSKextExcludeList dictionary\n");
3882 }
3883 break;
3884 }
3885 } // for (i = 0; i < theInfoArray->getCount()...
3886
3887 return;
3888}
3889
3890/* static */
3891boolean_t
3892OSKext::updateExcludeList(OSDictionary *infoDict)
3893{
3894 OSDictionary *myTempDict = NULL; // do not free
3895 OSString *myTempString = NULL; // do not free
3896 OSKextVersion newVersion = 0;
3897 boolean_t updated = false;
3898
3899 if (!infoDict) {
3900 return false;
3901 }
3902
3903 myTempDict = OSDynamicCast(OSDictionary, infoDict->getObject("OSKextExcludeList"));
3904 if (!myTempDict) {
3905 return false;
3906 }
3907
3908 myTempString = OSDynamicCast(OSString, infoDict->getObject(kCFBundleVersionKey));
3909 if (!myTempString) {
3910 return false;
3911 }
3912
3913 newVersion = OSKextParseVersionString(myTempString->getCStringNoCopy());
3914 if (newVersion == 0) {
3915 return false;
3916 }
3917
3918 IORecursiveLockLock(sKextLock);
3919
3920 if (newVersion > sExcludeListVersion) {
3921 OSSafeReleaseNULL(sExcludeListByID);
3922 sExcludeListByID = OSDictionary::withDictionary(myTempDict, 0);
3923 sExcludeListVersion = newVersion;
3924 updated = true;
3925 }
3926
3927 IORecursiveLockUnlock(sKextLock);
3928 return updated;
3929}
3930
3931#if PRAGMA_MARK
3932#pragma mark Accessors
3933#endif
3934/*********************************************************************
3935*********************************************************************/
3936const OSSymbol *
3937OSKext::getIdentifier(void)
3938{
3939 return bundleID;
3940}
3941
3942/*********************************************************************
3943* A kext must have a bundle identifier to even survive initialization;
3944* this is guaranteed to exist past then.
3945*********************************************************************/
3946const char *
3947OSKext::getIdentifierCString(void)
3948{
3949 return bundleID->getCStringNoCopy();
3950}
3951
3952/*********************************************************************
3953*********************************************************************/
3954OSKextVersion
3955OSKext::getVersion(void)
3956{
3957 return version;
3958}
3959
3960/*********************************************************************
3961*********************************************************************/
3962OSKextVersion
3963OSKext::getCompatibleVersion(void)
3964{
3965 return compatibleVersion;
3966}
3967
3968/*********************************************************************
3969*********************************************************************/
3970bool
3971OSKext::isLibrary(void)
3972{
3973 return (getCompatibleVersion() > 0);
3974}
3975
3976/*********************************************************************
3977*********************************************************************/
3978bool
3979OSKext::isCompatibleWithVersion(OSKextVersion aVersion)
3980{
3981 if ((compatibleVersion > -1 && version > -1) &&
3982 (compatibleVersion <= version && aVersion <= version)) {
3983 return true;
3984 }
3985 return false;
3986}
3987
3988/*********************************************************************
3989*********************************************************************/
3990bool
3991OSKext::declaresExecutable(void)
3992{
3993 return (getPropertyForHostArch(kCFBundleExecutableKey) != NULL);
3994}
3995
3996/*********************************************************************
3997*********************************************************************/
3998OSData *
3999OSKext::getExecutable(void)
4000{
4001 OSData * result = NULL;
4002 OSData * extractedExecutable = NULL; // must release
4003 OSData * mkextExecutableRef = NULL; // do not release
4004
4005 if (flags.builtin) return (sKernelKext->linkedExecutable);
4006
4007 result = OSDynamicCast(OSData, infoDict->getObject(_kOSKextExecutableKey));
4008 if (result) {
4009 goto finish;
4010 }
4011
4012 mkextExecutableRef = OSDynamicCast(OSData,
4013 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey));
4014
4015 if (mkextExecutableRef) {
4016
4017 MkextEntryRef * mkextEntryRef = (MkextEntryRef *)
4018 mkextExecutableRef->getBytesNoCopy();
4019 uint32_t mkextVersion = MKEXT_GET_VERSION(mkextEntryRef->mkext);
4020 if (mkextVersion == MKEXT_VERS_2) {
4021 mkext2_file_entry * fileinfo =
4022 (mkext2_file_entry *)mkextEntryRef->fileinfo;
4023 uint32_t compressedSize = MKEXT2_GET_ENTRY_COMPSIZE(fileinfo);
4024 uint32_t fullSize = MKEXT2_GET_ENTRY_FULLSIZE(fileinfo);
4025 extractedExecutable = extractMkext2FileData(
4026 MKEXT2_GET_ENTRY_DATA(fileinfo), "executable",
4027 compressedSize, fullSize);
4028 } else {
4029 OSKextLog(this, kOSKextLogErrorLevel |
4030 kOSKextLogArchiveFlag,
4031 "Kext %s - unknown mkext version 0x%x for executable.",
4032 getIdentifierCString(), mkextVersion);
4033 }
4034
4035 /* Regardless of success, remove the mkext executable,
4036 * and drop one reference on the mkext. (setExecutable() does not
4037 * replace, it removes, or panics if asked to replace.)
4038 */
4039 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
4040 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
4041
4042 if (extractedExecutable && extractedExecutable->getLength()) {
4043 if (!setExecutable(extractedExecutable)) {
4044 goto finish;
4045 }
4046 result = extractedExecutable;
4047 } else {
4048 goto finish;
4049 }
4050 }
4051
4052finish:
4053
4054 OSSafeReleaseNULL(extractedExecutable);
4055
4056 return result;
4057}
4058
4059/*********************************************************************
4060*********************************************************************/
4061bool
4062OSKext::isInterface(void)
4063{
4064 return flags.interface;
4065}
4066
4067/*********************************************************************
4068*********************************************************************/
4069bool
4070OSKext::isKernel(void)
4071{
4072 return (this == sKernelKext);
4073}
4074
4075/*********************************************************************
4076*********************************************************************/
4077bool
4078OSKext::isKernelComponent(void)
4079{
4080 return flags.kernelComponent ? true : false;
4081}
4082
4083/*********************************************************************
4084*********************************************************************/
4085bool
4086OSKext::isExecutable(void)
4087{
4088 return (!isKernel() && !isInterface() && declaresExecutable());
4089}
4090
4091/*********************************************************************
4092* We might want to check this recursively for all dependencies,
4093* since a subtree of dependencies could get loaded before we hit
4094* a dependency that isn't safe-boot-loadable.
4095*
4096* xxx - Might want to return false if OSBundleEnableKextLogging or
4097* OSBundleDebugLevel
4098* or IOKitDebug is nonzero too (we used to do that, but I don't see
4099* the point except it's usually development drivers, which might
4100* cause panics on startup, that have those properties). Heh; could
4101* use a "kx" boot-arg!
4102*********************************************************************/
4103bool
4104OSKext::isLoadableInSafeBoot(void)
4105{
4106 bool result = false;
4107 OSString * required = NULL; // do not release
4108
4109 if (isKernel()) {
4110 result = true;
4111 goto finish;
4112 }
4113
4114 required = OSDynamicCast(OSString,
4115 getPropertyForHostArch(kOSBundleRequiredKey));
4116 if (!required) {
4117 goto finish;
4118 }
4119 if (required->isEqualTo(kOSBundleRequiredRoot) ||
4120 required->isEqualTo(kOSBundleRequiredLocalRoot) ||
4121 required->isEqualTo(kOSBundleRequiredNetworkRoot) ||
4122 required->isEqualTo(kOSBundleRequiredSafeBoot) ||
4123 required->isEqualTo(kOSBundleRequiredConsole)) {
4124
4125 result = true;
4126 }
4127
4128finish:
4129 return result;
4130}
4131
4132/*********************************************************************
4133*********************************************************************/
4134bool
4135OSKext::isPrelinked(void)
4136{
4137 return flags.prelinked ? true : false;
4138}
4139
4140/*********************************************************************
4141*********************************************************************/
4142bool OSKext::isLoaded(void)
4143{
4144 return flags.loaded ? true : false;
4145}
4146
4147/*********************************************************************
4148*********************************************************************/
4149bool
4150OSKext::isStarted(void)
4151{
4152 return flags.started ? true : false;
4153}
4154
4155/*********************************************************************
4156*********************************************************************/
4157bool
4158OSKext::isCPPInitialized(void)
4159{
4160 return flags.CPPInitialized;
4161}
4162
4163/*********************************************************************
4164*********************************************************************/
4165void
4166OSKext::setCPPInitialized(bool initialized)
4167{
4168 flags.CPPInitialized = initialized;
4169}
4170
4171/*********************************************************************
4172*********************************************************************/
4173uint32_t
4174OSKext::getLoadTag(void)
4175{
4176 return loadTag;
4177}
4178
4179/*********************************************************************
4180 *********************************************************************/
4181void OSKext::getSizeInfo(uint32_t *loadSize, uint32_t *wiredSize)
4182{
4183 if (linkedExecutable) {
4184 *loadSize = linkedExecutable->getLength();
4185
4186 /* If we have a kmod_info struct, calculated the wired size
4187 * from that. Otherwise it's the full load size.
4188 */
4189 if (kmod_info) {
4190 *wiredSize = *loadSize - kmod_info->hdr_size;
4191 } else {
4192 *wiredSize = *loadSize;
4193 }
4194 }
4195 else {
4196 *wiredSize = 0;
4197 *loadSize = 0;
4198 }
4199}
4200
4201/*********************************************************************
4202*********************************************************************/
4203OSData *
4204OSKext::copyUUID(void)
4205{
4206 OSData * result = NULL;
4207 OSData * theExecutable = NULL; // do not release
4208 const kernel_mach_header_t * header;
4209
4210 /* An interface kext doesn't have a linked executable with an LC_UUID,
4211 * we create one when it's linked.
4212 */
4213 if (interfaceUUID) {
4214 result = interfaceUUID;
4215 result->retain();
4216 goto finish;
4217 }
4218
4219 if (flags.builtin || isInterface()) return (sKernelKext->copyUUID());
4220
4221 /* For real kexts, try to get the UUID from the linked executable,
4222 * or if is hasn't been linked yet, the unrelocated executable.
4223 */
4224 theExecutable = linkedExecutable;
4225 if (!theExecutable) {
4226 theExecutable = getExecutable();
4227 }
4228 if (!theExecutable) {
4229 goto finish;
4230 }
4231
4232 header = (const kernel_mach_header_t *)theExecutable->getBytesNoCopy();
4233 result = copyMachoUUID(header);
4234
4235finish:
4236 return result;
4237}
4238
4239/*********************************************************************
4240*********************************************************************/
4241OSData *
4242OSKext::copyTextUUID(void)
4243{
4244 if (flags.builtin)
4245 {
4246 return (copyMachoUUID((const kernel_mach_header_t *)kmod_info->address));
4247 }
4248 return (copyUUID());
4249}
4250
4251/*********************************************************************
4252*********************************************************************/
4253OSData *
4254OSKext::copyMachoUUID(const kernel_mach_header_t * header)
4255{
4256 OSData * result = NULL;
4257 const struct load_command * load_cmd = NULL;
4258 const struct uuid_command * uuid_cmd = NULL;
4259 uint32_t i;
4260
4261 load_cmd = (const struct load_command *)&header[1];
4262
4263 if (header->magic != MH_MAGIC_KERNEL) {
4264 OSKextLog(NULL,
4265 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4266 "%s: bad header %p",
4267 __func__,
4268 header);
4269 goto finish;
4270 }
4271
4272 for (i = 0; i < header->ncmds; i++) {
4273 if (load_cmd->cmd == LC_UUID) {
4274 uuid_cmd = (struct uuid_command *)load_cmd;
4275 result = OSData::withBytes(uuid_cmd->uuid, sizeof(uuid_cmd->uuid));
4276 goto finish;
4277 }
4278 load_cmd = (struct load_command *)((caddr_t)load_cmd + load_cmd->cmdsize);
4279 }
4280
4281finish:
4282 return result;
4283}
4284
4285/*********************************************************************
4286*********************************************************************/
4287#if defined (__arm__)
4288#include <arm/arch.h>
4289#endif
4290
4291#if defined (__x86_64__)
4292#define ARCHNAME "x86_64"
4293#elif defined (__arm64__)
4294#define ARCHNAME "arm64"
4295#elif defined (__arm__)
4296
4297#if defined (__ARM_ARCH_7S__)
4298#define ARCHNAME "armv7s"
4299#elif defined (__ARM_ARCH_7F__)
4300#define ARCHNAME "armv7f"
4301#elif defined (__ARM_ARCH_7K__)
4302#define ARCHNAME "armv7k"
4303#elif defined (_ARM_ARCH_7) /* umbrella for all remaining */
4304#define ARCHNAME "armv7"
4305#elif defined (_ARM_ARCH_6) /* umbrella for all armv6 */
4306#define ARCHNAME "armv6"
4307#endif
4308
4309#elif defined (__arm64__)
4310#define ARCHNAME "arm64"
4311#else
4312#error architecture not supported
4313#endif
4314
4315#define ARCH_SEPARATOR_CHAR '_'
4316
4317static char * makeHostArchKey(const char * key, uint32_t * keySizeOut)
4318{
4319 char * result = NULL;
4320 uint32_t keyLength = strlen(key);
4321 uint32_t keySize;
4322
4323 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
4324 */
4325 keySize = 1 + 1 + strlen(key) + strlen(ARCHNAME);
4326 result = (char *)kalloc_tag(keySize, VM_KERN_MEMORY_OSKEXT);
4327 if (!result) {
4328 goto finish;
4329 }
4330 strlcpy(result, key, keySize);
4331 result[keyLength++] = ARCH_SEPARATOR_CHAR;
4332 result[keyLength] = '\0';
4333 strlcat(result, ARCHNAME, keySize);
4334 *keySizeOut = keySize;
4335
4336finish:
4337 return result;
4338}
4339
4340/*********************************************************************
4341*********************************************************************/
4342OSObject *
4343OSKext::getPropertyForHostArch(const char * key)
4344{
4345 OSObject * result = NULL; // do not release
4346 uint32_t hostArchKeySize = 0;
4347 char * hostArchKey = NULL; // must kfree
4348
4349 if (!key || !infoDict) {
4350 goto finish;
4351 }
4352
4353 /* Some properties are not allowed to be arch-variant:
4354 * - Any CFBundle... property.
4355 * - OSBundleIsInterface.
4356 * - OSKernelResource.
4357 */
4358 if (STRING_HAS_PREFIX(key, "OS") ||
4359 STRING_HAS_PREFIX(key, "IO")) {
4360
4361 hostArchKey = makeHostArchKey(key, &hostArchKeySize);
4362 if (!hostArchKey) {
4363 OSKextLog(/* kext (this isn't about a kext) */ NULL,
4364 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4365 "Allocation failure.");
4366 goto finish;
4367 }
4368 result = infoDict->getObject(hostArchKey);
4369 }
4370
4371 if (!result) {
4372 result = infoDict->getObject(key);
4373 }
4374
4375finish:
4376 if (hostArchKey) kfree(hostArchKey, hostArchKeySize);
4377 return result;
4378}
4379
4380#if PRAGMA_MARK
4381#pragma mark Load/Start/Stop/Unload
4382#endif
4383
4384#define isWhiteSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == ',' || (c) == '\n')
4385
4386/*********************************************************************
4387 * sExcludeListByID is a dictionary with keys / values of:
4388 * key = bundleID string of kext we will not allow to load
4389 * value = version string(s) of the kext that is to be denied loading.
4390 * The version strings can be comma delimited. For example if kext
4391 * com.foocompany.fookext has two versions that we want to deny
4392 * loading then the version strings might look like:
4393 * 1.0.0, 1.0.1
4394 * If the current fookext has a version of 1.0.0 OR 1.0.1 we will
4395 * not load the kext.
4396 *
4397 * Value may also be in the form of "LE 2.0.0" (version numbers
4398 * less than or equal to 2.0.0 will not load) or "LT 2.0.0" (version
4399 * number less than 2.0.0 will not load)
4400 *
4401 * NOTE - we cannot use the characters "<=" or "<" because we have code
4402 * that serializes plists and treats '<' as a special character.
4403 *********************************************************************/
4404bool
4405OSKext::isInExcludeList(void)
4406{
4407 OSString * versionString = NULL; // do not release
4408 char * versionCString = NULL; // do not free
4409 size_t i;
4410 boolean_t wantLessThan = false;
4411 boolean_t wantLessThanEqualTo = false;
4412 boolean_t isInExcludeList = true;
4413 char myBuffer[32];
4414
4415 IORecursiveLockLock(sKextLock);
4416
4417 if (!sExcludeListByID) {
4418 isInExcludeList = false;
4419 } else {
4420 /* look up by bundleID in our exclude list and if found get version
4421 * string (or strings) that we will not allow to load
4422 */
4423 versionString = OSDynamicCast(OSString, sExcludeListByID->getObject(bundleID));
4424 if (versionString == NULL || versionString->getLength() > (sizeof(myBuffer) - 1)) {
4425 isInExcludeList = false;
4426 }
4427 }
4428
4429 IORecursiveLockUnlock(sKextLock);
4430
4431 if (!isInExcludeList) {
4432 return(false);
4433 }
4434
4435 /* parse version strings */
4436 versionCString = (char *) versionString->getCStringNoCopy();
4437
4438 /* look for "LT" or "LE" form of version string, must be in first two
4439 * positions.
4440 */
4441 if (*versionCString == 'L' && *(versionCString + 1) == 'T') {
4442 wantLessThan = true;
4443 versionCString +=2;
4444 }
4445 else if (*versionCString == 'L' && *(versionCString + 1) == 'E') {
4446 wantLessThanEqualTo = true;
4447 versionCString +=2;
4448 }
4449
4450 for (i = 0; *versionCString != 0x00; versionCString++) {
4451 /* skip whitespace */
4452 if (isWhiteSpace(*versionCString)) {
4453 continue;
4454 }
4455
4456 /* peek ahead for version string separator or null terminator */
4457 if (*(versionCString + 1) == ',' || *(versionCString + 1) == 0x00) {
4458
4459 /* OK, we have a version string */
4460 myBuffer[i++] = *versionCString;
4461 myBuffer[i] = 0x00;
4462
4463 OSKextVersion excludeVers;
4464 excludeVers = OSKextParseVersionString(myBuffer);
4465
4466 if (wantLessThanEqualTo) {
4467 if (version <= excludeVers) {
4468 return(true);
4469 }
4470 }
4471 else if (wantLessThan) {
4472 if (version < excludeVers) {
4473 return(true);
4474 }
4475 }
4476 else if ( version == excludeVers ) {
4477 return(true);
4478 }
4479
4480 /* reset for the next (if any) version string */
4481 i = 0;
4482 wantLessThan = false;
4483 wantLessThanEqualTo = false;
4484 }
4485 else {
4486 /* save valid version character */
4487 myBuffer[i++] = *versionCString;
4488
4489 /* make sure bogus version string doesn't overrun local buffer */
4490 if ( i >= sizeof(myBuffer) ) {
4491 break;
4492 }
4493 }
4494 }
4495
4496 return(false);
4497}
4498
4499/*********************************************************************
4500*********************************************************************/
4501/* static */
4502OSReturn
4503OSKext::loadKextWithIdentifier(
4504 const char * kextIdentifierCString,
4505 Boolean allowDeferFlag,
4506 Boolean delayAutounloadFlag,
4507 OSKextExcludeLevel startOpt,
4508 OSKextExcludeLevel startMatchingOpt,
4509 OSArray * personalityNames)
4510{
4511 OSReturn result = kOSReturnError;
4512 OSString * kextIdentifier = NULL; // must release
4513
4514 kextIdentifier = OSString::withCString(kextIdentifierCString);
4515 if (!kextIdentifier) {
4516 result = kOSKextReturnNoMemory;
4517 goto finish;
4518 }
4519 result = OSKext::loadKextWithIdentifier(kextIdentifier,
4520 allowDeferFlag, delayAutounloadFlag,
4521 startOpt, startMatchingOpt, personalityNames);
4522
4523finish:
4524 OSSafeReleaseNULL(kextIdentifier);
4525 return result;
4526}
4527
4528/*********************************************************************
4529*********************************************************************/
4530OSReturn
4531OSKext::loadKextWithIdentifier(
4532 OSString * kextIdentifier,
4533 Boolean allowDeferFlag,
4534 Boolean delayAutounloadFlag,
4535 OSKextExcludeLevel startOpt,
4536 OSKextExcludeLevel startMatchingOpt,
4537 OSArray * personalityNames)
4538{
4539 OSReturn result = kOSReturnError;
4540 OSReturn pingResult = kOSReturnError;
4541 OSKext * theKext = NULL; // do not release
4542 OSDictionary * loadRequest = NULL; // must release
4543 const OSSymbol * kextIdentifierSymbol = NULL; // must release
4544
4545 IORecursiveLockLock(sKextLock);
4546
4547 if (!kextIdentifier) {
4548 result = kOSKextReturnInvalidArgument;
4549 goto finish;
4550 }
4551
4552 OSKext::recordIdentifierRequest(kextIdentifier);
4553
4554 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
4555 if (!theKext) {
4556 if (!allowDeferFlag) {
4557 OSKextLog(/* kext */ NULL,
4558 kOSKextLogErrorLevel |
4559 kOSKextLogLoadFlag,
4560 "Can't load kext %s - not found.",
4561 kextIdentifier->getCStringNoCopy());
4562 goto finish;
4563 }
4564
4565 if (!sKernelRequestsEnabled) {
4566 OSKextLog(theKext,
4567 kOSKextLogErrorLevel |
4568 kOSKextLogLoadFlag,
4569 "Can't load kext %s - requests to user space are disabled.",
4570 kextIdentifier->getCStringNoCopy());
4571 result = kOSKextReturnDisabled;
4572 goto finish;
4573 }
4574
4575 /* Create a new request unless one is already sitting
4576 * in sKernelRequests for this bundle identifier
4577 */
4578 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
4579 if (!sPostedKextLoadIdentifiers->containsObject(kextIdentifierSymbol)) {
4580 result = _OSKextCreateRequest(kKextRequestPredicateRequestLoad,
4581 &loadRequest);
4582 if (result != kOSReturnSuccess) {
4583 goto finish;
4584 }
4585 if (!_OSKextSetRequestArgument(loadRequest,
4586 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
4587
4588 result = kOSKextReturnNoMemory;
4589 goto finish;
4590 }
4591 if (!sKernelRequests->setObject(loadRequest)) {
4592 result = kOSKextReturnNoMemory;
4593 goto finish;
4594 }
4595
4596 if (!sPostedKextLoadIdentifiers->setObject(kextIdentifierSymbol)) {
4597 result = kOSKextReturnNoMemory;
4598 goto finish;
4599 }
4600
4601 OSKextLog(theKext,
4602 kOSKextLogDebugLevel |
4603 kOSKextLogLoadFlag,
4604 "Kext %s not found; queued load request to user space.",
4605 kextIdentifier->getCStringNoCopy());
4606 }
4607
4608 pingResult = OSKext::pingKextd();
4609 if (pingResult == kOSKextReturnDisabled) {
4610 OSKextLog(/* kext */ NULL,
4611 ((sPrelinkBoot) ? kOSKextLogDebugLevel : kOSKextLogErrorLevel) |
4612 kOSKextLogLoadFlag,
4613 "Kext %s might not load - kextd is currently unavailable.",
4614 kextIdentifier->getCStringNoCopy());
4615 }
4616
4617 result = kOSKextReturnDeferred;
4618 goto finish;
4619 }
4620
4621 result = theKext->load(startOpt, startMatchingOpt, personalityNames);
4622
4623 if (result != kOSReturnSuccess) {
4624 OSKextLog(theKext,
4625 kOSKextLogErrorLevel |
4626 kOSKextLogLoadFlag,
4627 "Failed to load kext %s (error 0x%x).",
4628 kextIdentifier->getCStringNoCopy(), (int)result);
4629
4630 OSKext::removeKext(theKext,
4631 /* terminateService/removePersonalities */ true);
4632 goto finish;
4633 }
4634
4635 if (delayAutounloadFlag) {
4636 OSKextLog(theKext,
4637 kOSKextLogProgressLevel |
4638 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4639 "Setting delayed autounload for %s.",
4640 kextIdentifier->getCStringNoCopy());
4641 theKext->flags.delayAutounload = 1;
4642 }
4643
4644finish:
4645 OSSafeReleaseNULL(loadRequest);
4646 OSSafeReleaseNULL(kextIdentifierSymbol);
4647
4648 IORecursiveLockUnlock(sKextLock);
4649
4650 return result;
4651}
4652
4653/*********************************************************************
4654*********************************************************************/
4655/* static */
4656void
4657OSKext::recordIdentifierRequest(
4658 OSString * kextIdentifier)
4659{
4660 const OSSymbol * kextIdentifierSymbol = NULL; // must release
4661 bool fail = false;
4662
4663 if (!sAllKextLoadIdentifiers || !kextIdentifier) {
4664 goto finish;
4665 }
4666
4667 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
4668 if (!kextIdentifierSymbol) {
4669 // xxx - this is really a basic alloc failure
4670 fail = true;
4671 goto finish;
4672 }
4673
4674 IORecursiveLockLock(sKextLock);
4675 if (!sAllKextLoadIdentifiers->containsObject(kextIdentifierSymbol)) {
4676 if (!sAllKextLoadIdentifiers->setObject(kextIdentifierSymbol)) {
4677 fail = true;
4678 } else {
4679 // xxx - need to find a way to associate this whole func w/the kext
4680 OSKextLog(/* kext */ NULL,
4681 // xxx - check level
4682 kOSKextLogStepLevel |
4683 kOSKextLogArchiveFlag,
4684 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
4685 kextIdentifier->getCStringNoCopy());
4686 }
4687 }
4688 IORecursiveLockUnlock(sKextLock);
4689
4690finish:
4691
4692 if (fail) {
4693 OSKextLog(/* kext */ NULL,
4694 kOSKextLogErrorLevel |
4695 kOSKextLogArchiveFlag,
4696 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
4697 kextIdentifier->getCStringNoCopy());
4698 }
4699 OSSafeReleaseNULL(kextIdentifierSymbol);
4700 return;
4701}
4702
4703/*********************************************************************
4704*********************************************************************/
4705OSReturn
4706OSKext::load(
4707 OSKextExcludeLevel startOpt,
4708 OSKextExcludeLevel startMatchingOpt,
4709 OSArray * personalityNames)
4710{
4711 OSReturn result = kOSReturnError;
4712 kern_return_t kxldResult;
4713 OSKextExcludeLevel dependenciesStartOpt = startOpt;
4714 OSKextExcludeLevel dependenciesStartMatchingOpt = startMatchingOpt;
4715 unsigned int i, count;
4716 Boolean alreadyLoaded = false;
4717 OSKext * lastLoadedKext = NULL;
4718
4719 if (isInExcludeList()) {
4720 OSKextLog(this,
4721 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
4722 kOSKextLogLoadFlag,
4723 "Kext %s is in exclude list, not loadable",
4724 getIdentifierCString());
4725
4726 result = kOSKextReturnNotLoadable;
4727 goto finish;
4728 }
4729
4730 if (isLoaded()) {
4731 alreadyLoaded = true;
4732 result = kOSReturnSuccess;
4733
4734 OSKextLog(this,
4735 kOSKextLogDebugLevel |
4736 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4737 "Kext %s is already loaded.",
4738 getIdentifierCString());
4739 goto loaded;
4740 }
4741
4742#if CONFIG_MACF
4743 if (current_task() != kernel_task) {
4744 int macCheckResult = 0;
4745 kauth_cred_t cred = NULL;
4746
4747 cred = kauth_cred_get_with_ref();
4748 macCheckResult = mac_kext_check_load(cred, getIdentifierCString());
4749 kauth_cred_unref(&cred);
4750
4751 if (macCheckResult != 0) {
4752 result = kOSReturnError;
4753 OSKextLog(this,
4754 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
4755 "Failed to load kext %s (MAC policy error 0x%x).",
4756 getIdentifierCString(), macCheckResult);
4757 goto finish;
4758 }
4759 }
4760#endif
4761
4762 if (!sLoadEnabled) {
4763 OSKextLog(this,
4764 kOSKextLogErrorLevel |
4765 kOSKextLogLoadFlag,
4766 "Kext loading is disabled (attempt to load kext %s).",
4767 getIdentifierCString());
4768 result = kOSKextReturnDisabled;
4769 goto finish;
4770 }
4771
4772 /* If we've pushed the next available load tag to the invalid value,
4773 * we can't load any more kexts.
4774 */
4775 if (sNextLoadTag == kOSKextInvalidLoadTag) {
4776 OSKextLog(this,
4777 kOSKextLogErrorLevel |
4778 kOSKextLogLoadFlag,
4779 "Can't load kext %s - no more load tags to assign.",
4780 getIdentifierCString());
4781 result = kOSKextReturnNoResources;
4782 goto finish;
4783 }
4784
4785 /* This is a bit of a hack, because we shouldn't be handling
4786 * personalities within the load function.
4787 */
4788 if (!declaresExecutable()) {
4789 /* There is a special case where a non-executable kext can be loaded: the
4790 * AppleKextExcludeList. Detect that special kext by bundle identifier and
4791 * load its metadata into the global data structures, if appropriate
4792 */
4793 if (strcmp(getIdentifierCString(), "com.apple.driver.KextExcludeList") == 0) {
4794 boolean_t updated = updateExcludeList(infoDict);
4795 if (updated) {
4796 OSKextLog(this,
4797 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
4798 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
4799 }
4800 }
4801 result = kOSReturnSuccess;
4802 goto loaded;
4803 }
4804
4805 /* Are we in safe boot?
4806 */
4807 if (sSafeBoot && !isLoadableInSafeBoot()) {
4808 OSKextLog(this,
4809 kOSKextLogErrorLevel |
4810 kOSKextLogLoadFlag,
4811 "Can't load kext %s - not loadable during safe boot.",
4812 getIdentifierCString());
4813 result = kOSKextReturnBootLevel;
4814 goto finish;
4815 }
4816
4817 OSKextLog(this,
4818 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
4819 "Loading kext %s.",
4820 getIdentifierCString());
4821
4822 if (!sKxldContext) {
4823 kxldResult = kxld_create_context(&sKxldContext, &kern_allocate,
4824 &kxld_log_callback, /* Flags */ (KXLDFlags) 0,
4825 /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
4826 if (kxldResult) {
4827 OSKextLog(this,
4828 kOSKextLogErrorLevel |
4829 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
4830 "Can't load kext %s - failed to create link context.",
4831 getIdentifierCString());
4832 result = kOSKextReturnNoMemory;
4833 goto finish;
4834 }
4835 }
4836
4837 /* We only need to resolve dependencies once for the whole graph, but
4838 * resolveDependencies will just return if there's no work to do, so it's
4839 * safe to call it more than once.
4840 */
4841 if (!resolveDependencies()) {
4842 // xxx - check resolveDependencies() for log msg
4843 OSKextLog(this,
4844 kOSKextLogErrorLevel |
4845 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4846 "Can't load kext %s - failed to resolve library dependencies.",
4847 getIdentifierCString());
4848 result = kOSKextReturnDependencies;
4849 goto finish;
4850 }
4851
4852 /* If we are excluding just the kext being loaded now (and not its
4853 * dependencies), drop the exclusion level to none so dependencies
4854 * start and/or add their personalities.
4855 */
4856 if (dependenciesStartOpt == kOSKextExcludeKext) {
4857 dependenciesStartOpt = kOSKextExcludeNone;
4858 }
4859
4860 if (dependenciesStartMatchingOpt == kOSKextExcludeKext) {
4861 dependenciesStartMatchingOpt = kOSKextExcludeNone;
4862 }
4863
4864 /* Load the dependencies, recursively.
4865 */
4866 count = getNumDependencies();
4867 for (i = 0; i < count; i++) {
4868 OSKext * dependency = OSDynamicCast(OSKext,
4869 dependencies->getObject(i));
4870 if (dependency == NULL) {
4871 OSKextLog(this,
4872 kOSKextLogErrorLevel |
4873 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4874 "Internal error loading kext %s; dependency disappeared.",
4875 getIdentifierCString());
4876 result = kOSKextReturnInternalError;
4877 goto finish;
4878 }
4879
4880 /* Dependencies must be started accorting to the opt,
4881 * but not given the personality names of the main kext.
4882 */
4883 result = dependency->load(dependenciesStartOpt,
4884 dependenciesStartMatchingOpt,
4885 /* personalityNames */ NULL);
4886 if (result != KERN_SUCCESS) {
4887 OSKextLog(this,
4888 kOSKextLogErrorLevel |
4889 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4890 "Dependency %s of kext %s failed to load.",
4891 dependency->getIdentifierCString(),
4892 getIdentifierCString());
4893
4894 OSKext::removeKext(dependency,
4895 /* terminateService/removePersonalities */ true);
4896 result = kOSKextReturnDependencyLoadError;
4897
4898 goto finish;
4899 }
4900 }
4901
4902 result = loadExecutable();
4903 if (result != KERN_SUCCESS) {
4904 goto finish;
4905 }
4906
4907 pendingPgoHead.next = &pendingPgoHead;
4908 pendingPgoHead.prev = &pendingPgoHead;
4909
4910 // The kernel PRNG is not initialized when the first kext is
4911 // loaded, so use early random
4912 uuid_generate_early_random(instance_uuid);
4913 account = IONew(OSKextAccount, 1);
4914 if (!account) {
4915 result = KERN_MEMORY_ERROR;
4916 goto finish;
4917 }
4918 bzero(account, sizeof(*account));
4919 account->loadTag = kmod_info->id;
4920 account->site.refcount = 0;
4921 account->site.flags = VM_TAG_KMOD;
4922 account->kext = this;
4923 if (gIOSurfaceIdentifier == bundleID) {
4924 vm_tag_alloc(&account->site);
4925 gIOSurfaceTag = account->site.tag;
4926 }
4927
4928 flags.loaded = true;
4929
4930 /* Add the kext to the list of loaded kexts and update the kmod_info
4931 * struct to point to that of the last loaded kext (which is the way
4932 * it's always been done, though I'd rather do them in order now).
4933 */
4934 lastLoadedKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
4935 sLoadedKexts->setObject(this);
4936
4937 /* Keep the kernel itself out of the kmod list.
4938 */
4939 if (lastLoadedKext->isKernel()) {
4940 lastLoadedKext = NULL;
4941 }
4942
4943 if (lastLoadedKext) {
4944 kmod_info->next = lastLoadedKext->kmod_info;
4945 }
4946
4947 notifyKextLoadObservers(this, kmod_info);
4948
4949 /* Make the global kmod list point at the just-loaded kext. Note that the
4950 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
4951 * although we do report it in kextstat these days by using the newer
4952 * OSArray of loaded kexts, which does contain it.
4953 *
4954 * (The OSKext object representing the kernel doesn't even have a kmod_info
4955 * struct, though I suppose we could stick a pointer to it from the
4956 * static struct in OSRuntime.cpp.)
4957 */
4958 kmod = kmod_info;
4959
4960 /* Save the list of loaded kexts in case we panic.
4961 */
4962 OSKext::saveLoadedKextPanicList();
4963
4964 if (isExecutable()) {
4965 OSKext::updateLoadedKextSummaries();
4966 savePanicString(/* isLoading */ true);
4967
4968#if CONFIG_DTRACE
4969 registerWithDTrace();
4970#else
4971 jettisonLinkeditSegment();
4972#endif /* CONFIG_DTRACE */
4973
4974#if !VM_MAPPED_KEXTS
4975 /* If there is a page (or more) worth of padding after the end
4976 * of the last data section but before the end of the data segment
4977 * then free it in the same manner the LinkeditSegment is freed
4978 */
4979 jettisonDATASegmentPadding();
4980#endif
4981 }
4982
4983loaded:
4984 if (isExecutable() && !flags.started) {
4985 if (startOpt == kOSKextExcludeNone) {
4986 result = start();
4987 if (result != kOSReturnSuccess) {
4988 OSKextLog(this,
4989 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
4990 "Kext %s start failed (result 0x%x).",
4991 getIdentifierCString(), result);
4992 result = kOSKextReturnStartStopError;
4993 }
4994 }
4995 }
4996
4997 /* If not excluding matching, send the personalities to the kernel.
4998 * This never affects the result of the load operation.
4999 * This is a bit of a hack, because we shouldn't be handling
5000 * personalities within the load function.
5001 */
5002 if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
5003 result = sendPersonalitiesToCatalog(true, personalityNames);
5004 }
5005
5006finish:
5007
5008 /* More hack! If the kext doesn't declare an executable, even if we
5009 * "loaded" it, we have to remove any personalities naming it, or we'll
5010 * never see the registry go quiet. Errors here do not count for the
5011 * load operation itself.
5012 *
5013 * Note that in every other regard it's perfectly ok for a kext to
5014 * not declare an executable and serve only as a package for personalities
5015 * naming another kext, so we do have to allow such kexts to be "loaded"
5016 * so that those other personalities get added & matched.
5017 */
5018 if (!declaresExecutable()) {
5019 OSKextLog(this,
5020 kOSKextLogStepLevel | kOSKextLogLoadFlag,
5021 "Kext %s has no executable; removing any personalities naming it.",
5022 getIdentifierCString());
5023 removePersonalitiesFromCatalog();
5024 }
5025
5026 if (result != kOSReturnSuccess) {
5027 OSKextLog(this,
5028 kOSKextLogErrorLevel |
5029 kOSKextLogLoadFlag,
5030 "Kext %s failed to load (0x%x).",
5031 getIdentifierCString(), (int)result);
5032 } else if (!alreadyLoaded) {
5033 OSKextLog(this,
5034 kOSKextLogProgressLevel |
5035 kOSKextLogLoadFlag,
5036 "Kext %s loaded.",
5037 getIdentifierCString());
5038
5039 queueKextNotification(kKextRequestPredicateLoadNotification,
5040 OSDynamicCast(OSString, bundleID));
5041 }
5042 return result;
5043}
5044
5045/*********************************************************************
5046*
5047*********************************************************************/
5048static char * strdup(const char * string)
5049{
5050 char * result = NULL;
5051 size_t size;
5052
5053 if (!string) {
5054 goto finish;
5055 }
5056
5057 size = 1 + strlen(string);
5058 result = (char *)kalloc_tag(size, VM_KERN_MEMORY_OSKEXT);
5059 if (!result) {
5060 goto finish;
5061 }
5062
5063 memcpy(result, string, size);
5064
5065finish:
5066 return result;
5067}
5068
5069/*********************************************************************
5070*
5071*********************************************************************/
5072
5073kernel_section_t *
5074OSKext::lookupSection(const char *segname, const char *secname)
5075{
5076 kernel_section_t * found_section = NULL;
5077 kernel_mach_header_t * mh = NULL;
5078 kernel_segment_command_t * seg = NULL;
5079 kernel_section_t * sec = NULL;
5080
5081 if (!linkedExecutable) return (NULL);
5082
5083 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
5084
5085 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
5086
5087 if (0 != strcmp(seg->segname, segname)) {
5088 continue;
5089 }
5090
5091 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
5092
5093 if (0 == strcmp(sec->sectname, secname)) {
5094 found_section = sec;
5095 goto out;
5096 }
5097 }
5098 }
5099
5100 out:
5101 return found_section;
5102}
5103
5104/*********************************************************************
5105*
5106*********************************************************************/
5107
5108OSReturn
5109OSKext::slidePrelinkedExecutable(bool doCoalesedSlides)
5110{
5111 OSReturn result = kOSKextReturnBadData;
5112 kernel_mach_header_t * mh = NULL;
5113 kernel_segment_command_t * seg = NULL;
5114 kernel_segment_command_t * linkeditSeg = NULL;
5115 kernel_section_t * sec = NULL;
5116 char * linkeditBase = NULL;
5117 bool haveLinkeditBase = false;
5118 char * relocBase = NULL;
5119 bool haveRelocBase = false;
5120 struct dysymtab_command * dysymtab = NULL;
5121 struct linkedit_data_command * segmentSplitInfo = NULL;
5122 struct symtab_command * symtab = NULL;
5123 kernel_nlist_t * sym = NULL;
5124 struct relocation_info * reloc = NULL;
5125 uint32_t i = 0;
5126 int reloc_size;
5127 vm_offset_t new_kextsize;
5128
5129 if (linkedExecutable == NULL || flags.builtin) {
5130 result = kOSReturnSuccess;
5131 goto finish;
5132 }
5133
5134 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
5135 segmentSplitInfo = (struct linkedit_data_command *) getcommandfromheader(mh, LC_SEGMENT_SPLIT_INFO);
5136
5137 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
5138 if (!seg->vmaddr) {
5139 continue;
5140 }
5141
5142 seg->vmaddr = ml_static_slide(seg->vmaddr);
5143
5144#if KASLR_KEXT_DEBUG
5145 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
5146 seg->segname,
5147 (unsigned long)ml_static_unslide(seg->vmaddr),
5148 (unsigned long)seg->vmaddr);
5149#endif
5150
5151 if (!haveRelocBase) {
5152 relocBase = (char *) seg->vmaddr;
5153 haveRelocBase = true;
5154 }
5155 if (!strcmp(seg->segname, "__LINKEDIT")) {
5156 linkeditBase = (char *) seg->vmaddr - seg->fileoff;
5157 haveLinkeditBase = true;
5158 linkeditSeg = seg;
5159 }
5160 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
5161 sec->addr = ml_static_slide(sec->addr);
5162
5163#if KASLR_KEXT_DEBUG
5164 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
5165 sec->sectname,
5166 (unsigned long)ml_static_unslide(sec->addr),
5167 (unsigned long)sec->addr);
5168#endif
5169 }
5170 }
5171
5172 dysymtab = (struct dysymtab_command *) getcommandfromheader(mh, LC_DYSYMTAB);
5173
5174 symtab = (struct symtab_command *) getcommandfromheader(mh, LC_SYMTAB);
5175
5176 if (symtab != NULL && doCoalesedSlides == false) {
5177 /* Some pseudo-kexts have symbol tables without segments.
5178 * Ignore them. */
5179 if (symtab->nsyms > 0 && haveLinkeditBase) {
5180 sym = (kernel_nlist_t *) (linkeditBase + symtab->symoff);
5181 for (i = 0; i < symtab->nsyms; i++) {
5182 if (sym[i].n_type & N_STAB) {
5183 continue;
5184 }
5185 sym[i].n_value = ml_static_slide(sym[i].n_value);
5186
5187#if KASLR_KEXT_DEBUG
5188#define MAX_SYMS_TO_LOG 5
5189 if ( i < MAX_SYMS_TO_LOG ) {
5190 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
5191 (unsigned long)ml_static_unslide(sym[i].n_value),
5192 (unsigned long)sym[i].n_value);
5193 }
5194#endif
5195 }
5196 }
5197 }
5198
5199 if (dysymtab != NULL && doCoalesedSlides == false) {
5200 if (dysymtab->nextrel > 0) {
5201 OSKextLog(this,
5202 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
5203 kOSKextLogLinkFlag,
5204 "Sliding kext %s: External relocations found.",
5205 getIdentifierCString());
5206 goto finish;
5207 }
5208
5209 if (dysymtab->nlocrel > 0) {
5210 if (!haveLinkeditBase) {
5211 OSKextLog(this,
5212 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
5213 kOSKextLogLinkFlag,
5214 "Sliding kext %s: No linkedit segment.",
5215 getIdentifierCString());
5216 goto finish;
5217 }
5218
5219 if (!haveRelocBase) {
5220 OSKextLog(this,
5221 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
5222 kOSKextLogLinkFlag,
5223#if __x86_64__
5224 "Sliding kext %s: No writable segments.",
5225#else
5226 "Sliding kext %s: No segments.",
5227#endif
5228 getIdentifierCString());
5229 goto finish;
5230 }
5231
5232 reloc = (struct relocation_info *) (linkeditBase + dysymtab->locreloff);
5233 reloc_size = dysymtab->nlocrel * sizeof(struct relocation_info);
5234
5235 for (i = 0; i < dysymtab->nlocrel; i++) {
5236 if ( reloc[i].r_extern != 0
5237 || reloc[i].r_type != 0
5238 || reloc[i].r_length != (sizeof(void *) == 8 ? 3 : 2)
5239 ) {
5240 OSKextLog(this,
5241 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
5242 kOSKextLogLinkFlag,
5243 "Sliding kext %s: Unexpected relocation found.",
5244 getIdentifierCString());
5245 goto finish;
5246 }
5247 if (reloc[i].r_pcrel != 0) {
5248 continue;
5249 }
5250 uintptr_t *relocAddr = (uintptr_t*)(relocBase + reloc[i].r_address);
5251 *relocAddr = ml_static_slide(*relocAddr);
5252
5253#if KASLR_KEXT_DEBUG
5254#define MAX_DYSYMS_TO_LOG 5
5255 if ( i < MAX_DYSYMS_TO_LOG ) {
5256 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
5257 (unsigned long)ml_static_unslide(*((uintptr_t *)(relocAddr))),
5258 (unsigned long)*((uintptr_t *)(relocBase + reloc[i].r_address)));
5259 }
5260#endif
5261 }
5262
5263 /* We should free these relocations, not just delete the reference to them.
5264 * <rdar://problem/10535549> Free relocations from PIE kexts.
5265 *
5266 * For now, we do not free LINKEDIT for kexts with split segments.
5267 */
5268 new_kextsize = round_page(kmod_info->size - reloc_size);
5269 if (((kmod_info->size - new_kextsize) > PAGE_SIZE) && (!segmentSplitInfo)) {
5270 vm_offset_t endofkext = kmod_info->address + kmod_info->size;
5271 vm_offset_t new_endofkext = kmod_info->address + new_kextsize;
5272 vm_offset_t endofrelocInfo = (vm_offset_t) (((uint8_t *)reloc) + reloc_size);
5273 int bytes_remaining = endofkext - endofrelocInfo;
5274 OSData * new_osdata = NULL;
5275
5276 /* fix up symbol offsets if they are after the dsymtab local relocs */
5277 if (symtab) {
5278 if (dysymtab->locreloff < symtab->symoff){
5279 symtab->symoff -= reloc_size;
5280 }
5281 if (dysymtab->locreloff < symtab->stroff) {
5282 symtab->stroff -= reloc_size;
5283 }
5284 }
5285 if (dysymtab->locreloff < dysymtab->extreloff) {
5286 dysymtab->extreloff -= reloc_size;
5287 }
5288
5289 /* move data behind reloc info down to new offset */
5290 if (endofrelocInfo < endofkext) {
5291 memcpy(reloc, (void *)endofrelocInfo, bytes_remaining);
5292 }
5293
5294 /* Create a new OSData for the smaller kext object and reflect
5295 * new linkedit segment size.
5296 */
5297 linkeditSeg->vmsize = round_page(linkeditSeg->vmsize - reloc_size);
5298 linkeditSeg->filesize = linkeditSeg->vmsize;
5299
5300 new_osdata = OSData::withBytesNoCopy((void *)kmod_info->address, new_kextsize);
5301 if (new_osdata) {
5302 /* Fix up kmod info and linkedExecutable.
5303 */
5304 kmod_info->size = new_kextsize;
5305#if VM_MAPPED_KEXTS
5306 new_osdata->setDeallocFunction(osdata_kext_free);
5307#else
5308 new_osdata->setDeallocFunction(osdata_phys_free);
5309#endif
5310 linkedExecutable->setDeallocFunction(NULL);
5311 linkedExecutable->release();
5312 linkedExecutable = new_osdata;
5313
5314#if VM_MAPPED_KEXTS
5315 kext_free(new_endofkext, (endofkext - new_endofkext));
5316#else
5317 ml_static_mfree(new_endofkext, (endofkext - new_endofkext));
5318#endif
5319 }
5320 }
5321 dysymtab->nlocrel = 0;
5322 dysymtab->locreloff = 0;
5323 }
5324 }
5325
5326 result = kOSReturnSuccess;
5327finish:
5328 return result;
5329}
5330
5331/*********************************************************************
5332* called only by load()
5333*********************************************************************/
5334OSReturn
5335OSKext::loadExecutable()
5336{
5337 OSReturn result = kOSReturnError;
5338 kern_return_t kxldResult;
5339 KXLDDependency * kxlddeps = NULL; // must kfree
5340 uint32_t num_kxlddeps = 0;
5341 OSArray * linkDependencies = NULL; // must release
5342 uint32_t numDirectDependencies = 0;
5343 uint32_t num_kmod_refs = 0;
5344 struct mach_header ** kxldHeaderPtr = NULL; // do not free
5345 struct mach_header * kxld_header = NULL; // xxx - need to free here?
5346 OSData * theExecutable = NULL; // do not release
5347 OSString * versString = NULL; // do not release
5348 const char * versCString = NULL; // do not free
5349 const char * string = NULL; // do not free
5350 unsigned int i;
5351
5352 /* We need the version string for a variety of bits below.
5353 */
5354 versString = OSDynamicCast(OSString,
5355 getPropertyForHostArch(kCFBundleVersionKey));
5356 if (!versString) {
5357 goto finish;
5358 }
5359 versCString = versString->getCStringNoCopy();
5360
5361 if (isKernelComponent()) {
5362 if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
5363
5364 if (strncmp(versCString, KERNEL6_VERSION, strlen(KERNEL6_VERSION))) {
5365 OSKextLog(this,
5366 kOSKextLogErrorLevel |
5367 kOSKextLogLoadFlag,
5368 "Kernel component %s has incorrect version %s; "
5369 "expected %s.",
5370 getIdentifierCString(),
5371 versCString, KERNEL6_VERSION);
5372 result = kOSKextReturnInternalError;
5373 goto finish;
5374 } else if (strcmp(versCString, osrelease)) {
5375 OSKextLog(this,
5376 kOSKextLogErrorLevel |
5377 kOSKextLogLoadFlag,
5378 "Kernel component %s has incorrect version %s; "
5379 "expected %s.",
5380 getIdentifierCString(),
5381 versCString, osrelease);
5382 result = kOSKextReturnInternalError;
5383 goto finish;
5384 }
5385 }
5386 }
5387
5388 if (isPrelinked()) {
5389 goto register_kmod;
5390 }
5391
5392 /* <rdar://problem/21444003> all callers must be entitled */
5393 if (FALSE == IOTaskHasEntitlement(current_task(), "com.apple.rootless.kext-secure-management")) {
5394 OSKextLog(this,
5395 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5396 "Not entitled to link kext '%s'",
5397 getIdentifierCString());
5398 result = kOSKextReturnNotPrivileged;
5399 goto finish;
5400 }
5401
5402 theExecutable = getExecutable();
5403 if (!theExecutable) {
5404 if (declaresExecutable()) {
5405 OSKextLog(this,
5406 kOSKextLogErrorLevel |
5407 kOSKextLogLoadFlag,
5408 "Can't load kext %s - executable is missing.",
5409 getIdentifierCString());
5410 result = kOSKextReturnValidation;
5411 goto finish;
5412 }
5413 goto register_kmod;
5414 }
5415
5416 if (isInterface()) {
5417 OSData *executableCopy = OSData::withData(theExecutable);
5418 setLinkedExecutable(executableCopy);
5419 executableCopy->release();
5420 goto register_kmod;
5421 }
5422
5423 numDirectDependencies = getNumDependencies();
5424
5425 if (flags.hasBleedthrough) {
5426 linkDependencies = dependencies;
5427 linkDependencies->retain();
5428 } else {
5429 linkDependencies = OSArray::withArray(dependencies);
5430 if (!linkDependencies) {
5431 OSKextLog(this,
5432 kOSKextLogErrorLevel |
5433 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
5434 "Can't allocate link dependencies to load kext %s.",
5435 getIdentifierCString());
5436 goto finish;
5437 }
5438
5439 for (i = 0; i < numDirectDependencies; ++i) {
5440 OSKext * dependencyKext = OSDynamicCast(OSKext,
5441 dependencies->getObject(i));
5442 dependencyKext->addBleedthroughDependencies(linkDependencies);
5443 }
5444 }
5445
5446 num_kxlddeps = linkDependencies->getCount();
5447 if (!num_kxlddeps) {
5448 OSKextLog(this,
5449 kOSKextLogErrorLevel |
5450 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5451 "Can't load kext %s - it has no library dependencies.",
5452 getIdentifierCString());
5453 goto finish;
5454 }
5455
5456 kxlddeps = (KXLDDependency *)kalloc_tag(num_kxlddeps * sizeof(*kxlddeps), VM_KERN_MEMORY_OSKEXT);
5457 if (!kxlddeps) {
5458 OSKextLog(this,
5459 kOSKextLogErrorLevel |
5460 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
5461 "Can't allocate link context to load kext %s.",
5462 getIdentifierCString());
5463 goto finish;
5464 }
5465 bzero(kxlddeps, num_kxlddeps * sizeof(*kxlddeps));
5466
5467 for (i = 0; i < num_kxlddeps; ++i ) {
5468 OSKext * dependency = OSDynamicCast(OSKext, linkDependencies->getObject(i));
5469
5470 if (dependency->isInterface()) {
5471 OSKext *interfaceTargetKext = NULL;
5472 OSData * interfaceTarget = NULL;
5473
5474 if (dependency->isKernelComponent()) {
5475 interfaceTargetKext = sKernelKext;
5476 interfaceTarget = sKernelKext->linkedExecutable;
5477 } else {
5478 interfaceTargetKext = OSDynamicCast(OSKext,
5479 dependency->dependencies->getObject(0));
5480
5481 interfaceTarget = interfaceTargetKext->linkedExecutable;
5482 }
5483
5484 if (!interfaceTarget) {
5485 // panic?
5486 goto finish;
5487 }
5488
5489 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
5490 * it will be useful to have them in the debugger.
5491 * strdup() failing isn't critical right here so we don't check that.
5492 */
5493 kxlddeps[i].kext = (u_char *) interfaceTarget->getBytesNoCopy();
5494 kxlddeps[i].kext_size = interfaceTarget->getLength();
5495 kxlddeps[i].kext_name = strdup(interfaceTargetKext->getIdentifierCString());
5496
5497 kxlddeps[i].interface = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
5498 kxlddeps[i].interface_size = dependency->linkedExecutable->getLength();
5499 kxlddeps[i].interface_name = strdup(dependency->getIdentifierCString());
5500 } else {
5501 kxlddeps[i].kext = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
5502 kxlddeps[i].kext_size = dependency->linkedExecutable->getLength();
5503 kxlddeps[i].kext_name = strdup(dependency->getIdentifierCString());
5504 }
5505
5506 kxlddeps[i].is_direct_dependency = (i < numDirectDependencies);
5507 }
5508
5509 kxldHeaderPtr = &kxld_header;
5510
5511#if DEBUG
5512 OSKextLog(this,
5513 kOSKextLogExplicitLevel |
5514 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
5515 "Kext %s - calling kxld_link_file:\n"
5516 " kxld_context: %p\n"
5517 " executable: %p executable_length: %d\n"
5518 " user_data: %p\n"
5519 " kxld_dependencies: %p num_dependencies: %d\n"
5520 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
5521 getIdentifierCString(), sKxldContext,
5522 theExecutable->getBytesNoCopy(), theExecutable->getLength(),
5523 this, kxlddeps, num_kxlddeps,
5524 kxldHeaderPtr, &kmod_info);
5525#endif
5526
5527 /* After this call, the linkedExecutable instance variable
5528 * should exist.
5529 */
5530 kxldResult = kxld_link_file(sKxldContext,
5531 (u_char *)theExecutable->getBytesNoCopy(),
5532 theExecutable->getLength(),
5533 getIdentifierCString(), this, kxlddeps, num_kxlddeps,
5534 (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info);
5535
5536 if (kxldResult != KERN_SUCCESS) {
5537 // xxx - add kxldResult here?
5538 OSKextLog(this,
5539 kOSKextLogErrorLevel |
5540 kOSKextLogLoadFlag,
5541 "Can't load kext %s - link failed.",
5542 getIdentifierCString());
5543 result = kOSKextReturnLinkError;
5544 goto finish;
5545 }
5546
5547 /* We've written data & instructions into kernel memory, so flush the data
5548 * cache and invalidate the instruction cache.
5549 * I/D caches are coherent on x86
5550 */
5551#if !defined(__i386__) && !defined(__x86_64__)
5552 flush_dcache(kmod_info->address, kmod_info->size, false);
5553 invalidate_icache(kmod_info->address, kmod_info->size, false);
5554#endif
5555register_kmod:
5556
5557 if (isInterface()) {
5558
5559 /* Whip up a fake kmod_info entry for the interface kext.
5560 */
5561 kmod_info = (kmod_info_t *)kalloc_tag(sizeof(kmod_info_t), VM_KERN_MEMORY_OSKEXT);
5562 if (!kmod_info) {
5563 result = KERN_MEMORY_ERROR;
5564 goto finish;
5565 }
5566
5567 /* A pseudokext has almost nothing in its kmod_info struct.
5568 */
5569 bzero(kmod_info, sizeof(kmod_info_t));
5570
5571 kmod_info->info_version = KMOD_INFO_VERSION;
5572
5573 /* An interface kext doesn't have a linkedExecutable, so save a
5574 * copy of the UUID out of the original executable via copyUUID()
5575 * while we still have the original executable.
5576 */
5577 interfaceUUID = copyUUID();
5578 }
5579
5580 kmod_info->id = loadTag = sNextLoadTag++;
5581 kmod_info->reference_count = 0; // KMOD_DECL... sets it to -1 (invalid).
5582
5583 /* Stamp the bundle ID and version from the OSKext over anything
5584 * resident inside the kmod_info.
5585 */
5586 string = getIdentifierCString();
5587 strlcpy(kmod_info->name, string, sizeof(kmod_info->name));
5588
5589 string = versCString;
5590 strlcpy(kmod_info->version, string, sizeof(kmod_info->version));
5591
5592 /* Add the dependencies' kmod_info structs as kmod_references.
5593 */
5594 num_kmod_refs = getNumDependencies();
5595 if (num_kmod_refs) {
5596 kmod_info->reference_list = (kmod_reference_t *)kalloc_tag(
5597 num_kmod_refs * sizeof(kmod_reference_t), VM_KERN_MEMORY_OSKEXT);
5598 if (!kmod_info->reference_list) {
5599 result = KERN_MEMORY_ERROR;
5600 goto finish;
5601 }
5602 bzero(kmod_info->reference_list,
5603 num_kmod_refs * sizeof(kmod_reference_t));
5604 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
5605 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
5606 OSKext * refKext = OSDynamicCast(OSKext, dependencies->getObject(refIndex));
5607 ref->info = refKext->kmod_info;
5608 ref->info->reference_count++;
5609
5610 if (refIndex + 1 < num_kmod_refs) {
5611 ref->next = kmod_info->reference_list + refIndex + 1;
5612 }
5613 }
5614 }
5615
5616 if (!isInterface() && linkedExecutable) {
5617 OSKextLog(this,
5618 kOSKextLogProgressLevel |
5619 kOSKextLogLoadFlag,
5620 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
5621 kmod_info->name,
5622 (unsigned)kmod_info->size / PAGE_SIZE,
5623 (unsigned long)ml_static_unslide(kmod_info->address),
5624 (unsigned)kmod_info->id);
5625 }
5626
5627 /* if prelinked, VM protections are already set */
5628 result = setVMAttributes(!isPrelinked(), true);
5629 if (result != KERN_SUCCESS) {
5630 goto finish;
5631 }
5632
5633#if KASAN
5634 if (linkedExecutable) {
5635 kasan_load_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(),
5636 linkedExecutable->getLength(), getIdentifierCString());
5637 }
5638#else
5639 if (lookupSection(KASAN_GLOBAL_SEGNAME, KASAN_GLOBAL_SECTNAME)) {
5640 OSKextLog(this,
5641 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5642 "KASAN: cannot load KASAN-ified kext %s on a non-KASAN kernel\n",
5643 getIdentifierCString()
5644 );
5645 result = KERN_FAILURE;
5646 goto finish;
5647 }
5648#endif
5649
5650 result = kOSReturnSuccess;
5651
5652finish:
5653 OSSafeReleaseNULL(linkDependencies);
5654
5655 /* Clear up locally allocated dependency info.
5656 */
5657 for (i = 0; i < num_kxlddeps; ++i ) {
5658 size_t size;
5659
5660 if (kxlddeps[i].kext_name) {
5661 size = 1 + strlen(kxlddeps[i].kext_name);
5662 kfree(kxlddeps[i].kext_name, size);
5663 }
5664 if (kxlddeps[i].interface_name) {
5665 size = 1 + strlen(kxlddeps[i].interface_name);
5666 kfree(kxlddeps[i].interface_name, size);
5667 }
5668 }
5669 if (kxlddeps) kfree(kxlddeps, (num_kxlddeps * sizeof(*kxlddeps)));
5670
5671 /* We no longer need the unrelocated executable (which the linker
5672 * has altered anyhow).
5673 */
5674 setExecutable(NULL);
5675
5676 if (result != kOSReturnSuccess) {
5677 OSKextLog(this,
5678 kOSKextLogErrorLevel |
5679 kOSKextLogLoadFlag,
5680 "Failed to load executable for kext %s.",
5681 getIdentifierCString());
5682
5683 if (kmod_info && kmod_info->reference_list) {
5684 kfree(kmod_info->reference_list,
5685 num_kmod_refs * sizeof(kmod_reference_t));
5686 }
5687 if (isInterface()) {
5688 kfree(kmod_info, sizeof(kmod_info_t));
5689 }
5690 kmod_info = NULL;
5691 if (linkedExecutable) {
5692 linkedExecutable->release();
5693 linkedExecutable = NULL;
5694 }
5695 }
5696
5697 return result;
5698}
5699
5700/*********************************************************************
5701* The linkedit segment is used by the kext linker for dependency
5702* resolution, and by dtrace for probe initialization. We can free it
5703* for non-library kexts, since no kexts depend on non-library kexts
5704* by definition, once dtrace has been initialized.
5705*********************************************************************/
5706void
5707OSKext::jettisonLinkeditSegment(void)
5708{
5709 kernel_mach_header_t * machhdr = (kernel_mach_header_t *)kmod_info->address;
5710 kernel_segment_command_t * linkedit = NULL;
5711 vm_offset_t start;
5712 vm_size_t linkeditsize, kextsize;
5713 OSData * data = NULL;
5714
5715#if NO_KEXTD
5716 /* We can free symbol tables for all embedded kexts because we don't
5717 * support runtime kext linking.
5718 */
5719 if (sKeepSymbols || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
5720#else
5721 if (sKeepSymbols || isLibrary() || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
5722#endif
5723 goto finish;
5724 }
5725
5726 /* Find the linkedit segment. If it's not the last segment, then freeing
5727 * it will fragment the kext into multiple VM regions, which OSKext is not
5728 * designed to handle, so we'll have to skip it.
5729 */
5730 linkedit = getsegbynamefromheader(machhdr, SEG_LINKEDIT);
5731 if (!linkedit) {
5732 goto finish;
5733 }
5734
5735 if (round_page(kmod_info->address + kmod_info->size) !=
5736 round_page(linkedit->vmaddr + linkedit->vmsize))
5737 {
5738 goto finish;
5739 }
5740
5741 /* Create a new OSData for the smaller kext object.
5742 */
5743 linkeditsize = round_page(linkedit->vmsize);
5744 kextsize = kmod_info->size - linkeditsize;
5745 start = linkedit->vmaddr;
5746
5747 data = OSData::withBytesNoCopy((void *)kmod_info->address, kextsize);
5748 if (!data) {
5749 goto finish;
5750 }
5751
5752 /* Fix the kmod info and linkedExecutable.
5753 */
5754 kmod_info->size = kextsize;
5755
5756#if VM_MAPPED_KEXTS
5757 data->setDeallocFunction(osdata_kext_free);
5758#else
5759 data->setDeallocFunction(osdata_phys_free);
5760#endif
5761 linkedExecutable->setDeallocFunction(NULL);
5762 linkedExecutable->release();
5763 linkedExecutable = data;
5764 flags.jettisonLinkeditSeg = 1;
5765
5766 /* Free the linkedit segment.
5767 */
5768#if VM_MAPPED_KEXTS
5769 kext_free(start, linkeditsize);
5770#else
5771 ml_static_mfree(start, linkeditsize);
5772#endif
5773
5774finish:
5775 return;
5776}
5777
5778/*********************************************************************
5779* If there are whole pages that are unused betweem the last section
5780* of the DATA segment and the end of the DATA segment then we can free
5781* them
5782*********************************************************************/
5783void
5784OSKext::jettisonDATASegmentPadding(void)
5785{
5786 kernel_mach_header_t * mh;
5787 kernel_segment_command_t * dataSeg;
5788 kernel_section_t * sec, * lastSec;
5789 vm_offset_t dataSegEnd, lastSecEnd;
5790 vm_size_t padSize;
5791
5792 if (flags.builtin) return;
5793 mh = (kernel_mach_header_t *)kmod_info->address;
5794
5795 dataSeg = getsegbynamefromheader(mh, SEG_DATA);
5796 if (dataSeg == NULL) {
5797 return;
5798 }
5799
5800 lastSec = NULL;
5801 sec = firstsect(dataSeg);
5802 while (sec != NULL) {
5803 lastSec = sec;
5804 sec = nextsect(dataSeg, sec);
5805 }
5806
5807 if (lastSec == NULL) {
5808 return;
5809 }
5810
5811 if ((dataSeg->vmaddr != round_page(dataSeg->vmaddr)) ||
5812 (dataSeg->vmsize != round_page(dataSeg->vmsize))) {
5813 return;
5814 }
5815
5816 dataSegEnd = dataSeg->vmaddr + dataSeg->vmsize;
5817 lastSecEnd = round_page(lastSec->addr + lastSec->size);
5818
5819 if (dataSegEnd <= lastSecEnd) {
5820 return;
5821 }
5822
5823 padSize = dataSegEnd - lastSecEnd;
5824
5825 if (padSize >= PAGE_SIZE) {
5826#if VM_MAPPED_KEXTS
5827 kext_free(lastSecEnd, padSize);
5828#else
5829 ml_static_mfree(lastSecEnd, padSize);
5830#endif
5831 }
5832}
5833
5834/*********************************************************************
5835*********************************************************************/
5836void
5837OSKext::setLinkedExecutable(OSData * anExecutable)
5838{
5839 if (linkedExecutable) {
5840 panic("Attempt to set linked executable on kext "
5841 "that already has one (%s).\n",
5842 getIdentifierCString());
5843 }
5844 linkedExecutable = anExecutable;
5845 linkedExecutable->retain();
5846 return;
5847}
5848
5849#if CONFIG_DTRACE
5850/*********************************************************************
5851* Go through all loaded kexts and tell them to register with dtrace.
5852* The instance method only registers if necessary.
5853*********************************************************************/
5854/* static */
5855void
5856OSKext::registerKextsWithDTrace(void)
5857{
5858 uint32_t count = sLoadedKexts->getCount();
5859 uint32_t i;
5860
5861 IORecursiveLockLock(sKextLock);
5862
5863 for (i = 0; i < count; i++) {
5864 OSKext * thisKext = NULL; // do not release
5865
5866 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
5867 if (!thisKext || !thisKext->isExecutable()) {
5868 continue;
5869 }
5870
5871 thisKext->registerWithDTrace();
5872 }
5873
5874 IORecursiveLockUnlock(sKextLock);
5875
5876 return;
5877}
5878
5879extern "C" {
5880 extern int (*dtrace_modload)(struct kmod_info *, uint32_t);
5881 extern int (*dtrace_modunload)(struct kmod_info *);
5882};
5883
5884/*********************************************************************
5885*********************************************************************/
5886void
5887OSKext::registerWithDTrace(void)
5888{
5889 /* Register kext with dtrace. A dtrace_modload failure should not
5890 * prevent a kext from loading, so we ignore the return code.
5891 */
5892 if (!flags.dtraceInitialized && (dtrace_modload != NULL)) {
5893 uint32_t modflag = 0;
5894 OSObject * forceInit = getPropertyForHostArch("OSBundleForceDTraceInit");
5895 if (forceInit == kOSBooleanTrue) {
5896 modflag |= KMOD_DTRACE_FORCE_INIT;
5897 }
5898 if (flags.builtin) {
5899 modflag |= KMOD_DTRACE_STATIC_KEXT;
5900 }
5901
5902 (void)(*dtrace_modload)(kmod_info, modflag);
5903 flags.dtraceInitialized = true;
5904 jettisonLinkeditSegment();
5905 }
5906 return;
5907}
5908/*********************************************************************
5909*********************************************************************/
5910void
5911OSKext::unregisterWithDTrace(void)
5912{
5913 /* Unregister kext with dtrace. A dtrace_modunload failure should not
5914 * prevent a kext from loading, so we ignore the return code.
5915 */
5916 if (flags.dtraceInitialized && (dtrace_modunload != NULL)) {
5917 (void)(*dtrace_modunload)(kmod_info);
5918 flags.dtraceInitialized = false;
5919 }
5920 return;
5921}
5922#endif /* CONFIG_DTRACE */
5923
5924
5925/*********************************************************************
5926* called only by loadExecutable()
5927*********************************************************************/
5928#if !VM_MAPPED_KEXTS
5929#if defined(__arm__) || defined(__arm64__)
5930static inline kern_return_t
5931OSKext_protect(
5932 vm_map_t map,
5933 vm_map_offset_t start,
5934 vm_map_offset_t end,
5935 vm_prot_t new_prot,
5936 boolean_t set_max)
5937{
5938#pragma unused(map)
5939 assert(map == kernel_map); // we can handle KEXTs arising from the PRELINK segment and no others
5940 assert(start <= end);
5941 if (start >= end)
5942 return KERN_SUCCESS; // Punt segments of length zero (e.g., headers) or less (i.e., blunders)
5943 else if (set_max)
5944 return KERN_SUCCESS; // Punt set_max, as there's no mechanism to record that state
5945 else
5946 return ml_static_protect(start, end - start, new_prot);
5947}
5948
5949static inline kern_return_t
5950OSKext_wire(
5951 vm_map_t map,
5952 vm_map_offset_t start,
5953 vm_map_offset_t end,
5954 vm_prot_t access_type,
5955 boolean_t user_wire)
5956{
5957#pragma unused(map,start,end,access_type,user_wire)
5958 return KERN_SUCCESS; // No-op as PRELINK kexts are cemented into physical memory at boot
5959}
5960#else
5961#error Unrecognized architecture
5962#endif
5963#else
5964static inline kern_return_t
5965OSKext_protect(
5966 vm_map_t map,
5967 vm_map_offset_t start,
5968 vm_map_offset_t end,
5969 vm_prot_t new_prot,
5970 boolean_t set_max)
5971{
5972 if (start == end) { // 10538581
5973 return(KERN_SUCCESS);
5974 }
5975 return vm_map_protect(map, start, end, new_prot, set_max);
5976}
5977
5978static inline kern_return_t
5979OSKext_wire(
5980 vm_map_t map,
5981 vm_map_offset_t start,
5982 vm_map_offset_t end,
5983 vm_prot_t access_type,
5984 boolean_t user_wire)
5985{
5986 return vm_map_wire_kernel(map, start, end, access_type, VM_KERN_MEMORY_KEXT, user_wire);
5987}
5988#endif
5989
5990OSReturn
5991OSKext::setVMAttributes(bool protect, bool wire)
5992{
5993 vm_map_t kext_map = NULL;
5994 kernel_segment_command_t * seg = NULL;
5995 vm_map_offset_t start = 0;
5996 vm_map_offset_t end = 0;
5997 OSReturn result = kOSReturnError;
5998
5999 if (isInterface() || !declaresExecutable() || flags.builtin) {
6000 result = kOSReturnSuccess;
6001 goto finish;
6002 }
6003
6004 /* Get the kext's vm map */
6005 kext_map = kext_get_vm_map(kmod_info);
6006 if (!kext_map) {
6007 result = KERN_MEMORY_ERROR;
6008 goto finish;
6009 }
6010
6011#if !VM_MAPPED_KEXTS
6012 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
6013 /* This is a split kext in a prelinked kernelcache; we'll let the
6014 * platform code take care of protecting it. It is already wired.
6015 */
6016 /* TODO: Should this still allow protections for the first segment
6017 * to go through, in the event that we have a mix of split and
6018 * unsplit kexts?
6019 */
6020 result = KERN_SUCCESS;
6021 goto finish;
6022 }
6023#endif
6024
6025 /* Protect the headers as read-only; they do not need to be wired */
6026 result = (protect) ? OSKext_protect(kext_map, kmod_info->address,
6027 kmod_info->address + kmod_info->hdr_size, VM_PROT_READ, TRUE)
6028 : KERN_SUCCESS;
6029 if (result != KERN_SUCCESS) {
6030 goto finish;
6031 }
6032
6033 /* Set the VM protections and wire down each of the segments */
6034 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
6035 while (seg) {
6036
6037#if __arm__
6038 /* We build all ARM kexts, so we can ensure they are aligned */
6039 assert((seg->vmaddr & PAGE_MASK) == 0);
6040 assert((seg->vmsize & PAGE_MASK) == 0);
6041#endif
6042
6043 start = round_page(seg->vmaddr);
6044 end = trunc_page(seg->vmaddr + seg->vmsize);
6045
6046 if (protect) {
6047 result = OSKext_protect(kext_map, start, end, seg->maxprot, TRUE);
6048 if (result != KERN_SUCCESS) {
6049 OSKextLog(this,
6050 kOSKextLogErrorLevel |
6051 kOSKextLogLoadFlag,
6052 "Kext %s failed to set maximum VM protections "
6053 "for segment %s - 0x%x.",
6054 getIdentifierCString(), seg->segname, (int)result);
6055 goto finish;
6056 }
6057
6058 result = OSKext_protect(kext_map, start, end, seg->initprot, FALSE);
6059 if (result != KERN_SUCCESS) {
6060 OSKextLog(this,
6061 kOSKextLogErrorLevel |
6062 kOSKextLogLoadFlag,
6063 "Kext %s failed to set initial VM protections "
6064 "for segment %s - 0x%x.",
6065 getIdentifierCString(), seg->segname, (int)result);
6066 goto finish;
6067 }
6068 }
6069
6070 if (segmentShouldBeWired(seg) && wire) {
6071 result = OSKext_wire(kext_map, start, end, seg->initprot, FALSE);
6072 if (result != KERN_SUCCESS) {
6073 goto finish;
6074 }
6075 }
6076
6077 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
6078 }
6079
6080finish:
6081 return result;
6082}
6083
6084/*********************************************************************
6085*********************************************************************/
6086boolean_t
6087OSKext::segmentShouldBeWired(kernel_segment_command_t *seg)
6088{
6089 return (sKeepSymbols || strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)));
6090}
6091
6092/*********************************************************************
6093*********************************************************************/
6094OSReturn
6095OSKext::validateKextMapping(bool startFlag)
6096{
6097 OSReturn result = kOSReturnError;
6098 const char * whichOp = startFlag ? "start" : "stop";
6099 kern_return_t kern_result = 0;
6100 vm_map_t kext_map = NULL;
6101 kernel_segment_command_t * seg = NULL;
6102 mach_vm_address_t address = 0;
6103 mach_vm_size_t size = 0;
6104 uint32_t depth = 0;
6105 mach_msg_type_number_t count;
6106 vm_region_submap_short_info_data_64_t info;
6107
6108 if (flags.builtin) return (kOSReturnSuccess);
6109
6110 count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
6111 bzero(&info, sizeof(info));
6112
6113 // xxx - do we need a distinct OSReturn value for these or is "bad data"
6114 // xxx - sufficient?
6115
6116 /* Verify that the kmod_info and start/stop pointers are non-NULL.
6117 */
6118 if (!kmod_info) {
6119 OSKextLog(this,
6120 kOSKextLogErrorLevel |
6121 kOSKextLogLoadFlag,
6122 "Kext %s - NULL kmod_info pointer.",
6123 getIdentifierCString());
6124 result = kOSKextReturnBadData;
6125 goto finish;
6126 }
6127
6128 if (startFlag) {
6129 address = (mach_vm_address_t)kmod_info->start;
6130 } else {
6131 address = (mach_vm_address_t)kmod_info->stop;
6132 }
6133
6134 if (!address) {
6135 OSKextLog(this,
6136 kOSKextLogErrorLevel |
6137 kOSKextLogLoadFlag,
6138 "Kext %s - NULL module %s pointer.",
6139 getIdentifierCString(), whichOp);
6140 result = kOSKextReturnBadData;
6141 goto finish;
6142 }
6143
6144 kext_map = kext_get_vm_map(kmod_info);
6145 depth = (kernel_map == kext_map) ? 1 : 2;
6146
6147 /* Verify that the start/stop function lies within the kext's address range.
6148 */
6149 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
6150 /* This will likely be how we deal with split kexts; walk the segments to
6151 * check that the function lies inside one of the segments of this kext.
6152 */
6153 for (seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
6154 seg != NULL;
6155 seg = nextsegfromheader((kernel_mach_header_t *)kmod_info->address, seg)) {
6156 if ((address >= seg->vmaddr) && address < (seg->vmaddr + seg->vmsize)) {
6157 break;
6158 }
6159 }
6160
6161 if (!seg) {
6162 OSKextLog(this,
6163 kOSKextLogErrorLevel |
6164 kOSKextLogLoadFlag,
6165 "Kext %s module %s pointer is outside of kext range "
6166 "(%s %p - kext starts at %p).",
6167 getIdentifierCString(),
6168 whichOp,
6169 whichOp,
6170 (void *)ml_static_unslide(address),
6171 (void *)ml_static_unslide(kmod_info->address));
6172 result = kOSKextReturnBadData;
6173 goto finish;
6174 }
6175
6176 seg = NULL;
6177 } else {
6178 if (address < kmod_info->address + kmod_info->hdr_size ||
6179 kmod_info->address + kmod_info->size <= address)
6180 {
6181 OSKextLog(this,
6182 kOSKextLogErrorLevel |
6183 kOSKextLogLoadFlag,
6184 "Kext %s module %s pointer is outside of kext range "
6185 "(%s %p - kext at %p-%p).",
6186 getIdentifierCString(),
6187 whichOp,
6188 whichOp,
6189 (void *)ml_static_unslide(address),
6190 (void *)ml_static_unslide(kmod_info->address),
6191 (void *)(ml_static_unslide(kmod_info->address) + kmod_info->size));
6192 result = kOSKextReturnBadData;
6193 goto finish;
6194 }
6195 }
6196
6197 /* Only do these checks before calling the start function;
6198 * If anything goes wrong with the mapping while the kext is running,
6199 * we'll likely have panicked well before any attempt to stop the kext.
6200 */
6201 if (startFlag) {
6202
6203 /* Verify that the start/stop function is executable.
6204 */
6205 kern_result = mach_vm_region_recurse(kernel_map, &address, &size, &depth,
6206 (vm_region_recurse_info_t)&info, &count);
6207 if (kern_result != KERN_SUCCESS) {
6208 OSKextLog(this,
6209 kOSKextLogErrorLevel |
6210 kOSKextLogLoadFlag,
6211 "Kext %s - bad %s pointer %p.",
6212 getIdentifierCString(),
6213 whichOp, (void *)ml_static_unslide(address));
6214 result = kOSKextReturnBadData;
6215 goto finish;
6216 }
6217
6218#if VM_MAPPED_KEXTS
6219 if (!(info.protection & VM_PROT_EXECUTE)) {
6220 OSKextLog(this,
6221 kOSKextLogErrorLevel |
6222 kOSKextLogLoadFlag,
6223 "Kext %s - memory region containing module %s function "
6224 "is not executable.",
6225 getIdentifierCString(), whichOp);
6226 result = kOSKextReturnBadData;
6227 goto finish;
6228 }
6229#endif
6230
6231 /* Verify that the kext's segments are backed by physical memory.
6232 */
6233 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
6234 while (seg) {
6235 if (!verifySegmentMapping(seg)) {
6236 result = kOSKextReturnBadData;
6237 goto finish;
6238 }
6239
6240 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
6241 }
6242
6243 }
6244
6245 result = kOSReturnSuccess;
6246finish:
6247 return result;
6248}
6249
6250/*********************************************************************
6251*********************************************************************/
6252boolean_t
6253OSKext::verifySegmentMapping(kernel_segment_command_t *seg)
6254{
6255 mach_vm_address_t address = 0;
6256
6257 if (!segmentShouldBeWired(seg)) return true;
6258
6259 for (address = seg->vmaddr;
6260 address < round_page(seg->vmaddr + seg->vmsize);
6261 address += PAGE_SIZE)
6262 {
6263 if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
6264 OSKextLog(this,
6265 kOSKextLogErrorLevel |
6266 kOSKextLogLoadFlag,
6267 "Kext %s - page %p is not backed by physical memory.",
6268 getIdentifierCString(),
6269 (void *)address);
6270 return false;
6271 }
6272 }
6273
6274 return true;
6275}
6276
6277/*********************************************************************
6278*********************************************************************/
6279static void
6280OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code)
6281{
6282
6283 uint64_t stamp = 0;
6284 firehose_tracepoint_id_u trace_id;
6285 struct firehose_trace_uuid_info_s uuid_info_s;
6286 firehose_trace_uuid_info_t uuid_info = &uuid_info_s;
6287 size_t uuid_info_len = sizeof(struct firehose_trace_uuid_info_s);
6288 OSData *uuid_data;
6289
6290 stamp = firehose_tracepoint_time(firehose_activity_flags_default);
6291 trace_id.ftid_value = FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata, _firehose_tracepoint_type_metadata_kext, (firehose_tracepoint_flags_t)0, code);
6292
6293 uuid_data = aKext->copyTextUUID();
6294 if (uuid_data) {
6295 memcpy(uuid_info->ftui_uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_info->ftui_uuid));
6296 OSSafeReleaseNULL(uuid_data);
6297 }
6298
6299 uuid_info->ftui_size = size;
6300 uuid_info->ftui_address = ml_static_unslide(address);
6301
6302 firehose_trace_metadata(firehose_stream_metadata, trace_id, stamp, uuid_info, uuid_info_len);
6303 return;
6304}
6305
6306/*********************************************************************
6307*********************************************************************/
6308OSReturn
6309OSKext::start(bool startDependenciesFlag)
6310{
6311 OSReturn result = kOSReturnError;
6312 kern_return_t (* startfunc)(kmod_info_t *, void *);
6313 unsigned int i, count;
6314 void * kmodStartData = NULL;
6315
6316 if (isStarted() || isInterface() || isKernelComponent()) {
6317 result = kOSReturnSuccess;
6318 goto finish;
6319 }
6320
6321 if (!isLoaded()) {
6322 OSKextLog(this,
6323 kOSKextLogErrorLevel |
6324 kOSKextLogLoadFlag,
6325 "Attempt to start nonloaded kext %s.",
6326 getIdentifierCString());
6327 result = kOSKextReturnInvalidArgument;
6328 goto finish;
6329 }
6330
6331 if (!sLoadEnabled) {
6332 OSKextLog(this,
6333 kOSKextLogErrorLevel |
6334 kOSKextLogLoadFlag,
6335 "Kext loading is disabled (attempt to start kext %s).",
6336 getIdentifierCString());
6337 result = kOSKextReturnDisabled;
6338 goto finish;
6339 }
6340
6341 result = validateKextMapping(/* start? */ true);
6342 if (result != kOSReturnSuccess) {
6343 goto finish;
6344 }
6345
6346 startfunc = kmod_info->start;
6347
6348 count = getNumDependencies();
6349 for (i = 0; i < count; i++) {
6350 OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
6351 if (dependency == NULL) {
6352 OSKextLog(this,
6353 kOSKextLogErrorLevel |
6354 kOSKextLogLoadFlag,
6355 "Kext %s start - internal error, dependency disappeared.",
6356 getIdentifierCString());
6357 goto finish;
6358 }
6359 if (!dependency->isStarted()) {
6360 if (startDependenciesFlag) {
6361 OSReturn dependencyResult =
6362 dependency->start(startDependenciesFlag);
6363 if (dependencyResult != KERN_SUCCESS) {
6364 OSKextLog(this,
6365 kOSKextLogErrorLevel |
6366 kOSKextLogLoadFlag,
6367 "Kext %s start - dependency %s failed to start (error 0x%x).",
6368 getIdentifierCString(),
6369 dependency->getIdentifierCString(),
6370 dependencyResult);
6371 goto finish;
6372 }
6373 } else {
6374 OSKextLog(this,
6375 kOSKextLogErrorLevel |
6376 kOSKextLogLoadFlag,
6377 "Not starting %s - dependency %s not started yet.",
6378 getIdentifierCString(),
6379 dependency->getIdentifierCString());
6380 result = kOSKextReturnStartStopError; // xxx - make new return?
6381 goto finish;
6382 }
6383 }
6384 }
6385
6386 OSKextLog(this,
6387 kOSKextLogDetailLevel |
6388 kOSKextLogLoadFlag,
6389 "Kext %s calling module start function.",
6390 getIdentifierCString());
6391
6392 flags.starting = 1;
6393
6394 // Drop a log message so logd can grab the needed information to decode this kext
6395 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_load);
6396 result = OSRuntimeInitializeCPP(this);
6397 if (result == KERN_SUCCESS) {
6398 result = startfunc(kmod_info, kmodStartData);
6399 }
6400
6401 flags.starting = 0;
6402
6403 /* On success overlap the setting of started/starting. On failure just
6404 * clear starting.
6405 */
6406 if (result == KERN_SUCCESS) {
6407 flags.started = 1;
6408
6409 // xxx - log start error from kernel?
6410 OSKextLog(this,
6411 kOSKextLogProgressLevel |
6412 kOSKextLogLoadFlag,
6413 "Kext %s is now started.",
6414 getIdentifierCString());
6415 } else {
6416 invokeOrCancelRequestCallbacks(
6417 /* result not actually used */ kOSKextReturnStartStopError,
6418 /* invokeFlag */ false);
6419 OSKextLog(this,
6420 kOSKextLogProgressLevel |
6421 kOSKextLogLoadFlag,
6422 "Kext %s did not start (return code 0x%x).",
6423 getIdentifierCString(), result);
6424 }
6425
6426finish:
6427 return result;
6428}
6429
6430/*********************************************************************
6431*********************************************************************/
6432/* static */
6433bool OSKext::canUnloadKextWithIdentifier(
6434 OSString * kextIdentifier,
6435 bool checkClassesFlag)
6436{
6437 bool result = false;
6438 OSKext * aKext = NULL; // do not release
6439
6440 IORecursiveLockLock(sKextLock);
6441
6442 aKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
6443
6444 if (!aKext) {
6445 goto finish; // can't unload what's not loaded
6446 }
6447
6448 if (aKext->isLoaded()) {
6449 if (aKext->getRetainCount() > kOSKextMinLoadedRetainCount) {
6450 goto finish;
6451 }
6452 if (checkClassesFlag && aKext->hasOSMetaClassInstances()) {
6453 goto finish;
6454 }
6455 }
6456
6457 result = true;
6458
6459finish:
6460 IORecursiveLockUnlock(sKextLock);
6461 return result;
6462}
6463
6464/*********************************************************************
6465*********************************************************************/
6466OSReturn
6467OSKext::stop(void)
6468{
6469 OSReturn result = kOSReturnError;
6470 kern_return_t (*stopfunc)(kmod_info_t *, void *);
6471
6472 if (!isStarted() || isInterface()) {
6473 result = kOSReturnSuccess;
6474 goto finish;
6475 }
6476
6477 if (!isLoaded()) {
6478 OSKextLog(this,
6479 kOSKextLogErrorLevel |
6480 kOSKextLogLoadFlag,
6481 "Attempt to stop nonloaded kext %s.",
6482 getIdentifierCString());
6483 result = kOSKextReturnInvalidArgument;
6484 goto finish;
6485 }
6486
6487 /* Refuse to stop if we have clients or instances. It is up to
6488 * the caller to make sure those aren't true.
6489 */
6490 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
6491 OSKextLog(this,
6492 kOSKextLogErrorLevel |
6493 kOSKextLogLoadFlag,
6494 "Kext %s - C++ instances; can't stop.",
6495 getIdentifierCString());
6496 result = kOSKextReturnInUse;
6497 goto finish;
6498 }
6499
6500 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
6501
6502 OSKextLog(this,
6503 kOSKextLogErrorLevel |
6504 kOSKextLogLoadFlag,
6505 "Kext %s - has references (linkage or tracking object); "
6506 "can't stop.",
6507 getIdentifierCString());
6508 result = kOSKextReturnInUse;
6509 goto finish;
6510 }
6511
6512 /* Note: If validateKextMapping fails on the stop & unload path,
6513 * we are in serious trouble and a kernel panic is likely whether
6514 * we stop & unload the kext or not.
6515 */
6516 result = validateKextMapping(/* start? */ false);
6517 if (result != kOSReturnSuccess) {
6518 goto finish;
6519 }
6520
6521 stopfunc = kmod_info->stop;
6522 if (stopfunc) {
6523 OSKextLog(this,
6524 kOSKextLogDetailLevel |
6525 kOSKextLogLoadFlag,
6526 "Kext %s calling module stop function.",
6527 getIdentifierCString());
6528
6529 flags.stopping = 1;
6530
6531 result = stopfunc(kmod_info, /* userData */ NULL);
6532 if (result == KERN_SUCCESS) {
6533 result = OSRuntimeFinalizeCPP(this);
6534 }
6535
6536 flags.stopping = 0;
6537
6538 if (result == KERN_SUCCESS) {
6539 flags.started = 0;
6540
6541 OSKextLog(this,
6542 kOSKextLogDetailLevel |
6543 kOSKextLogLoadFlag,
6544 "Kext %s is now stopped and ready to unload.",
6545 getIdentifierCString());
6546 } else {
6547 OSKextLog(this,
6548 kOSKextLogErrorLevel |
6549 kOSKextLogLoadFlag,
6550 "Kext %s did not stop (return code 0x%x).",
6551 getIdentifierCString(), result);
6552 result = kOSKextReturnStartStopError;
6553 }
6554 }
6555
6556finish:
6557 // Drop a log message so logd can update this kext's metadata
6558 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_unload);
6559 return result;
6560}
6561
6562/*********************************************************************
6563*********************************************************************/
6564OSReturn
6565OSKext::unload(void)
6566{
6567 OSReturn result = kOSReturnError;
6568 unsigned int index;
6569 uint32_t num_kmod_refs = 0;
6570 OSKextAccount * freeAccount;
6571
6572 if (!sUnloadEnabled) {
6573 OSKextLog(this,
6574 kOSKextLogErrorLevel |
6575 kOSKextLogLoadFlag,
6576 "Kext unloading is disabled (%s).",
6577 this->getIdentifierCString());
6578
6579 result = kOSKextReturnDisabled;
6580 goto finish;
6581 }
6582
6583 /* Refuse to unload if we have clients or instances. It is up to
6584 * the caller to make sure those aren't true.
6585 */
6586 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
6587 // xxx - Don't log under errors? this is more of an info thing
6588 OSKextLog(this,
6589 kOSKextLogErrorLevel |
6590 kOSKextLogKextBookkeepingFlag,
6591 "Can't unload kext %s; outstanding references (linkage or tracking object).",
6592 getIdentifierCString());
6593 result = kOSKextReturnInUse;
6594 goto finish;
6595 }
6596
6597 if (!isLoaded()) {
6598 result = kOSReturnSuccess;
6599 goto finish;
6600 }
6601
6602 if (isKernelComponent()) {
6603 result = kOSKextReturnInvalidArgument;
6604 goto finish;
6605 }
6606
6607 if (metaClasses && !OSMetaClass::removeClasses(metaClasses)) {
6608 OSKextLog(this,
6609 kOSKextLogErrorLevel |
6610 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6611 "Can't unload kext %s; classes have instances:",
6612 getIdentifierCString());
6613 reportOSMetaClassInstances(kOSKextLogErrorLevel |
6614 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag);
6615 result = kOSKextReturnInUse;
6616 goto finish;
6617 }
6618
6619 /* Note that the kext is unloading before running any code that
6620 * might be in the kext (request callbacks, module stop function).
6621 * We will deny certain requests made against a kext in the process
6622 * of unloading.
6623 */
6624 flags.unloading = 1;
6625
6626 /* Update the string describing the last kext to unload in case we panic.
6627 */
6628 savePanicString(/* isLoading */ false);
6629
6630 if (isStarted()) {
6631 result = stop();
6632 if (result != KERN_SUCCESS) {
6633 OSKextLog(this,
6634 kOSKextLogErrorLevel |
6635 kOSKextLogLoadFlag,
6636 "Kext %s can't unload - module stop returned 0x%x.",
6637 getIdentifierCString(), (unsigned)result);
6638 result = kOSKextReturnStartStopError;
6639 goto finish;
6640 }
6641 }
6642
6643 OSKextLog(this,
6644 kOSKextLogProgressLevel |
6645 kOSKextLogLoadFlag,
6646 "Kext %s unloading.",
6647 getIdentifierCString());
6648
6649 {
6650 struct list_head *p;
6651 struct list_head *prev;
6652 struct list_head *next;
6653 for (p = pendingPgoHead.next; p != &pendingPgoHead; p = next) {
6654 OSKextGrabPgoStruct *s = container_of(p, OSKextGrabPgoStruct, list_head);
6655 s->err = OSKextGrabPgoDataLocked(this, s->metadata, instance_uuid, s->pSize, s->pBuffer, s->bufferSize);
6656 prev = p->prev;
6657 next = p->next;
6658 prev->next = next;
6659 next->prev = prev;
6660 p->prev = p;
6661 p->next = p;
6662 IORecursiveLockWakeup(sKextLock, s, false);
6663 }
6664 }
6665
6666
6667 /* Even if we don't call the stop function, we want to be sure we
6668 * have no OSMetaClass references before unloading the kext executable
6669 * from memory. OSMetaClasses may have pointers into the kext executable
6670 * and that would cause a panic on OSKext::free() when metaClasses is freed.
6671 */
6672 if (metaClasses) {
6673 metaClasses->flushCollection();
6674 }
6675 (void) OSRuntimeFinalizeCPP(this);
6676
6677 /* Remove the kext from the list of loaded kexts, patch the gap
6678 * in the kmod_info_t linked list, and reset "kmod" to point to the
6679 * last loaded kext that isn't the fake kernel kext (sKernelKext).
6680 */
6681 index = sLoadedKexts->getNextIndexOfObject(this, 0);
6682 if (index != (unsigned int)-1) {
6683
6684 sLoadedKexts->removeObject(index);
6685
6686 OSKext * nextKext = OSDynamicCast(OSKext,
6687 sLoadedKexts->getObject(index));
6688
6689 if (nextKext) {
6690 if (index > 0) {
6691 OSKext * gapKext = OSDynamicCast(OSKext,
6692 sLoadedKexts->getObject(index - 1));
6693
6694 nextKext->kmod_info->next = gapKext->kmod_info;
6695
6696 } else /* index == 0 */ {
6697 nextKext->kmod_info->next = NULL;
6698 }
6699 }
6700
6701 OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
6702 if (lastKext && !lastKext->isKernel()) {
6703 kmod = lastKext->kmod_info;
6704 } else {
6705 kmod = NULL; // clear the global kmod variable
6706 }
6707 }
6708
6709 /* Clear out the kmod references that we're keeping for compatibility
6710 * with current panic backtrace code & kgmacros.
6711 * xxx - will want to update those bits sometime and remove this.
6712 */
6713 num_kmod_refs = getNumDependencies();
6714 if (num_kmod_refs && kmod_info && kmod_info->reference_list) {
6715 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
6716 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
6717 ref->info->reference_count--;
6718 }
6719 kfree(kmod_info->reference_list,
6720 num_kmod_refs * sizeof(kmod_reference_t));
6721 }
6722
6723#if CONFIG_DTRACE
6724 unregisterWithDTrace();
6725#endif /* CONFIG_DTRACE */
6726
6727 notifyKextUnloadObservers(this);
6728
6729 freeAccount = NULL;
6730 IOSimpleLockLock(sKextAccountsLock);
6731 account->kext = NULL;
6732 if (account->site.tag) account->site.flags |= VM_TAG_UNLOAD;
6733 else freeAccount = account;
6734 IOSimpleLockUnlock(sKextAccountsLock);
6735 if (freeAccount) IODelete(freeAccount, OSKextAccount, 1);
6736
6737 /* Unwire and free the linked executable.
6738 */
6739 if (linkedExecutable) {
6740#if KASAN
6741 kasan_unload_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(), linkedExecutable->getLength());
6742#endif
6743
6744#if VM_MAPPED_KEXTS
6745 if (!isInterface()) {
6746 kernel_segment_command_t *seg = NULL;
6747 vm_map_t kext_map = kext_get_vm_map(kmod_info);
6748
6749 if (!kext_map) {
6750 OSKextLog(this,
6751 kOSKextLogErrorLevel |
6752 kOSKextLogLoadFlag,
6753 "Failed to free kext %s; couldn't find the kext map.",
6754 getIdentifierCString());
6755 result = kOSKextReturnInternalError;
6756 goto finish;
6757 }
6758
6759 OSKextLog(this,
6760 kOSKextLogProgressLevel |
6761 kOSKextLogLoadFlag,
6762 "Kext %s unwiring and unmapping linked executable.",
6763 getIdentifierCString());
6764
6765 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
6766 while (seg) {
6767 if (segmentShouldBeWired(seg)) {
6768 result = vm_map_unwire(kext_map, seg->vmaddr,
6769 seg->vmaddr + seg->vmsize, FALSE);
6770 if (result != KERN_SUCCESS) {
6771 OSKextLog(this,
6772 kOSKextLogErrorLevel |
6773 kOSKextLogLoadFlag,
6774 "Failed to unwire kext %s.",
6775 getIdentifierCString());
6776 result = kOSKextReturnInternalError;
6777 goto finish;
6778 }
6779 }
6780
6781 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
6782 }
6783 }
6784#endif
6785 OSSafeReleaseNULL(linkedExecutable);
6786 }
6787
6788 /* An interface kext has a fake kmod_info that was allocated,
6789 * so we have to free it.
6790 */
6791 if (isInterface()) {
6792 kfree(kmod_info, sizeof(kmod_info_t));
6793 }
6794
6795 kmod_info = NULL;
6796
6797 flags.loaded = false;
6798 flushDependencies();
6799
6800 /* save a copy of the bundle ID for us to check when deciding to
6801 * rebuild the kernel cache file. If a kext was already in the kernel
6802 * cache and unloaded then later loaded we do not need to rebuild the
6803 * kernel cache. 9055303
6804 */
6805 if (isPrelinked()) {
6806 if (!_OSKextInUnloadedPrelinkedKexts(bundleID)) {
6807 IORecursiveLockLock(sKextLock);
6808 if (sUnloadedPrelinkedKexts) {
6809 sUnloadedPrelinkedKexts->setObject(bundleID);
6810 }
6811 IORecursiveLockUnlock(sKextLock);
6812 }
6813 }
6814
6815 OSKextLog(this,
6816 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
6817 "Kext %s unloaded.", getIdentifierCString());
6818
6819 queueKextNotification(kKextRequestPredicateUnloadNotification,
6820 OSDynamicCast(OSString, bundleID));
6821
6822finish:
6823 OSKext::saveLoadedKextPanicList();
6824 OSKext::updateLoadedKextSummaries();
6825
6826 flags.unloading = 0;
6827 return result;
6828}
6829
6830/*********************************************************************
6831* Assumes sKextLock is held.
6832*********************************************************************/
6833/* static */
6834OSReturn
6835OSKext::queueKextNotification(
6836 const char * notificationName,
6837 OSString * kextIdentifier)
6838{
6839 OSReturn result = kOSReturnError;
6840 OSDictionary * loadRequest = NULL; // must release
6841
6842 if (!kextIdentifier) {
6843 result = kOSKextReturnInvalidArgument;
6844 goto finish;
6845 }
6846
6847 /* Create a new request unless one is already sitting
6848 * in sKernelRequests for this bundle identifier
6849 */
6850 result = _OSKextCreateRequest(notificationName, &loadRequest);
6851 if (result != kOSReturnSuccess) {
6852 goto finish;
6853 }
6854 if (!_OSKextSetRequestArgument(loadRequest,
6855 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
6856
6857 result = kOSKextReturnNoMemory;
6858 goto finish;
6859 }
6860 if (!sKernelRequests->setObject(loadRequest)) {
6861 result = kOSKextReturnNoMemory;
6862 goto finish;
6863 }
6864
6865 /* We might want to only queue the notification if kextd is active,
6866 * but that wouldn't work for embedded. Note that we don't care if
6867 * the ping immediately succeeds here so don't do anything with the
6868 * result of this call.
6869 */
6870 OSKext::pingKextd();
6871
6872 result = kOSReturnSuccess;
6873
6874finish:
6875 OSSafeReleaseNULL(loadRequest);
6876
6877 return result;
6878}
6879
6880/*********************************************************************
6881*********************************************************************/
6882static void
6883_OSKextConsiderDestroyingLinkContext(
6884 __unused thread_call_param_t p0,
6885 __unused thread_call_param_t p1)
6886{
6887 /* Take multiple locks in the correct order.
6888 */
6889 IORecursiveLockLock(sKextLock);
6890 IORecursiveLockLock(sKextInnerLock);
6891
6892 /* The first time we destroy the kxldContext is in the first
6893 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
6894 * before calling this function. Thereafter any call to this function
6895 * will actually destroy the context.
6896 */
6897 if (sConsiderUnloadsCalled && sKxldContext) {
6898 kxld_destroy_context(sKxldContext);
6899 sKxldContext = NULL;
6900 }
6901
6902 /* Free the thread_call that was allocated to execute this function.
6903 */
6904 if (sDestroyLinkContextThread) {
6905 if (!thread_call_free(sDestroyLinkContextThread)) {
6906 OSKextLog(/* kext */ NULL,
6907 kOSKextLogErrorLevel |
6908 kOSKextLogGeneralFlag,
6909 "thread_call_free() failed for kext link context.");
6910 }
6911 sDestroyLinkContextThread = 0;
6912 }
6913
6914 IORecursiveLockUnlock(sKextInnerLock);
6915 IORecursiveLockUnlock(sKextLock);
6916
6917 return;
6918}
6919
6920/*********************************************************************
6921* Destroying the kxldContext requires checking variables under both
6922* sKextInnerLock and sKextLock, so we do it on a separate thread
6923* to avoid deadlocks with IOService, with which OSKext has a reciprocal
6924* call relationship.
6925*
6926* This function must be invoked with sKextInnerLock held.
6927* Do not call any function that takes sKextLock here!
6928*********************************************************************/
6929/* static */
6930void
6931OSKext::considerDestroyingLinkContext(void)
6932{
6933 IORecursiveLockLock(sKextInnerLock);
6934
6935 /* If we have already queued a thread to destroy the link context,
6936 * don't bother resetting; that thread will take care of it.
6937 */
6938 if (sDestroyLinkContextThread) {
6939 goto finish;
6940 }
6941
6942 /* The function to be invoked in the thread will deallocate
6943 * this thread_call, so don't share it around.
6944 */
6945 sDestroyLinkContextThread = thread_call_allocate(
6946 &_OSKextConsiderDestroyingLinkContext, 0);
6947 if (!sDestroyLinkContextThread) {
6948 OSKextLog(/* kext */ NULL,
6949 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogLinkFlag,
6950 "Can't create thread to destroy kext link context.");
6951 goto finish;
6952 }
6953
6954 thread_call_enter(sDestroyLinkContextThread);
6955
6956finish:
6957 IORecursiveLockUnlock(sKextInnerLock);
6958 return;
6959}
6960
6961#if PRAGMA_MARK
6962#pragma mark Autounload
6963#endif
6964/*********************************************************************
6965* This is a static method because the kext will be deallocated if it
6966* does unload!
6967*********************************************************************/
6968/* static */
6969OSReturn
6970OSKext::autounloadKext(OSKext * aKext)
6971{
6972 OSReturn result = kOSKextReturnInUse;
6973
6974 /* Check for external references to this kext (usu. dependents),
6975 * instances of defined classes (or classes derived from them),
6976 * outstanding requests.
6977 */
6978 if ((aKext->getRetainCount() > kOSKextMinLoadedRetainCount) ||
6979 !aKext->flags.autounloadEnabled ||
6980 aKext->isKernelComponent()) {
6981
6982 goto finish;
6983 }
6984
6985 /* Skip a delay-autounload kext, once.
6986 */
6987 if (aKext->flags.delayAutounload) {
6988 OSKextLog(aKext,
6989 kOSKextLogProgressLevel |
6990 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6991 "Kext %s has delayed autounload set; skipping and clearing flag.",
6992 aKext->getIdentifierCString());
6993 aKext->flags.delayAutounload = 0;
6994 goto finish;
6995 }
6996
6997 if (aKext->hasOSMetaClassInstances() ||
6998 aKext->countRequestCallbacks()) {
6999 goto finish;
7000 }
7001
7002 result = OSKext::removeKext(aKext);
7003
7004finish:
7005 return result;
7006}
7007
7008/*********************************************************************
7009*********************************************************************/
7010void
7011_OSKextConsiderUnloads(
7012 __unused thread_call_param_t p0,
7013 __unused thread_call_param_t p1)
7014{
7015 bool didUnload = false;
7016 unsigned int count, i;
7017
7018 /* Take multiple locks in the correct order
7019 * (note also sKextSummaries lock further down).
7020 */
7021 IORecursiveLockLock(sKextLock);
7022 IORecursiveLockLock(sKextInnerLock);
7023
7024 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
7025
7026 /* If the system is powering down, don't try to unload anything.
7027 */
7028 if (sSystemSleep) {
7029 goto finish;
7030 }
7031
7032 OSKextLog(/* kext */ NULL,
7033 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
7034 "Checking for unused kexts to autounload.");
7035
7036 /*****
7037 * Remove any request callbacks marked as stale,
7038 * and mark as stale any currently in flight.
7039 */
7040 count = sRequestCallbackRecords->getCount();
7041 if (count) {
7042 i = count - 1;
7043 do {
7044 OSDictionary * callbackRecord = OSDynamicCast(OSDictionary,
7045 sRequestCallbackRecords->getObject(i));
7046 OSBoolean * stale = OSDynamicCast(OSBoolean,
7047 callbackRecord->getObject(kKextRequestStaleKey));
7048
7049 if (stale == kOSBooleanTrue) {
7050 OSKext::invokeRequestCallback(callbackRecord,
7051 kOSKextReturnTimeout);
7052 } else {
7053 callbackRecord->setObject(kKextRequestStaleKey,
7054 kOSBooleanTrue);
7055 }
7056 } while (i--);
7057 }
7058
7059 /*****
7060 * Make multiple passes through the array of loaded kexts until
7061 * we don't unload any. This handles unwinding of dependency
7062 * chains. We have to go *backwards* through the array because
7063 * kexts are removed from it when unloaded, and we cannot make
7064 * a copy or we'll mess up the retain counts we rely on to
7065 * check whether a kext will unload. If only we could have
7066 * nonretaining collections like CF has....
7067 */
7068 do {
7069 didUnload = false;
7070
7071 count = sLoadedKexts->getCount();
7072 if (count) {
7073 i = count - 1;
7074 do {
7075 OSKext * thisKext = OSDynamicCast(OSKext,
7076 sLoadedKexts->getObject(i));
7077 didUnload |= (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
7078 } while (i--);
7079 }
7080 } while (didUnload);
7081
7082finish:
7083 sConsiderUnloadsPending = false;
7084 sConsiderUnloadsExecuted = true;
7085
7086 (void) OSKext::considerRebuildOfPrelinkedKernel();
7087
7088 IORecursiveLockUnlock(sKextInnerLock);
7089 IORecursiveLockUnlock(sKextLock);
7090
7091 return;
7092}
7093
7094/*********************************************************************
7095* Do not call any function that takes sKextLock here!
7096*********************************************************************/
7097void OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
7098{
7099 AbsoluteTime when;
7100
7101 IORecursiveLockLock(sKextInnerLock);
7102
7103 if (!sUnloadCallout) {
7104 sUnloadCallout = thread_call_allocate(&_OSKextConsiderUnloads, 0);
7105 }
7106
7107 /* we only reset delay value for unloading if we already have something
7108 * pending. rescheduleOnlyFlag should not start the count down.
7109 */
7110 if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
7111 goto finish;
7112 }
7113
7114 thread_call_cancel(sUnloadCallout);
7115 if (OSKext::getAutounloadEnabled() && !sSystemSleep) {
7116 clock_interval_to_deadline(sConsiderUnloadDelay,
7117 1000 * 1000 * 1000, &when);
7118
7119 OSKextLog(/* kext */ NULL,
7120 kOSKextLogProgressLevel |
7121 kOSKextLogLoadFlag,
7122 "%scheduling %sscan for unused kexts in %lu seconds.",
7123 sConsiderUnloadsPending ? "Res" : "S",
7124 sConsiderUnloadsCalled ? "" : "initial ",
7125 (unsigned long)sConsiderUnloadDelay);
7126
7127 sConsiderUnloadsPending = true;
7128 thread_call_enter_delayed(sUnloadCallout, when);
7129 }
7130
7131finish:
7132 /* The kxld context should be reused throughout boot. We mark the end of
7133 * period as the first time considerUnloads() is called, and we destroy
7134 * the first kxld context in that function. Afterwards, it will be
7135 * destroyed in flushNonloadedKexts.
7136 */
7137 if (!sConsiderUnloadsCalled) {
7138 sConsiderUnloadsCalled = true;
7139 OSKext::considerDestroyingLinkContext();
7140 }
7141
7142 IORecursiveLockUnlock(sKextInnerLock);
7143 return;
7144}
7145
7146/*********************************************************************
7147* Do not call any function that takes sKextLock here!
7148*********************************************************************/
7149extern "C" {
7150
7151IOReturn OSKextSystemSleepOrWake(UInt32 messageType);
7152IOReturn OSKextSystemSleepOrWake(UInt32 messageType)
7153{
7154 IORecursiveLockLock(sKextInnerLock);
7155
7156 /* If the system is going to sleep, cancel the reaper thread timer,
7157 * and note that we're in a sleep state in case it just fired but hasn't
7158 * taken the lock yet. If we are coming back from sleep, just
7159 * clear the sleep flag; IOService's normal operation will cause
7160 * unloads to be considered soon enough.
7161 */
7162 if (messageType == kIOMessageSystemWillSleep) {
7163 if (sUnloadCallout) {
7164 thread_call_cancel(sUnloadCallout);
7165 }
7166 sSystemSleep = true;
7167 AbsoluteTime_to_scalar(&sLastWakeTime) = 0;
7168 } else if (messageType == kIOMessageSystemHasPoweredOn) {
7169 sSystemSleep = false;
7170 clock_get_uptime(&sLastWakeTime);
7171 }
7172 IORecursiveLockUnlock(sKextInnerLock);
7173
7174 return kIOReturnSuccess;
7175}
7176
7177};
7178
7179
7180#if PRAGMA_MARK
7181#pragma mark Prelinked Kernel
7182#endif
7183/*********************************************************************
7184* Do not access sConsiderUnloads... variables other than
7185* sConsiderUnloadsExecuted in this function. They are guarded by a
7186* different lock.
7187*********************************************************************/
7188/* static */
7189void
7190OSKext::considerRebuildOfPrelinkedKernel(void)
7191{
7192 static bool requestedPrelink = false;
7193 OSReturn checkResult = kOSReturnError;
7194 OSDictionary * prelinkRequest = NULL; // must release
7195 OSCollectionIterator * kextIterator = NULL; // must release
7196 const OSSymbol * thisID = NULL; // do not release
7197 bool doRebuild = false;
7198 AbsoluteTime my_abstime;
7199 UInt64 my_ns;
7200 SInt32 delta_secs;
7201
7202 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
7203 if (requestedPrelink || !sPrelinkBoot) {
7204 return;
7205 }
7206
7207 /* no direct return from this point */
7208 IORecursiveLockLock(sKextLock);
7209
7210 /* We need to wait for kextd to get up and running with unloads already done
7211 * and any new startup kexts loaded.
7212 */
7213 if (!sConsiderUnloadsExecuted ||
7214 !sDeferredLoadSucceeded) {
7215 goto finish;
7216 }
7217
7218 /* we really only care about boot / system start up related kexts so bail
7219 * if we're here after REBUILD_MAX_TIME.
7220 */
7221 if (!_OSKextInPrelinkRebuildWindow()) {
7222 OSKextLog(/* kext */ NULL,
7223 kOSKextLogArchiveFlag,
7224 "%s prebuild rebuild has expired",
7225 __FUNCTION__);
7226 requestedPrelink = true;
7227 goto finish;
7228 }
7229
7230 /* we do not want to trigger a rebuild if we get here too close to waking
7231 * up. (see radar 10233768)
7232 */
7233 IORecursiveLockLock(sKextInnerLock);
7234
7235 clock_get_uptime(&my_abstime);
7236 delta_secs = MINIMUM_WAKEUP_SECONDS + 1;
7237 if (AbsoluteTime_to_scalar(&sLastWakeTime) != 0) {
7238 SUB_ABSOLUTETIME(&my_abstime, &sLastWakeTime);
7239 absolutetime_to_nanoseconds(my_abstime, &my_ns);
7240 delta_secs = (SInt32)(my_ns / NSEC_PER_SEC);
7241 }
7242 IORecursiveLockUnlock(sKextInnerLock);
7243
7244 if (delta_secs < MINIMUM_WAKEUP_SECONDS) {
7245 /* too close to time of last wake from sleep */
7246 goto finish;
7247 }
7248 requestedPrelink = true;
7249
7250 /* Now it's time to see if we have a reason to rebuild. We may have done
7251 * some loads and unloads but the kernel cache didn't actually change.
7252 * We will rebuild if any kext is not marked prelinked AND is not in our
7253 * list of prelinked kexts that got unloaded. (see radar 9055303)
7254 */
7255 kextIterator = OSCollectionIterator::withCollection(sKextsByID);
7256 if (!kextIterator) {
7257 goto finish;
7258 }
7259
7260 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
7261 OSKext * thisKext; // do not release
7262
7263 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
7264 if (!thisKext || thisKext->isPrelinked() || thisKext->isKernel()) {
7265 continue;
7266 }
7267
7268 if (_OSKextInUnloadedPrelinkedKexts(thisKext->bundleID)) {
7269 continue;
7270 }
7271 /* kext is loaded and was not in current kernel cache so let's rebuild
7272 */
7273 doRebuild = true;
7274 OSKextLog(/* kext */ NULL,
7275 kOSKextLogArchiveFlag,
7276 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
7277 thisKext->bundleID->getCStringNoCopy());
7278 break;
7279 }
7280 sUnloadedPrelinkedKexts->flushCollection();
7281
7282 if (!doRebuild) {
7283 goto finish;
7284 }
7285
7286 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
7287 &prelinkRequest);
7288 if (checkResult != kOSReturnSuccess) {
7289 goto finish;
7290 }
7291
7292 if (!sKernelRequests->setObject(prelinkRequest)) {
7293 goto finish;
7294 }
7295
7296 OSKext::pingKextd();
7297
7298finish:
7299 IORecursiveLockUnlock(sKextLock);
7300 OSSafeReleaseNULL(prelinkRequest);
7301 OSSafeReleaseNULL(kextIterator);
7302
7303 return;
7304}
7305
7306#if PRAGMA_MARK
7307#pragma mark Dependencies
7308#endif
7309/*********************************************************************
7310*********************************************************************/
7311bool
7312OSKext::resolveDependencies(
7313 OSArray * loopStack)
7314{
7315 bool result = false;
7316 OSArray * localLoopStack = NULL; // must release
7317 bool addedToLoopStack = false;
7318 OSDictionary * libraries = NULL; // do not release
7319 OSCollectionIterator * libraryIterator = NULL; // must release
7320 OSString * libraryID = NULL; // do not release
7321 OSString * infoString = NULL; // do not release
7322 OSString * readableString = NULL; // do not release
7323 OSKext * libraryKext = NULL; // do not release
7324 bool hasRawKernelDependency = false;
7325 bool hasKernelDependency = false;
7326 bool hasKPIDependency = false;
7327 bool hasPrivateKPIDependency = false;
7328 unsigned int count;
7329
7330 /* A kernel component will automatically have this flag set,
7331 * and a loaded kext should also have it set (as should all its
7332 * loaded dependencies).
7333 */
7334 if (flags.hasAllDependencies) {
7335 result = true;
7336 goto finish;
7337 }
7338
7339 /* Check for loops in the dependency graph.
7340 */
7341 if (loopStack) {
7342 if (loopStack->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
7343 OSKextLog(this,
7344 kOSKextLogErrorLevel |
7345 kOSKextLogDependenciesFlag,
7346 "Kext %s has a dependency loop; can't resolve dependencies.",
7347 getIdentifierCString());
7348 goto finish;
7349 }
7350 } else {
7351 OSKextLog(this,
7352 kOSKextLogStepLevel |
7353 kOSKextLogDependenciesFlag,
7354 "Kext %s resolving dependencies.",
7355 getIdentifierCString());
7356
7357 loopStack = OSArray::withCapacity(6); // any small capacity will do
7358 if (!loopStack) {
7359 OSKextLog(this,
7360 kOSKextLogErrorLevel |
7361 kOSKextLogDependenciesFlag,
7362 "Kext %s can't create bookkeeping stack to resolve dependencies.",
7363 getIdentifierCString());
7364 goto finish;
7365 }
7366 localLoopStack = loopStack;
7367 }
7368 if (!loopStack->setObject(this)) {
7369 OSKextLog(this,
7370 kOSKextLogErrorLevel |
7371 kOSKextLogDependenciesFlag,
7372 "Kext %s - internal error resolving dependencies.",
7373 getIdentifierCString());
7374 goto finish;
7375 }
7376 addedToLoopStack = true;
7377
7378 /* Purge any existing kexts in the dependency list and start over.
7379 */
7380 flushDependencies();
7381 if (dependencies) {
7382 OSKextLog(this,
7383 kOSKextLogErrorLevel |
7384 kOSKextLogDependenciesFlag,
7385 "Kext %s - internal error resolving dependencies.",
7386 getIdentifierCString());
7387 }
7388
7389 libraries = OSDynamicCast(OSDictionary,
7390 getPropertyForHostArch(kOSBundleLibrariesKey));
7391 if (libraries == NULL || libraries->getCount() == 0) {
7392 OSKextLog(this,
7393 kOSKextLogErrorLevel |
7394 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
7395 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
7396 getIdentifierCString(), kOSBundleLibrariesKey);
7397 goto finish;
7398 }
7399
7400 /* Make a new array to hold the dependencies (flush freed the old one).
7401 */
7402 dependencies = OSArray::withCapacity(libraries->getCount());
7403 if (!dependencies) {
7404 OSKextLog(this,
7405 kOSKextLogErrorLevel |
7406 kOSKextLogDependenciesFlag,
7407 "Kext %s - can't allocate dependencies array.",
7408 getIdentifierCString());
7409 goto finish;
7410 }
7411
7412 // xxx - compat: We used to add an implicit dependency on kernel 6.0
7413 // xxx - compat: if none were declared.
7414
7415 libraryIterator = OSCollectionIterator::withCollection(libraries);
7416 if (!libraryIterator) {
7417 OSKextLog(this,
7418 kOSKextLogErrorLevel |
7419 kOSKextLogDependenciesFlag,
7420 "Kext %s - can't allocate dependencies iterator.",
7421 getIdentifierCString());
7422 goto finish;
7423 }
7424
7425 while ((libraryID = OSDynamicCast(OSString,
7426 libraryIterator->getNextObject()))) {
7427
7428 const char * library_id = libraryID->getCStringNoCopy();
7429
7430 OSString * libraryVersion = OSDynamicCast(OSString,
7431 libraries->getObject(libraryID));
7432 if (libraryVersion == NULL) {
7433 OSKextLog(this,
7434 kOSKextLogErrorLevel |
7435 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
7436 "Kext %s - illegal type in OSBundleLibraries.",
7437 getIdentifierCString());
7438 goto finish;
7439 }
7440
7441 OSKextVersion libraryVers =
7442 OSKextParseVersionString(libraryVersion->getCStringNoCopy());
7443 if (libraryVers == -1) {
7444 OSKextLog(this,
7445 kOSKextLogErrorLevel |
7446 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
7447 "Kext %s - invalid library version %s.",
7448 getIdentifierCString(),
7449 libraryVersion->getCStringNoCopy());
7450 goto finish;
7451 }
7452
7453 libraryKext = OSDynamicCast(OSKext, sKextsByID->getObject(libraryID));
7454 if (libraryKext == NULL) {
7455 OSKextLog(this,
7456 kOSKextLogErrorLevel |
7457 kOSKextLogDependenciesFlag,
7458 "Kext %s - library kext %s not found.",
7459 getIdentifierCString(), library_id);
7460 goto finish;
7461 }
7462
7463 if (!libraryKext->isCompatibleWithVersion(libraryVers)) {
7464 OSKextLog(this,
7465 kOSKextLogErrorLevel |
7466 kOSKextLogDependenciesFlag,
7467 "Kext %s - library kext %s not compatible "
7468 "with requested version %s.",
7469 getIdentifierCString(), library_id,
7470 libraryVersion->getCStringNoCopy());
7471 goto finish;
7472 }
7473
7474 /* If a nonprelinked library somehow got into the mix for a
7475 * prelinked kext, at any point in the chain, we must fail
7476 * because the prelinked relocs for the library will be all wrong.
7477 */
7478 if (this->isPrelinked() &&
7479 libraryKext->declaresExecutable() &&
7480 !libraryKext->isPrelinked()) {
7481
7482 OSKextLog(this,
7483 kOSKextLogErrorLevel |
7484 kOSKextLogDependenciesFlag,
7485 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
7486 getIdentifierCString(), library_id,
7487 libraryVersion->getCStringNoCopy());
7488 goto finish;
7489 }
7490
7491 if (!libraryKext->resolveDependencies(loopStack)) {
7492 goto finish;
7493 }
7494
7495 /* Add the library directly only if it has an executable to link.
7496 * Otherwise it's just used to collect other dependencies, so put
7497 * *its* dependencies on the list for this kext.
7498 */
7499 // xxx - We are losing info here; would like to make fake entries or
7500 // xxx - keep these in the dependency graph for loaded kexts.
7501 // xxx - I really want to make kernel components not a special case!
7502 if (libraryKext->declaresExecutable() ||
7503 libraryKext->isInterface()) {
7504
7505 if (dependencies->getNextIndexOfObject(libraryKext, 0) == (unsigned)-1) {
7506 dependencies->setObject(libraryKext);
7507
7508 OSKextLog(this,
7509 kOSKextLogDetailLevel |
7510 kOSKextLogDependenciesFlag,
7511 "Kext %s added dependency %s.",
7512 getIdentifierCString(),
7513 libraryKext->getIdentifierCString());
7514 }
7515 } else {
7516 int numLibDependencies = libraryKext->getNumDependencies();
7517 OSArray * libraryDependencies = libraryKext->getDependencies();
7518 int index;
7519
7520 if (numLibDependencies) {
7521 // xxx - this msg level should be 1 lower than the per-kext one
7522 OSKextLog(this,
7523 kOSKextLogDetailLevel |
7524 kOSKextLogDependenciesFlag,
7525 "Kext %s pulling %d dependencies from codeless library %s.",
7526 getIdentifierCString(),
7527 numLibDependencies,
7528 libraryKext->getIdentifierCString());
7529 }
7530 for (index = 0; index < numLibDependencies; index++) {
7531 OSKext * thisLibDependency = OSDynamicCast(OSKext,
7532 libraryDependencies->getObject(index));
7533 if (dependencies->getNextIndexOfObject(thisLibDependency, 0) == (unsigned)-1) {
7534 dependencies->setObject(thisLibDependency);
7535 OSKextLog(this,
7536 kOSKextLogDetailLevel |
7537 kOSKextLogDependenciesFlag,
7538 "Kext %s added dependency %s from codeless library %s.",
7539 getIdentifierCString(),
7540 thisLibDependency->getIdentifierCString(),
7541 libraryKext->getIdentifierCString());
7542 }
7543 }
7544 }
7545
7546 if ((strlen(library_id) == strlen(KERNEL_LIB)) &&
7547 0 == strncmp(library_id, KERNEL_LIB, sizeof(KERNEL_LIB)-1)) {
7548
7549 hasRawKernelDependency = true;
7550 } else if (STRING_HAS_PREFIX(library_id, KERNEL_LIB_PREFIX)) {
7551 hasKernelDependency = true;
7552 } else if (STRING_HAS_PREFIX(library_id, KPI_LIB_PREFIX)) {
7553 hasKPIDependency = true;
7554 if (!strncmp(library_id, PRIVATE_KPI, sizeof(PRIVATE_KPI)-1)) {
7555 hasPrivateKPIDependency = true;
7556 }
7557 }
7558 }
7559
7560 if (hasRawKernelDependency) {
7561 OSKextLog(this,
7562 kOSKextLogErrorLevel |
7563 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
7564 "Error - kext %s declares a dependency on %s, which is not permitted.",
7565 getIdentifierCString(), KERNEL_LIB);
7566 goto finish;
7567 }
7568#if __LP64__
7569 if (hasKernelDependency) {
7570 OSKextLog(this,
7571 kOSKextLogErrorLevel |
7572 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
7573 "Error - kext %s declares %s dependencies. "
7574 "Only %s* dependencies are supported for 64-bit kexts.",
7575 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
7576 goto finish;
7577 }
7578 if (!hasKPIDependency) {
7579 OSKextLog(this,
7580 kOSKextLogWarningLevel |
7581 kOSKextLogDependenciesFlag,
7582 "Warning - kext %s declares no %s* dependencies. "
7583 "If it uses any KPIs, the link may fail with undefined symbols.",
7584 getIdentifierCString(), KPI_LIB_PREFIX);
7585 }
7586#else /* __LP64__ */
7587 // xxx - will change to flatly disallow "kernel" dependencies at some point
7588 // xxx - is it invalid to do both "com.apple.kernel" and any
7589 // xxx - "com.apple.kernel.*"?
7590
7591 if (hasKernelDependency && hasKPIDependency) {
7592 OSKextLog(this,
7593 kOSKextLogWarningLevel |
7594 kOSKextLogDependenciesFlag,
7595 "Warning - kext %s has immediate dependencies on both "
7596 "%s* and %s* components; use only one style.",
7597 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
7598 }
7599
7600 if (!hasKernelDependency && !hasKPIDependency) {
7601 // xxx - do we want to use validation flag for these too?
7602 OSKextLog(this,
7603 kOSKextLogWarningLevel |
7604 kOSKextLogDependenciesFlag,
7605 "Warning - %s declares no kernel dependencies; using %s.",
7606 getIdentifierCString(), KERNEL6_LIB);
7607 OSKext * kernelKext = OSDynamicCast(OSKext,
7608 sKextsByID->getObject(KERNEL6_LIB));
7609 if (kernelKext) {
7610 dependencies->setObject(kernelKext);
7611 } else {
7612 OSKextLog(this,
7613 kOSKextLogErrorLevel |
7614 kOSKextLogDependenciesFlag,
7615 "Error - Library %s not found for %s.",
7616 KERNEL6_LIB, getIdentifierCString());
7617 }
7618 }
7619
7620 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
7621 * its indirect dependencies to simulate old-style linking. XXX - Should
7622 * check for duplicates.
7623 */
7624 if (!hasKPIDependency) {
7625 unsigned int i;
7626
7627 flags.hasBleedthrough = true;
7628
7629 count = getNumDependencies();
7630
7631 /* We add to the dependencies array in this loop, but do not iterate
7632 * past its original count.
7633 */
7634 for (i = 0; i < count; i++) {
7635 OSKext * dependencyKext = OSDynamicCast(OSKext,
7636 dependencies->getObject(i));
7637 dependencyKext->addBleedthroughDependencies(dependencies);
7638 }
7639 }
7640#endif /* __LP64__ */
7641
7642 if (hasPrivateKPIDependency) {
7643 bool hasApplePrefix = false;
7644 bool infoCopyrightIsValid = false;
7645 bool readableCopyrightIsValid = false;
7646
7647 hasApplePrefix = STRING_HAS_PREFIX(getIdentifierCString(),
7648 APPLE_KEXT_PREFIX);
7649
7650 infoString = OSDynamicCast(OSString,
7651 getPropertyForHostArch("CFBundleGetInfoString"));
7652 if (infoString) {
7653 infoCopyrightIsValid =
7654 kxld_validate_copyright_string(infoString->getCStringNoCopy());
7655 }
7656
7657 readableString = OSDynamicCast(OSString,
7658 getPropertyForHostArch("NSHumanReadableCopyright"));
7659 if (readableString) {
7660 readableCopyrightIsValid =
7661 kxld_validate_copyright_string(readableString->getCStringNoCopy());
7662 }
7663
7664 if (!hasApplePrefix || (!infoCopyrightIsValid && !readableCopyrightIsValid)) {
7665 OSKextLog(this,
7666 kOSKextLogErrorLevel |
7667 kOSKextLogDependenciesFlag,
7668 "Error - kext %s declares a dependency on %s. "
7669 "Only Apple kexts may declare a dependency on %s.",
7670 getIdentifierCString(), PRIVATE_KPI, PRIVATE_KPI);
7671 goto finish;
7672 }
7673 }
7674
7675 result = true;
7676 flags.hasAllDependencies = 1;
7677
7678finish:
7679
7680 if (addedToLoopStack) {
7681 count = loopStack->getCount();
7682 if (count > 0 && (this == loopStack->getObject(count - 1))) {
7683 loopStack->removeObject(count - 1);
7684 } else {
7685 OSKextLog(this,
7686 kOSKextLogErrorLevel |
7687 kOSKextLogDependenciesFlag,
7688 "Kext %s - internal error resolving dependencies.",
7689 getIdentifierCString());
7690 }
7691 }
7692
7693 if (result && localLoopStack) {
7694 OSKextLog(this,
7695 kOSKextLogStepLevel |
7696 kOSKextLogDependenciesFlag,
7697 "Kext %s successfully resolved dependencies.",
7698 getIdentifierCString());
7699 }
7700
7701 OSSafeReleaseNULL(localLoopStack);
7702 OSSafeReleaseNULL(libraryIterator);
7703
7704 return result;
7705}
7706
7707/*********************************************************************
7708*********************************************************************/
7709bool
7710OSKext::addBleedthroughDependencies(OSArray * anArray)
7711{
7712 bool result = false;
7713 unsigned int dependencyIndex, dependencyCount;
7714
7715 dependencyCount = getNumDependencies();
7716
7717 for (dependencyIndex = 0;
7718 dependencyIndex < dependencyCount;
7719 dependencyIndex++) {
7720
7721 OSKext * dependency = OSDynamicCast(OSKext,
7722 dependencies->getObject(dependencyIndex));
7723 if (!dependency) {
7724 OSKextLog(this,
7725 kOSKextLogErrorLevel |
7726 kOSKextLogDependenciesFlag,
7727 "Kext %s - internal error propagating compatibility dependencies.",
7728 getIdentifierCString());
7729 goto finish;
7730 }
7731 if (anArray->getNextIndexOfObject(dependency, 0) == (unsigned int)-1) {
7732 anArray->setObject(dependency);
7733 }
7734 dependency->addBleedthroughDependencies(anArray);
7735 }
7736
7737 result = true;
7738
7739finish:
7740 return result;
7741}
7742
7743/*********************************************************************
7744*********************************************************************/
7745bool
7746OSKext::flushDependencies(bool forceFlag)
7747{
7748 bool result = false;
7749
7750 /* Only clear the dependencies if the kext isn't loaded;
7751 * we need the info for loaded kexts to track references.
7752 */
7753 if (!isLoaded() || forceFlag) {
7754 if (dependencies) {
7755 // xxx - check level
7756 OSKextLog(this,
7757 kOSKextLogProgressLevel |
7758 kOSKextLogDependenciesFlag,
7759 "Kext %s flushing dependencies.",
7760 getIdentifierCString());
7761 OSSafeReleaseNULL(dependencies);
7762
7763 }
7764 if (!isKernelComponent()) {
7765 flags.hasAllDependencies = 0;
7766 }
7767 result = true;
7768 }
7769
7770 return result;
7771}
7772
7773/*********************************************************************
7774*********************************************************************/
7775uint32_t
7776OSKext::getNumDependencies(void)
7777{
7778 if (!dependencies) {
7779 return 0;
7780 }
7781 return dependencies->getCount();
7782}
7783
7784/*********************************************************************
7785*********************************************************************/
7786OSArray *
7787OSKext::getDependencies(void)
7788{
7789 return dependencies;
7790}
7791
7792#if PRAGMA_MARK
7793#pragma mark OSMetaClass Support
7794#endif
7795/*********************************************************************
7796*********************************************************************/
7797OSReturn
7798OSKext::addClass(
7799 OSMetaClass * aClass,
7800 uint32_t numClasses)
7801{
7802 OSReturn result = kOSMetaClassNoInsKModSet;
7803
7804 if (!metaClasses) {
7805 metaClasses = OSSet::withCapacity(numClasses);
7806 if (!metaClasses) {
7807 goto finish;
7808 }
7809 }
7810
7811 if (metaClasses->containsObject(aClass)) {
7812 OSKextLog(this,
7813 kOSKextLogWarningLevel |
7814 kOSKextLogLoadFlag,
7815 "Notice - kext %s has already registered class %s.",
7816 getIdentifierCString(),
7817 aClass->getClassName());
7818 result = kOSReturnSuccess;
7819 goto finish;
7820 }
7821
7822 if (!metaClasses->setObject(aClass)) {
7823 goto finish;
7824 } else {
7825 OSKextLog(this,
7826 kOSKextLogDetailLevel |
7827 kOSKextLogLoadFlag,
7828 "Kext %s registered class %s.",
7829 getIdentifierCString(),
7830 aClass->getClassName());
7831 }
7832
7833 if (!flags.autounloadEnabled) {
7834 const OSMetaClass * metaScan = NULL; // do not release
7835
7836 for (metaScan = aClass; metaScan; metaScan = metaScan->getSuperClass()) {
7837 if (metaScan == OSTypeID(IOService)) {
7838
7839 OSKextLog(this,
7840 kOSKextLogProgressLevel |
7841 kOSKextLogLoadFlag,
7842 "Kext %s has IOService subclass %s; enabling autounload.",
7843 getIdentifierCString(),
7844 aClass->getClassName());
7845
7846 flags.autounloadEnabled = 1;
7847 break;
7848 }
7849 }
7850 }
7851
7852 notifyAddClassObservers(this, aClass, flags);
7853
7854 result = kOSReturnSuccess;
7855
7856finish:
7857 if (result != kOSReturnSuccess) {
7858 OSKextLog(this,
7859 kOSKextLogErrorLevel |
7860 kOSKextLogLoadFlag,
7861 "Kext %s failed to register class %s.",
7862 getIdentifierCString(),
7863 aClass->getClassName());
7864 }
7865
7866 return result;
7867}
7868
7869/*********************************************************************
7870*********************************************************************/
7871OSReturn
7872OSKext::removeClass(
7873 OSMetaClass * aClass)
7874{
7875 OSReturn result = kOSMetaClassNoKModSet;
7876
7877 if (!metaClasses) {
7878 goto finish;
7879 }
7880
7881 if (!metaClasses->containsObject(aClass)) {
7882 OSKextLog(this,
7883 kOSKextLogWarningLevel |
7884 kOSKextLogLoadFlag,
7885 "Notice - kext %s asked to unregister unknown class %s.",
7886 getIdentifierCString(),
7887 aClass->getClassName());
7888 result = kOSReturnSuccess;
7889 goto finish;
7890 }
7891
7892 OSKextLog(this,
7893 kOSKextLogDetailLevel |
7894 kOSKextLogLoadFlag,
7895 "Kext %s unregistering class %s.",
7896 getIdentifierCString(),
7897 aClass->getClassName());
7898
7899 metaClasses->removeObject(aClass);
7900
7901 notifyRemoveClassObservers(this, aClass, flags);
7902
7903 result = kOSReturnSuccess;
7904
7905finish:
7906 if (result != kOSReturnSuccess) {
7907 OSKextLog(this,
7908 kOSKextLogErrorLevel |
7909 kOSKextLogLoadFlag,
7910 "Failed to unregister kext %s class %s.",
7911 getIdentifierCString(),
7912 aClass->getClassName());
7913 }
7914 return result;
7915}
7916
7917/*********************************************************************
7918*********************************************************************/
7919OSSet *
7920OSKext::getMetaClasses(void)
7921{
7922 return metaClasses;
7923}
7924
7925/*********************************************************************
7926*********************************************************************/
7927bool
7928OSKext::hasOSMetaClassInstances(void)
7929{
7930 bool result = false;
7931 OSCollectionIterator * classIterator = NULL; // must release
7932 OSMetaClass * checkClass = NULL; // do not release
7933
7934 if (!metaClasses) {
7935 goto finish;
7936 }
7937
7938 classIterator = OSCollectionIterator::withCollection(metaClasses);
7939 if (!classIterator) {
7940 // xxx - log alloc failure?
7941 goto finish;
7942 }
7943 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
7944 if (checkClass->getInstanceCount()) {
7945 result = true;
7946 goto finish;
7947 }
7948 }
7949
7950finish:
7951
7952 OSSafeReleaseNULL(classIterator);
7953 return result;
7954}
7955
7956/*********************************************************************
7957*********************************************************************/
7958/* static */
7959void
7960OSKext::reportOSMetaClassInstances(
7961 const char * kextIdentifier,
7962 OSKextLogSpec msgLogSpec)
7963{
7964 OSKext * theKext = NULL; // must release
7965
7966 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
7967 if (!theKext) {
7968 goto finish;
7969 }
7970
7971 theKext->reportOSMetaClassInstances(msgLogSpec);
7972finish:
7973 OSSafeReleaseNULL(theKext);
7974 return;
7975}
7976
7977/*********************************************************************
7978*********************************************************************/
7979void
7980OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
7981{
7982 OSCollectionIterator * classIterator = NULL; // must release
7983 OSMetaClass * checkClass = NULL; // do not release
7984
7985 if (!metaClasses) {
7986 goto finish;
7987 }
7988
7989 classIterator = OSCollectionIterator::withCollection(metaClasses);
7990 if (!classIterator) {
7991 goto finish;
7992 }
7993 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
7994 if (checkClass->getInstanceCount()) {
7995 OSKextLog(this,
7996 msgLogSpec,
7997 " Kext %s class %s has %d instance%s.",
7998 getIdentifierCString(),
7999 checkClass->getClassName(),
8000 checkClass->getInstanceCount(),
8001 checkClass->getInstanceCount() == 1 ? "" : "s");
8002 }
8003 }
8004
8005finish:
8006 OSSafeReleaseNULL(classIterator);
8007 return;
8008}
8009
8010#if PRAGMA_MARK
8011#pragma mark User-Space Requests
8012#endif
8013/*********************************************************************
8014* XXX - this function is a big ugly mess
8015*********************************************************************/
8016/* static */
8017OSReturn
8018OSKext::handleRequest(
8019 host_priv_t hostPriv,
8020 OSKextLogSpec clientLogFilter,
8021 char * requestBuffer,
8022 uint32_t requestLength,
8023 char ** responseOut,
8024 uint32_t * responseLengthOut,
8025 char ** logInfoOut,
8026 uint32_t * logInfoLengthOut)
8027{
8028 OSReturn result = kOSReturnError;
8029 kern_return_t kmem_result = KERN_FAILURE;
8030
8031 char * response = NULL; // returned by reference
8032 uint32_t responseLength = 0;
8033
8034 OSObject * parsedXML = NULL; // must release
8035 OSDictionary * requestDict = NULL; // do not release
8036 OSString * errorString = NULL; // must release
8037
8038 OSObject * responseObject = NULL; // must release
8039
8040 OSSerialize * serializer = NULL; // must release
8041
8042 OSArray * logInfoArray = NULL; // must release
8043
8044 OSString * predicate = NULL; // do not release
8045 OSString * kextIdentifier = NULL; // do not release
8046 OSArray * kextIdentifiers = NULL; // do not release
8047 OSKext * theKext = NULL; // do not release
8048 OSBoolean * boolArg = NULL; // do not release
8049
8050 IORecursiveLockLock(sKextLock);
8051
8052 if (responseOut) {
8053 *responseOut = NULL;
8054 *responseLengthOut = 0;
8055 }
8056 if (logInfoOut) {
8057 *logInfoOut = NULL;
8058 *logInfoLengthOut = 0;
8059 }
8060
8061 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
8062
8063 /* XML must be nul-terminated.
8064 */
8065 if (requestBuffer[requestLength - 1] != '\0') {
8066 OSKextLog(/* kext */ NULL,
8067 kOSKextLogErrorLevel |
8068 kOSKextLogIPCFlag,
8069 "Invalid request from user space (not nul-terminated).");
8070 result = kOSKextReturnBadData;
8071 goto finish;
8072 }
8073 parsedXML = OSUnserializeXML((const char *)requestBuffer, &errorString);
8074 if (parsedXML) {
8075 requestDict = OSDynamicCast(OSDictionary, parsedXML);
8076 }
8077 if (!requestDict) {
8078 const char * errorCString = "(unknown error)";
8079
8080 if (errorString && errorString->getCStringNoCopy()) {
8081 errorCString = errorString->getCStringNoCopy();
8082 } else if (parsedXML) {
8083 errorCString = "not a dictionary";
8084 }
8085 OSKextLog(/* kext */ NULL,
8086 kOSKextLogErrorLevel |
8087 kOSKextLogIPCFlag,
8088 "Error unserializing request from user space: %s.",
8089 errorCString);
8090 result = kOSKextReturnSerialization;
8091 goto finish;
8092 }
8093
8094 predicate = _OSKextGetRequestPredicate(requestDict);
8095 if (!predicate) {
8096 OSKextLog(/* kext */ NULL,
8097 kOSKextLogErrorLevel |
8098 kOSKextLogIPCFlag,
8099 "Recieved kext request from user space with no predicate.");
8100 result = kOSKextReturnInvalidArgument;
8101 goto finish;
8102 }
8103
8104 OSKextLog(/* kext */ NULL,
8105 kOSKextLogDebugLevel |
8106 kOSKextLogIPCFlag,
8107 "Received '%s' request from user space.",
8108 predicate->getCStringNoCopy());
8109
8110 result = kOSKextReturnNotPrivileged;
8111 if (hostPriv == HOST_PRIV_NULL) {
8112 /* must be root to use these kext requests */
8113 if (predicate->isEqualTo(kKextRequestPredicateUnload) ||
8114 predicate->isEqualTo(kKextRequestPredicateStart) ||
8115 predicate->isEqualTo(kKextRequestPredicateStop) ||
8116 predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
8117 predicate->isEqualTo(kKextRequestPredicateSendResource) ) {
8118 OSKextLog(/* kext */ NULL,
8119 kOSKextLogErrorLevel |
8120 kOSKextLogIPCFlag,
8121 "Access Failure - must be root user.");
8122 goto finish;
8123 }
8124 }
8125
8126 /* Get common args in anticipation of use.
8127 */
8128 kextIdentifier = OSDynamicCast(OSString, _OSKextGetRequestArgument(
8129 requestDict, kKextRequestArgumentBundleIdentifierKey));
8130 kextIdentifiers = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
8131 requestDict, kKextRequestArgumentBundleIdentifierKey));
8132 if (kextIdentifier) {
8133 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
8134 }
8135 boolArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
8136 requestDict, kKextRequestArgumentValueKey));
8137
8138 result = kOSKextReturnInvalidArgument;
8139
8140 if (predicate->isEqualTo(kKextRequestPredicateStart)) {
8141 if (!kextIdentifier) {
8142 OSKextLog(/* kext */ NULL,
8143 kOSKextLogErrorLevel |
8144 kOSKextLogIPCFlag,
8145 "Invalid arguments to kext start request.");
8146 } else if (!theKext) {
8147 OSKextLog(/* kext */ NULL,
8148 kOSKextLogErrorLevel |
8149 kOSKextLogIPCFlag,
8150 "Kext %s not found for start request.",
8151 kextIdentifier->getCStringNoCopy());
8152 result = kOSKextReturnNotFound;
8153 } else {
8154 result = theKext->start();
8155 }
8156
8157 } else if (predicate->isEqualTo(kKextRequestPredicateStop)) {
8158 if (!kextIdentifier) {
8159 OSKextLog(/* kext */ NULL,
8160 kOSKextLogErrorLevel |
8161 kOSKextLogIPCFlag,
8162 "Invalid arguments to kext stop request.");
8163 } else if (!theKext) {
8164 OSKextLog(/* kext */ NULL,
8165 kOSKextLogErrorLevel |
8166 kOSKextLogIPCFlag,
8167 "Kext %s not found for stop request.",
8168 kextIdentifier->getCStringNoCopy());
8169 result = kOSKextReturnNotFound;
8170 } else {
8171 result = theKext->stop();
8172 }
8173
8174 } else if (predicate->isEqualTo(kKextRequestPredicateUnload)) {
8175 if (!kextIdentifier) {
8176 OSKextLog(/* kext */ NULL,
8177 kOSKextLogErrorLevel |
8178 kOSKextLogIPCFlag,
8179 "Invalid arguments to kext unload request.");
8180 } else if (!theKext) {
8181 OSKextLog(/* kext */ NULL,
8182 kOSKextLogErrorLevel |
8183 kOSKextLogIPCFlag,
8184 "Kext %s not found for unload request.",
8185 kextIdentifier->getCStringNoCopy());
8186 result = kOSKextReturnNotFound;
8187 } else {
8188 OSBoolean * terminateFlag = OSDynamicCast(OSBoolean,
8189 _OSKextGetRequestArgument(requestDict,
8190 kKextRequestArgumentTerminateIOServicesKey));
8191 result = OSKext::removeKext(theKext, terminateFlag == kOSBooleanTrue);
8192 }
8193
8194 } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
8195 result = OSKext::dispatchResource(requestDict);
8196
8197 } else if (predicate->isEqualTo(kKextRequestPredicateGetUUIDByAddress)) {
8198
8199 OSNumber *lookupNum = NULL;
8200 lookupNum = OSDynamicCast(OSNumber,
8201 _OSKextGetRequestArgument(requestDict,
8202 kKextRequestArgumentLookupAddressKey));
8203
8204 responseObject = OSKext::copyKextUUIDForAddress(lookupNum);
8205 if (responseObject) {
8206 result = kOSReturnSuccess;
8207 } else {
8208 goto finish;
8209 }
8210
8211 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded) ||
8212 predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
8213 OSBoolean * delayAutounloadBool = NULL;
8214 OSObject * infoKeysRaw = NULL;
8215 OSArray * infoKeys = NULL;
8216 uint32_t infoKeysCount = 0;
8217
8218 delayAutounloadBool = OSDynamicCast(OSBoolean,
8219 _OSKextGetRequestArgument(requestDict,
8220 kKextRequestArgumentDelayAutounloadKey));
8221
8222 /* If asked to delay autounload, reset the timer if it's currently set.
8223 * (That is, don't schedule an unload if one isn't already pending.
8224 */
8225 if (delayAutounloadBool == kOSBooleanTrue) {
8226 OSKext::considerUnloads(/* rescheduleOnly? */ true);
8227 }
8228
8229 infoKeysRaw = _OSKextGetRequestArgument(requestDict,
8230 kKextRequestArgumentInfoKeysKey);
8231 infoKeys = OSDynamicCast(OSArray, infoKeysRaw);
8232 if (infoKeysRaw && !infoKeys) {
8233 OSKextLog(/* kext */ NULL,
8234 kOSKextLogErrorLevel |
8235 kOSKextLogIPCFlag,
8236 "Invalid arguments to kext info request.");
8237 goto finish;
8238 }
8239
8240 if (infoKeys) {
8241 infoKeysCount = infoKeys->getCount();
8242 for (uint32_t i = 0; i < infoKeysCount; i++) {
8243 if (!OSDynamicCast(OSString, infoKeys->getObject(i))) {
8244 OSKextLog(/* kext */ NULL,
8245 kOSKextLogErrorLevel |
8246 kOSKextLogIPCFlag,
8247 "Invalid arguments to kext info request.");
8248 goto finish;
8249 }
8250 }
8251 }
8252
8253 if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
8254 responseObject = OSKext::copyLoadedKextInfo(kextIdentifiers, infoKeys);
8255 }
8256 else if (predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
8257 responseObject = OSKext::copyLoadedKextInfoByUUID(kextIdentifiers, infoKeys);
8258 }
8259 if (!responseObject) {
8260 result = kOSKextReturnInternalError;
8261 } else {
8262 OSKextLog(/* kext */ NULL,
8263 kOSKextLogDebugLevel |
8264 kOSKextLogIPCFlag,
8265 "Returning loaded kext info.");
8266 result = kOSReturnSuccess;
8267 }
8268 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
8269
8270 /* Hand the current sKernelRequests array to the caller
8271 * (who must release it), and make a new one.
8272 */
8273 responseObject = sKernelRequests;
8274 sKernelRequests = OSArray::withCapacity(0);
8275 sPostedKextLoadIdentifiers->flushCollection();
8276 OSKextLog(/* kext */ NULL,
8277 kOSKextLogDebugLevel |
8278 kOSKextLogIPCFlag,
8279 "Returning kernel requests.");
8280 result = kOSReturnSuccess;
8281
8282 } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
8283
8284 /* Return the set of all requested bundle identifiers */
8285 responseObject = sAllKextLoadIdentifiers;
8286 responseObject->retain();
8287 OSKextLog(/* kext */ NULL,
8288 kOSKextLogDebugLevel |
8289 kOSKextLogIPCFlag,
8290 "Returning load requests.");
8291 result = kOSReturnSuccess;
8292 }
8293 else {
8294 OSKextLog(/* kext */ NULL,
8295 kOSKextLogDebugLevel |
8296 kOSKextLogIPCFlag,
8297 "Received '%s' invalid request from user space.",
8298 predicate->getCStringNoCopy());
8299 goto finish;
8300 }
8301
8302 /**********
8303 * Now we have handle the request, or not. Gather up the response & logging
8304 * info to ship to user space.
8305 *********/
8306
8307 /* Note: Nothing in OSKext is supposed to retain requestDict,
8308 * but you never know....
8309 */
8310 if (requestDict->getRetainCount() > 1) {
8311 OSKextLog(/* kext */ NULL,
8312 kOSKextLogWarningLevel |
8313 kOSKextLogIPCFlag,
8314 "Request from user space still retained by a kext; "
8315 "probable memory leak.");
8316 }
8317
8318 if (responseOut && responseObject) {
8319 serializer = OSSerialize::withCapacity(0);
8320 if (!serializer) {
8321 result = kOSKextReturnNoMemory;
8322 goto finish;
8323 }
8324
8325 if (!responseObject->serialize(serializer)) {
8326 OSKextLog(/* kext */ NULL,
8327 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
8328 "Failed to serialize response to request from user space.");
8329 result = kOSKextReturnSerialization;
8330 goto finish;
8331 }
8332
8333 response = (char *)serializer->text();
8334 responseLength = serializer->getLength();
8335 }
8336
8337 if (responseOut && response) {
8338 char * buffer;
8339
8340 /* This kmem_alloc sets the return value of the function.
8341 */
8342 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer,
8343 round_page(responseLength), VM_KERN_MEMORY_OSKEXT);
8344 if (kmem_result != KERN_SUCCESS) {
8345 OSKextLog(/* kext */ NULL,
8346 kOSKextLogErrorLevel |
8347 kOSKextLogIPCFlag,
8348 "Failed to copy response to request from user space.");
8349 result = kmem_result;
8350 goto finish;
8351 } else {
8352 /* 11981737 - clear uninitialized data in last page */
8353 bzero((void *)(buffer + responseLength),
8354 (round_page(responseLength) - responseLength));
8355 memcpy(buffer, response, responseLength);
8356 *responseOut = buffer;
8357 *responseLengthOut = responseLength;
8358 }
8359 }
8360
8361finish:
8362
8363 /* Gather up the collected log messages for user space. Any messages
8364 * messages past this call will not make it up as log messages but
8365 * will be in the system log. Note that we ignore the return of the
8366 * serialize; it has no bearing on the operation at hand even if we
8367 * fail to get the log messages.
8368 */
8369 logInfoArray = OSKext::clearUserSpaceLogFilter();
8370
8371 if (logInfoArray && logInfoOut && logInfoLengthOut) {
8372 (void)OSKext::serializeLogInfo(logInfoArray,
8373 logInfoOut, logInfoLengthOut);
8374 }
8375
8376 IORecursiveLockUnlock(sKextLock);
8377
8378 OSSafeReleaseNULL(parsedXML);
8379 OSSafeReleaseNULL(errorString);
8380 OSSafeReleaseNULL(responseObject);
8381 OSSafeReleaseNULL(serializer);
8382 OSSafeReleaseNULL(logInfoArray);
8383
8384 return result;
8385}
8386
8387
8388// #include <InstrProfiling.h>
8389extern "C" {
8390
8391 uint64_t __llvm_profile_get_size_for_buffer_internal(const char *DataBegin,
8392 const char *DataEnd,
8393 const char *CountersBegin,
8394 const char *CountersEnd ,
8395 const char *NamesBegin,
8396 const char *NamesEnd);
8397 int __llvm_profile_write_buffer_internal(char *Buffer,
8398 const char *DataBegin,
8399 const char *DataEnd,
8400 const char *CountersBegin,
8401 const char *CountersEnd ,
8402 const char *NamesBegin,
8403 const char *NamesEnd);
8404}
8405
8406
8407static
8408void OSKextPgoMetadataPut(char *pBuffer,
8409 size_t *position,
8410 size_t bufferSize,
8411 uint32_t *num_pairs,
8412 const char *key,
8413 const char *value)
8414{
8415 size_t strlen_key = strlen(key);
8416 size_t strlen_value = strlen(value);
8417 size_t len = strlen(key) + 1 + strlen(value) + 1;
8418 char *pos = pBuffer + *position;
8419 *position += len;
8420 if (pBuffer && bufferSize && *position <= bufferSize) {
8421 memcpy(pos, key, strlen_key); pos += strlen_key;
8422 *(pos++) = '=';
8423 memcpy(pos, value, strlen_value); pos += strlen_value;
8424 *(pos++) = 0;
8425 if (num_pairs) {
8426 (*num_pairs)++;
8427 }
8428 }
8429}
8430
8431
8432static
8433void OSKextPgoMetadataPutMax(size_t *position, const char *key, size_t value_max)
8434{
8435 *position += strlen(key) + 1 + value_max + 1;
8436}
8437
8438
8439static
8440void OSKextPgoMetadataPutAll(OSKext *kext,
8441 uuid_t instance_uuid,
8442 char *pBuffer,
8443 size_t *position,
8444 size_t bufferSize,
8445 uint32_t *num_pairs)
8446{
8447 _static_assert_1_arg(sizeof(clock_sec_t) % 2 == 0);
8448 //log_10 2^16 ≈ 4.82
8449 const size_t max_secs_string_size = 5 * sizeof(clock_sec_t)/2;
8450 const size_t max_timestamp_string_size = max_secs_string_size + 1 + 6;
8451
8452 if (!pBuffer) {
8453 OSKextPgoMetadataPutMax(position, "INSTANCE", 36);
8454 OSKextPgoMetadataPutMax(position, "UUID", 36);
8455 OSKextPgoMetadataPutMax(position, "TIMESTAMP", max_timestamp_string_size);
8456 } else {
8457 uuid_string_t instance_uuid_string;
8458 uuid_unparse(instance_uuid, instance_uuid_string);
8459 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
8460 "INSTANCE", instance_uuid_string);
8461
8462 OSData *uuid_data;
8463 uuid_t uuid;
8464 uuid_string_t uuid_string;
8465 uuid_data = kext->copyUUID();
8466 if (uuid_data) {
8467 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
8468 OSSafeReleaseNULL(uuid_data);
8469 uuid_unparse(uuid, uuid_string);
8470 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
8471 "UUID", uuid_string);
8472 }
8473
8474 clock_sec_t secs;
8475 clock_usec_t usecs;
8476 clock_get_calendar_microtime(&secs, &usecs);
8477 assert(usecs < 1000000);
8478 char timestamp[max_timestamp_string_size + 1];
8479 _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t));
8480 snprintf(timestamp, sizeof(timestamp), "%lu.%06d", (unsigned long)secs, (int)usecs);
8481 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
8482 "TIMESTAMP", timestamp);
8483 }
8484
8485 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
8486 "NAME", kext->getIdentifierCString());
8487
8488 char versionCString[kOSKextVersionMaxLength];
8489 OSKextVersionGetString(kext->getVersion(), versionCString, kOSKextVersionMaxLength);
8490 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
8491 "VERSION", versionCString);
8492
8493}
8494
8495static
8496size_t OSKextPgoMetadataSize(OSKext *kext)
8497{
8498 size_t position = 0;
8499 uuid_t fakeuuid = {};
8500 OSKextPgoMetadataPutAll(kext, fakeuuid, NULL, &position, 0, NULL);
8501 return position;
8502}
8503
8504int OSKextGrabPgoDataLocked(OSKext *kext,
8505 bool metadata,
8506 uuid_t instance_uuid,
8507 uint64_t *pSize,
8508 char *pBuffer,
8509 uint64_t bufferSize)
8510{
8511 int err = 0;
8512
8513 kernel_section_t *sect_prf_data = NULL;
8514 kernel_section_t *sect_prf_name = NULL;
8515 kernel_section_t *sect_prf_cnts = NULL;
8516 uint64_t size;
8517 size_t metadata_size = 0;
8518
8519 sect_prf_data = kext->lookupSection("__DATA", "__llvm_prf_data");
8520 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_name");
8521 sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
8522
8523 if (!sect_prf_data || !sect_prf_name || !sect_prf_cnts) {
8524 err = ENOTSUP;
8525 goto out;
8526 }
8527
8528 size = __llvm_profile_get_size_for_buffer_internal(
8529 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
8530 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
8531 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
8532
8533 if (metadata) {
8534 metadata_size = OSKextPgoMetadataSize(kext);
8535 size += metadata_size;
8536 size += sizeof(pgo_metadata_footer);
8537 }
8538
8539
8540 if (pSize) {
8541 *pSize = size;
8542 }
8543
8544 if (pBuffer && bufferSize) {
8545 if (bufferSize < size) {
8546 err = ERANGE;
8547 goto out;
8548 }
8549
8550 err = __llvm_profile_write_buffer_internal(
8551 pBuffer,
8552 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
8553 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
8554 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
8555
8556 if (err) {
8557 err = EIO;
8558 goto out;
8559 }
8560
8561 if (metadata) {
8562 char *end_of_buffer = pBuffer + size;
8563 struct pgo_metadata_footer *footerp = (struct pgo_metadata_footer *) (end_of_buffer - sizeof(struct pgo_metadata_footer));
8564 char *metadata_buffer = end_of_buffer - (sizeof(struct pgo_metadata_footer) + metadata_size);
8565
8566 size_t metadata_position = 0;
8567 uint32_t num_pairs = 0;
8568 OSKextPgoMetadataPutAll(kext, instance_uuid, metadata_buffer, &metadata_position, metadata_size, &num_pairs);
8569 while (metadata_position < metadata_size) {
8570 metadata_buffer[metadata_position++] = 0;
8571 }
8572
8573 struct pgo_metadata_footer footer;
8574 footer.magic = htonl(0x6d657461);
8575 footer.number_of_pairs = htonl( num_pairs );
8576 footer.offset_to_pairs = htonl( sizeof(struct pgo_metadata_footer) + metadata_size );
8577 memcpy(footerp, &footer, sizeof(footer));
8578 }
8579
8580 }
8581
8582out:
8583 return err;
8584}
8585
8586
8587int
8588OSKextGrabPgoData(uuid_t uuid,
8589 uint64_t *pSize,
8590 char *pBuffer,
8591 uint64_t bufferSize,
8592 int wait_for_unload,
8593 int metadata)
8594{
8595 int err = 0;
8596 OSKext *kext = NULL;
8597
8598
8599 IORecursiveLockLock(sKextLock);
8600
8601 kext = OSKext::lookupKextWithUUID(uuid);
8602 if (!kext) {
8603 err = ENOENT;
8604 goto out;
8605 }
8606
8607 if (wait_for_unload) {
8608 OSKextGrabPgoStruct s;
8609
8610 s.metadata = metadata;
8611 s.pSize = pSize;
8612 s.pBuffer = pBuffer;
8613 s.bufferSize = bufferSize;
8614 s.err = EINTR;
8615
8616 struct list_head *prev = &kext->pendingPgoHead;
8617 struct list_head *next = kext->pendingPgoHead.next;
8618
8619 s.list_head.prev = prev;
8620 s.list_head.next = next;
8621
8622 prev->next = &s.list_head;
8623 next->prev = &s.list_head;
8624
8625 kext->release();
8626 kext = NULL;
8627
8628 IORecursiveLockSleep(sKextLock, &s, THREAD_ABORTSAFE);
8629
8630 prev = s.list_head.prev;
8631 next = s.list_head.next;
8632
8633 prev->next = next;
8634 next->prev = prev;
8635
8636 err = s.err;
8637
8638 } else {
8639 err = OSKextGrabPgoDataLocked(kext, metadata, kext->instance_uuid, pSize, pBuffer, bufferSize);
8640 }
8641
8642 out:
8643 if (kext) {
8644 kext->release();
8645 }
8646
8647 IORecursiveLockUnlock(sKextLock);
8648
8649 return err;
8650}
8651
8652void
8653OSKextResetPgoCountersLock()
8654{
8655 IORecursiveLockLock(sKextLock);
8656}
8657
8658void
8659OSKextResetPgoCountersUnlock()
8660{
8661 IORecursiveLockUnlock(sKextLock);
8662}
8663
8664
8665extern unsigned int not_in_kdp;
8666
8667void
8668OSKextResetPgoCounters()
8669{
8670 assert(!not_in_kdp);
8671 uint32_t count = sLoadedKexts->getCount();
8672 for (uint32_t i = 0; i < count; i++) {
8673 OSKext *kext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
8674 kernel_section_t *sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
8675 if (!sect_prf_cnts) {
8676 continue;
8677 }
8678 memset((void*)sect_prf_cnts->addr, 0, sect_prf_cnts->size);
8679 }
8680}
8681
8682OSDictionary *
8683OSKext::copyLoadedKextInfoByUUID(
8684 OSArray * kextIdentifiers,
8685 OSArray * infoKeys)
8686{
8687 OSDictionary * result = NULL;
8688 OSDictionary * kextInfo = NULL; // must release
8689 uint32_t count, i;
8690 uint32_t idCount = 0;
8691 uint32_t idIndex = 0;
8692
8693 IORecursiveLockLock(sKextLock);
8694
8695#if CONFIG_MACF
8696 /* Is the calling process allowed to query kext info? */
8697 if (current_task() != kernel_task) {
8698 int macCheckResult = 0;
8699 kauth_cred_t cred = NULL;
8700
8701 cred = kauth_cred_get_with_ref();
8702 macCheckResult = mac_kext_check_query(cred);
8703 kauth_cred_unref(&cred);
8704
8705 if (macCheckResult != 0) {
8706 OSKextLog(/* kext */ NULL,
8707 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
8708 "Failed to query kext info (MAC policy error 0x%x).",
8709 macCheckResult);
8710 goto finish;
8711 }
8712 }
8713#endif
8714
8715 /* Empty list of UUIDs is equivalent to no list (get all).
8716 */
8717 if (kextIdentifiers && !kextIdentifiers->getCount()) {
8718 kextIdentifiers = NULL;
8719 } else if (kextIdentifiers) {
8720 idCount = kextIdentifiers->getCount();
8721 }
8722
8723 /* Same for keys.
8724 */
8725 if (infoKeys && !infoKeys->getCount()) {
8726 infoKeys = NULL;
8727 }
8728
8729 count = sLoadedKexts->getCount();
8730 result = OSDictionary::withCapacity(count);
8731 if (!result) {
8732 goto finish;
8733 }
8734
8735 for (i = 0; i < count; i++) {
8736 OSKext *thisKext = NULL; // do not release
8737 Boolean includeThis = true;
8738 uuid_t thisKextUUID;
8739 uuid_t thisKextTextUUID;
8740 OSData *uuid_data;
8741 uuid_string_t uuid_key;
8742
8743 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
8744 if (!thisKext) {
8745 continue;
8746 }
8747
8748 uuid_data = thisKext->copyUUID();
8749 if (!uuid_data) {
8750 continue;
8751 }
8752
8753 memcpy(&thisKextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextUUID));
8754 OSSafeReleaseNULL(uuid_data);
8755
8756 uuid_unparse(thisKextUUID, uuid_key);
8757
8758 uuid_data = thisKext->copyTextUUID();
8759 if (!uuid_data) {
8760 continue;
8761 }
8762 memcpy(&thisKextTextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextTextUUID));
8763 OSSafeReleaseNULL(uuid_data);
8764
8765 /* Skip current kext if we have a list of UUIDs and
8766 * it isn't in the list.
8767 */
8768 if (kextIdentifiers) {
8769 includeThis = false;
8770
8771 for (idIndex = 0; idIndex < idCount; idIndex++) {
8772 const OSString* wantedUUID = OSDynamicCast(OSString,
8773 kextIdentifiers->getObject(idIndex));
8774
8775 uuid_t uuid;
8776 uuid_parse(wantedUUID->getCStringNoCopy(), uuid);
8777
8778 if ((0 == uuid_compare(uuid, thisKextUUID))
8779 || (0 == uuid_compare(uuid, thisKextTextUUID))) {
8780 includeThis = true;
8781 /* Only need to find the first kext if multiple match,
8782 * ie. asking for the kernel uuid does not need to find
8783 * interface kexts or builtin static kexts.
8784 */
8785 kextIdentifiers->removeObject(idIndex);
8786 uuid_unparse(uuid, uuid_key);
8787 break;
8788 }
8789
8790 }
8791 }
8792
8793 if (!includeThis) {
8794 continue;
8795 }
8796
8797 kextInfo = thisKext->copyInfo(infoKeys);
8798 if (kextInfo) {
8799 result->setObject(uuid_key, kextInfo);
8800 kextInfo->release();
8801 }
8802
8803 if (kextIdentifiers && !kextIdentifiers->getCount()) {
8804 break;
8805 }
8806 }
8807
8808finish:
8809 IORecursiveLockUnlock(sKextLock);
8810
8811 return result;
8812}
8813
8814/*********************************************************************
8815*********************************************************************/
8816/* static */
8817OSDictionary *
8818OSKext::copyLoadedKextInfo(
8819 OSArray * kextIdentifiers,
8820 OSArray * infoKeys)
8821{
8822 OSDictionary * result = NULL;
8823 uint32_t idCount = 0;
8824 bool onlyLoaded;
8825
8826 IORecursiveLockLock(sKextLock);
8827
8828#if CONFIG_MACF
8829 /* Is the calling process allowed to query kext info? */
8830 if (current_task() != kernel_task) {
8831 int macCheckResult = 0;
8832 kauth_cred_t cred = NULL;
8833
8834 cred = kauth_cred_get_with_ref();
8835 macCheckResult = mac_kext_check_query(cred);
8836 kauth_cred_unref(&cred);
8837
8838 if (macCheckResult != 0) {
8839 OSKextLog(/* kext */ NULL,
8840 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
8841 "Failed to query kext info (MAC policy error 0x%x).",
8842 macCheckResult);
8843 goto finish;
8844 }
8845 }
8846#endif
8847
8848 /* Empty list of bundle ids is equivalent to no list (get all).
8849 */
8850 if (kextIdentifiers && !kextIdentifiers->getCount()) {
8851 kextIdentifiers = NULL;
8852 } else if (kextIdentifiers) {
8853 idCount = kextIdentifiers->getCount();
8854 }
8855
8856 /* Same for keys.
8857 */
8858 if (infoKeys && !infoKeys->getCount()) {
8859 infoKeys = NULL;
8860 }
8861
8862 onlyLoaded = (!infoKeys || !_OSArrayContainsCString(infoKeys, kOSBundleAllPrelinkedKey));
8863
8864 result = OSDictionary::withCapacity(128);
8865 if (!result) {
8866 goto finish;
8867 }
8868
8869#if 0
8870 OSKextLog(/* kext */ NULL,
8871 kOSKextLogErrorLevel |
8872 kOSKextLogGeneralFlag,
8873 "kaslr: vm_kernel_slide 0x%lx \n",
8874 vm_kernel_slide);
8875 OSKextLog(/* kext */ NULL,
8876 kOSKextLogErrorLevel |
8877 kOSKextLogGeneralFlag,
8878 "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
8879 vm_kernel_stext, vm_kernel_etext);
8880 OSKextLog(/* kext */ NULL,
8881 kOSKextLogErrorLevel |
8882 kOSKextLogGeneralFlag,
8883 "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
8884 vm_kernel_base, vm_kernel_top);
8885 OSKextLog(/* kext */ NULL,
8886 kOSKextLogErrorLevel |
8887 kOSKextLogGeneralFlag,
8888 "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
8889 vm_kext_base, vm_kext_top);
8890 OSKextLog(/* kext */ NULL,
8891 kOSKextLogErrorLevel |
8892 kOSKextLogGeneralFlag,
8893 "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
8894 vm_prelink_stext, vm_prelink_etext);
8895 OSKextLog(/* kext */ NULL,
8896 kOSKextLogErrorLevel |
8897 kOSKextLogGeneralFlag,
8898 "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
8899 vm_prelink_sinfo, vm_prelink_einfo);
8900 OSKextLog(/* kext */ NULL,
8901 kOSKextLogErrorLevel |
8902 kOSKextLogGeneralFlag,
8903 "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
8904 vm_slinkedit, vm_elinkedit);
8905#endif
8906
8907 sKextsByID->iterateObjects(^bool(const OSSymbol * thisKextID, OSObject * obj)
8908 {
8909 OSKext * thisKext = NULL; // do not release
8910 Boolean includeThis = true;
8911 OSDictionary * kextInfo = NULL; // must release
8912
8913 thisKext = OSDynamicCast(OSKext, obj);
8914 if (!thisKext) {
8915 return (false);;
8916 }
8917
8918 /* Skip current kext if not yet started and caller didn't request all.
8919 */
8920 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
8921 return (false);;
8922 }
8923
8924 /* Skip current kext if we have a list of bundle IDs and
8925 * it isn't in the list.
8926 */
8927 if (kextIdentifiers) {
8928
8929 includeThis = false;
8930
8931 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
8932 const OSString * thisRequestID = OSDynamicCast(OSString,
8933 kextIdentifiers->getObject(idIndex));
8934 if (thisKextID->isEqualTo(thisRequestID)) {
8935 includeThis = true;
8936 break;
8937 }
8938 }
8939 }
8940
8941 if (!includeThis) {
8942 return (false);
8943 }
8944
8945 kextInfo = thisKext->copyInfo(infoKeys);
8946 if (kextInfo) {
8947 result->setObject(thisKext->getIdentifier(), kextInfo);
8948 kextInfo->release();
8949 }
8950 return (false);
8951 });
8952
8953finish:
8954 IORecursiveLockUnlock(sKextLock);
8955
8956 return result;
8957}
8958
8959/*********************************************************************
8960* Any info that needs to do allocations must goto finish on alloc
8961* failure. Info that is just a lookup should just not set the object
8962* if the info does not exist.
8963*********************************************************************/
8964#define _OSKextLoadInfoDictCapacity (12)
8965
8966OSDictionary *
8967OSKext::copyInfo(OSArray * infoKeys)
8968{
8969 OSDictionary * result = NULL;
8970 bool success = false;
8971 OSData * headerData = NULL; // must release
8972 OSData * logData = NULL; // must release
8973 OSNumber * cpuTypeNumber = NULL; // must release
8974 OSNumber * cpuSubtypeNumber = NULL; // must release
8975 OSString * versionString = NULL; // do not release
8976 uint32_t executablePathCStringSize = 0;
8977 char * executablePathCString = NULL; // must release
8978 OSString * executablePathString = NULL; // must release
8979 OSData * uuid = NULL; // must release
8980 OSNumber * scratchNumber = NULL; // must release
8981 OSArray * dependencyLoadTags = NULL; // must release
8982 OSCollectionIterator * metaClassIterator = NULL; // must release
8983 OSArray * metaClassInfo = NULL; // must release
8984 OSDictionary * metaClassDict = NULL; // must release
8985 OSMetaClass * thisMetaClass = NULL; // do not release
8986 OSString * metaClassName = NULL; // must release
8987 OSString * superclassName = NULL; // must release
8988 uint32_t count, i;
8989
8990 result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
8991 if (!result) {
8992 goto finish;
8993 }
8994
8995
8996 /* Empty keys means no keys, but NULL is quicker to check.
8997 */
8998 if (infoKeys && !infoKeys->getCount()) {
8999 infoKeys = NULL;
9000 }
9001
9002 /* Headers, CPU type, and CPU subtype.
9003 */
9004 if (!infoKeys ||
9005 _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey) ||
9006 _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey) ||
9007 _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey) ||
9008 _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey))
9009 {
9010
9011 if (linkedExecutable && !isInterface()) {
9012
9013 kernel_mach_header_t *kext_mach_hdr = (kernel_mach_header_t *)
9014 linkedExecutable->getBytesNoCopy();
9015
9016#if !SECURE_KERNEL
9017 // do not return macho header info on shipping iOS - 19095897
9018 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey)) {
9019 kernel_mach_header_t * temp_kext_mach_hdr;
9020 struct load_command * lcp;
9021
9022 headerData = OSData::withBytes(kext_mach_hdr,
9023 (u_int) (sizeof(*kext_mach_hdr) + kext_mach_hdr->sizeofcmds));
9024 if (!headerData) {
9025 goto finish;
9026 }
9027
9028 // unslide any vmaddrs we return to userspace - 10726716
9029 temp_kext_mach_hdr = (kernel_mach_header_t *)
9030 headerData->getBytesNoCopy();
9031 if (temp_kext_mach_hdr == NULL) {
9032 goto finish;
9033 }
9034
9035 lcp = (struct load_command *) (temp_kext_mach_hdr + 1);
9036 for (i = 0; i < temp_kext_mach_hdr->ncmds; i++) {
9037 if (lcp->cmd == LC_SEGMENT_KERNEL) {
9038 kernel_segment_command_t * segp;
9039 kernel_section_t * secp;
9040
9041 segp = (kernel_segment_command_t *) lcp;
9042 // 10543468 - if we jettisoned __LINKEDIT clear size info
9043 if (flags.jettisonLinkeditSeg) {
9044 if (strncmp(segp->segname, SEG_LINKEDIT, sizeof(segp->segname)) == 0) {
9045 segp->vmsize = 0;
9046 segp->fileoff = 0;
9047 segp->filesize = 0;
9048 }
9049 }
9050
9051#if 0
9052 OSKextLog(/* kext */ NULL,
9053 kOSKextLogErrorLevel |
9054 kOSKextLogGeneralFlag,
9055 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
9056 __FUNCTION__, segp->segname, segp->vmaddr,
9057 VM_KERNEL_UNSLIDE(segp->vmaddr),
9058 segp->vmsize, segp->nsects);
9059 if ( (VM_KERNEL_IS_SLID(segp->vmaddr) == false) &&
9060 (VM_KERNEL_IS_KEXT(segp->vmaddr) == false) &&
9061 (VM_KERNEL_IS_PRELINKTEXT(segp->vmaddr) == false) &&
9062 (VM_KERNEL_IS_PRELINKINFO(segp->vmaddr) == false) &&
9063 (VM_KERNEL_IS_KEXT_LINKEDIT(segp->vmaddr) == false) ) {
9064 OSKextLog(/* kext */ NULL,
9065 kOSKextLogErrorLevel |
9066 kOSKextLogGeneralFlag,
9067 "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
9068 __FUNCTION__, segp->vmaddr, vm_kext_base, vm_kext_top);
9069 }
9070#endif
9071 segp->vmaddr = ml_static_unslide(segp->vmaddr);
9072
9073 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
9074 secp->addr = ml_static_unslide(secp->addr);
9075 }
9076 }
9077 lcp = (struct load_command *)((caddr_t)lcp + lcp->cmdsize);
9078 }
9079 result->setObject(kOSBundleMachOHeadersKey, headerData);
9080 }
9081#endif // SECURE_KERNEL
9082
9083 if (_OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
9084 osLogDataHeaderRef *header;
9085 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
9086
9087 void *os_log_data = NULL;
9088 void *cstring_data = NULL;
9089 unsigned long os_log_size = 0;
9090 unsigned long cstring_size = 0;
9091 uint32_t os_log_offset = 0;
9092 uint32_t cstring_offset = 0;
9093 bool res;
9094
9095 os_log_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__os_log", &os_log_size);
9096 os_log_offset = getsectoffsetfromheader(kext_mach_hdr, "__TEXT", "__os_log");
9097 cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__cstring", &cstring_size);
9098 cstring_offset = getsectoffsetfromheader(kext_mach_hdr, "__TEXT", "__cstring");
9099
9100 header = (osLogDataHeaderRef *) headerBytes;
9101 header->version = OS_LOG_HDR_VERSION;
9102 header->sect_count = NUM_OS_LOG_SECTIONS;
9103 header->sections[OS_LOG_SECT_IDX].sect_offset = os_log_offset;
9104 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) os_log_size;
9105 header->sections[CSTRING_SECT_IDX].sect_offset = cstring_offset;
9106 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) cstring_size;
9107
9108
9109 logData = OSData::withBytes(header, (u_int) (sizeof(osLogDataHeaderRef)));
9110 if (!logData) {
9111 goto finish;
9112 }
9113 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
9114 if (!res) {
9115 goto finish;
9116 }
9117 if (os_log_data) {
9118 res = logData->appendBytes(os_log_data, (u_int)header->sections[OS_LOG_SECT_IDX].sect_size);
9119 if (!res) {
9120 goto finish;
9121 }
9122 }
9123 if (cstring_data) {
9124 res = logData->appendBytes(cstring_data, (u_int)header->sections[CSTRING_SECT_IDX].sect_size);
9125 if (!res) {
9126 goto finish;
9127 }
9128 }
9129 result->setObject(kOSBundleLogStringsKey, logData);
9130 }
9131
9132 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey)) {
9133 cpuTypeNumber = OSNumber::withNumber(
9134 (uint64_t) kext_mach_hdr->cputype,
9135 8 * sizeof(kext_mach_hdr->cputype));
9136 if (!cpuTypeNumber) {
9137 goto finish;
9138 }
9139 result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber);
9140 }
9141
9142 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
9143 cpuSubtypeNumber = OSNumber::withNumber(
9144 (uint64_t) kext_mach_hdr->cpusubtype,
9145 8 * sizeof(kext_mach_hdr->cpusubtype));
9146 if (!cpuSubtypeNumber) {
9147 goto finish;
9148 }
9149 result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber);
9150 }
9151 }
9152 }
9153
9154 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
9155 */
9156 result->setObject(kCFBundleIdentifierKey, bundleID);
9157
9158 /* CFBundleVersion.
9159 */
9160 if (!infoKeys || _OSArrayContainsCString(infoKeys, kCFBundleVersionKey)) {
9161 versionString = OSDynamicCast(OSString,
9162 getPropertyForHostArch(kCFBundleVersionKey));
9163 if (versionString) {
9164 result->setObject(kCFBundleVersionKey, versionString);
9165 }
9166 }
9167
9168 /* OSBundleCompatibleVersion.
9169 */
9170 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCompatibleVersionKey)) {
9171 versionString = OSDynamicCast(OSString,
9172 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
9173 if (versionString) {
9174 result->setObject(kOSBundleCompatibleVersionKey, versionString);
9175 }
9176 }
9177
9178 /* Path.
9179 */
9180 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePathKey)) {
9181 if (path) {
9182 result->setObject(kOSBundlePathKey, path);
9183 }
9184 }
9185
9186
9187 /* OSBundleExecutablePath.
9188 */
9189 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecutablePathKey)) {
9190 if (path && executableRelPath) {
9191
9192 uint32_t pathLength = path->getLength(); // gets incremented below
9193
9194 // +1 for slash, +1 for \0
9195 executablePathCStringSize = pathLength + executableRelPath->getLength() + 2;
9196
9197 executablePathCString = (char *)kalloc_tag((executablePathCStringSize) *
9198 sizeof(char), VM_KERN_MEMORY_OSKEXT); // +1 for \0
9199 if (!executablePathCString) {
9200 goto finish;
9201 }
9202 strlcpy(executablePathCString, path->getCStringNoCopy(),
9203 executablePathCStringSize);
9204 executablePathCString[pathLength++] = '/';
9205 executablePathCString[pathLength++] = '\0';
9206 strlcat(executablePathCString, executableRelPath->getCStringNoCopy(),
9207 executablePathCStringSize);
9208
9209 executablePathString = OSString::withCString(executablePathCString);
9210
9211 if (!executablePathString) {
9212 goto finish;
9213 }
9214
9215 result->setObject(kOSBundleExecutablePathKey, executablePathString);
9216 } else if (flags.builtin) {
9217 result->setObject(kOSBundleExecutablePathKey, bundleID);
9218 }
9219 }
9220
9221 /* UUID, if the kext has one.
9222 */
9223 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleUUIDKey)) {
9224 uuid = copyUUID();
9225 if (uuid) {
9226 result->setObject(kOSBundleUUIDKey, uuid);
9227 uuid->release();
9228 }
9229 }
9230 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleTextUUIDKey)) {
9231 uuid = copyTextUUID();
9232 if (uuid) {
9233 result->setObject(kOSBundleTextUUIDKey, uuid); uuid->release();
9234 }
9235 }
9236
9237 /*****
9238 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
9239 */
9240 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKernelResourceKey)) {
9241 result->setObject(kOSKernelResourceKey,
9242 isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
9243 }
9244
9245 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleIsInterfaceKey)) {
9246 result->setObject(kOSBundleIsInterfaceKey,
9247 isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
9248 }
9249
9250 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePrelinkedKey)) {
9251 result->setObject(kOSBundlePrelinkedKey,
9252 isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
9253 }
9254
9255 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleStartedKey)) {
9256 result->setObject(kOSBundleStartedKey,
9257 isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
9258 }
9259
9260 /* LoadTag (Index).
9261 */
9262 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadTagKey)) {
9263 scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
9264 /* numBits */ 8 * sizeof(loadTag));
9265 if (!scratchNumber) {
9266 goto finish;
9267 }
9268 result->setObject(kOSBundleLoadTagKey, scratchNumber);
9269 OSSafeReleaseNULL(scratchNumber);
9270 }
9271
9272 /* LoadAddress, LoadSize.
9273 */
9274 if (!infoKeys ||
9275 _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey) ||
9276 _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey) ||
9277 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey) ||
9278 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey) ||
9279 _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey))
9280 {
9281 if (isInterface() || flags.builtin || linkedExecutable) {
9282 /* These go to userspace via serialization, so we don't want any doubts
9283 * about their size.
9284 */
9285 uint64_t loadAddress = 0;
9286 uint32_t loadSize = 0;
9287 uint32_t wiredSize = 0;
9288 uint64_t execLoadAddress = 0;
9289 uint32_t execLoadSize = 0;
9290
9291 /* Interfaces always report 0 load address & size.
9292 * Just the way they roll.
9293 *
9294 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
9295 * xxx - shouldn't have one!
9296 */
9297
9298 if (flags.builtin || linkedExecutable) {
9299 kernel_mach_header_t *mh = NULL;
9300 kernel_segment_command_t *seg = NULL;
9301
9302 if (flags.builtin) {
9303 loadAddress = kmod_info->address;
9304 loadSize = kmod_info->size;
9305 } else {
9306 loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
9307 loadSize = linkedExecutable->getLength();
9308 }
9309 mh = (kernel_mach_header_t *)loadAddress;
9310 loadAddress = ml_static_unslide(loadAddress);
9311
9312 /* Walk through the kext, looking for the first executable
9313 * segment in case we were asked for its size/address.
9314 */
9315 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
9316 if (seg->initprot & VM_PROT_EXECUTE) {
9317 execLoadAddress = ml_static_unslide(seg->vmaddr);
9318 execLoadSize = seg->vmsize;
9319 break;
9320 }
9321 }
9322
9323 /* If we have a kmod_info struct, calculated the wired size
9324 * from that. Otherwise it's the full load size.
9325 */
9326 if (kmod_info) {
9327 wiredSize = loadSize - kmod_info->hdr_size;
9328 } else {
9329 wiredSize = loadSize;
9330 }
9331 }
9332
9333 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey)) {
9334 scratchNumber = OSNumber::withNumber(
9335 (unsigned long long)(loadAddress),
9336 /* numBits */ 8 * sizeof(loadAddress));
9337 if (!scratchNumber) {
9338 goto finish;
9339 }
9340 result->setObject(kOSBundleLoadAddressKey, scratchNumber);
9341 OSSafeReleaseNULL(scratchNumber);
9342 }
9343#if CONFIG_EMBEDDED
9344 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCacheLoadAddressKey))
9345 && loadAddress && loadSize) {
9346 scratchNumber = OSNumber::withNumber(
9347 (unsigned long long)ml_static_unslide((uintptr_t)segLOWESTTEXT),
9348 /* numBits */ 8 * sizeof(loadAddress));
9349 if (!scratchNumber) {
9350 goto finish;
9351 }
9352 result->setObject(kOSBundleCacheLoadAddressKey, scratchNumber);
9353 OSSafeReleaseNULL(scratchNumber);
9354 }
9355 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleKextsInKernelTextKey))
9356 && (this == sKernelKext) && gBuiltinKmodsCount) {
9357 result->setObject(kOSBundleKextsInKernelTextKey, kOSBooleanTrue);
9358 }
9359#endif /* CONFIG_EMBEDDED */
9360 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey)) {
9361 scratchNumber = OSNumber::withNumber(
9362 (unsigned long long)(execLoadAddress),
9363 /* numBits */ 8 * sizeof(execLoadAddress));
9364 if (!scratchNumber) {
9365 goto finish;
9366 }
9367 result->setObject(kOSBundleExecLoadAddressKey, scratchNumber);
9368 OSSafeReleaseNULL(scratchNumber);
9369 }
9370 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey)) {
9371 scratchNumber = OSNumber::withNumber(
9372 (unsigned long long)(loadSize),
9373 /* numBits */ 8 * sizeof(loadSize));
9374 if (!scratchNumber) {
9375 goto finish;
9376 }
9377 result->setObject(kOSBundleLoadSizeKey, scratchNumber);
9378 OSSafeReleaseNULL(scratchNumber);
9379 }
9380 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey)) {
9381 scratchNumber = OSNumber::withNumber(
9382 (unsigned long long)(execLoadSize),
9383 /* numBits */ 8 * sizeof(execLoadSize));
9384 if (!scratchNumber) {
9385 goto finish;
9386 }
9387 result->setObject(kOSBundleExecLoadSizeKey, scratchNumber);
9388 OSSafeReleaseNULL(scratchNumber);
9389 }
9390 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
9391 scratchNumber = OSNumber::withNumber(
9392 (unsigned long long)(wiredSize),
9393 /* numBits */ 8 * sizeof(wiredSize));
9394 if (!scratchNumber) {
9395 goto finish;
9396 }
9397 result->setObject(kOSBundleWiredSizeKey, scratchNumber);
9398 OSSafeReleaseNULL(scratchNumber);
9399 }
9400 }
9401 }
9402
9403 /* OSBundleDependencies. In descending order for
9404 * easy compatibility with kextstat(8).
9405 */
9406 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleDependenciesKey)) {
9407 if ((count = getNumDependencies())) {
9408 dependencyLoadTags = OSArray::withCapacity(count);
9409 result->setObject(kOSBundleDependenciesKey, dependencyLoadTags);
9410
9411 i = count - 1;
9412 do {
9413 OSKext * dependency = OSDynamicCast(OSKext,
9414 dependencies->getObject(i));
9415
9416 OSSafeReleaseNULL(scratchNumber);
9417
9418 if (!dependency) {
9419 continue;
9420 }
9421 scratchNumber = OSNumber::withNumber(
9422 (unsigned long long)dependency->getLoadTag(),
9423 /* numBits*/ 8 * sizeof(loadTag));
9424 if (!scratchNumber) {
9425 goto finish;
9426 }
9427 dependencyLoadTags->setObject(scratchNumber);
9428 } while (i--);
9429 }
9430 }
9431
9432 OSSafeReleaseNULL(scratchNumber);
9433
9434 /* OSBundleMetaClasses.
9435 */
9436 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleClassesKey)) {
9437 if (metaClasses && metaClasses->getCount()) {
9438 metaClassIterator = OSCollectionIterator::withCollection(metaClasses);
9439 metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
9440 if (!metaClassIterator || !metaClassInfo) {
9441 goto finish;
9442 }
9443 result->setObject(kOSBundleClassesKey, metaClassInfo);
9444
9445 while ( (thisMetaClass = OSDynamicCast(OSMetaClass,
9446 metaClassIterator->getNextObject())) ) {
9447
9448 OSSafeReleaseNULL(metaClassDict);
9449 OSSafeReleaseNULL(scratchNumber);
9450 OSSafeReleaseNULL(metaClassName);
9451 OSSafeReleaseNULL(superclassName);
9452
9453 metaClassDict = OSDictionary::withCapacity(3);
9454 if (!metaClassDict) {
9455 goto finish;
9456 }
9457
9458 metaClassName = OSString::withCString(thisMetaClass->getClassName());
9459 if (thisMetaClass->getSuperClass()) {
9460 superclassName = OSString::withCString(
9461 thisMetaClass->getSuperClass()->getClassName());
9462 }
9463 scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
9464 8 * sizeof(unsigned int));
9465
9466 /* Bail if any of the essentials is missing. The root class lacks a superclass,
9467 * of course.
9468 */
9469 if (!metaClassDict || !metaClassName || !scratchNumber) {
9470 goto finish;
9471 }
9472
9473 metaClassInfo->setObject(metaClassDict);
9474 metaClassDict->setObject(kOSMetaClassNameKey, metaClassName);
9475 if (superclassName) {
9476 metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName);
9477 }
9478 metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber);
9479 }
9480 }
9481 }
9482
9483 /* OSBundleRetainCount.
9484 */
9485 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleRetainCountKey)) {
9486 OSSafeReleaseNULL(scratchNumber);
9487 {
9488 int kextRetainCount = getRetainCount() - 1;
9489 if (isLoaded()) {
9490 kextRetainCount--;
9491 }
9492 scratchNumber = OSNumber::withNumber(
9493 (int)kextRetainCount,
9494 /* numBits*/ 8 * sizeof(int));
9495 if (scratchNumber) {
9496 result->setObject(kOSBundleRetainCountKey, scratchNumber);
9497 }
9498 }
9499 }
9500
9501 success = true;
9502
9503finish:
9504 OSSafeReleaseNULL(headerData);
9505 OSSafeReleaseNULL(logData);
9506 OSSafeReleaseNULL(cpuTypeNumber);
9507 OSSafeReleaseNULL(cpuSubtypeNumber);
9508 OSSafeReleaseNULL(executablePathString);
9509 if (executablePathCString) kfree(executablePathCString, executablePathCStringSize);
9510 OSSafeReleaseNULL(scratchNumber);
9511 OSSafeReleaseNULL(dependencyLoadTags);
9512 OSSafeReleaseNULL(metaClassIterator);
9513 OSSafeReleaseNULL(metaClassInfo);
9514 OSSafeReleaseNULL(metaClassDict);
9515 OSSafeReleaseNULL(metaClassName);
9516 OSSafeReleaseNULL(superclassName);
9517 if (!success) {
9518 OSSafeReleaseNULL(result);
9519 }
9520 return result;
9521}
9522
9523/*********************************************************************
9524 *********************************************************************/
9525/* static */
9526OSReturn
9527OSKext::requestResource(
9528 const char * kextIdentifierCString,
9529 const char * resourceNameCString,
9530 OSKextRequestResourceCallback callback,
9531 void * context,
9532 OSKextRequestTag * requestTagOut)
9533{
9534 OSReturn result = kOSReturnError;
9535 OSKext * callbackKext = NULL; // must release (looked up)
9536
9537 OSKextRequestTag requestTag = -1;
9538 OSNumber * requestTagNum = NULL; // must release
9539
9540 OSDictionary * requestDict = NULL; // must release
9541 OSString * kextIdentifier = NULL; // must release
9542 OSString * resourceName = NULL; // must release
9543
9544 OSDictionary * callbackRecord = NULL; // must release
9545 OSData * callbackWrapper = NULL; // must release
9546
9547 OSData * contextWrapper = NULL; // must release
9548
9549 IORecursiveLockLock(sKextLock);
9550
9551 if (requestTagOut) {
9552 *requestTagOut = kOSKextRequestTagInvalid;
9553 }
9554
9555 /* If requests to user space are disabled, don't go any further */
9556 if (!sKernelRequestsEnabled) {
9557 OSKextLog(/* kext */ NULL,
9558 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
9559 "Can't request resource %s for %s - requests to user space are disabled.",
9560 resourceNameCString,
9561 kextIdentifierCString);
9562 result = kOSKextReturnDisabled;
9563 goto finish;
9564 }
9565
9566 if (!kextIdentifierCString || !resourceNameCString || !callback) {
9567 result = kOSKextReturnInvalidArgument;
9568 goto finish;
9569 }
9570
9571 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
9572 if (!callbackKext) {
9573 OSKextLog(/* kext */ NULL,
9574 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
9575 "Resource request has bad callback address.");
9576 result = kOSKextReturnInvalidArgument;
9577 goto finish;
9578 }
9579 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
9580 OSKextLog(/* kext */ NULL,
9581 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
9582 "Resource request callback is in a kext that is not started.");
9583 result = kOSKextReturnInvalidArgument;
9584 goto finish;
9585 }
9586
9587 /* Do not allow any new requests to be made on a kext that is unloading.
9588 */
9589 if (callbackKext->flags.stopping) {
9590 result = kOSKextReturnStopping;
9591 goto finish;
9592 }
9593
9594 /* If we're wrapped the next available request tag around to the negative
9595 * numbers, we can't service any more requests.
9596 */
9597 if (sNextRequestTag == kOSKextRequestTagInvalid) {
9598 OSKextLog(/* kext */ NULL,
9599 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
9600 "No more request tags available; restart required.");
9601 result = kOSKextReturnNoResources;
9602 goto finish;
9603 }
9604 requestTag = sNextRequestTag++;
9605
9606 result = _OSKextCreateRequest(kKextRequestPredicateRequestResource,
9607 &requestDict);
9608 if (result != kOSReturnSuccess) {
9609 goto finish;
9610 }
9611
9612 kextIdentifier = OSString::withCString(kextIdentifierCString);
9613 resourceName = OSString::withCString(resourceNameCString);
9614 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
9615 8 * sizeof(requestTag));
9616 if (!kextIdentifier ||
9617 !resourceName ||
9618 !requestTagNum ||
9619 !_OSKextSetRequestArgument(requestDict,
9620 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
9621 !_OSKextSetRequestArgument(requestDict,
9622 kKextRequestArgumentNameKey, resourceName) ||
9623 !_OSKextSetRequestArgument(requestDict,
9624 kKextRequestArgumentRequestTagKey, requestTagNum)) {
9625
9626 result = kOSKextReturnNoMemory;
9627 goto finish;
9628 }
9629
9630 callbackRecord = OSDynamicCast(OSDictionary, requestDict->copyCollection());
9631 if (!callbackRecord) {
9632 result = kOSKextReturnNoMemory;
9633 goto finish;
9634 }
9635 // we validate callback address at call time
9636 callbackWrapper = OSData::withBytes((void *)&callback, sizeof(void *));
9637 if (context) {
9638 contextWrapper = OSData::withBytes((void *)&context, sizeof(void *));
9639 }
9640 if (!callbackWrapper || !_OSKextSetRequestArgument(callbackRecord,
9641 kKextRequestArgumentCallbackKey, callbackWrapper)) {
9642
9643 result = kOSKextReturnNoMemory;
9644 goto finish;
9645 }
9646
9647 if (context) {
9648 if (!contextWrapper || !_OSKextSetRequestArgument(callbackRecord,
9649 kKextRequestArgumentContextKey, contextWrapper)) {
9650
9651 result = kOSKextReturnNoMemory;
9652 goto finish;
9653 }
9654 }
9655
9656 /* Only post the requests after all the other potential failure points
9657 * have been passed.
9658 */
9659 if (!sKernelRequests->setObject(requestDict) ||
9660 !sRequestCallbackRecords->setObject(callbackRecord)) {
9661
9662 result = kOSKextReturnNoMemory;
9663 goto finish;
9664 }
9665
9666 OSKext::pingKextd();
9667
9668 result = kOSReturnSuccess;
9669 if (requestTagOut) {
9670 *requestTagOut = requestTag;
9671 }
9672
9673finish:
9674
9675 /* If we didn't succeed, yank the request & callback
9676 * from their holding arrays.
9677 */
9678 if (result != kOSReturnSuccess) {
9679 unsigned int index;
9680
9681 index = sKernelRequests->getNextIndexOfObject(requestDict, 0);
9682 if (index != (unsigned int)-1) {
9683 sKernelRequests->removeObject(index);
9684 }
9685 index = sRequestCallbackRecords->getNextIndexOfObject(callbackRecord, 0);
9686 if (index != (unsigned int)-1) {
9687 sRequestCallbackRecords->removeObject(index);
9688 }
9689 }
9690
9691 OSKext::considerUnloads(/* rescheduleOnly? */ true);
9692
9693 IORecursiveLockUnlock(sKextLock);
9694
9695 if (callbackKext) callbackKext->release();
9696 if (requestTagNum) requestTagNum->release();
9697
9698 if (requestDict) requestDict->release();
9699 if (kextIdentifier) kextIdentifier->release();
9700 if (resourceName) resourceName->release();
9701
9702 if (callbackRecord) callbackRecord->release();
9703 if (callbackWrapper) callbackWrapper->release();
9704 if (contextWrapper) contextWrapper->release();
9705
9706 return result;
9707}
9708
9709/*********************************************************************
9710* Assumes sKextLock is held.
9711*********************************************************************/
9712/* static */
9713OSReturn
9714OSKext::dequeueCallbackForRequestTag(
9715 OSKextRequestTag requestTag,
9716 OSDictionary ** callbackRecordOut)
9717{
9718 OSReturn result = kOSReturnError;
9719 OSNumber * requestTagNum = NULL; // must release
9720
9721 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
9722 8 * sizeof(requestTag));
9723 if (!requestTagNum) {
9724 goto finish;
9725 }
9726
9727 result = OSKext::dequeueCallbackForRequestTag(requestTagNum,
9728 callbackRecordOut);
9729
9730finish:
9731 OSSafeReleaseNULL(requestTagNum);
9732
9733 return result;
9734}
9735
9736/*********************************************************************
9737* Assumes sKextLock is held.
9738*********************************************************************/
9739/* static */
9740OSReturn
9741OSKext::dequeueCallbackForRequestTag(
9742 OSNumber * requestTagNum,
9743 OSDictionary ** callbackRecordOut)
9744{
9745 OSReturn result = kOSKextReturnInvalidArgument;
9746 OSDictionary * callbackRecord = NULL; // retain if matched!
9747 OSNumber * callbackTagNum = NULL; // do not release
9748 unsigned int count, i;
9749
9750 result = kOSReturnError;
9751 count = sRequestCallbackRecords->getCount();
9752 for (i = 0; i < count; i++) {
9753 callbackRecord = OSDynamicCast(OSDictionary,
9754 sRequestCallbackRecords->getObject(i));
9755 if (!callbackRecord) {
9756 goto finish;
9757 }
9758
9759 /* If we don't find a tag, we basically have a leak here. Maybe
9760 * we should just remove it.
9761 */
9762 callbackTagNum = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(
9763 callbackRecord, kKextRequestArgumentRequestTagKey));
9764 if (!callbackTagNum) {
9765 goto finish;
9766 }
9767
9768 /* We could be even more paranoid and check that all the incoming
9769 * args match what's in the callback record.
9770 */
9771 if (callbackTagNum->isEqualTo(requestTagNum)) {
9772 if (callbackRecordOut) {
9773 *callbackRecordOut = callbackRecord;
9774 callbackRecord->retain();
9775 }
9776 sRequestCallbackRecords->removeObject(i);
9777 result = kOSReturnSuccess;
9778 goto finish;
9779 }
9780 }
9781 result = kOSKextReturnNotFound;
9782
9783finish:
9784 return result;
9785}
9786
9787
9788/*********************************************************************
9789* Busy timeout triage
9790*********************************************************************/
9791/* static */
9792bool
9793OSKext::isWaitingKextd(void)
9794{
9795 return sRequestCallbackRecords && sRequestCallbackRecords->getCount();
9796}
9797
9798/*********************************************************************
9799* Assumes sKextLock is held.
9800*********************************************************************/
9801/* static */
9802OSReturn
9803OSKext::dispatchResource(OSDictionary * requestDict)
9804{
9805 OSReturn result = kOSReturnError;
9806 OSDictionary * callbackRecord = NULL; // must release
9807 OSNumber * requestTag = NULL; // do not release
9808 OSNumber * requestResult = NULL; // do not release
9809 OSData * dataObj = NULL; // do not release
9810 uint32_t dataLength = 0;
9811 const void * dataPtr = NULL; // do not free
9812 OSData * callbackWrapper = NULL; // do not release
9813 OSKextRequestResourceCallback callback = NULL;
9814 OSData * contextWrapper = NULL; // do not release
9815 void * context = NULL; // do not free
9816 OSKext * callbackKext = NULL; // must release (looked up)
9817
9818 /* Get the args from the request. Right now we need the tag
9819 * to look up the callback record, and the result for invoking the callback.
9820 */
9821 requestTag = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
9822 kKextRequestArgumentRequestTagKey));
9823 requestResult = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
9824 kKextRequestArgumentResultKey));
9825 if (!requestTag || !requestResult) {
9826 result = kOSKextReturnInvalidArgument;
9827 goto finish;
9828 }
9829
9830 /* Look for a callback record matching this request's tag.
9831 */
9832 result = dequeueCallbackForRequestTag(requestTag, &callbackRecord);
9833 if (result != kOSReturnSuccess) {
9834 goto finish;
9835 }
9836
9837 /*****
9838 * Get the context pointer of the callback record (if there is one).
9839 */
9840 contextWrapper = OSDynamicCast(OSData, _OSKextGetRequestArgument(callbackRecord,
9841 kKextRequestArgumentContextKey));
9842 context = _OSKextExtractPointer(contextWrapper);
9843 if (contextWrapper && !context) {
9844 goto finish;
9845 }
9846
9847 callbackWrapper = OSDynamicCast(OSData,
9848 _OSKextGetRequestArgument(callbackRecord,
9849 kKextRequestArgumentCallbackKey));
9850 callback = (OSKextRequestResourceCallback)
9851 _OSKextExtractPointer(callbackWrapper);
9852 if (!callback) {
9853 goto finish;
9854 }
9855
9856 /* Check for a data obj. We might not have one and that's ok, that means
9857 * we didn't find the requested resource, and we still have to tell the
9858 * caller that via the callback.
9859 */
9860 dataObj = OSDynamicCast(OSData, _OSKextGetRequestArgument(requestDict,
9861 kKextRequestArgumentValueKey));
9862 if (dataObj) {
9863 dataPtr = dataObj->getBytesNoCopy();
9864 dataLength = dataObj->getLength();
9865 }
9866
9867 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
9868 if (!callbackKext) {
9869 OSKextLog(/* kext */ NULL,
9870 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
9871 "Can't invoke callback for resource request; ");
9872 goto finish;
9873 }
9874 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
9875 OSKextLog(/* kext */ NULL,
9876 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
9877 "Can't invoke kext resource callback; ");
9878 goto finish;
9879 }
9880
9881 (void)callback(requestTag->unsigned32BitValue(),
9882 (OSReturn)requestResult->unsigned32BitValue(),
9883 dataPtr, dataLength, context);
9884
9885 result = kOSReturnSuccess;
9886
9887finish:
9888 if (callbackKext) callbackKext->release();
9889 if (callbackRecord) callbackRecord->release();
9890
9891 return result;
9892}
9893
9894/*********************************************************************
9895*********************************************************************/
9896/* static */
9897void
9898OSKext::invokeRequestCallback(
9899 OSDictionary * callbackRecord,
9900 OSReturn callbackResult)
9901{
9902 OSString * predicate = _OSKextGetRequestPredicate(callbackRecord);
9903 OSNumber * resultNum = NULL; // must release
9904
9905 if (!predicate) {
9906 goto finish;
9907 }
9908
9909 resultNum = OSNumber::withNumber((long long unsigned int)callbackResult,
9910 8 * sizeof(callbackResult));
9911 if (!resultNum) {
9912 goto finish;
9913 }
9914
9915 /* Insert the result into the callback record and dispatch it as if it
9916 * were the reply coming down from user space.
9917 */
9918 _OSKextSetRequestArgument(callbackRecord, kKextRequestArgumentResultKey,
9919 resultNum);
9920
9921 if (predicate->isEqualTo(kKextRequestPredicateRequestResource)) {
9922 /* This removes the pending callback record.
9923 */
9924 OSKext::dispatchResource(callbackRecord);
9925 }
9926
9927finish:
9928 if (resultNum) resultNum->release();
9929 return;
9930}
9931
9932/*********************************************************************
9933* Assumes sKextLock is held.
9934*********************************************************************/
9935/* static */
9936OSReturn
9937OSKext::cancelRequest(
9938 OSKextRequestTag requestTag,
9939 void ** contextOut)
9940{
9941 OSReturn result = kOSKextReturnNoMemory;
9942 OSDictionary * callbackRecord = NULL; // must release
9943 OSData * contextWrapper = NULL; // do not release
9944
9945 IORecursiveLockLock(sKextLock);
9946 result = OSKext::dequeueCallbackForRequestTag(requestTag,
9947 &callbackRecord);
9948 IORecursiveLockUnlock(sKextLock);
9949
9950 if (result == kOSReturnSuccess && contextOut) {
9951 contextWrapper = OSDynamicCast(OSData,
9952 _OSKextGetRequestArgument(callbackRecord,
9953 kKextRequestArgumentContextKey));
9954 *contextOut = _OSKextExtractPointer(contextWrapper);
9955 }
9956
9957 if (callbackRecord) callbackRecord->release();
9958
9959 return result;
9960}
9961
9962/*********************************************************************
9963* Assumes sKextLock is held.
9964*********************************************************************/
9965void
9966OSKext::invokeOrCancelRequestCallbacks(
9967 OSReturn callbackResult,
9968 bool invokeFlag)
9969{
9970 unsigned int count, i;
9971
9972 count = sRequestCallbackRecords->getCount();
9973 if (!count) {
9974 goto finish;
9975 }
9976
9977 i = count - 1;
9978 do {
9979 OSDictionary * request = OSDynamicCast(OSDictionary,
9980 sRequestCallbackRecords->getObject(i));
9981
9982 if (!request) {
9983 continue;
9984 }
9985 OSData * callbackWrapper = OSDynamicCast(OSData,
9986 _OSKextGetRequestArgument(request,
9987 kKextRequestArgumentCallbackKey));
9988
9989 if (!callbackWrapper) {
9990 sRequestCallbackRecords->removeObject(i);
9991 continue;
9992 }
9993
9994 vm_address_t callbackAddress = (vm_address_t)
9995 _OSKextExtractPointer(callbackWrapper);
9996
9997 if ((kmod_info->address <= callbackAddress) &&
9998 (callbackAddress < (kmod_info->address + kmod_info->size))) {
9999
10000 if (invokeFlag) {
10001 /* This removes the callback record.
10002 */
10003 invokeRequestCallback(request, callbackResult);
10004 } else {
10005 sRequestCallbackRecords->removeObject(i);
10006 }
10007 }
10008 } while (i--);
10009
10010finish:
10011 return;
10012}
10013
10014/*********************************************************************
10015* Assumes sKextLock is held.
10016*********************************************************************/
10017uint32_t
10018OSKext::countRequestCallbacks(void)
10019{
10020 uint32_t result = 0;
10021 unsigned int count, i;
10022
10023 count = sRequestCallbackRecords->getCount();
10024 if (!count) {
10025 goto finish;
10026 }
10027
10028 i = count - 1;
10029 do {
10030 OSDictionary * request = OSDynamicCast(OSDictionary,
10031 sRequestCallbackRecords->getObject(i));
10032
10033 if (!request) {
10034 continue;
10035 }
10036 OSData * callbackWrapper = OSDynamicCast(OSData,
10037 _OSKextGetRequestArgument(request,
10038 kKextRequestArgumentCallbackKey));
10039
10040 if (!callbackWrapper) {
10041 continue;
10042 }
10043
10044 vm_address_t callbackAddress = (vm_address_t)
10045 _OSKextExtractPointer(callbackWrapper);
10046
10047 if ((kmod_info->address <= callbackAddress) &&
10048 (callbackAddress < (kmod_info->address + kmod_info->size))) {
10049
10050 result++;
10051 }
10052 } while (i--);
10053
10054finish:
10055 return result;
10056}
10057
10058/*********************************************************************
10059*********************************************************************/
10060static OSReturn _OSKextCreateRequest(
10061 const char * predicate,
10062 OSDictionary ** requestP)
10063{
10064 OSReturn result = kOSKextReturnNoMemory;
10065 OSDictionary * request = NULL; // must release on error
10066
10067 request = OSDictionary::withCapacity(2);
10068 if (!request) {
10069 goto finish;
10070 }
10071 result = _OSDictionarySetCStringValue(request,
10072 kKextRequestPredicateKey, predicate);
10073 if (result != kOSReturnSuccess) {
10074 goto finish;
10075 }
10076 result = kOSReturnSuccess;
10077
10078finish:
10079 if (result != kOSReturnSuccess) {
10080 if (request) request->release();
10081 } else {
10082 *requestP = request;
10083 }
10084
10085 return result;
10086}
10087
10088/*********************************************************************
10089*********************************************************************/
10090static OSString * _OSKextGetRequestPredicate(OSDictionary * requestDict)
10091{
10092 return OSDynamicCast(OSString,
10093 requestDict->getObject(kKextRequestPredicateKey));
10094}
10095
10096/*********************************************************************
10097*********************************************************************/
10098static OSObject * _OSKextGetRequestArgument(
10099 OSDictionary * requestDict,
10100 const char * argName)
10101{
10102 OSDictionary * args = OSDynamicCast(OSDictionary,
10103 requestDict->getObject(kKextRequestArgumentsKey));
10104 if (args) {
10105 return args->getObject(argName);
10106 }
10107 return NULL;
10108}
10109
10110/*********************************************************************
10111*********************************************************************/
10112static bool _OSKextSetRequestArgument(
10113 OSDictionary * requestDict,
10114 const char * argName,
10115 OSObject * value)
10116{
10117 OSDictionary * args = OSDynamicCast(OSDictionary,
10118 requestDict->getObject(kKextRequestArgumentsKey));
10119 if (!args) {
10120 args = OSDictionary::withCapacity(2);
10121 if (!args) {
10122 goto finish;
10123 }
10124 requestDict->setObject(kKextRequestArgumentsKey, args);
10125 args->release();
10126 }
10127 if (args) {
10128 return args->setObject(argName, value);
10129 }
10130finish:
10131 return false;
10132}
10133
10134/*********************************************************************
10135*********************************************************************/
10136static void * _OSKextExtractPointer(OSData * wrapper)
10137{
10138 void * result = NULL;
10139 const void * resultPtr = NULL;
10140
10141 if (!wrapper) {
10142 goto finish;
10143 }
10144 resultPtr = wrapper->getBytesNoCopy();
10145 result = *(void **)resultPtr;
10146finish:
10147 return result;
10148}
10149
10150/*********************************************************************
10151*********************************************************************/
10152static OSReturn _OSDictionarySetCStringValue(
10153 OSDictionary * dict,
10154 const char * cKey,
10155 const char * cValue)
10156{
10157 OSReturn result = kOSKextReturnNoMemory;
10158 const OSSymbol * key = NULL; // must release
10159 OSString * value = NULL; // must release
10160
10161 key = OSSymbol::withCString(cKey);
10162 value = OSString::withCString(cValue);
10163 if (!key || !value) {
10164 goto finish;
10165 }
10166 if (dict->setObject(key, value)) {
10167 result = kOSReturnSuccess;
10168 }
10169
10170finish:
10171 if (key) key->release();
10172 if (value) value->release();
10173
10174 return result;
10175}
10176
10177/*********************************************************************
10178*********************************************************************/
10179static bool _OSArrayContainsCString(
10180 OSArray * array,
10181 const char * cString)
10182{
10183 bool result = false;
10184 const OSSymbol * symbol = NULL;
10185 uint32_t count, i;
10186
10187 if (!array || !cString) {
10188 goto finish;
10189 }
10190
10191 symbol = OSSymbol::withCStringNoCopy(cString);
10192 if (!symbol) {
10193 goto finish;
10194 }
10195
10196 count = array->getCount();
10197 for (i = 0; i < count; i++) {
10198 OSObject * thisObject = array->getObject(i);
10199 if (symbol->isEqualTo(thisObject)) {
10200 result = true;
10201 goto finish;
10202 }
10203 }
10204
10205finish:
10206 if (symbol) symbol->release();
10207 return result;
10208}
10209
10210/*********************************************************************
10211 * We really only care about boot / system start up related kexts.
10212 * We return true if we're less than REBUILD_MAX_TIME since start up,
10213 * otherwise return false.
10214 *********************************************************************/
10215bool _OSKextInPrelinkRebuildWindow(void)
10216{
10217 static bool outside_the_window = false;
10218 AbsoluteTime my_abstime;
10219 UInt64 my_ns;
10220 SInt32 my_secs;
10221
10222 if (outside_the_window) {
10223 return(false);
10224 }
10225 clock_get_uptime(&my_abstime);
10226 absolutetime_to_nanoseconds(my_abstime, &my_ns);
10227 my_secs = (SInt32)(my_ns / NSEC_PER_SEC);
10228 if (my_secs > REBUILD_MAX_TIME) {
10229 outside_the_window = true;
10230 return(false);
10231 }
10232 return(true);
10233}
10234
10235/*********************************************************************
10236 *********************************************************************/
10237bool _OSKextInUnloadedPrelinkedKexts( const OSSymbol * theBundleID )
10238{
10239 int unLoadedCount, i;
10240 bool result = false;
10241
10242 IORecursiveLockLock(sKextLock);
10243
10244 if (sUnloadedPrelinkedKexts == NULL) {
10245 goto finish;
10246 }
10247 unLoadedCount = sUnloadedPrelinkedKexts->getCount();
10248 if (unLoadedCount == 0) {
10249 goto finish;
10250 }
10251
10252 for (i = 0; i < unLoadedCount; i++) {
10253 const OSSymbol * myBundleID; // do not release
10254
10255 myBundleID = OSDynamicCast(OSSymbol, sUnloadedPrelinkedKexts->getObject(i));
10256 if (!myBundleID) continue;
10257 if (theBundleID->isEqualTo(myBundleID->getCStringNoCopy())) {
10258 result = true;
10259 break;
10260 }
10261 }
10262finish:
10263 IORecursiveLockUnlock(sKextLock);
10264 return(result);
10265}
10266
10267#if PRAGMA_MARK
10268#pragma mark Personalities (IOKit Drivers)
10269#endif
10270/*********************************************************************
10271*********************************************************************/
10272/* static */
10273OSArray *
10274OSKext::copyAllKextPersonalities(bool filterSafeBootFlag)
10275{
10276 OSArray * result = NULL; // returned
10277 OSCollectionIterator * kextIterator = NULL; // must release
10278 OSArray * personalities = NULL; // must release
10279 OSCollectionIterator * personalitiesIterator = NULL; // must release
10280
10281 OSString * kextID = NULL; // do not release
10282 OSKext * theKext = NULL; // do not release
10283
10284 IORecursiveLockLock(sKextLock);
10285
10286 /* Let's conservatively guess that any given kext has around 3
10287 * personalities for now.
10288 */
10289 result = OSArray::withCapacity(sKextsByID->getCount() * 3);
10290 if (!result) {
10291 goto finish;
10292 }
10293
10294 kextIterator = OSCollectionIterator::withCollection(sKextsByID);
10295 if (!kextIterator) {
10296 goto finish;
10297 }
10298
10299 while ((kextID = OSDynamicCast(OSString, kextIterator->getNextObject()))) {
10300 if (personalitiesIterator) {
10301 personalitiesIterator->release();
10302 personalitiesIterator = NULL;
10303 }
10304 if (personalities) {
10305 personalities->release();
10306 personalities = NULL;
10307 }
10308
10309 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextID));
10310 if (!sSafeBoot || !filterSafeBootFlag || theKext->isLoadableInSafeBoot()) {
10311 personalities = theKext->copyPersonalitiesArray();
10312 if (!personalities) {
10313 continue;
10314 }
10315 result->merge(personalities);
10316 } else {
10317 // xxx - check for better place to put this log msg
10318 OSKextLog(theKext,
10319 kOSKextLogWarningLevel |
10320 kOSKextLogLoadFlag,
10321 "Kext %s is not loadable during safe boot; "
10322 "omitting its personalities.",
10323 theKext->getIdentifierCString());
10324 }
10325
10326 }
10327
10328finish:
10329 IORecursiveLockUnlock(sKextLock);
10330
10331 if (kextIterator) kextIterator->release();
10332 if (personalitiesIterator) personalitiesIterator->release();
10333 if (personalities) personalities->release();
10334
10335 return result;
10336}
10337
10338/*********************************************************************
10339*********************************************************************/
10340/* static */
10341void
10342OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching)
10343{
10344 int numPersonalities = 0;
10345
10346 OSKextLog(/* kext */ NULL,
10347 kOSKextLogStepLevel |
10348 kOSKextLogLoadFlag,
10349 "Sending all eligible registered kexts' personalities "
10350 "to the IOCatalogue %s.",
10351 startMatching ? "and starting matching" : "but not starting matching");
10352
10353 OSArray * personalities = OSKext::copyAllKextPersonalities(
10354 /* filterSafeBootFlag */ true);
10355
10356 if (personalities) {
10357 gIOCatalogue->addDrivers(personalities, startMatching);
10358 numPersonalities = personalities->getCount();
10359 personalities->release();
10360 }
10361
10362 OSKextLog(/* kext */ NULL,
10363 kOSKextLogStepLevel |
10364 kOSKextLogLoadFlag,
10365 "%d kext personalit%s sent to the IOCatalogue; %s.",
10366 numPersonalities, numPersonalities > 0 ? "ies" : "y",
10367 startMatching ? "matching started" : "matching not started");
10368 return;
10369}
10370
10371/*********************************************************************
10372* Do not make a deep copy, just convert the IOKitPersonalities dict
10373* to an array for sending to the IOCatalogue.
10374*********************************************************************/
10375OSArray *
10376OSKext::copyPersonalitiesArray(void)
10377{
10378 OSArray * result = NULL;
10379 OSDictionary * personalities = NULL; // do not release
10380 OSCollectionIterator * personalitiesIterator = NULL; // must release
10381
10382 OSString * personalityName = NULL; // do not release
10383 OSString * personalityBundleIdentifier = NULL; // do not release
10384
10385 personalities = OSDynamicCast(OSDictionary,
10386 getPropertyForHostArch(kIOKitPersonalitiesKey));
10387 if (!personalities) {
10388 goto finish;
10389 }
10390
10391 result = OSArray::withCapacity(personalities->getCount());
10392 if (!result) {
10393 goto finish;
10394 }
10395
10396 personalitiesIterator =
10397 OSCollectionIterator::withCollection(personalities);
10398 if (!personalitiesIterator) {
10399 goto finish;
10400 }
10401 while ((personalityName = OSDynamicCast(OSString,
10402 personalitiesIterator->getNextObject()))) {
10403
10404 OSDictionary * personality = OSDynamicCast(OSDictionary,
10405 personalities->getObject(personalityName));
10406
10407 /******
10408 * If the personality doesn't have a CFBundleIdentifier, or if it
10409 * differs from the kext's, insert the kext's ID so we can find it.
10410 * The publisher ID is used to remove personalities from bundles
10411 * correctly.
10412 */
10413 personalityBundleIdentifier = OSDynamicCast(OSString,
10414 personality->getObject(kCFBundleIdentifierKey));
10415
10416 if (!personalityBundleIdentifier) {
10417 personality->setObject(kCFBundleIdentifierKey, bundleID);
10418 } else if (!personalityBundleIdentifier->isEqualTo(bundleID)) {
10419 personality->setObject(kIOPersonalityPublisherKey, bundleID);
10420 }
10421
10422 result->setObject(personality);
10423 }
10424
10425finish:
10426 if (personalitiesIterator) personalitiesIterator->release();
10427
10428 return result;
10429}
10430
10431/*********************************************************************
10432Might want to change this to a bool return?
10433*********************************************************************/
10434OSReturn
10435OSKext::sendPersonalitiesToCatalog(
10436 bool startMatching,
10437 OSArray * personalityNames)
10438{
10439 OSReturn result = kOSReturnSuccess;
10440 OSArray * personalitiesToSend = NULL; // must release
10441 OSDictionary * kextPersonalities = NULL; // do not release
10442 int count, i;
10443
10444 if (!sLoadEnabled) {
10445 OSKextLog(this,
10446 kOSKextLogErrorLevel |
10447 kOSKextLogLoadFlag,
10448 "Kext loading is disabled (attempt to start matching for kext %s).",
10449 getIdentifierCString());
10450 result = kOSKextReturnDisabled;
10451 goto finish;
10452 }
10453
10454 if (sSafeBoot && !isLoadableInSafeBoot()) {
10455 OSKextLog(this,
10456 kOSKextLogErrorLevel |
10457 kOSKextLogLoadFlag,
10458 "Kext %s is not loadable during safe boot; "
10459 "not sending personalities to the IOCatalogue.",
10460 getIdentifierCString());
10461 result = kOSKextReturnNotLoadable;
10462 goto finish;
10463 }
10464
10465 if (!personalityNames || !personalityNames->getCount()) {
10466 personalitiesToSend = copyPersonalitiesArray();
10467 } else {
10468 kextPersonalities = OSDynamicCast(OSDictionary,
10469 getPropertyForHostArch(kIOKitPersonalitiesKey));
10470 if (!kextPersonalities || !kextPersonalities->getCount()) {
10471 // not an error
10472 goto finish;
10473 }
10474 personalitiesToSend = OSArray::withCapacity(0);
10475 if (!personalitiesToSend) {
10476 result = kOSKextReturnNoMemory;
10477 goto finish;
10478 }
10479 count = personalityNames->getCount();
10480 for (i = 0; i < count; i++) {
10481 OSString * name = OSDynamicCast(OSString,
10482 personalityNames->getObject(i));
10483 if (!name) {
10484 continue;
10485 }
10486 OSDictionary * personality = OSDynamicCast(OSDictionary,
10487 kextPersonalities->getObject(name));
10488 if (personality) {
10489 personalitiesToSend->setObject(personality);
10490 }
10491 }
10492 }
10493 if (personalitiesToSend) {
10494 unsigned numPersonalities = personalitiesToSend->getCount();
10495 OSKextLog(this,
10496 kOSKextLogStepLevel |
10497 kOSKextLogLoadFlag,
10498 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
10499 getIdentifierCString(),
10500 numPersonalities,
10501 numPersonalities > 1 ? "ies" : "y",
10502 startMatching ? " and starting matching" : " but not starting matching");
10503 gIOCatalogue->addDrivers(personalitiesToSend, startMatching);
10504 }
10505finish:
10506 if (personalitiesToSend) {
10507 personalitiesToSend->release();
10508 }
10509 return result;
10510}
10511
10512/*********************************************************************
10513* xxx - We should allow removing the kext's declared personalities,
10514* xxx - even with other bundle identifiers.
10515*********************************************************************/
10516void
10517OSKext::removePersonalitiesFromCatalog(void)
10518{
10519 OSDictionary * personality = NULL; // do not release
10520
10521 personality = OSDictionary::withCapacity(1);
10522 if (!personality) {
10523 goto finish;
10524 }
10525 personality->setObject(kCFBundleIdentifierKey, getIdentifier());
10526
10527 OSKextLog(this,
10528 kOSKextLogStepLevel |
10529 kOSKextLogLoadFlag,
10530 "Kext %s removing all personalities naming it from the IOCatalogue.",
10531 getIdentifierCString());
10532
10533 /* Have the IOCatalog remove all personalities matching this kext's
10534 * bundle ID and trigger matching anew.
10535 */
10536 gIOCatalogue->removeDrivers(personality, /* startMatching */ true);
10537
10538 finish:
10539 if (personality) personality->release();
10540
10541 return;
10542}
10543
10544
10545#if PRAGMA_MARK
10546#pragma mark Logging
10547#endif
10548/*********************************************************************
10549* Do not call any function that takes sKextLock here!
10550*********************************************************************/
10551/* static */
10552OSKextLogSpec
10553OSKext::setUserSpaceLogFilter(
10554 OSKextLogSpec newUserLogFilter,
10555 bool captureFlag)
10556{
10557 OSKextLogSpec result;
10558 bool allocError = false;
10559
10560 /* Do not call any function that takes sKextLoggingLock during
10561 * this critical block. That means do logging after.
10562 */
10563 IOLockLock(sKextLoggingLock);
10564
10565 result = sUserSpaceKextLogFilter;
10566 sUserSpaceKextLogFilter = newUserLogFilter;
10567
10568 if (newUserLogFilter && captureFlag &&
10569 !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
10570
10571 // xxx - do some measurements for a good initial capacity?
10572 sUserSpaceLogSpecArray = OSArray::withCapacity(0);
10573 sUserSpaceLogMessageArray = OSArray::withCapacity(0);
10574
10575 if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
10576 OSSafeReleaseNULL(sUserSpaceLogSpecArray);
10577 OSSafeReleaseNULL(sUserSpaceLogMessageArray);
10578 allocError = true;
10579 }
10580 }
10581
10582 IOLockUnlock(sKextLoggingLock);
10583
10584 /* If the config flag itself is changing, log the state change
10585 * going both ways, before setting up the user-space log arrays,
10586 * so that this is only logged in the kernel.
10587 */
10588 if (result != newUserLogFilter) {
10589 OSKextLog(/* kext */ NULL,
10590 kOSKextLogDebugLevel |
10591 kOSKextLogGeneralFlag,
10592 "User-space log flags changed from 0x%x to 0x%x.",
10593 result, newUserLogFilter);
10594 }
10595 if (allocError) {
10596 OSKextLog(/* kext */ NULL,
10597 kOSKextLogErrorLevel |
10598 kOSKextLogGeneralFlag,
10599 "Failed to allocate user-space log message arrays.");
10600 }
10601
10602 return result;
10603}
10604
10605/*********************************************************************
10606* Do not call any function that takes sKextLock here!
10607*********************************************************************/
10608/* static */
10609OSArray *
10610OSKext::clearUserSpaceLogFilter(void)
10611{
10612 OSArray * result = NULL;
10613 OSKextLogSpec oldLogFilter;
10614 OSKextLogSpec newLogFilter = kOSKextLogSilentFilter;
10615
10616 /* Do not call any function that takes sKextLoggingLock during
10617 * this critical block. That means do logging after.
10618 */
10619 IOLockLock(sKextLoggingLock);
10620
10621 result = OSArray::withCapacity(2);
10622 if (result) {
10623 result->setObject(sUserSpaceLogSpecArray);
10624 result->setObject(sUserSpaceLogMessageArray);
10625 }
10626 OSSafeReleaseNULL(sUserSpaceLogSpecArray);
10627 OSSafeReleaseNULL(sUserSpaceLogMessageArray);
10628
10629 oldLogFilter = sUserSpaceKextLogFilter;
10630 sUserSpaceKextLogFilter = newLogFilter;
10631
10632 IOLockUnlock(sKextLoggingLock);
10633
10634 /* If the config flag itself is changing, log the state change
10635 * going both ways, after tearing down the user-space log
10636 * arrays, so this is only logged within the kernel.
10637 */
10638 if (oldLogFilter != newLogFilter) {
10639 OSKextLog(/* kext */ NULL,
10640 kOSKextLogDebugLevel |
10641 kOSKextLogGeneralFlag,
10642 "User-space log flags changed from 0x%x to 0x%x.",
10643 oldLogFilter, newLogFilter);
10644 }
10645
10646 return result;
10647}
10648
10649
10650/*********************************************************************
10651* Do not call any function that takes sKextLock here!
10652*********************************************************************/
10653/* static */
10654OSKextLogSpec
10655OSKext::getUserSpaceLogFilter(void)
10656{
10657 OSKextLogSpec result;
10658
10659 IOLockLock(sKextLoggingLock);
10660 result = sUserSpaceKextLogFilter;
10661 IOLockUnlock(sKextLoggingLock);
10662
10663 return result;
10664}
10665
10666/*********************************************************************
10667* This function is called by OSMetaClass during kernel C++ setup.
10668* Be careful what you access here; assume only OSKext::initialize()
10669* has been called.
10670*
10671* Do not call any function that takes sKextLock here!
10672*********************************************************************/
10673#define VTRESET "\033[0m"
10674
10675#define VTBOLD "\033[1m"
10676#define VTUNDER "\033[4m"
10677
10678#define VTRED "\033[31m"
10679#define VTGREEN "\033[32m"
10680#define VTYELLOW "\033[33m"
10681#define VTBLUE "\033[34m"
10682#define VTMAGENTA "\033[35m"
10683#define VTCYAN "\033[36m"
10684
10685inline const char * colorForFlags(OSKextLogSpec flags)
10686{
10687 OSKextLogSpec logLevel = flags & kOSKextLogLevelMask;
10688
10689 switch (logLevel) {
10690 case kOSKextLogErrorLevel:
10691 return VTRED VTBOLD;
10692 case kOSKextLogWarningLevel:
10693 return VTRED;
10694 case kOSKextLogBasicLevel:
10695 return VTYELLOW VTUNDER;
10696 case kOSKextLogProgressLevel:
10697 return VTYELLOW;
10698 case kOSKextLogStepLevel:
10699 return VTGREEN;
10700 case kOSKextLogDetailLevel:
10701 return VTCYAN;
10702 case kOSKextLogDebugLevel:
10703 return VTMAGENTA;
10704 default:
10705 return ""; // white
10706 }
10707}
10708
10709inline bool logSpecMatch(
10710 OSKextLogSpec msgLogSpec,
10711 OSKextLogSpec logFilter)
10712{
10713 OSKextLogSpec filterKextGlobal = logFilter & kOSKextLogKextOrGlobalMask;
10714 OSKextLogSpec filterLevel = logFilter & kOSKextLogLevelMask;
10715 OSKextLogSpec filterFlags = logFilter & kOSKextLogFlagsMask;
10716
10717 OSKextLogSpec msgKextGlobal = msgLogSpec & kOSKextLogKextOrGlobalMask;
10718 OSKextLogSpec msgLevel = msgLogSpec & kOSKextLogLevelMask;
10719 OSKextLogSpec msgFlags = msgLogSpec & kOSKextLogFlagsMask;
10720
10721 /* Explicit messages always get logged.
10722 */
10723 if (msgLevel == kOSKextLogExplicitLevel) {
10724 return true;
10725 }
10726
10727 /* Warnings and errors are logged regardless of the flags.
10728 */
10729 if (msgLevel <= kOSKextLogBasicLevel && (msgLevel <= filterLevel)) {
10730 return true;
10731 }
10732
10733 /* A verbose message that isn't for a logging-enabled kext and isn't global
10734 * does *not* get logged.
10735 */
10736 if (!msgKextGlobal && !filterKextGlobal) {
10737 return false;
10738 }
10739
10740 /* Warnings and errors are logged regardless of the flags.
10741 * All other messages must fit the flags and
10742 * have a level at or below the filter.
10743 *
10744 */
10745 if ((msgFlags & filterFlags) && (msgLevel <= filterLevel)) {
10746 return true;
10747 }
10748 return false;
10749}
10750
10751extern "C" {
10752
10753void
10754OSKextLog(
10755 OSKext * aKext,
10756 OSKextLogSpec msgLogSpec,
10757 const char * format, ...)
10758{
10759 va_list argList;
10760
10761 va_start(argList, format);
10762 OSKextVLog(aKext, msgLogSpec, format, argList);
10763 va_end(argList);
10764}
10765
10766void
10767OSKextVLog(
10768 OSKext * aKext,
10769 OSKextLogSpec msgLogSpec,
10770 const char * format,
10771 va_list srcArgList)
10772{
10773 extern int disableConsoleOutput;
10774
10775 bool logForKernel = false;
10776 bool logForUser = false;
10777 va_list argList;
10778 char stackBuffer[120];
10779 uint32_t length = 0;
10780 char * allocBuffer = NULL; // must kfree
10781 OSNumber * logSpecNum = NULL; // must release
10782 OSString * logString = NULL; // must release
10783 char * buffer = stackBuffer; // do not free
10784
10785 IOLockLock(sKextLoggingLock);
10786
10787 /* Set the kext/global bit in the message spec if we have no
10788 * kext or if the kext requests logging.
10789 */
10790 if (!aKext || aKext->flags.loggingEnabled) {
10791 msgLogSpec = msgLogSpec | kOSKextLogKextOrGlobalMask;
10792 }
10793
10794 logForKernel = logSpecMatch(msgLogSpec, sKernelLogFilter);
10795 if (sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
10796 logForUser = logSpecMatch(msgLogSpec, sUserSpaceKextLogFilter);
10797 }
10798
10799 if (! (logForKernel || logForUser) ) {
10800 goto finish;
10801 }
10802
10803 /* No goto from here until past va_end()!
10804 */
10805 va_copy(argList, srcArgList);
10806 length = vsnprintf(stackBuffer, sizeof(stackBuffer), format, argList);
10807 va_end(argList);
10808
10809 if (length + 1 >= sizeof(stackBuffer)) {
10810 allocBuffer = (char *)kalloc_tag((length + 1) * sizeof(char), VM_KERN_MEMORY_OSKEXT);
10811 if (!allocBuffer) {
10812 goto finish;
10813 }
10814
10815 /* No goto from here until past va_end()!
10816 */
10817 va_copy(argList, srcArgList);
10818 vsnprintf(allocBuffer, length + 1, format, argList);
10819 va_end(argList);
10820
10821 buffer = allocBuffer;
10822 }
10823
10824 /* If user space wants the log message, queue it up.
10825 */
10826 if (logForUser && sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
10827 logSpecNum = OSNumber::withNumber(msgLogSpec, 8 * sizeof(msgLogSpec));
10828 logString = OSString::withCString(buffer);
10829 if (logSpecNum && logString) {
10830 sUserSpaceLogSpecArray->setObject(logSpecNum);
10831 sUserSpaceLogMessageArray->setObject(logString);
10832 }
10833 }
10834
10835 /* Always log messages from the kernel according to the kernel's
10836 * log flags.
10837 */
10838 if (logForKernel) {
10839
10840 /* If we are in console mode and have a custom log filter,
10841 * colorize the log message.
10842 */
10843 if (!disableConsoleOutput && sBootArgLogFilterFound) {
10844 const char * color = ""; // do not free
10845 color = colorForFlags(msgLogSpec);
10846 printf("%s%s%s\n", colorForFlags(msgLogSpec),
10847 buffer, color[0] ? VTRESET : "");
10848 } else {
10849 printf("%s\n", buffer);
10850 }
10851 }
10852
10853finish:
10854 IOLockUnlock(sKextLoggingLock);
10855
10856 if (allocBuffer) {
10857 kfree(allocBuffer, (length + 1) * sizeof(char));
10858 }
10859 OSSafeReleaseNULL(logString);
10860 OSSafeReleaseNULL(logSpecNum);
10861 return;
10862}
10863
10864#if KASLR_IOREG_DEBUG
10865
10866#define IOLOG_INDENT( the_indention ) \
10867{ \
10868 int i; \
10869 for ( i = 0; i < (the_indention); i++ ) { \
10870 IOLog(" "); \
10871 } \
10872}
10873
10874extern vm_offset_t vm_kernel_stext;
10875extern vm_offset_t vm_kernel_etext;
10876extern mach_vm_offset_t kext_alloc_base;
10877extern mach_vm_offset_t kext_alloc_max;
10878
10879bool ScanForAddrInObject(OSObject * theObject,
10880 int indent );
10881
10882bool ScanForAddrInObject(OSObject * theObject,
10883 int indent)
10884{
10885 const OSMetaClass * myTypeID;
10886 OSCollectionIterator * myIter;
10887 OSSymbol * myKey;
10888 OSObject * myValue;
10889 bool myResult = false;
10890
10891 if ( theObject == NULL ) {
10892 IOLog("%s: theObject is NULL \n",
10893 __FUNCTION__);
10894 return myResult;
10895 }
10896
10897 myTypeID = OSTypeIDInst(theObject);
10898
10899 if ( myTypeID == OSTypeID(OSDictionary) ) {
10900 OSDictionary * myDictionary;
10901
10902 myDictionary = OSDynamicCast(OSDictionary, theObject);
10903 myIter = OSCollectionIterator::withCollection( myDictionary );
10904 if ( myIter == NULL )
10905 return myResult;
10906 myIter->reset();
10907
10908 while ( (myKey = OSDynamicCast(OSSymbol, myIter->getNextObject())) ) {
10909 bool myTempResult;
10910
10911 myValue = myDictionary->getObject(myKey);
10912 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
10913 if (myTempResult) {
10914 // if we ever get a true result return true
10915 myResult = true;
10916 IOLOG_INDENT(indent);
10917 IOLog("OSDictionary key \"%s\" \n", myKey->getCStringNoCopy());
10918 }
10919 }
10920 myIter->release();
10921 }
10922 else if ( myTypeID == OSTypeID(OSArray) ) {
10923 OSArray * myArray;
10924
10925 myArray = OSDynamicCast(OSArray, theObject);
10926 myIter = OSCollectionIterator::withCollection(myArray);
10927 if ( myIter == NULL )
10928 return myResult;
10929 myIter->reset();
10930
10931 while ( (myValue = myIter->getNextObject()) ) {
10932 bool myTempResult;
10933 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
10934 if (myTempResult) {
10935 // if we ever get a true result return true
10936 myResult = true;
10937 IOLOG_INDENT(indent);
10938 IOLog("OSArray: \n");
10939 }
10940 }
10941 myIter->release();
10942 }
10943 else if ( myTypeID == OSTypeID(OSString) || myTypeID == OSTypeID(OSSymbol) ) {
10944
10945 // should we look for addresses in strings?
10946 }
10947 else if ( myTypeID == OSTypeID(OSData) ) {
10948
10949 void * * myPtrPtr;
10950 unsigned int myLen;
10951 OSData * myDataObj;
10952
10953 myDataObj = OSDynamicCast(OSData, theObject);
10954 myPtrPtr = (void * *) myDataObj->getBytesNoCopy();
10955 myLen = myDataObj->getLength();
10956
10957 if (myPtrPtr && myLen && myLen > 7) {
10958 int i;
10959 int myPtrCount = (myLen / sizeof(void *));
10960
10961 for (i = 0; i < myPtrCount; i++) {
10962 UInt64 numberValue = (UInt64) *(myPtrPtr);
10963
10964 if ( kext_alloc_max != 0 &&
10965 numberValue >= kext_alloc_base &&
10966 numberValue < kext_alloc_max ) {
10967
10968 OSKext * myKext = NULL; // must release (looked up)
10969 // IOLog("found OSData %p in kext map %p to %p \n",
10970 // *(myPtrPtr),
10971 // (void *) kext_alloc_base,
10972 // (void *) kext_alloc_max);
10973
10974 myKext = OSKext::lookupKextWithAddress( (vm_address_t) *(myPtrPtr) );
10975 if (myKext) {
10976 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
10977 *(myPtrPtr),
10978 myKext->getIdentifierCString());
10979 myKext->release();
10980 }
10981 myResult = true;
10982 }
10983 if ( vm_kernel_etext != 0 &&
10984 numberValue >= vm_kernel_stext &&
10985 numberValue < vm_kernel_etext ) {
10986 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
10987 *(myPtrPtr),
10988 (void *) vm_kernel_stext,
10989 (void *) vm_kernel_etext);
10990 myResult = true;
10991 }
10992 myPtrPtr++;
10993 }
10994 }
10995 }
10996 else if ( myTypeID == OSTypeID(OSBoolean) ) {
10997
10998 // do nothing here...
10999 }
11000 else if ( myTypeID == OSTypeID(OSNumber) ) {
11001
11002 OSNumber * number = OSDynamicCast(OSNumber, theObject);
11003
11004 UInt64 numberValue = number->unsigned64BitValue();
11005
11006 if ( kext_alloc_max != 0 &&
11007 numberValue >= kext_alloc_base &&
11008 numberValue < kext_alloc_max ) {
11009
11010 OSKext * myKext = NULL; // must release (looked up)
11011 IOLog("found OSNumber in kext map %p to %p \n",
11012 (void *) kext_alloc_base,
11013 (void *) kext_alloc_max);
11014 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
11015
11016 myKext = OSKext::lookupKextWithAddress( (vm_address_t) numberValue );
11017 if (myKext) {
11018 IOLog("found in kext \"%s\" \n",
11019 myKext->getIdentifierCString());
11020 myKext->release();
11021 }
11022
11023 myResult = true;
11024 }
11025 if ( vm_kernel_etext != 0 &&
11026 numberValue >= vm_kernel_stext &&
11027 numberValue < vm_kernel_etext ) {
11028 IOLog("found OSNumber in kernel text segment %p to %p \n",
11029 (void *) vm_kernel_stext,
11030 (void *) vm_kernel_etext);
11031 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
11032 myResult = true;
11033 }
11034 }
11035#if 0
11036 else {
11037 const OSMetaClass* myMetaClass = NULL;
11038
11039 myMetaClass = theObject->getMetaClass();
11040 if ( myMetaClass ) {
11041 IOLog("class %s \n", myMetaClass->getClassName() );
11042 }
11043 else {
11044 IOLog("Unknown object \n" );
11045 }
11046 }
11047#endif
11048
11049 return myResult;
11050}
11051#endif // KASLR_KEXT_DEBUG
11052
11053}; /* extern "C" */
11054
11055#if PRAGMA_MARK
11056#pragma mark Backtrace Dump & kmod_get_info() support
11057#endif
11058/*********************************************************************
11059* This function must be safe to call in panic context.
11060*********************************************************************/
11061/* static */
11062void
11063OSKext::printKextsInBacktrace(
11064 vm_offset_t * addr __unused,
11065 unsigned int cnt __unused,
11066 int (* printf_func)(const char *fmt, ...) __unused,
11067 uint32_t flags __unused)
11068{
11069 addr64_t summary_page = 0;
11070 addr64_t last_summary_page = 0;
11071 bool found_kmod = false;
11072 u_int i = 0;
11073
11074 if (kPrintKextsLock & flags) {
11075 if (!sKextSummariesLock) return;
11076 IOLockLock(sKextSummariesLock);
11077 }
11078
11079 if (!gLoadedKextSummaries) {
11080 (*printf_func)(" can't perform kext scan: no kext summary");
11081 goto finish;
11082 }
11083
11084 summary_page = trunc_page((addr64_t)(uintptr_t)gLoadedKextSummaries);
11085 last_summary_page = round_page(summary_page + sLoadedKextSummariesAllocSize);
11086 for (; summary_page < last_summary_page; summary_page += PAGE_SIZE) {
11087 if (pmap_find_phys(kernel_pmap, summary_page) == 0) {
11088 (*printf_func)(" can't perform kext scan: "
11089 "missing kext summary page %p", summary_page);
11090 goto finish;
11091 }
11092 }
11093
11094 for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
11095 OSKextLoadedKextSummary * summary;
11096
11097 summary = gLoadedKextSummaries->summaries + i;
11098 if (!summary->address) {
11099 continue;
11100 }
11101
11102 if (!summaryIsInBacktrace(summary, addr, cnt)) {
11103 continue;
11104 }
11105
11106 if (!found_kmod) {
11107 if (!(kPrintKextsTerse & flags)) {
11108 (*printf_func)(" Kernel Extensions in backtrace:\n");
11109 }
11110 found_kmod = true;
11111 }
11112
11113 printSummary(summary, printf_func, flags);
11114 }
11115
11116finish:
11117 if (kPrintKextsLock & flags) {
11118 IOLockUnlock(sKextSummariesLock);
11119 }
11120
11121 return;
11122}
11123
11124/*********************************************************************
11125* This function must be safe to call in panic context.
11126*********************************************************************/
11127/* static */
11128boolean_t
11129OSKext::summaryIsInBacktrace(
11130 OSKextLoadedKextSummary * summary,
11131 vm_offset_t * addr,
11132 unsigned int cnt)
11133{
11134 u_int i = 0;
11135
11136 for (i = 0; i < cnt; i++) {
11137 vm_offset_t kscan_addr = addr[i];
11138 if ((kscan_addr >= summary->address) &&
11139 (kscan_addr < (summary->address + summary->size)))
11140 {
11141 return TRUE;
11142 }
11143 }
11144
11145 return FALSE;
11146}
11147
11148/*
11149 * Get the kext summary object for the kext where 'addr' lies. Must be called with
11150 * sKextSummariesLock held.
11151 */
11152OSKextLoadedKextSummary *
11153OSKext::summaryForAddress(const uintptr_t addr)
11154{
11155 for (unsigned i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
11156
11157 OSKextLoadedKextSummary *summary = &gLoadedKextSummaries->summaries[i];
11158 if (!summary->address) {
11159 continue;
11160 }
11161
11162#if VM_MAPPED_KEXTS
11163 /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
11164 * support split kexts, but we also may unmap the kexts, which can
11165 * race with the above codepath (see OSKext::unload). As such,
11166 * use a simple range lookup if we are using VM_MAPPED_KEXTS.
11167 */
11168 if ((addr >= summary->address) && (addr < (summary->address + summary->size))) {
11169 return summary;
11170 }
11171#else
11172 kernel_mach_header_t *mh = (kernel_mach_header_t *)summary->address;
11173 kernel_segment_command_t *seg;
11174
11175 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
11176 if ((addr >= seg->vmaddr) && (addr < (seg->vmaddr + seg->vmsize))) {
11177 return summary;
11178 }
11179 }
11180#endif
11181 }
11182
11183 /* addr did not map to any kext */
11184 return NULL;
11185}
11186
11187/* static */
11188void *
11189OSKext::kextForAddress(const void *address)
11190{
11191 void * image = NULL;
11192 OSKextActiveAccount * active;
11193 OSKext * kext = NULL;
11194 uint32_t baseIdx;
11195 uint32_t lim;
11196 uintptr_t addr = (uintptr_t) address;
11197
11198 if (!addr) {
11199 return NULL;
11200 }
11201
11202 if (sKextAccountsCount)
11203 {
11204 IOSimpleLockLock(sKextAccountsLock);
11205 // bsearch sKextAccounts list
11206 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1)
11207 {
11208 active = &sKextAccounts[baseIdx + (lim >> 1)];
11209 if ((addr >= active->address) && (addr < active->address_end))
11210 {
11211 kext = active->account->kext;
11212 if (kext && kext->kmod_info) image = (void *) kext->kmod_info->address;
11213 break;
11214 }
11215 else if (addr > active->address)
11216 {
11217 // move right
11218 baseIdx += (lim >> 1) + 1;
11219 lim--;
11220 }
11221 // else move left
11222 }
11223 IOSimpleLockUnlock(sKextAccountsLock);
11224 }
11225 if (!image && (addr >= vm_kernel_stext) && (addr < vm_kernel_etext))
11226 {
11227 image = (void *) &_mh_execute_header;
11228 }
11229
11230 return image;
11231}
11232
11233/*********************************************************************
11234 * scan list of loaded kext summaries looking for a load address match and if
11235 * found return the UUID C string. If not found then set empty string.
11236 *********************************************************************/
11237static void findSummaryUUID(
11238 uint32_t tag_ID,
11239 uuid_string_t uuid);
11240
11241static void findSummaryUUID(
11242 uint32_t tag_ID,
11243 uuid_string_t uuid)
11244{
11245 u_int i;
11246
11247 uuid[0] = 0x00; // default to no UUID
11248
11249 for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
11250 OSKextLoadedKextSummary * summary;
11251
11252 summary = gLoadedKextSummaries->summaries + i;
11253
11254 if (summary->loadTag == tag_ID) {
11255 (void) uuid_unparse(summary->uuid, uuid);
11256 break;
11257 }
11258 }
11259 return;
11260}
11261
11262/*********************************************************************
11263* This function must be safe to call in panic context.
11264*********************************************************************/
11265void OSKext::printSummary(
11266 OSKextLoadedKextSummary * summary,
11267 int (* printf_func)(const char *fmt, ...),
11268 uint32_t flags)
11269{
11270 kmod_reference_t * kmod_ref = NULL;
11271 uuid_string_t uuid;
11272 char version[kOSKextVersionMaxLength];
11273 uint64_t tmpAddr;
11274
11275 if (!OSKextVersionGetString(summary->version, version, sizeof(version))) {
11276 strlcpy(version, "unknown version", sizeof(version));
11277 }
11278 (void) uuid_unparse(summary->uuid, uuid);
11279
11280 if (kPrintKextsUnslide & flags) {
11281 tmpAddr = ml_static_unslide(summary->address);
11282 }
11283 else {
11284 tmpAddr = summary->address;
11285 }
11286 (*printf_func)("%s%s(%s)[%s]@0x%llx->0x%llx\n",
11287 (kPrintKextsTerse & flags) ? "" : " ",
11288 summary->name, version, uuid,
11289 tmpAddr, tmpAddr + summary->size - 1);
11290
11291 if (kPrintKextsTerse & flags) return;
11292
11293 /* print dependency info */
11294 for (kmod_ref = (kmod_reference_t *) summary->reference_list;
11295 kmod_ref;
11296 kmod_ref = kmod_ref->next) {
11297 kmod_info_t * rinfo;
11298
11299 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_ref)) == 0) {
11300 (*printf_func)(" kmod dependency scan stopped "
11301 "due to missing dependency page: %p\n",
11302 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)kmod_ref) : kmod_ref);
11303 break;
11304 }
11305 rinfo = kmod_ref->info;
11306
11307 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
11308 (*printf_func)(" kmod dependency scan stopped "
11309 "due to missing kmod page: %p\n",
11310 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)rinfo) : rinfo);
11311 break;
11312 }
11313
11314 if (!rinfo->address) {
11315 continue; // skip fake entries for built-ins
11316 }
11317
11318 /* locate UUID in gLoadedKextSummaries */
11319 findSummaryUUID(rinfo->id, uuid);
11320
11321 if (kPrintKextsUnslide & flags) {
11322 tmpAddr = ml_static_unslide(rinfo->address);
11323 }
11324 else {
11325 tmpAddr = rinfo->address;
11326 }
11327 (*printf_func)(" dependency: %s(%s)[%s]@%p\n",
11328 rinfo->name, rinfo->version, uuid, tmpAddr);
11329 }
11330 return;
11331}
11332
11333
11334/*******************************************************************************
11335* substitute() looks at an input string (a pointer within a larger buffer)
11336* for a match to a substring, and on match it writes the marker & substitution
11337* character to an output string, updating the scan (from) and
11338* output (to) indexes as appropriate.
11339*******************************************************************************/
11340static int substitute(
11341 const char * scan_string,
11342 char * string_out,
11343 uint32_t * to_index,
11344 uint32_t * from_index,
11345 const char * substring,
11346 char marker,
11347 char substitution);
11348
11349/* string_out must be at least KMOD_MAX_NAME bytes.
11350 */
11351static int
11352substitute(
11353 const char * scan_string,
11354 char * string_out,
11355 uint32_t * to_index,
11356 uint32_t * from_index,
11357 const char * substring,
11358 char marker,
11359 char substitution)
11360{
11361 uint32_t substring_length = strnlen(substring, KMOD_MAX_NAME - 1);
11362
11363 /* On a substring match, append the marker (if there is one) and then
11364 * the substitution character, updating the output (to) index accordingly.
11365 * Then update the input (from) length by the length of the substring
11366 * that got replaced.
11367 */
11368 if (!strncmp(scan_string, substring, substring_length)) {
11369 if (marker) {
11370 string_out[(*to_index)++] = marker;
11371 }
11372 string_out[(*to_index)++] = substitution;
11373 (*from_index) += substring_length;
11374 return 1;
11375 }
11376 return 0;
11377}
11378
11379/*******************************************************************************
11380* compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
11381* KMOD_MAX_NAME characters and performs various substitutions of common
11382* prefixes & substrings as defined by tables in kext_panic_report.h.
11383*******************************************************************************/
11384static void compactIdentifier(
11385 const char * identifier,
11386 char * identifier_out,
11387 char ** identifier_out_end);
11388
11389static void
11390compactIdentifier(
11391 const char * identifier,
11392 char * identifier_out,
11393 char ** identifier_out_end)
11394{
11395 uint32_t from_index, to_index;
11396 uint32_t scan_from_index = 0;
11397 uint32_t scan_to_index = 0;
11398 subs_entry_t * subs_entry = NULL;
11399 int did_sub = 0;
11400
11401 from_index = to_index = 0;
11402 identifier_out[0] = '\0';
11403
11404 /* Replace certain identifier prefixes with shorter @+character sequences.
11405 * Check the return value of substitute() so we only replace the prefix.
11406 */
11407 for (subs_entry = &kext_identifier_prefix_subs[0];
11408 subs_entry->substring && !did_sub;
11409 subs_entry++) {
11410
11411 did_sub = substitute(identifier, identifier_out,
11412 &scan_to_index, &scan_from_index,
11413 subs_entry->substring, /* marker */ '\0', subs_entry->substitute);
11414 }
11415 did_sub = 0;
11416
11417 /* Now scan through the identifier looking for the common substrings
11418 * and replacing them with shorter !+character sequences via substitute().
11419 */
11420 for (/* see above */;
11421 scan_from_index < KMOD_MAX_NAME - 1 && identifier[scan_from_index];
11422 /* see loop */) {
11423
11424 const char * scan_string = &identifier[scan_from_index];
11425
11426 did_sub = 0;
11427
11428 if (scan_from_index) {
11429 for (subs_entry = &kext_identifier_substring_subs[0];
11430 subs_entry->substring && !did_sub;
11431 subs_entry++) {
11432
11433 did_sub = substitute(scan_string, identifier_out,
11434 &scan_to_index, &scan_from_index,
11435 subs_entry->substring, '!', subs_entry->substitute);
11436 }
11437 }
11438
11439 /* If we didn't substitute, copy the input character to the output.
11440 */
11441 if (!did_sub) {
11442 identifier_out[scan_to_index++] = identifier[scan_from_index++];
11443 }
11444 }
11445
11446 identifier_out[scan_to_index] = '\0';
11447 if (identifier_out_end) {
11448 *identifier_out_end = &identifier_out[scan_to_index];
11449 }
11450
11451 return;
11452}
11453
11454/*******************************************************************************
11455* assemble_identifier_and_version() adds to a string buffer a compacted
11456* bundle identifier followed by a version string.
11457*******************************************************************************/
11458
11459/* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
11460 */
11461static int assemble_identifier_and_version(
11462 kmod_info_t * kmod_info,
11463 char * identPlusVers,
11464 int bufSize);
11465
11466static int
11467assemble_identifier_and_version(
11468 kmod_info_t * kmod_info,
11469 char * identPlusVers,
11470 int bufSize)
11471{
11472 int result = 0;
11473
11474 compactIdentifier(kmod_info->name, identPlusVers, NULL);
11475 result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
11476 identPlusVers[result++] = '\t'; // increment for real char
11477 identPlusVers[result] = '\0'; // don't increment for nul char
11478 result = strlcat(identPlusVers, kmod_info->version, bufSize);
11479 if (result >= bufSize) {
11480 identPlusVers[bufSize - 1] = '\0';
11481 result = bufSize - 1;
11482 }
11483
11484 return result;
11485}
11486
11487/*******************************************************************************
11488* Assumes sKextLock is held.
11489*******************************************************************************/
11490/* static */
11491int
11492OSKext::saveLoadedKextPanicListTyped(
11493 const char * prefix,
11494 int invertFlag,
11495 int libsFlag,
11496 char * paniclist,
11497 uint32_t list_size)
11498{
11499 int result = -1;
11500 unsigned int count, i;
11501
11502 count = sLoadedKexts->getCount();
11503 if (!count) {
11504 goto finish;
11505 }
11506
11507 i = count - 1;
11508 do {
11509 OSObject * rawKext = sLoadedKexts->getObject(i);
11510 OSKext * theKext = OSDynamicCast(OSKext, rawKext);
11511 int match;
11512 uint32_t identPlusVersLength;
11513 uint32_t tempLen;
11514 char identPlusVers[2*KMOD_MAX_NAME];
11515
11516 if (!rawKext) {
11517 printf("OSKext::saveLoadedKextPanicListTyped - "
11518 "NULL kext in loaded kext list; continuing\n");
11519 continue;
11520 }
11521
11522 if (!theKext) {
11523 printf("OSKext::saveLoadedKextPanicListTyped - "
11524 "Kext type cast failed in loaded kext list; continuing\n");
11525 continue;
11526 }
11527
11528 /* Skip all built-in kexts.
11529 */
11530 if (theKext->isKernelComponent()) {
11531 continue;
11532 }
11533
11534 kmod_info_t * kmod_info = theKext->kmod_info;
11535
11536 /* Filter for kmod name (bundle identifier).
11537 */
11538 match = !strncmp(kmod_info->name, prefix, strnlen(prefix, KMOD_MAX_NAME));
11539 if ((match && invertFlag) || (!match && !invertFlag)) {
11540 continue;
11541 }
11542
11543 /* Filter for libraries (kexts that have a compatible version).
11544 */
11545 if ((libsFlag == 0 && theKext->getCompatibleVersion() > 1) ||
11546 (libsFlag == 1 && theKext->getCompatibleVersion() < 1)) {
11547
11548 continue;
11549 }
11550
11551 if (!kmod_info ||
11552 !pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_info))) {
11553
11554 printf("kext scan stopped due to missing kmod_info page: %p\n",
11555 kmod_info);
11556 goto finish;
11557 }
11558
11559 identPlusVersLength = assemble_identifier_and_version(kmod_info,
11560 identPlusVers,
11561 sizeof(identPlusVers));
11562 if (!identPlusVersLength) {
11563 printf("error saving loaded kext info\n");
11564 goto finish;
11565 }
11566
11567 /* make sure everything fits and we null terminate.
11568 */
11569 tempLen = strlcat(paniclist, identPlusVers, list_size);
11570 if (tempLen >= list_size) {
11571 // panic list is full, keep it and null terminate
11572 paniclist[list_size - 1] = 0x00;
11573 result = 0;
11574 goto finish;
11575 }
11576 tempLen = strlcat(paniclist, "\n", list_size);
11577 if (tempLen >= list_size) {
11578 // panic list is full, keep it and null terminate
11579 paniclist[list_size - 1] = 0x00;
11580 result = 0;
11581 goto finish;
11582 }
11583 } while (i--);
11584
11585 result = 0;
11586finish:
11587
11588 return result;
11589}
11590
11591/*********************************************************************
11592*********************************************************************/
11593/* static */
11594void
11595OSKext::saveLoadedKextPanicList(void)
11596{
11597 char * newlist = NULL;
11598 uint32_t newlist_size = 0;
11599
11600 newlist_size = KEXT_PANICLIST_SIZE;
11601 newlist = (char *)kalloc_tag(newlist_size, VM_KERN_MEMORY_OSKEXT);
11602
11603 if (!newlist) {
11604 OSKextLog(/* kext */ NULL,
11605 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
11606 "Couldn't allocate kext panic log buffer.");
11607 goto finish;
11608 }
11609
11610 newlist[0] = '\0';
11611
11612 // non-"com.apple." kexts
11613 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
11614 /* libs? */ -1, newlist, newlist_size) != 0) {
11615
11616 goto finish;
11617 }
11618 // "com.apple." nonlibrary kexts
11619 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
11620 /* libs? */ 0, newlist, newlist_size) != 0) {
11621
11622 goto finish;
11623 }
11624 // "com.apple." library kexts
11625 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
11626 /* libs? */ 1, newlist, newlist_size) != 0) {
11627
11628 goto finish;
11629 }
11630
11631 if (loaded_kext_paniclist) {
11632 kfree(loaded_kext_paniclist, loaded_kext_paniclist_size);
11633 }
11634 loaded_kext_paniclist = newlist;
11635 newlist = NULL;
11636 loaded_kext_paniclist_size = newlist_size;
11637
11638finish:
11639 if (newlist) {
11640 kfree(newlist, newlist_size);
11641 }
11642 return;
11643}
11644
11645/*********************************************************************
11646* Assumes sKextLock is held.
11647*********************************************************************/
11648void
11649OSKext::savePanicString(bool isLoading)
11650{
11651 u_long len;
11652
11653 if (!kmod_info) {
11654 return; // do not goto finish here b/c of lock
11655 }
11656
11657 len = assemble_identifier_and_version( kmod_info,
11658 (isLoading) ? last_loaded_str_buf : last_unloaded_str_buf,
11659 (isLoading) ? sizeof(last_loaded_str_buf) : sizeof(last_unloaded_str_buf) );
11660 if (!len) {
11661 printf("error saving unloaded kext info\n");
11662 goto finish;
11663 }
11664
11665 if (isLoading) {
11666 last_loaded_strlen = len;
11667 last_loaded_address = (void *)kmod_info->address;
11668 last_loaded_size = kmod_info->size;
11669 clock_get_uptime(&last_loaded_timestamp);
11670 } else {
11671 last_unloaded_strlen = len;
11672 last_unloaded_address = (void *)kmod_info->address;
11673 last_unloaded_size = kmod_info->size;
11674 clock_get_uptime(&last_unloaded_timestamp);
11675 }
11676
11677finish:
11678 return;
11679}
11680
11681/*********************************************************************
11682*********************************************************************/
11683/* static */
11684void
11685OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
11686{
11687 if (last_loaded_strlen) {
11688 printf_func("last loaded kext at %llu: %.*s (addr %p, size %lu)\n",
11689 AbsoluteTime_to_scalar(&last_loaded_timestamp),
11690 last_loaded_strlen, last_loaded_str_buf,
11691 last_loaded_address, last_loaded_size);
11692 }
11693
11694 if (last_unloaded_strlen) {
11695 printf_func("last unloaded kext at %llu: %.*s (addr %p, size %lu)\n",
11696 AbsoluteTime_to_scalar(&last_unloaded_timestamp),
11697 last_unloaded_strlen, last_unloaded_str_buf,
11698 last_unloaded_address, last_unloaded_size);
11699 }
11700
11701 printf_func("loaded kexts:\n");
11702 if (loaded_kext_paniclist &&
11703 pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
11704 loaded_kext_paniclist[0]) {
11705
11706 printf_func("%.*s",
11707 strnlen(loaded_kext_paniclist, loaded_kext_paniclist_size),
11708 loaded_kext_paniclist);
11709 } else {
11710 printf_func("(none)\n");
11711 }
11712 return;
11713}
11714
11715/*********************************************************************
11716* Assumes sKextLock is held.
11717*********************************************************************/
11718/* static */
11719void
11720OSKext::updateLoadedKextSummaries(void)
11721{
11722 kern_return_t result = KERN_FAILURE;
11723 OSKextLoadedKextSummaryHeader *summaryHeader = NULL;
11724 OSKextLoadedKextSummaryHeader *summaryHeaderAlloc = NULL;
11725 OSKext *aKext;
11726 vm_map_offset_t start, end;
11727 size_t summarySize = 0;
11728 size_t size;
11729 u_int count;
11730 u_int maxKexts;
11731 u_int i, j;
11732 OSKextActiveAccount * accountingList;
11733 OSKextActiveAccount * prevAccountingList;
11734 uint32_t idx, accountingListAlloc, accountingListCount, prevAccountingListCount;
11735
11736 prevAccountingList = NULL;
11737 prevAccountingListCount = 0;
11738
11739#if DEVELOPMENT || DEBUG
11740 if (IORecursiveLockHaveLock(sKextLock) == false) {
11741 panic("sKextLock must be held");
11742 }
11743#endif
11744
11745 IOLockLock(sKextSummariesLock);
11746
11747 count = sLoadedKexts->getCount();
11748 for (i = 0, maxKexts = 0; i < count; ++i) {
11749 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
11750 maxKexts += (aKext && aKext->isExecutable());
11751 }
11752
11753 if (!maxKexts) goto finish;
11754 if (maxKexts < kOSKextTypicalLoadCount) maxKexts = kOSKextTypicalLoadCount;
11755
11756 /* Calculate the size needed for the new summary headers.
11757 */
11758
11759 size = sizeof(*gLoadedKextSummaries);
11760 size += maxKexts * sizeof(*gLoadedKextSummaries->summaries);
11761 size = round_page(size);
11762
11763 if (gLoadedKextSummaries == NULL || sLoadedKextSummariesAllocSize < size) {
11764 if (gLoadedKextSummaries) {
11765 kmem_free(kernel_map, (vm_offset_t)gLoadedKextSummaries, sLoadedKextSummariesAllocSize);
11766 gLoadedKextSummaries = NULL;
11767 gLoadedKextSummariesTimestamp = mach_absolute_time();
11768 sLoadedKextSummariesAllocSize = 0;
11769 }
11770 result = kmem_alloc(kernel_map, (vm_offset_t *)&summaryHeaderAlloc, size, VM_KERN_MEMORY_OSKEXT);
11771 if (result != KERN_SUCCESS) goto finish;
11772 summaryHeader = summaryHeaderAlloc;
11773 summarySize = size;
11774 }
11775 else {
11776 summaryHeader = gLoadedKextSummaries;
11777 summarySize = sLoadedKextSummariesAllocSize;
11778
11779 start = (vm_map_offset_t) summaryHeader;
11780 end = start + summarySize;
11781 result = vm_map_protect(kernel_map,
11782 start,
11783 end,
11784 VM_PROT_DEFAULT,
11785 FALSE);
11786 if (result != KERN_SUCCESS) goto finish;
11787 }
11788
11789 /* Populate the summary header.
11790 */
11791
11792 bzero(summaryHeader, summarySize);
11793 summaryHeader->version = kOSKextLoadedKextSummaryVersion;
11794 summaryHeader->entry_size = sizeof(OSKextLoadedKextSummary);
11795
11796 /* Populate each kext summary.
11797 */
11798
11799 count = sLoadedKexts->getCount();
11800 accountingListAlloc = 0;
11801 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
11802 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
11803 if (!aKext || !aKext->isExecutable()) {
11804 continue;
11805 }
11806
11807 aKext->updateLoadedKextSummary(&summaryHeader->summaries[j++]);
11808 summaryHeader->numSummaries++;
11809 accountingListAlloc++;
11810 }
11811
11812 accountingList = IONew(typeof(accountingList[0]), accountingListAlloc);
11813 accountingListCount = 0;
11814 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
11815 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
11816 if (!aKext || !aKext->isExecutable()) {
11817 continue;
11818 }
11819
11820 OSKextActiveAccount activeAccount;
11821 aKext->updateActiveAccount(&activeAccount);
11822 // order by address
11823 for (idx = 0; idx < accountingListCount; idx++)
11824 {
11825 if (activeAccount.address < accountingList[idx].address) break;
11826 }
11827 bcopy(&accountingList[idx], &accountingList[idx + 1], (accountingListCount - idx) * sizeof(accountingList[0]));
11828 accountingList[idx] = activeAccount;
11829 accountingListCount++;
11830 }
11831 assert(accountingListCount == accountingListAlloc);
11832 /* Write protect the buffer and move it into place.
11833 */
11834
11835 start = (vm_map_offset_t) summaryHeader;
11836 end = start + summarySize;
11837
11838 result = vm_map_protect(kernel_map, start, end, VM_PROT_READ, FALSE);
11839 if (result != KERN_SUCCESS)
11840 goto finish;
11841
11842 gLoadedKextSummaries = summaryHeader;
11843 gLoadedKextSummariesTimestamp = mach_absolute_time();
11844 sLoadedKextSummariesAllocSize = summarySize;
11845 summaryHeaderAlloc = NULL;
11846
11847 /* Call the magic breakpoint function through a static function pointer so
11848 * the compiler can't optimize the function away.
11849 */
11850 if (sLoadedKextSummariesUpdated) (*sLoadedKextSummariesUpdated)();
11851
11852 IOSimpleLockLock(sKextAccountsLock);
11853 prevAccountingList = sKextAccounts;
11854 prevAccountingListCount = sKextAccountsCount;
11855 sKextAccounts = accountingList;
11856 sKextAccountsCount = accountingListCount;
11857 IOSimpleLockUnlock(sKextAccountsLock);
11858
11859finish:
11860 IOLockUnlock(sKextSummariesLock);
11861
11862 /* If we had to allocate a new buffer but failed to generate the summaries,
11863 * free that now.
11864 */
11865 if (summaryHeaderAlloc) {
11866 kmem_free(kernel_map, (vm_offset_t)summaryHeaderAlloc, summarySize);
11867 }
11868 if (prevAccountingList) {
11869 IODelete(prevAccountingList, typeof(accountingList[0]), prevAccountingListCount);
11870 }
11871
11872 return;
11873}
11874
11875/*********************************************************************
11876*********************************************************************/
11877void
11878OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary *summary)
11879{
11880 OSData *uuid;
11881
11882 strlcpy(summary->name, getIdentifierCString(),
11883 sizeof(summary->name));
11884
11885 uuid = copyUUID();
11886 if (uuid) {
11887 memcpy(summary->uuid, uuid->getBytesNoCopy(), sizeof(summary->uuid));
11888 OSSafeReleaseNULL(uuid);
11889 }
11890
11891 if (flags.builtin) {
11892// this value will stop lldb from parsing the mach-o header
11893// summary->address = UINT64_MAX;
11894// summary->size = 0;
11895 summary->address = kmod_info->address;
11896 summary->size = kmod_info->size;
11897 } else {
11898 summary->address = kmod_info->address;
11899 summary->size = kmod_info->size;
11900 }
11901 summary->version = getVersion();
11902 summary->loadTag = kmod_info->id;
11903 summary->flags = 0;
11904 summary->reference_list = (uint64_t) kmod_info->reference_list;
11905
11906 return;
11907}
11908
11909/*********************************************************************
11910*********************************************************************/
11911
11912void
11913OSKext::updateActiveAccount(OSKextActiveAccount *accountp)
11914{
11915 kernel_mach_header_t *hdr = NULL;
11916 kernel_segment_command_t *seg = NULL;
11917
11918 bzero(accountp, sizeof(*accountp));
11919
11920 hdr = (kernel_mach_header_t *)kmod_info->address;
11921 if (getcommandfromheader(hdr, LC_SEGMENT_SPLIT_INFO)) {
11922 /* If this kext supports split segments, use the first
11923 * executable segment as the range for instructions
11924 * (and thus for backtracing.
11925 */
11926 for (seg = firstsegfromheader(hdr); seg != NULL; seg = nextsegfromheader(hdr, seg)) {
11927 if (seg->initprot & VM_PROT_EXECUTE) {
11928 break;
11929 }
11930 }
11931 }
11932 if (seg) {
11933 accountp->address = seg->vmaddr;
11934 if (accountp->address) {
11935 accountp->address_end = seg->vmaddr + seg->vmsize;
11936 }
11937 } else {
11938 /* For non-split kexts and for kexts without executable
11939 * segments, just use the kmod_info range (as the kext
11940 * is either all in one range or should not show up in
11941 * instruction backtraces).
11942 */
11943 accountp->address = kmod_info->address;
11944 if (accountp->address) {
11945 accountp->address_end = kmod_info->address + kmod_info->size;
11946 }
11947 }
11948
11949 accountp->account = this->account;
11950}
11951
11952extern "C" const vm_allocation_site_t *
11953OSKextGetAllocationSiteForCaller(uintptr_t address)
11954{
11955 OSKextActiveAccount * active;
11956 vm_allocation_site_t * site;
11957 vm_allocation_site_t * releasesite;
11958
11959 uint32_t baseIdx;
11960 uint32_t lim;
11961
11962 IOSimpleLockLock(sKextAccountsLock);
11963 site = releasesite = NULL;
11964
11965 // bsearch sKextAccounts list
11966 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1)
11967 {
11968 active = &sKextAccounts[baseIdx + (lim >> 1)];
11969 if ((address >= active->address) && (address < active->address_end))
11970 {
11971 site = &active->account->site;
11972 if (!site->tag) vm_tag_alloc_locked(site, &releasesite);
11973 break;
11974 }
11975 else if (address > active->address)
11976 {
11977 // move right
11978 baseIdx += (lim >> 1) + 1;
11979 lim--;
11980 }
11981 // else move left
11982 }
11983 IOSimpleLockUnlock(sKextAccountsLock);
11984 if (releasesite) kern_allocation_name_release(releasesite);
11985
11986 return (site);
11987}
11988
11989extern "C" uint32_t
11990OSKextGetKmodIDForSite(const vm_allocation_site_t * site, char * name, vm_size_t namelen)
11991{
11992 OSKextAccount * account = (typeof(account)) site;
11993 const char * kname;
11994
11995 if (name)
11996 {
11997 if (account->kext) kname = account->kext->getIdentifierCString();
11998 else kname = "<>";
11999 strlcpy(name, kname, namelen);
12000 }
12001
12002 return (account->loadTag);
12003}
12004
12005extern "C" void
12006OSKextFreeSite(vm_allocation_site_t * site)
12007{
12008 OSKextAccount * freeAccount = (typeof(freeAccount)) site;
12009 IODelete(freeAccount, OSKextAccount, 1);
12010}
12011
12012/*********************************************************************
12013*********************************************************************/
12014
12015#if CONFIG_IMAGEBOOT
12016int OSKextGetUUIDForName(const char *name, uuid_t uuid)
12017{
12018 OSKext *kext = OSKext::lookupKextWithIdentifier(name);
12019 if (!kext) {
12020 return 1;
12021 }
12022
12023 OSData *uuid_data = kext->copyUUID();
12024 if (uuid_data) {
12025 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_t));
12026 OSSafeReleaseNULL(uuid_data);
12027 return 0;
12028 }
12029
12030 return 1;
12031}
12032#endif
12033