]> git.saurik.com Git - apple/xnu.git/blame - libkern/c++/OSKext.cpp
xnu-2050.7.9.tar.gz
[apple/xnu.git] / libkern / c++ / OSKext.cpp
CommitLineData
b0d623f7
A
1/*
2 * Copyright (c) 2008-2009 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 <kern/clock.h>
31#include <kern/host.h>
32#include <kern/kext_alloc.h>
33#include <kextd/kextd_mach.h>
34#include <libkern/kernel_mach_header.h>
35#include <libkern/kext_panic_report.h>
36#include <libkern/kext_request_keys.h>
37#include <libkern/mkext.h>
38#include <libkern/prelink.h>
39#include <libkern/version.h>
40#include <libkern/zlib.h>
6d2010ae 41#include <mach/host_special_ports.h>
b0d623f7 42#include <mach/mach_vm.h>
6d2010ae 43#include <mach/mach_time.h>
b0d623f7 44#include <sys/sysctl.h>
6d2010ae
A
45#include <uuid/uuid.h>
46// 04/18/11 - gab: <rdar://problem/9236163>
47#include <sys/random.h>
b0d623f7
A
48};
49
50#include <libkern/OSKextLibPrivate.h>
51#include <libkern/c++/OSKext.h>
52#include <libkern/c++/OSLib.h>
53
54#include <IOKit/IOLib.h>
55#include <IOKit/IOCatalogue.h>
56#include <IOKit/IORegistryEntry.h>
57#include <IOKit/IOService.h>
58
6d2010ae
A
59#include <IOKit/IOStatisticsPrivate.h>
60
b0d623f7
A
61#if PRAGMA_MARK
62#pragma mark External & Internal Function Protos
63#endif
64/*********************************************************************
65*********************************************************************/
66extern "C" {
b0d623f7
A
67extern int IODTGetLoaderInfo(const char * key, void ** infoAddr, int * infoSize);
68extern void IODTFreeLoaderInfo(const char * key, void * infoAddr, int infoSize);
69extern void OSRuntimeUnloadCPPForSegment(kernel_segment_command_t * segment);
70extern void OSRuntimeUnloadCPP(kmod_info_t * ki, void * data);
71
72extern ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va); /* osfmk/machine/pmap.h */
73}
74
75static OSReturn _OSKextCreateRequest(
76 const char * predicate,
77 OSDictionary ** requestP);
78static OSString * _OSKextGetRequestPredicate(OSDictionary * requestDict);
79static OSObject * _OSKextGetRequestArgument(
80 OSDictionary * requestDict,
81 const char * argName);
82static bool _OSKextSetRequestArgument(
83 OSDictionary * requestDict,
84 const char * argName,
85 OSObject * value);
86static void * _OSKextExtractPointer(OSData * wrapper);
87static OSReturn _OSDictionarySetCStringValue(
88 OSDictionary * dict,
89 const char * key,
90 const char * value);
316670eb
A
91static bool _OSKextInPrelinkRebuildWindow(void);
92static bool _OSKextInUnloadedPrelinkedKexts(const OSSymbol * theBundleID);
6d2010ae
A
93
94// We really should add containsObject() & containsCString to OSCollection & subclasses.
95// So few pad slots, though....
96static bool _OSArrayContainsCString(OSArray * array, const char * cString);
97
316670eb
A
98#if CONFIG_KEC_FIPS
99static void * GetAppleTEXTHashForKext(OSKext * theKext, OSDictionary *theInfoDict);
100#endif // CONFIG_KEC_FIPS
101
102/* Prelinked arm kexts do not have VM entries because the method we use to
103 * fake an entry (see libsa/bootstrap.cpp:readPrelinkedExtensions()) does
104 * not work on ARM. To get around that, we must free prelinked kext
105 * executables with ml_static_mfree() instead of kext_free().
106 */
107#if __i386__ || __x86_64__
108#define VM_MAPPED_KEXTS 1
109#define KASLR_KEXT_DEBUG 0
110#define KASLR_IOREG_DEBUG 0
111#else
112#error Unsupported architecture
113#endif
b0d623f7
A
114
115#if PRAGMA_MARK
116#pragma mark Constants & Macros
117#endif
118/*********************************************************************
119* Constants & Macros
120*********************************************************************/
121
122/* A typical Snow Leopard system has a bit under 120 kexts loaded.
123 * Use this number to create containers.
124 */
125#define kOSKextTypicalLoadCount (120)
126
127/* Any kext will have at least 1 retain for the internal lookup-by-ID dict.
128 * A loaded kext will no dependents or external retains will have 2 retains.
129 */
130#define kOSKextMinRetainCount (1)
131#define kOSKextMinLoadedRetainCount (2)
132
133/**********
134 * Strings and substrings used in dependency resolution.
135 */
136#define APPLE_KEXT_PREFIX "com.apple."
137#define KERNEL_LIB "com.apple.kernel"
138
139#define PRIVATE_KPI "com.apple.kpi.private"
140
141/* Version for compatbility pseudokexts (com.apple.kernel.*),
142 * compatible back to v6.0.
143 */
144#define KERNEL6_LIB "com.apple.kernel.6.0"
145#define KERNEL6_VERSION "7.9.9"
146
147#define KERNEL_LIB_PREFIX "com.apple.kernel."
148#define KPI_LIB_PREFIX "com.apple.kpi."
149
150#define STRING_HAS_PREFIX(s, p) (strncmp((s), (p), strlen(p)) == 0)
151
316670eb
A
152#define REBUILD_MAX_TIME (60 * 5) // 5 minutes
153#define MINIMUM_WAKEUP_SECONDS (30)
154
b0d623f7
A
155/*********************************************************************
156* infoDict keys for internally-stored data. Saves on ivar slots for
157* objects we don't keep around past boot time or during active load.
158*********************************************************************/
159
160/* A usable, uncompressed file is stored under this key.
161 */
162#define _kOSKextExecutableKey "_OSKextExecutable"
163
164/* An indirect reference to the executable file from an mkext
165 * is stored under this key.
166 */
167#define _kOSKextMkextExecutableReferenceKey "_OSKextMkextExecutableReference"
168
169/* If the file is contained in a larger buffer laid down by the booter or
170 * sent from user space, the OSKext stores that OSData under this key so that
171 * references are properly tracked. This is always an mkext, right now.
172 */
173#define _kOSKextExecutableExternalDataKey "_OSKextExecutableExternalData"
174
175#if PRAGMA_MARK
176#pragma mark Typedefs
177#endif
178/*********************************************************************
179* Typedefs
180*********************************************************************/
181
182/*********************************************************************
183* MkextEntryRef describes the contents of an OSData object
184* referencing a file entry from an mkext so that we can uncompress
185* (if necessary) and extract it on demand.
186*
187* It contains the mkextVersion in case we ever wind up supporting
188* multiple mkext formats. Mkext format 1 is officially retired as of
189* Snow Leopard.
190*********************************************************************/
191typedef struct MkextEntryRef {
192 mkext_basic_header * mkext; // beginning of whole mkext file
193 void * fileinfo; // mkext2_file_entry or equiv; see mkext.h
194} MkextEntryRef;
195
196#if PRAGMA_MARK
197#pragma mark Global and static Module Variables
198#endif
199/*********************************************************************
200* Global & static variables, used to keep track of kexts.
201*********************************************************************/
202
203static bool sPrelinkBoot = false;
204static bool sSafeBoot = false;
6d2010ae 205static bool sKeepSymbols = false;
b0d623f7 206
6d2010ae
A
207/*********************************************************************
208* sKextLock is the principal lock for OSKext, and guards all static
209* and global variables not owned by other locks (declared further
210* below). It must be taken by any entry-point method or function,
211* including internal functions called on scheduled threads.
212*
213* sKextLock and sKextInnerLock are recursive due to multiple functions
214* that are called both externally and internally. The other locks are
215* nonrecursive.
216*
217* Which locks are taken depends on what they protect, but if more than
218* one must be taken, they must always be locked in this order
219* (and unlocked in reverse order) to prevent deadlocks:
220*
221* 1. sKextLock
222* 2. sKextInnerLock
223* 3. sKextSummariesLock
224* 4. sKextLoggingLock
b0d623f7
A
225*/
226static IORecursiveLock * sKextLock = NULL;
227
228static OSDictionary * sKextsByID = NULL;
229static OSArray * sLoadedKexts = NULL;
6d2010ae 230static OSArray * sUnloadedPrelinkedKexts = NULL;
b0d623f7 231
b0d623f7
A
232// Requests to kextd waiting to be picked up.
233static OSArray * sKernelRequests = NULL;
234// Identifier of kext load requests in sKernelRequests
235static OSSet * sPostedKextLoadIdentifiers = NULL;
236static OSArray * sRequestCallbackRecords = NULL;
237
238// Identifiers of all kexts ever requested in kernel; used for prelinked kernel
239static OSSet * sAllKextLoadIdentifiers = NULL;
240static KXLDContext * sKxldContext = NULL;
241static uint32_t sNextLoadTag = 0;
242static uint32_t sNextRequestTag = 0;
243
244static bool sUserLoadsActive = false;
245static bool sKextdActive = false;
246static bool sDeferredLoadSucceeded = false;
247static bool sConsiderUnloadsExecuted = false;
248
6d2010ae
A
249#if NO_KEXTD
250static bool sKernelRequestsEnabled = false;
251#else
b0d623f7 252static bool sKernelRequestsEnabled = true;
6d2010ae 253#endif
b0d623f7
A
254static bool sLoadEnabled = true;
255static bool sUnloadEnabled = true;
256
257/*********************************************************************
258* Stuff for the OSKext representing the kernel itself.
259**********/
260static OSKext * sKernelKext = NULL;
261
262/* Set up a fake kmod_info struct for the kernel.
263 * It's used in OSRuntime.cpp to call OSRuntimeInitializeCPP()
264 * before OSKext is initialized; that call only needs the name
265 * and address to be set correctly.
266 *
267 * We don't do much else with the kerne's kmod_info; we never
268 * put it into the kmod list, never adjust the reference count,
269 * and never have kernel components reference it.
270 * For that matter, we don't do much with kmod_info structs
271 * at all anymore! We just keep them filled in for gdb and
272 * binary compability.
273 */
274kmod_info_t g_kernel_kmod_info = {
275 /* next */ 0,
276 /* info_version */ KMOD_INFO_VERSION,
277 /* id */ 0, // loadTag: kernel is always 0
278 /* name */ kOSKextKernelIdentifier, // bundle identifier
279 /* version */ "0", // filled in in OSKext::initialize()
280 /* reference_count */ -1, // never adjusted; kernel never unloads
281 /* reference_list */ NULL,
316670eb 282 /* address */ NULL,
b0d623f7
A
283 /* size */ 0, // filled in in OSKext::initialize()
284 /* hdr_size */ 0,
285 /* start */ 0,
286 /* stop */ 0
287};
288
289extern "C" {
290// symbol 'kmod' referenced in: model_dep.c, db_trace.c, symbols.c, db_low_trace.c,
291// dtrace.c, dtrace_glue.h, OSKext.cpp, locore.s, lowmem_vectors.s,
292// misc_protos.h, db_low_trace.c, kgmacros
293// 'kmod' is a holdover from the old kmod system, we can't rename it.
294kmod_info_t * kmod = NULL;
295
296#define KEXT_PANICLIST_SIZE (2 * PAGE_SIZE)
297
6d2010ae
A
298
299static char * loaded_kext_paniclist = NULL;
300static uint32_t loaded_kext_paniclist_size = 0;
301static uint32_t loaded_kext_paniclist_length = 0;
302
b0d623f7 303AbsoluteTime last_loaded_timestamp;
6d2010ae
A
304static char last_loaded_str[2*KMOD_MAX_NAME];
305static u_long last_loaded_strlen = 0;
306static void * last_loaded_address = NULL;
307static u_long last_loaded_size = 0;
b0d623f7 308
b0d623f7 309AbsoluteTime last_unloaded_timestamp;
6d2010ae
A
310static char last_unloaded_str[2*KMOD_MAX_NAME];
311static u_long last_unloaded_strlen = 0;
312static void * last_unloaded_address = NULL;
313static u_long last_unloaded_size = 0;
b0d623f7
A
314
315/*********************************************************************
6d2010ae
A
316* sKextInnerLock protects against cross-calls with IOService and
317* IOCatalogue, and owns the variables declared immediately below.
b0d623f7
A
318*
319* Note that sConsiderUnloadsExecuted above belongs to sKextLock!
320*
321* When both sKextLock and sKextInnerLock need to be taken,
322* always lock sKextLock first and unlock it second. Never take both
323* locks in an entry point to OSKext; if you need to do so, you must
324* spawn an independent thread to avoid potential deadlocks for threads
325* calling into OSKext.
b0d623f7
A
326**********/
327static IORecursiveLock * sKextInnerLock = NULL;
328
329static bool sAutounloadEnabled = true;
330static bool sConsiderUnloadsCalled = false;
331static bool sConsiderUnloadsPending = false;
332
333static unsigned int sConsiderUnloadDelay = 60; // seconds
334static thread_call_t sUnloadCallout = 0;
335static thread_call_t sDestroyLinkContextThread = 0; // one-shot, one-at-a-time thread
336static bool sSystemSleep = false; // true when system going to sleep
316670eb 337static AbsoluteTime sLastWakeTime; // last time we woke up
b0d623f7 338
6d2010ae
A
339/*********************************************************************
340* Backtraces can be printed at various times so we need a tight lock
341* on data used for that. sKextSummariesLock protects the variables
342* declared immediately below.
343*
344* gLoadedKextSummaries is accessed by other modules, but only during
345* a panic so the lock isn't needed then.
346**********/
347static IOLock * sKextSummariesLock = NULL;
348
349void (*sLoadedKextSummariesUpdated)(void) = OSKextLoadedKextSummariesUpdated;
350OSKextLoadedKextSummaryHeader * gLoadedKextSummaries = NULL;
351static size_t sLoadedKextSummariesAllocSize = 0;
352OSKextLoadedKextSummaryHeader * sPrevLoadedKextSummaries = NULL;
353static size_t sPrevLoadedKextSummariesAllocSize = 0;
354};
355
356/*********************************************************************
357* sKextLoggingLock protects the logging variables declared immediately below.
358**********/
359static IOLock * sKextLoggingLock = NULL;
360
b0d623f7
A
361static const OSKextLogSpec kDefaultKernelLogFilter = kOSKextLogBasicLevel |
362 kOSKextLogVerboseFlagsMask;
363static OSKextLogSpec sKernelLogFilter = kDefaultKernelLogFilter;
364static bool sBootArgLogFilterFound = false;
6d2010ae 365SYSCTL_INT(_debug, OID_AUTO, kextlog, CTLFLAG_RW | CTLFLAG_LOCKED, &sKernelLogFilter,
b0d623f7
A
366 sKernelLogFilter, "kernel kext logging");
367
368static OSKextLogSpec sUserSpaceKextLogFilter = kOSKextLogSilentFilter;
369static OSArray * sUserSpaceLogSpecArray = NULL;
370static OSArray * sUserSpaceLogMessageArray = NULL;
371
372/*********
373* End scope for sKextInnerLock-protected variables.
374*********************************************************************/
375
376#if PRAGMA_MARK
377#pragma mark OSData callbacks (need to move to OSData)
378#endif
379/*********************************************************************
380* C functions used for callbacks.
381*********************************************************************/
382extern "C" {
383void osdata_kmem_free(void * ptr, unsigned int length) {
384 kmem_free(kernel_map, (vm_address_t)ptr, length);
385 return;
386}
387
388void osdata_phys_free(void * ptr, unsigned int length) {
389 ml_static_mfree((vm_offset_t)ptr, length);
390 return;
391}
392
393void osdata_vm_deallocate(void * ptr, unsigned int length)
394{
395 (void)vm_deallocate(kernel_map, (vm_offset_t)ptr, length);
396 return;
397}
6d2010ae
A
398
399void osdata_kext_free(void * ptr, unsigned int length)
400{
401 (void)kext_free((vm_offset_t)ptr, length);
402}
403
b0d623f7
A
404};
405
406#if PRAGMA_MARK
407#pragma mark KXLD Allocation Callback
408#endif
409/*********************************************************************
410* KXLD Allocation Callback
411*********************************************************************/
412kxld_addr_t
413kern_allocate(
414 u_long size,
415 KXLDAllocateFlags * flags,
416 void * user_data)
417{
418 vm_address_t result = 0; // returned
419 kern_return_t mach_result = KERN_FAILURE;
420 bool success = false;
421 OSKext * theKext = (OSKext *)user_data;
422 u_long roundSize = round_page(size);
423 OSData * linkBuffer = NULL; // must release
424
425 mach_result = kext_alloc(&result, roundSize, /* fixed */ FALSE);
426 if (mach_result != KERN_SUCCESS) {
427 OSKextLog(theKext,
428 kOSKextLogErrorLevel |
429 kOSKextLogGeneralFlag,
430 "Can't allocate kernel memory to link %s.",
431 theKext->getIdentifierCString());
432 goto finish;
433 }
434
435 /* Create an OSData wrapper for the allocated buffer.
b0d623f7
A
436 */
437 linkBuffer = OSData::withBytesNoCopy((void *)result, roundSize);
438 if (!linkBuffer) {
439 OSKextLog(theKext,
440 kOSKextLogErrorLevel |
441 kOSKextLogGeneralFlag,
442 "Can't allocate linked executable wrapper for %s.",
443 theKext->getIdentifierCString());
444 goto finish;
445 }
6d2010ae 446 linkBuffer->setDeallocFunction(osdata_kext_free);
b0d623f7
A
447
448 OSKextLog(theKext,
449 kOSKextLogProgressLevel |
450 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
451 "Allocated link buffer for kext %s at %p (%lu bytes).",
452 theKext->getIdentifierCString(),
453 (void *)result, (unsigned long)roundSize);
454
455 theKext->setLinkedExecutable(linkBuffer);
456
457 *flags = kKxldAllocateWritable;
458 success = true;
459
460finish:
461 if (!success && result) {
462 kext_free(result, roundSize);
463 result = 0;
464 }
465
466 OSSafeRelease(linkBuffer);
467
468 return (kxld_addr_t)result;
469}
470
471/*********************************************************************
472*********************************************************************/
473void
474kxld_log_callback(
475 KXLDLogSubsystem subsystem,
476 KXLDLogLevel level,
477 const char * format,
478 va_list argList,
479 void * user_data)
480{
481 OSKext *theKext = (OSKext *) user_data;
482 OSKextLogSpec logSpec = 0;
483
484 switch (subsystem) {
485 case kKxldLogLinking:
486 logSpec |= kOSKextLogLinkFlag;
487 break;
488 case kKxldLogPatching:
489 logSpec |= kOSKextLogPatchFlag;
490 break;
491 }
492
493 switch (level) {
494 case kKxldLogExplicit:
495 logSpec |= kOSKextLogExplicitLevel;
496 break;
497 case kKxldLogErr:
498 logSpec |= kOSKextLogErrorLevel;
499 break;
500 case kKxldLogWarn:
501 logSpec |= kOSKextLogWarningLevel;
502 break;
503 case kKxldLogBasic:
504 logSpec |= kOSKextLogProgressLevel;
505 break;
506 case kKxldLogDetail:
507 logSpec |= kOSKextLogDetailLevel;
508 break;
509 case kKxldLogDebug:
510 logSpec |= kOSKextLogDebugLevel;
511 break;
512 }
513
514 OSKextVLog(theKext, logSpec, format, argList);
515}
516
6d2010ae
A
517#if PRAGMA_MARK
518#pragma mark IOStatistics defines
519#endif
520
521#if IOKITSTATS
522
523#define notifyKextLoadObservers(kext, kmod_info) \
524do { \
316670eb 525 IOStatistics::onKextLoad(kext, kmod_info); \
6d2010ae
A
526} while (0)
527
528#define notifyKextUnloadObservers(kext) \
529do { \
316670eb 530 IOStatistics::onKextUnload(kext); \
6d2010ae
A
531} while (0)
532
533#define notifyAddClassObservers(kext, addedClass, flags) \
534do { \
316670eb 535 IOStatistics::onClassAdded(kext, addedClass); \
6d2010ae
A
536} while (0)
537
538#define notifyRemoveClassObservers(kext, removedClass, flags) \
539do { \
316670eb 540 IOStatistics::onClassRemoved(kext, removedClass); \
6d2010ae
A
541} while (0)
542
543#else
544
545#define notifyKextLoadObservers(kext, kmod_info)
546#define notifyKextUnloadObservers(kext)
547#define notifyAddClassObservers(kext, addedClass, flags)
548#define notifyRemoveClassObservers(kext, removedClass, flags)
549
550#endif /* IOKITSTATS */
551
b0d623f7
A
552#if PRAGMA_MARK
553#pragma mark Module Config (Startup & Shutdown)
554#endif
555/*********************************************************************
556* Module Config (Class Definition & Class Methods)
557*********************************************************************/
558#define super OSObject
559OSDefineMetaClassAndStructors(OSKext, OSObject)
560
561/*********************************************************************
562*********************************************************************/
563/* static */
564void
565OSKext::initialize(void)
566{
567 OSData * kernelExecutable = NULL; // do not release
568 u_char * kernelStart = NULL; // do not free
569 size_t kernelLength = 0;
570 OSString * scratchString = NULL; // must release
571 IORegistryEntry * registryRoot = NULL; // do not release
572 OSNumber * kernelCPUType = NULL; // must release
573 OSNumber * kernelCPUSubtype = NULL; // must release
574 OSKextLogSpec bootLogFilter = kOSKextLogSilentFilter;
575 bool setResult = false;
576 uint64_t * timestamp = 0;
577 char bootArgBuffer[16]; // for PE_parse_boot_argn w/strings
578
579 /* This must be the first thing allocated. Everything else grabs this lock.
580 */
581 sKextLock = IORecursiveLockAlloc();
582 sKextInnerLock = IORecursiveLockAlloc();
6d2010ae
A
583 sKextSummariesLock = IOLockAlloc();
584 sKextLoggingLock = IOLockAlloc();
b0d623f7
A
585 assert(sKextLock);
586 assert(sKextInnerLock);
6d2010ae
A
587 assert(sKextSummariesLock);
588 assert(sKextLoggingLock);
b0d623f7
A
589
590 sKextsByID = OSDictionary::withCapacity(kOSKextTypicalLoadCount);
591 sLoadedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
6d2010ae 592 sUnloadedPrelinkedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount / 10);
b0d623f7
A
593 sKernelRequests = OSArray::withCapacity(0);
594 sPostedKextLoadIdentifiers = OSSet::withCapacity(0);
595 sAllKextLoadIdentifiers = OSSet::withCapacity(kOSKextTypicalLoadCount);
596 sRequestCallbackRecords = OSArray::withCapacity(0);
597 assert(sKextsByID && sLoadedKexts && sKernelRequests &&
598 sPostedKextLoadIdentifiers && sAllKextLoadIdentifiers &&
6d2010ae 599 sRequestCallbackRecords && sUnloadedPrelinkedKexts);
b0d623f7
A
600
601 /* Read the log flag boot-args and set the log flags.
602 */
316670eb 603 if (PE_parse_boot_argn("kextlog", &bootLogFilter, sizeof(bootLogFilter))) {
b0d623f7
A
604 sBootArgLogFilterFound = true;
605 sKernelLogFilter = bootLogFilter;
606 // log this if any flags are set
607 OSKextLog(/* kext */ NULL,
608 kOSKextLogBasicLevel |
609 kOSKextLogFlagsMask,
610 "Kernel kext log filter 0x%x per kextlog boot arg.",
611 (unsigned)sKernelLogFilter);
612 }
613
614 sSafeBoot = PE_parse_boot_argn("-x", bootArgBuffer,
615 sizeof(bootArgBuffer)) ? true : false;
616
617 if (sSafeBoot) {
618 OSKextLog(/* kext */ NULL,
619 kOSKextLogWarningLevel |
620 kOSKextLogGeneralFlag,
621 "SAFE BOOT DETECTED - "
622 "only valid OSBundleRequired kexts will be loaded.");
623 }
624
6d2010ae
A
625 PE_parse_boot_argn("keepsyms", &sKeepSymbols, sizeof(sKeepSymbols));
626
b0d623f7
A
627 /* Set up an OSKext instance to represent the kernel itself.
628 */
629 sKernelKext = new OSKext;
630 assert(sKernelKext);
631
632 kernelStart = (u_char *)&_mh_execute_header;
633 kernelLength = getlastaddr() - (vm_offset_t)kernelStart;
634 kernelExecutable = OSData::withBytesNoCopy(
635 kernelStart, kernelLength);
636 assert(kernelExecutable);
637
316670eb
A
638#if KASLR_KEXT_DEBUG
639 IOLog("kaslr: kernel start 0x%lx end 0x%lx length %lu \n",
640 (unsigned long)kernelStart,
641 (unsigned long)getlastaddr(),
642 kernelLength);
643#endif
644
b0d623f7
A
645 sKernelKext->loadTag = sNextLoadTag++; // the kernel is load tag 0
646 sKernelKext->bundleID = OSSymbol::withCString(kOSKextKernelIdentifier);
647
648 sKernelKext->version = OSKextParseVersionString(osrelease);
649 sKernelKext->compatibleVersion = sKernelKext->version;
650 sKernelKext->linkedExecutable = kernelExecutable;
b0d623f7
A
651
652 sKernelKext->flags.hasAllDependencies = 1;
653 sKernelKext->flags.kernelComponent = 1;
654 sKernelKext->flags.prelinked = 0;
655 sKernelKext->flags.loaded = 1;
656 sKernelKext->flags.started = 1;
657 sKernelKext->flags.CPPInitialized = 0;
316670eb 658 sKernelKext->flags.jettisonLinkeditSeg = 0;
b0d623f7
A
659
660 sKernelKext->kmod_info = &g_kernel_kmod_info;
661 strlcpy(g_kernel_kmod_info.version, osrelease,
662 sizeof(g_kernel_kmod_info.version));
663 g_kernel_kmod_info.size = kernelLength;
664 g_kernel_kmod_info.id = sKernelKext->loadTag;
665
666 /* Cons up an info dict, so we don't have to have special-case
667 * checking all over.
668 */
669 sKernelKext->infoDict = OSDictionary::withCapacity(5);
670 assert(sKernelKext->infoDict);
671 setResult = sKernelKext->infoDict->setObject(kCFBundleIdentifierKey,
672 sKernelKext->bundleID);
673 assert(setResult);
674 setResult = sKernelKext->infoDict->setObject(kOSKernelResourceKey,
675 kOSBooleanTrue);
676 assert(setResult);
677
678 scratchString = OSString::withCStringNoCopy(osrelease);
679 assert(scratchString);
680 setResult = sKernelKext->infoDict->setObject(kCFBundleVersionKey,
681 scratchString);
682 assert(setResult);
683 OSSafeReleaseNULL(scratchString);
684
685 scratchString = OSString::withCStringNoCopy("mach_kernel");
686 assert(scratchString);
687 setResult = sKernelKext->infoDict->setObject(kCFBundleNameKey,
688 scratchString);
689 assert(setResult);
690 OSSafeReleaseNULL(scratchString);
691
692 /* Add the kernel kext to the bookkeeping dictionaries. Note that
693 * the kernel kext doesn't have a kmod_info struct. copyInfo()
694 * gathers info from other places anyhow.
695 */
696 setResult = sKextsByID->setObject(sKernelKext->bundleID, sKernelKext);
697 assert(setResult);
698 setResult = sLoadedKexts->setObject(sKernelKext);
699 assert(setResult);
700 sKernelKext->release();
701
702 registryRoot = IORegistryEntry::getRegistryRoot();
703 kernelCPUType = OSNumber::withNumber(
704 (long long unsigned int)_mh_execute_header.cputype,
705 8 * sizeof(_mh_execute_header.cputype));
706 kernelCPUSubtype = OSNumber::withNumber(
707 (long long unsigned int)_mh_execute_header.cpusubtype,
708 8 * sizeof(_mh_execute_header.cpusubtype));
709 assert(registryRoot && kernelCPUSubtype && kernelCPUType);
710
711 registryRoot->setProperty(kOSKernelCPUTypeKey, kernelCPUType);
712 registryRoot->setProperty(kOSKernelCPUSubtypeKey, kernelCPUSubtype);
713
714 OSSafeRelease(kernelCPUType);
715 OSSafeRelease(kernelCPUSubtype);
716
717 timestamp = __OSAbsoluteTimePtr(&last_loaded_timestamp);
718 *timestamp = 0;
719 timestamp = __OSAbsoluteTimePtr(&last_unloaded_timestamp);
720 *timestamp = 0;
316670eb
A
721 timestamp = __OSAbsoluteTimePtr(&sLastWakeTime);
722 *timestamp = 0;
b0d623f7
A
723
724 OSKextLog(/* kext */ NULL,
725 kOSKextLogProgressLevel |
726 kOSKextLogGeneralFlag,
727 "Kext system initialized.");
728
6d2010ae 729 notifyKextLoadObservers(sKernelKext, sKernelKext->kmod_info);
316670eb 730
b0d623f7
A
731 return;
732}
733
734/*********************************************************************
735* This could be in OSKextLib.cpp but we need to hold a lock
736* while removing all the segments and sKextLock will do.
737*********************************************************************/
738/* static */
739OSReturn
740OSKext::removeKextBootstrap(void)
741{
742 OSReturn result = kOSReturnError;
743
744 static bool alreadyDone = false;
b0d623f7
A
745
746 const char * dt_kernel_header_name = "Kernel-__HEADER";
747 const char * dt_kernel_symtab_name = "Kernel-__SYMTAB";
748 kernel_mach_header_t * dt_mach_header = NULL;
749 int dt_mach_header_size = 0;
750 struct symtab_command * dt_symtab = NULL;
751 int dt_symtab_size = 0;
752 int dt_result = 0;
753
754 kernel_segment_command_t * seg_to_remove = NULL;
b0d623f7 755
316670eb 756
b0d623f7
A
757 /* This must be the very first thing done by this function.
758 */
759 IORecursiveLockLock(sKextLock);
760
761 /* If we already did this, it's a success.
762 */
763 if (alreadyDone) {
764 result = kOSReturnSuccess;
765 goto finish;
766 }
767
768 OSKextLog(/* kext */ NULL,
769 kOSKextLogProgressLevel |
770 kOSKextLogGeneralFlag,
771 "Jettisoning kext bootstrap segments.");
772
b0d623f7
A
773 /*****
774 * Dispose of unnecessary stuff that the booter didn't need to load.
775 */
776 dt_result = IODTGetLoaderInfo(dt_kernel_header_name,
777 (void **)&dt_mach_header, &dt_mach_header_size);
778 if (dt_result == 0 && dt_mach_header) {
779 IODTFreeLoaderInfo(dt_kernel_header_name, (void *)dt_mach_header,
780 round_page_32(dt_mach_header_size));
781 }
782 dt_result = IODTGetLoaderInfo(dt_kernel_symtab_name,
783 (void **)&dt_symtab, &dt_symtab_size);
784 if (dt_result == 0 && dt_symtab) {
785 IODTFreeLoaderInfo(dt_kernel_symtab_name, (void *)dt_symtab,
786 round_page_32(dt_symtab_size));
787 }
788
789 /*****
790 * KLD bootstrap segment.
791 */
792 // xxx - should rename KLD segment
793 seg_to_remove = getsegbyname("__KLD");
794 if (seg_to_remove) {
795 OSRuntimeUnloadCPPForSegment(seg_to_remove);
796 }
797
6d2010ae 798#if __i386__ || __x86_64__
b0d623f7
A
799 /* On x86, use the mapping data from the segment load command to
800 * unload KLD directly.
801 * This may invalidate any assumptions about "avail_start"
802 * defining the lower bound for valid physical addresses.
803 */
804 if (seg_to_remove && seg_to_remove->vmaddr && seg_to_remove->vmsize) {
316670eb
A
805 // 04/18/11 - gab: <rdar://problem/9236163>
806 // overwrite memory occupied by KLD segment with random data before
807 // releasing it.
808 read_random((void *) seg_to_remove->vmaddr, seg_to_remove->vmsize);
b0d623f7
A
809 ml_static_mfree(seg_to_remove->vmaddr, seg_to_remove->vmsize);
810 }
811#else
812#error arch
813#endif
814
815 seg_to_remove = NULL;
816
6d2010ae 817 /*****
b0d623f7
A
818 * Prelinked kernel's symtab (if there is one).
819 */
820 kernel_section_t * sect;
821 sect = getsectbyname("__PRELINK", "__symtab");
822 if (sect && sect->addr && sect->size) {
823 ml_static_mfree(sect->addr, sect->size);
824 }
825
6d2010ae
A
826 seg_to_remove = (kernel_segment_command_t *)getsegbyname("__LINKEDIT");
827
828 /* kxld always needs the kernel's __LINKEDIT segment, but we can make it
829 * pageable, unless keepsyms is set. To do that, we have to copy it from
830 * its booter-allocated memory, free the booter memory, reallocate proper
831 * managed memory, then copy the segment back in.
832 */
833#if CONFIG_KXLD
834 if (!sKeepSymbols) {
835 kern_return_t mem_result;
836 void *seg_copy = NULL;
837 void *seg_data = NULL;
838 vm_map_offset_t seg_offset = 0;
839 vm_map_offset_t seg_copy_offset = 0;
840 vm_map_size_t seg_length = 0;
841
842 seg_data = (void *) seg_to_remove->vmaddr;
843 seg_offset = (vm_map_offset_t) seg_to_remove->vmaddr;
844 seg_length = (vm_map_size_t) seg_to_remove->vmsize;
845
846 /* Allocate space for the LINKEDIT copy.
847 */
848 mem_result = kmem_alloc(kernel_map, (vm_offset_t *) &seg_copy,
849 seg_length);
850 if (mem_result != KERN_SUCCESS) {
851 OSKextLog(/* kext */ NULL,
852 kOSKextLogErrorLevel |
853 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
854 "Can't copy __LINKEDIT segment for VM reassign.");
855 goto finish;
b0d623f7 856 }
6d2010ae 857 seg_copy_offset = (vm_map_offset_t) seg_copy;
b0d623f7 858
6d2010ae
A
859 /* Copy it out.
860 */
861 memcpy(seg_copy, seg_data, seg_length);
316670eb 862
6d2010ae
A
863 /* Dump the booter memory.
864 */
865 ml_static_mfree(seg_offset, seg_length);
b0d623f7 866
6d2010ae
A
867 /* Set up the VM region.
868 */
869 mem_result = vm_map_enter_mem_object(
870 kernel_map,
871 &seg_offset,
872 seg_length, /* mask */ 0,
873 VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
874 (ipc_port_t)NULL,
875 (vm_object_offset_t) 0,
876 /* copy */ FALSE,
316670eb 877 /* cur_protection */ VM_PROT_READ | VM_PROT_WRITE,
6d2010ae
A
878 /* max_protection */ VM_PROT_ALL,
879 /* inheritance */ VM_INHERIT_DEFAULT);
880 if ((mem_result != KERN_SUCCESS) ||
881 (seg_offset != (vm_map_offset_t) seg_data))
882 {
883 OSKextLog(/* kext */ NULL,
884 kOSKextLogErrorLevel |
885 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
886 "Can't create __LINKEDIT VM entry at %p, length 0x%llx (error 0x%x).",
887 seg_data, seg_length, mem_result);
888 goto finish;
b0d623f7 889 }
6d2010ae
A
890
891 /* And copy it back.
892 */
893 memcpy(seg_data, seg_copy, seg_length);
894
895 /* Free the copy.
896 */
897 kmem_free(kernel_map, seg_copy_offset, seg_length);
898 }
899#else /* we are not CONFIG_KXLD */
316670eb 900#error CONFIG_KXLD is expected for this arch
6d2010ae
A
901
902 /*****
903 * Dump the LINKEDIT segment, unless keepsyms is set.
904 */
905 if (!sKeepSymbols) {
316670eb
A
906 const char *dt_segment_name = "Kernel-__LINKEDIT";
907 if (0 == IODTGetLoaderInfo(dt_segment_name,
908 &segment_paddress, &segment_size)) {
909#ifdef SECURE_KERNEL
910 vm_offset_t vmaddr = ml_static_ptovirt((vm_offset_t)segment_paddress);
911 bzero((void*)vmaddr, segment_size);
912#endif
913 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
914 (int)segment_size);
b0d623f7 915 }
b0d623f7
A
916 } else {
917 OSKextLog(/* kext */ NULL,
6d2010ae
A
918 kOSKextLogBasicLevel |
919 kOSKextLogGeneralFlag,
920 "keepsyms boot arg specified; keeping linkedit segment for symbols.");
b0d623f7 921 }
6d2010ae 922#endif /* CONFIG_KXLD */
b0d623f7
A
923
924 seg_to_remove = NULL;
925
926 alreadyDone = true;
927 result = kOSReturnSuccess;
928
929finish:
930
931 /* This must be the very last thing done before returning.
932 */
933 IORecursiveLockUnlock(sKextLock);
934
935 return result;
936}
937
938/*********************************************************************
939*********************************************************************/
940void
941OSKext::flushNonloadedKexts(
942 Boolean flushPrelinkedKexts)
943{
944 OSSet * prelinkedKexts = NULL; // must release
945 OSCollectionIterator * kextIterator = NULL; // must release
946 OSCollectionIterator * prelinkIterator = NULL; // must release
947 const OSSymbol * thisID = NULL; // do not release
948 OSKext * thisKext = NULL; // do not release
949 uint32_t count, i;
950
951 IORecursiveLockLock(sKextLock);
952
953 OSKextLog(/* kext */ NULL,
954 kOSKextLogProgressLevel |
955 kOSKextLogKextBookkeepingFlag,
956 "Flushing nonloaded kexts and other unused data.");
957
958 OSKext::considerDestroyingLinkContext();
959
960 /* If we aren't flushing unused prelinked kexts, we have to put them
961 * aside while we flush everything else so make a container for them.
962 */
963 if (!flushPrelinkedKexts) {
964 prelinkedKexts = OSSet::withCapacity(0);
965 if (!prelinkedKexts) {
966 goto finish;
967 }
968 }
969
970 /* Set aside prelinked kexts (in-use or not) and break
971 * any lingering inter-kext references for nonloaded kexts
972 * so they have min. retain counts.
973 */
974 kextIterator = OSCollectionIterator::withCollection(sKextsByID);
975 if (!kextIterator) {
976 goto finish;
977 }
978
979 while ((thisID = OSDynamicCast(OSSymbol,
980 kextIterator->getNextObject()))) {
981
982 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
983
984 if (thisKext) {
985 if (prelinkedKexts && thisKext->isPrelinked()) {
986 prelinkedKexts->setObject(thisKext);
987 }
988 thisKext->flushDependencies(/* forceIfLoaded */ false);
989 }
990 }
991
992 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
993 */
994 sKextsByID->flushCollection();
995
996 /* Now put the loaded kexts back into the ID dictionary.
997 */
998 count = sLoadedKexts->getCount();
999 for (i = 0; i < count; i++) {
1000 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
1001 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1002 }
1003
1004 /* Finally, put back the prelinked kexts if we saved any.
1005 */
1006 if (prelinkedKexts) {
1007 prelinkIterator = OSCollectionIterator::withCollection(prelinkedKexts);
1008 if (!prelinkIterator) {
1009 goto finish;
1010 }
1011
1012 while ((thisKext = OSDynamicCast(OSKext,
1013 prelinkIterator->getNextObject()))) {
1014
1015 sKextsByID->setObject(thisKext->getIdentifierCString(),
1016 thisKext);
1017 }
1018 }
1019
1020finish:
1021 IORecursiveLockUnlock(sKextLock);
1022
1023 OSSafeRelease(prelinkedKexts);
1024 OSSafeRelease(kextIterator);
1025 OSSafeRelease(prelinkIterator);
1026
1027 return;
1028}
1029
1030/*********************************************************************
1031*********************************************************************/
1032/* static */
1033void
1034OSKext::setKextdActive(Boolean active)
1035{
1036 IORecursiveLockLock(sKextLock);
1037 sKextdActive = active;
7e4a7d39 1038 if (sKernelRequests->getCount()) {
6d2010ae 1039 OSKext::pingKextd();
b0d623f7
A
1040 }
1041 IORecursiveLockUnlock(sKextLock);
1042
1043 return;
1044}
1045
6d2010ae
A
1046/*********************************************************************
1047* OSKextLib.cpp might need access to this someday but for now it's
1048* private.
1049*********************************************************************/
1050extern "C" {
1051extern void ipc_port_release_send(ipc_port_t);
1052};
1053
1054/* static */
1055OSReturn
1056OSKext::pingKextd(void)
1057{
1058 OSReturn result = kOSReturnError;
1059#if !NO_KEXTD
1060 mach_port_t kextd_port = IPC_PORT_NULL;
1061
1062 if (!sKextdActive) {
1063 result = kOSKextReturnDisabled; // basically unavailable
1064 goto finish;
1065 }
1066
1067 result = host_get_kextd_port(host_priv_self(), &kextd_port);
1068 if (result != KERN_SUCCESS || !IPC_PORT_VALID(kextd_port)) {
1069 OSKextLog(/* kext */ NULL,
1070 kOSKextLogErrorLevel |
1071 kOSKextLogIPCFlag,
1072 "Can't get kextd port.");
1073 goto finish;
1074 }
1075
1076 result = kextd_ping(kextd_port);
1077 if (result != KERN_SUCCESS) {
1078 OSKextLog(/* kext */ NULL,
1079 kOSKextLogErrorLevel |
1080 kOSKextLogIPCFlag,
1081 "kextd ping failed (0x%x).", (int)result);
1082 goto finish;
1083 }
1084
1085finish:
1086 if (IPC_PORT_VALID(kextd_port)) {
1087 ipc_port_release_send(kextd_port);
1088 }
1089#endif
1090
1091 return result;
1092}
1093
b0d623f7
A
1094/*********************************************************************
1095*********************************************************************/
1096/* static */
1097void
1098OSKext::setDeferredLoadSucceeded(Boolean succeeded)
1099{
1100 IORecursiveLockLock(sKextLock);
1101 sDeferredLoadSucceeded = succeeded;
1102 IORecursiveLockUnlock(sKextLock);
1103
1104 return;
1105}
1106
1107/*********************************************************************
1108* Called from IOSystemShutdownNotification.
1109*********************************************************************/
1110/* static */
1111void
1112OSKext::willShutdown(void)
1113{
6d2010ae 1114#if !NO_KEXTD
b0d623f7 1115 OSReturn checkResult = kOSReturnError;
6d2010ae 1116#endif
b0d623f7
A
1117 OSDictionary * exitRequest = NULL; // must release
1118
1119 IORecursiveLockLock(sKextLock);
1120
1121 OSKext::setLoadEnabled(false);
1122 OSKext::setUnloadEnabled(false);
1123 OSKext::setAutounloadsEnabled(false);
1124 OSKext::setKernelRequestsEnabled(false);
1125
6d2010ae 1126#if !NO_KEXTD
b0d623f7
A
1127 OSKextLog(/* kext */ NULL,
1128 kOSKextLogProgressLevel |
1129 kOSKextLogGeneralFlag,
1130 "System shutdown; requesting immediate kextd exit.");
1131
1132 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestKextdExit,
1133 &exitRequest);
1134 if (checkResult != kOSReturnSuccess) {
1135 goto finish;
1136 }
1137 if (!sKernelRequests->setObject(exitRequest)) {
1138 goto finish;
1139 }
1140
6d2010ae 1141 OSKext::pingKextd();
b0d623f7
A
1142
1143finish:
6d2010ae
A
1144#endif
1145
b0d623f7
A
1146 IORecursiveLockUnlock(sKextLock);
1147
1148 OSSafeRelease(exitRequest);
1149 return;
1150}
1151
1152/*********************************************************************
1153*********************************************************************/
1154/* static */
1155bool
1156OSKext::getLoadEnabled(void)
1157{
1158 bool result;
1159
1160 IORecursiveLockLock(sKextLock);
1161 result = sLoadEnabled;
1162 IORecursiveLockUnlock(sKextLock);
1163 return result;
1164}
1165
1166/*********************************************************************
1167*********************************************************************/
1168/* static */
1169bool
1170OSKext::setLoadEnabled(bool flag)
1171{
1172 bool result;
1173
1174 IORecursiveLockLock(sKextLock);
1175 result = sLoadEnabled;
1176 sLoadEnabled = (flag ? true : false);
1177
1178 if (sLoadEnabled != result) {
1179 OSKextLog(/* kext */ NULL,
1180 kOSKextLogBasicLevel |
1181 kOSKextLogLoadFlag,
1182 "Kext loading now %sabled.", sLoadEnabled ? "en" : "dis");
1183 }
1184
1185 IORecursiveLockUnlock(sKextLock);
1186
1187 return result;
1188}
1189
1190/*********************************************************************
1191*********************************************************************/
1192/* static */
1193bool
1194OSKext::getUnloadEnabled(void)
1195{
1196 bool result;
1197
1198 IORecursiveLockLock(sKextLock);
1199 result = sUnloadEnabled;
1200 IORecursiveLockUnlock(sKextLock);
1201 return result;
1202}
1203
1204/*********************************************************************
1205*********************************************************************/
1206/* static */
1207bool
1208OSKext::setUnloadEnabled(bool flag)
1209{
1210 bool result;
1211
1212 IORecursiveLockLock(sKextLock);
1213 result = sUnloadEnabled;
1214 sUnloadEnabled = (flag ? true : false);
1215 IORecursiveLockUnlock(sKextLock);
1216
1217 if (sUnloadEnabled != result) {
1218 OSKextLog(/* kext */ NULL,
1219 kOSKextLogBasicLevel |
1220 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1221 "Kext unloading now %sabled.", sUnloadEnabled ? "en" : "dis");
1222 }
1223
1224 return result;
1225}
1226
1227/*********************************************************************
1228* Do not call any function that takes sKextLock here!
1229*********************************************************************/
1230/* static */
1231bool
1232OSKext::getAutounloadEnabled(void)
1233{
1234 bool result;
1235
1236 IORecursiveLockLock(sKextInnerLock);
1237 result = sAutounloadEnabled ? true : false;
1238 IORecursiveLockUnlock(sKextInnerLock);
1239 return result;
1240}
1241
1242/*********************************************************************
1243* Do not call any function that takes sKextLock here!
1244*********************************************************************/
1245/* static */
1246bool
1247OSKext::setAutounloadsEnabled(bool flag)
1248{
1249 bool result;
1250
1251 IORecursiveLockLock(sKextInnerLock);
1252
1253 result = sAutounloadEnabled;
1254 sAutounloadEnabled = (flag ? true : false);
1255 if (!sAutounloadEnabled && sUnloadCallout) {
1256 thread_call_cancel(sUnloadCallout);
1257 }
1258
1259 if (sAutounloadEnabled != result) {
1260 OSKextLog(/* kext */ NULL,
1261 kOSKextLogBasicLevel |
1262 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1263 "Kext autounloading now %sabled.",
1264 sAutounloadEnabled ? "en" : "dis");
1265 }
1266
1267 IORecursiveLockUnlock(sKextInnerLock);
1268
1269 return result;
1270}
1271
1272/*********************************************************************
1273*********************************************************************/
1274/* instance method operating on OSKext field */
1275bool
1276OSKext::setAutounloadEnabled(bool flag)
1277{
1278 bool result = flags.autounloadEnabled ? true : false;
1279 flags.autounloadEnabled = flag ? 1 : 0;
1280
1281 if (result != (flag ? true : false)) {
1282 OSKextLog(this,
1283 kOSKextLogProgressLevel |
1284 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
1285 "Autounloading for kext %s now %sabled.",
1286 getIdentifierCString(),
1287 flags.autounloadEnabled ? "en" : "dis");
1288 }
1289 return result;
1290}
1291
1292/*********************************************************************
1293*********************************************************************/
1294/* static */
1295bool
1296OSKext::setKernelRequestsEnabled(bool flag)
1297{
1298 bool result;
1299
1300 IORecursiveLockLock(sKextLock);
1301 result = sKernelRequestsEnabled;
1302 sKernelRequestsEnabled = flag ? true : false;
1303
1304 if (sKernelRequestsEnabled != result) {
1305 OSKextLog(/* kext */ NULL,
1306 kOSKextLogBasicLevel |
1307 kOSKextLogGeneralFlag,
1308 "Kernel requests now %sabled.",
1309 sKernelRequestsEnabled ? "en" : "dis");
1310 }
1311 IORecursiveLockUnlock(sKextLock);
1312 return result;
1313}
1314
1315/*********************************************************************
1316*********************************************************************/
1317/* static */
1318bool
1319OSKext::getKernelRequestsEnabled(void)
1320{
1321 bool result;
1322
1323 IORecursiveLockLock(sKextLock);
1324 result = sKernelRequestsEnabled;
1325 IORecursiveLockUnlock(sKextLock);
1326 return result;
1327}
1328
1329#if PRAGMA_MARK
1330#pragma mark Kext Life Cycle
1331#endif
1332/*********************************************************************
1333*********************************************************************/
1334OSKext *
1335OSKext::withPrelinkedInfoDict(
1336 OSDictionary * anInfoDict)
1337{
1338 OSKext * newKext = new OSKext;
1339
1340 if (newKext && !newKext->initWithPrelinkedInfoDict(anInfoDict)) {
1341 newKext->release();
1342 return NULL;
1343 }
1344
1345 return newKext;
1346}
1347
1348/*********************************************************************
1349*********************************************************************/
1350bool
1351OSKext::initWithPrelinkedInfoDict(
1352 OSDictionary * anInfoDict)
1353{
1354 bool result = false;
b0d623f7
A
1355 OSString * kextPath = NULL; // do not release
1356 OSNumber * addressNum = NULL; // reused; do not release
1357 OSNumber * lengthNum = NULL; // reused; do not release
1358 void * data = NULL; // do not free
1359 void * srcData = NULL; // do not free
1360 OSData * prelinkedExecutable = NULL; // must release
b0d623f7
A
1361 uint32_t length = 0; // reused
1362
1363 if (!super::init()) {
1364 goto finish;
1365 }
1366
1367 /* Get the path. Don't look for an arch-specific path property.
1368 */
1369 kextPath = OSDynamicCast(OSString,
1370 anInfoDict->getObject(kPrelinkBundlePathKey));
1371
1372 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
1373 goto finish;
1374 }
316670eb
A
1375#if KASLR_KEXT_DEBUG
1376 IOLog("kaslr: kext %s \n", getIdentifierCString());
1377#endif
b0d623f7 1378
6d2010ae
A
1379 /* Also get the executable's bundle-relative path if present.
1380 * Don't look for an arch-specific path property.
b0d623f7 1381 */
6d2010ae
A
1382 executableRelPath = OSDynamicCast(OSString,
1383 anInfoDict->getObject(kPrelinkExecutableRelativePathKey));
1384 if (executableRelPath) {
1385 executableRelPath->retain();
1386 }
b0d623f7 1387
6d2010ae 1388 /* Don't need the paths to be in the info dictionary any more.
b0d623f7 1389 */
6d2010ae
A
1390 anInfoDict->removeObject(kPrelinkBundlePathKey);
1391 anInfoDict->removeObject(kPrelinkExecutableRelativePathKey);
b0d623f7
A
1392
1393 /* Create an OSData wrapper around the linked executable.
1394 */
1395 addressNum = OSDynamicCast(OSNumber,
1396 anInfoDict->getObject(kPrelinkExecutableLoadKey));
1397 if (addressNum) {
1398 lengthNum = OSDynamicCast(OSNumber,
1399 anInfoDict->getObject(kPrelinkExecutableSizeKey));
1400 if (!lengthNum) {
1401 OSKextLog(this,
1402 kOSKextLogErrorLevel |
1403 kOSKextLogArchiveFlag,
1404 "Kext %s can't find prelinked kext executable size.",
1405 getIdentifierCString());
1406 goto finish;
1407 }
1408
316670eb 1409 data = (void *) ((intptr_t) (addressNum->unsigned64BitValue()) + vm_kernel_slide);
b0d623f7
A
1410 length = (uint32_t) (lengthNum->unsigned32BitValue());
1411
316670eb
A
1412#if KASLR_KEXT_DEBUG
1413 IOLog("kaslr: unslid 0x%lx slid 0x%lx length %u - prelink executable \n",
1414 (unsigned long)VM_KERNEL_UNSLIDE(data),
1415 (unsigned long)data,
1416 length);
1417#endif
1418
b0d623f7
A
1419 anInfoDict->removeObject(kPrelinkExecutableLoadKey);
1420 anInfoDict->removeObject(kPrelinkExecutableSizeKey);
1421
1422 /* If the kext's load address differs from its source address, allocate
1423 * space in the kext map at the load address and copy the kext over.
1424 */
1425 addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject(kPrelinkExecutableSourceKey));
1426 if (addressNum) {
316670eb
A
1427 srcData = (void *) ((intptr_t) (addressNum->unsigned64BitValue()) + vm_kernel_slide);
1428
1429#if KASLR_KEXT_DEBUG
1430 IOLog("kaslr: unslid 0x%lx slid 0x%lx - prelink executable source \n",
1431 (unsigned long)VM_KERNEL_UNSLIDE(srcData),
1432 (unsigned long)srcData);
1433#endif
b0d623f7
A
1434
1435 if (data != srcData) {
1436#if __LP64__
6d2010ae
A
1437 kern_return_t alloc_result;
1438
b0d623f7
A
1439 alloc_result = kext_alloc((vm_offset_t *)&data, length, /* fixed */ TRUE);
1440 if (alloc_result != KERN_SUCCESS) {
1441 OSKextLog(this,
1442 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1443 "Failed to allocate space for prelinked kext %s.",
1444 getIdentifierCString());
1445 goto finish;
1446 }
1447 memcpy(data, srcData, length);
1448#else
1449 OSKextLog(this,
1450 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1451 "Error: prelinked kext %s - source and load addresses "
1452 "differ on ILP32 architecture.",
1453 getIdentifierCString());
1454 goto finish;
1455#endif /* __LP64__ */
1456 }
1457
1458 anInfoDict->removeObject(kPrelinkExecutableSourceKey);
1459 }
1460
b0d623f7
A
1461 prelinkedExecutable = OSData::withBytesNoCopy(data, length);
1462 if (!prelinkedExecutable) {
1463 OSKextLog(this,
1464 kOSKextLogErrorLevel |
1465 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1466 "Kext %s failed to create executable wrapper.",
1467 getIdentifierCString());
1468 goto finish;
1469 }
316670eb
A
1470
1471#if VM_MAPPED_KEXTS
6d2010ae 1472 prelinkedExecutable->setDeallocFunction(osdata_kext_free);
316670eb
A
1473#else
1474 prelinkedExecutable->setDeallocFunction(osdata_phys_free);
1475#endif
b0d623f7
A
1476 setLinkedExecutable(prelinkedExecutable);
1477
1478 addressNum = OSDynamicCast(OSNumber,
1479 anInfoDict->getObject(kPrelinkKmodInfoKey));
1480 if (!addressNum) {
1481 OSKextLog(this,
1482 kOSKextLogErrorLevel |
1483 kOSKextLogArchiveFlag,
1484 "Kext %s can't find prelinked kext kmod_info address.",
1485 getIdentifierCString());
1486 goto finish;
1487 }
1488
316670eb
A
1489 if (addressNum->unsigned64BitValue() != 0) {
1490 kmod_info = (kmod_info_t *) (intptr_t) (addressNum->unsigned64BitValue() + vm_kernel_slide);
1491 kmod_info->address += vm_kernel_slide;
1492#if KASLR_KEXT_DEBUG
1493 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info \n",
1494 (unsigned long)VM_KERNEL_UNSLIDE(kmod_info),
1495 (unsigned long)kmod_info);
1496 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info->address \n",
1497 (unsigned long)VM_KERNEL_UNSLIDE(kmod_info->address),
1498 (unsigned long)kmod_info->address);
1499 #endif
1500 }
b0d623f7
A
1501
1502 anInfoDict->removeObject(kPrelinkKmodInfoKey);
1503 }
1504
1505 /* If the plist has a UUID for an interface, save that off.
1506 */
1507 if (isInterface()) {
1508 interfaceUUID = OSDynamicCast(OSData,
1509 anInfoDict->getObject(kPrelinkInterfaceUUIDKey));
1510 if (interfaceUUID) {
1511 interfaceUUID->retain();
1512 anInfoDict->removeObject(kPrelinkInterfaceUUIDKey);
1513 }
1514 }
1515
1516 flags.prelinked = true;
1517
1518 /* If we created a kext from prelink info,
1519 * we must be booting from a prelinked kernel.
1520 */
1521 sPrelinkBoot = true;
1522
1523 result = registerIdentifier();
1524
1525finish:
b0d623f7
A
1526 OSSafeRelease(prelinkedExecutable);
1527
1528 return result;
1529}
1530
1531/*********************************************************************
1532*********************************************************************/
1533OSKext *
1534OSKext::withBooterData(
1535 OSString * deviceTreeName,
1536 OSData * booterData)
1537{
1538 OSKext * newKext = new OSKext;
1539
1540 if (newKext && !newKext->initWithBooterData(deviceTreeName, booterData)) {
1541 newKext->release();
1542 return NULL;
1543 }
1544
1545 return newKext;
1546}
1547
1548/*********************************************************************
1549*********************************************************************/
1550typedef struct _BooterKextFileInfo {
1551 uint32_t infoDictPhysAddr;
1552 uint32_t infoDictLength;
1553 uint32_t executablePhysAddr;
1554 uint32_t executableLength;
1555 uint32_t bundlePathPhysAddr;
1556 uint32_t bundlePathLength;
1557} _BooterKextFileInfo;
1558
1559bool
1560OSKext::initWithBooterData(
1561 OSString * deviceTreeName,
1562 OSData * booterData)
1563{
1564 bool result = false;
1565 _BooterKextFileInfo * kextFileInfo = NULL; // do not free
1566 char * infoDictAddr = NULL; // do not free
1567 void * executableAddr = NULL; // do not free
1568 char * bundlePathAddr = NULL; // do not free
1569
6d2010ae 1570 OSObject * parsedXML = NULL; // must release
b0d623f7
A
1571 OSDictionary * theInfoDict = NULL; // do not release
1572 OSString * kextPath = NULL; // must release
1573 OSString * errorString = NULL; // must release
1574 OSData * executable = NULL; // must release
1575
1576 if (!super::init()) {
1577 goto finish;
1578 }
1579
1580 kextFileInfo = (_BooterKextFileInfo *)booterData->getBytesNoCopy();
1581 if (!kextFileInfo) {
1582 OSKextLog(this,
1583 kOSKextLogErrorLevel |
1584 kOSKextLogGeneralFlag,
1585 "No booter-provided data for kext device tree entry %s.",
1586 deviceTreeName->getCStringNoCopy());
1587 goto finish;
1588 }
1589
1590 /* The info plist must exist or we can't read the kext.
1591 */
1592 if (!kextFileInfo->infoDictPhysAddr || !kextFileInfo->infoDictLength) {
1593 OSKextLog(this,
1594 kOSKextLogErrorLevel |
1595 kOSKextLogGeneralFlag,
1596 "No kext info dictionary for booter device tree entry %s.",
1597 deviceTreeName->getCStringNoCopy());
1598 goto finish;
1599 }
1600
1601 infoDictAddr = (char *)ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
1602 if (!infoDictAddr) {
1603 OSKextLog(this,
1604 kOSKextLogErrorLevel |
1605 kOSKextLogGeneralFlag,
1606 "Can't translate physical address 0x%x of kext info dictionary "
1607 "for device tree entry %s.",
1608 (int)kextFileInfo->infoDictPhysAddr,
1609 deviceTreeName->getCStringNoCopy());
1610 goto finish;
1611 }
1612
1613 parsedXML = OSUnserializeXML(infoDictAddr, &errorString);
1614 if (parsedXML) {
1615 theInfoDict = OSDynamicCast(OSDictionary, parsedXML);
1616 }
1617 if (!theInfoDict) {
1618 const char * errorCString = "(unknown error)";
1619
1620 if (errorString && errorString->getCStringNoCopy()) {
1621 errorCString = errorString->getCStringNoCopy();
1622 } else if (parsedXML) {
1623 errorCString = "not a dictionary";
1624 }
1625 OSKextLog(this,
1626 kOSKextLogErrorLevel |
1627 kOSKextLogGeneralFlag,
1628 "Error unserializing info dictionary for device tree entry %s: %s.",
1629 deviceTreeName->getCStringNoCopy(), errorCString);
1630 goto finish;
1631 }
1632
1633 /* A bundle path is not mandatory.
1634 */
1635 if (kextFileInfo->bundlePathPhysAddr && kextFileInfo->bundlePathLength) {
1636 bundlePathAddr = (char *)ml_static_ptovirt(kextFileInfo->bundlePathPhysAddr);
1637 if (!bundlePathAddr) {
1638 OSKextLog(this,
1639 kOSKextLogErrorLevel |
1640 kOSKextLogGeneralFlag,
1641 "Can't translate physical address 0x%x of kext bundle path "
1642 "for device tree entry %s.",
1643 (int)kextFileInfo->bundlePathPhysAddr,
1644 deviceTreeName->getCStringNoCopy());
1645 goto finish;
1646 }
1647 bundlePathAddr[kextFileInfo->bundlePathLength-1] = '\0'; // just in case!
1648
1649 kextPath = OSString::withCString(bundlePathAddr);
1650 if (!kextPath) {
1651 OSKextLog(this,
1652 kOSKextLogErrorLevel |
1653 kOSKextLogGeneralFlag,
1654 "Failed to create wrapper for device tree entry %s kext path %s.",
1655 deviceTreeName->getCStringNoCopy(), bundlePathAddr);
1656 goto finish;
1657 }
1658 }
1659
1660 if (!setInfoDictionaryAndPath(theInfoDict, kextPath)) {
1661 goto finish;
1662 }
1663
1664 /* An executable is not mandatory.
1665 */
1666 if (kextFileInfo->executablePhysAddr && kextFileInfo->executableLength) {
1667 executableAddr = (void *)ml_static_ptovirt(kextFileInfo->executablePhysAddr);
1668 if (!executableAddr) {
1669 OSKextLog(this,
1670 kOSKextLogErrorLevel |
1671 kOSKextLogGeneralFlag,
1672 "Can't translate physical address 0x%x of kext executable "
1673 "for device tree entry %s.",
1674 (int)kextFileInfo->executablePhysAddr,
1675 deviceTreeName->getCStringNoCopy());
1676 goto finish;
1677 }
1678
1679 executable = OSData::withBytesNoCopy(executableAddr,
1680 kextFileInfo->executableLength);
1681 if (!executable) {
1682 OSKextLog(this,
1683 kOSKextLogErrorLevel |
1684 kOSKextLogGeneralFlag,
1685 "Failed to create executable wrapper for device tree entry %s.",
1686 deviceTreeName->getCStringNoCopy());
1687 goto finish;
1688 }
1689
1690 /* A kext with an executable needs to retain the whole booterData
1691 * object to keep the executable in memory.
1692 */
1693 if (!setExecutable(executable, booterData)) {
1694 OSKextLog(this,
1695 kOSKextLogErrorLevel |
1696 kOSKextLogGeneralFlag,
1697 "Failed to set kext executable for device tree entry %s.",
1698 deviceTreeName->getCStringNoCopy());
1699 goto finish;
1700 }
1701 }
1702
1703 result = registerIdentifier();
1704
1705finish:
1706 OSSafeRelease(parsedXML);
1707 OSSafeRelease(kextPath);
1708 OSSafeRelease(errorString);
1709 OSSafeRelease(executable);
1710
1711 return result;
1712}
1713
1714/*********************************************************************
1715*********************************************************************/
1716bool
1717OSKext::registerIdentifier(void)
1718{
1719 bool result = false;
1720 OSKext * existingKext = NULL; // do not release
1721 bool existingIsLoaded = false;
1722 bool existingIsPrelinked = false;
1723 OSKextVersion newVersion = -1;
1724 OSKextVersion existingVersion = -1;
1725 char newVersionCString[kOSKextVersionMaxLength];
1726 char existingVersionCString[kOSKextVersionMaxLength];
1727 OSData * newUUID = NULL; // must release
1728 OSData * existingUUID = NULL; // must release
1729
6d2010ae
A
1730 IORecursiveLockLock(sKextLock);
1731
b0d623f7
A
1732 /* Get the new kext's version for checks & log messages.
1733 */
1734 newVersion = getVersion();
1735 OSKextVersionGetString(newVersion, newVersionCString,
1736 kOSKextVersionMaxLength);
1737
1738 /* If we don't have an existing kext with this identifier,
1739 * just record the new kext and we're done!
1740 */
1741 existingKext = OSDynamicCast(OSKext, sKextsByID->getObject(bundleID));
1742 if (!existingKext) {
1743 sKextsByID->setObject(bundleID, this);
1744 result = true;
1745 goto finish;
1746 }
1747
1748 /* Get the existing kext's version for checks & log messages.
1749 */
1750 existingVersion = existingKext->getVersion();
1751 OSKextVersionGetString(existingVersion,
1752 existingVersionCString, kOSKextVersionMaxLength);
1753
1754 existingIsLoaded = existingKext->isLoaded();
1755 existingIsPrelinked = existingKext->isPrelinked();
1756
1757 /* If we have a kext with this identifier that's already loaded/prelinked,
1758 * we can't use the new one, but let's be really thorough and check how
1759 * the two are related for a precise diagnostic log message.
1760 *
1761 * Note that user space can't find out about nonloaded prelinked kexts,
1762 * so in this case we log a message when new & existing are equivalent
1763 * at the step rather than warning level, because we are always going
1764 * be getting a copy of the kext in the user load request mkext.
1765 */
1766 if (existingIsLoaded || existingIsPrelinked) {
1767 bool sameVersion = (newVersion == existingVersion);
1768 bool sameExecutable = true; // assume true unless we have UUIDs
1769
1770 /* Only get the UUID if the existing kext is loaded. Doing so
1771 * might have to uncompress an mkext executable and we shouldn't
1772 * take that hit when neither kext is loaded.
1773 */
1774 newUUID = copyUUID();
1775 existingUUID = existingKext->copyUUID();
1776
1777 /* I'm entirely too paranoid about checking equivalence of executables,
1778 * but I remember nasty problems with it in the past.
1779 *
1780 * - If we have UUIDs for both kexts, compare them.
1781 * - If only one kext has a UUID, they're definitely different.
1782 */
1783 if (newUUID && existingUUID) {
1784 sameExecutable = newUUID->isEqualTo(existingUUID);
1785 } else if (newUUID || existingUUID) {
1786 sameExecutable = false;
1787 }
1788
1789 if (!newUUID && !existingUUID) {
1790
1791 /* If there are no UUIDs, we can't really tell that the executables
1792 * are *different* without a lot of work; the loaded kext's
1793 * unrelocated executable is no longer around (and we never had it
1794 * in-kernel for a prelinked kext). We certainly don't want to do
1795 * a whole fake link for the new kext just to compare, either.
1796 */
1797
1798 OSKextVersionGetString(version, newVersionCString,
1799 sizeof(newVersionCString));
1800 OSKextLog(this,
1801 kOSKextLogWarningLevel |
1802 kOSKextLogKextBookkeepingFlag,
1803 "Notice - new kext %s, v%s matches %s kext "
1804 "but can't determine if executables are the same (no UUIDs).",
1805 getIdentifierCString(),
1806 newVersionCString,
1807 (existingIsLoaded ? "loaded" : "prelinked"));
1808 }
1809
1810 if (sameVersion && sameExecutable) {
1811 OSKextLog(this,
1812 (existingIsLoaded ? kOSKextLogWarningLevel : kOSKextLogStepLevel) |
1813 kOSKextLogKextBookkeepingFlag,
1814 "Refusing new kext %s, v%s: a %s copy is already present "
1815 "(same version and executable).",
1816 getIdentifierCString(), newVersionCString,
1817 (existingIsLoaded ? "loaded" : "prelinked"));
1818 } else {
1819 if (!sameVersion) {
1820 /* This condition is significant so log it under warnings.
1821 */
1822 OSKextLog(this,
1823 kOSKextLogWarningLevel |
1824 kOSKextLogKextBookkeepingFlag,
1825 "Refusing new kext %s, v%s: already have %s v%s.",
1826 getIdentifierCString(),
1827 newVersionCString,
1828 (existingIsLoaded ? "loaded" : "prelinked"),
1829 existingVersionCString);
1830 } else {
1831 /* This condition is significant so log it under warnings.
1832 */
1833 OSKextLog(this,
1834 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
1835 "Refusing new kext %s, v%s: a %s copy with a different "
1836 "executable UUID is already present.",
1837 getIdentifierCString(), newVersionCString,
1838 (existingIsLoaded ? "loaded" : "prelinked"));
1839 }
1840 }
1841 goto finish;
1842 } /* if (existingIsLoaded || existingIsPrelinked) */
1843
1844 /* We have two nonloaded/nonprelinked kexts, so our decision depends on whether
1845 * user loads are happening or if we're still in early boot. User agents are
1846 * supposed to resolve dependencies topside and include only the exact
1847 * kexts needed; so we always accept the new kext (in fact we should never
1848 * see an older unloaded copy hanging around).
1849 */
1850 if (sUserLoadsActive) {
1851 sKextsByID->setObject(bundleID, this);
1852 result = true;
1853
1854 OSKextLog(this,
1855 kOSKextLogStepLevel |
1856 kOSKextLogKextBookkeepingFlag,
1857 "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
1858 getIdentifierCString(),
1859 existingVersionCString,
1860 newVersionCString);
1861
1862 goto finish;
1863 }
1864
1865 /* During early boot, the kext with the highest version always wins out.
1866 * Prelinked kernels will never hit this, but mkexts and booter-read
1867 * kexts might have duplicates.
1868 */
1869 if (newVersion > existingVersion) {
1870 sKextsByID->setObject(bundleID, this);
1871 result = true;
1872
1873 OSKextLog(this,
1874 kOSKextLogStepLevel |
1875 kOSKextLogKextBookkeepingFlag,
1876 "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
1877 existingVersionCString,
1878 getIdentifierCString(),
1879 newVersionCString);
1880
1881 } else {
1882 OSKextLog(this,
1883 kOSKextLogStepLevel |
1884 kOSKextLogKextBookkeepingFlag,
1885 "Kext %s is already registered with a higher/same version (v%s); "
1886 "dropping newly-added (v%s).",
1887 getIdentifierCString(),
1888 existingVersionCString,
1889 newVersionCString);
1890 }
1891
1892 /* result has been set appropriately by now. */
1893
1894finish:
1895
6d2010ae
A
1896 IORecursiveLockUnlock(sKextLock);
1897
b0d623f7
A
1898 if (result) {
1899 OSKextLog(this,
1900 kOSKextLogStepLevel |
1901 kOSKextLogKextBookkeepingFlag,
1902 "Kext %s, v%s registered and available for loading.",
1903 getIdentifierCString(), newVersionCString);
1904 }
1905
1906 OSSafeRelease(newUUID);
1907 OSSafeRelease(existingUUID);
1908
1909 return result;
1910}
1911
1912/*********************************************************************
1913* Does the bare minimum validation to look up a kext.
1914* All other validation is done on the spot as needed.
b0d623f7
A
1915**********************************************************************/
1916bool
1917OSKext::setInfoDictionaryAndPath(
1918 OSDictionary * aDictionary,
1919 OSString * aPath)
1920{
6d2010ae
A
1921 bool result = false;
1922 OSString * bundleIDString = NULL; // do not release
1923 OSString * versionString = NULL; // do not release
1924 OSString * compatibleVersionString = NULL; // do not release
1925 const char * versionCString = NULL; // do not free
1926 const char * compatibleVersionCString = NULL; // do not free
1927 OSBoolean * scratchBool = NULL; // do not release
1928 OSDictionary * scratchDict = NULL; // do not release
b0d623f7
A
1929
1930 if (infoDict) {
1931 panic("Attempt to set info dictionary on a kext "
1932 "that already has one (%s).",
1933 getIdentifierCString());
1934 }
1935
1936 if (!aDictionary || !OSDynamicCast(OSDictionary, aDictionary)) {
1937 goto finish;
1938 }
1939
1940 infoDict = aDictionary;
1941 infoDict->retain();
1942
1943 /* Check right away if the info dictionary has any log flags.
1944 */
1945 scratchBool = OSDynamicCast(OSBoolean,
1946 getPropertyForHostArch(kOSBundleEnableKextLoggingKey));
1947 if (scratchBool == kOSBooleanTrue) {
1948 flags.loggingEnabled = 1;
1949 }
1950
1951 /* The very next thing to get is the bundle identifier. Unlike
1952 * in user space, a kext with no bundle identifier gets axed
1953 * immediately.
1954 */
1955 bundleIDString = OSDynamicCast(OSString,
1956 getPropertyForHostArch(kCFBundleIdentifierKey));
1957 if (!bundleIDString) {
1958 OSKextLog(this,
1959 kOSKextLogErrorLevel |
1960 kOSKextLogValidationFlag,
1961 "CFBundleIdentifier missing/invalid type in kext %s.",
1962 aPath ? aPath->getCStringNoCopy() : "(unknown)");
1963 goto finish;
1964 }
1965 bundleID = OSSymbol::withString(bundleIDString);
1966 if (!bundleID) {
1967 OSKextLog(this,
1968 kOSKextLogErrorLevel |
1969 kOSKextLogValidationFlag,
1970 "Can't copy bundle identifier as symbol for kext %s.",
1971 bundleIDString->getCStringNoCopy());
1972 goto finish;
1973 }
1974
1975 /* Save the path if we got one (it should always be available but it's
1976 * just something nice to have for bookkeeping).
1977 */
1978 if (aPath) {
1979 path = aPath;
1980 path->retain();
1981 }
1982
1983 /*****
1984 * Minimal validation to initialize. We'll do other validation on the spot.
1985 */
1986 if (bundleID->getLength() >= KMOD_MAX_NAME) {
1987 OSKextLog(this,
1988 kOSKextLogErrorLevel |
1989 kOSKextLogValidationFlag,
1990 "Kext %s error - CFBundleIdentifier over max length %d.",
1991 getIdentifierCString(), KMOD_MAX_NAME - 1);
1992 goto finish;
1993 }
1994
1995 version = compatibleVersion = -1;
1996
1997 versionString = OSDynamicCast(OSString,
1998 getPropertyForHostArch(kCFBundleVersionKey));
1999 if (!versionString) {
2000 OSKextLog(this,
2001 kOSKextLogErrorLevel |
2002 kOSKextLogValidationFlag,
2003 "Kext %s error - CFBundleVersion missing/invalid type.",
2004 getIdentifierCString());
2005 goto finish;
2006 }
2007 versionCString = versionString->getCStringNoCopy();
2008 version = OSKextParseVersionString(versionCString);
2009 if (version < 0) {
2010 OSKextLog(this,
2011 kOSKextLogErrorLevel |
2012 kOSKextLogValidationFlag,
2013 "Kext %s error - CFBundleVersion bad value '%s'.",
2014 getIdentifierCString(), versionCString);
2015 goto finish;
2016 }
2017
2018 compatibleVersion = -1; // set to illegal value for kexts that don't have
2019
2020 compatibleVersionString = OSDynamicCast(OSString,
2021 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
2022 if (compatibleVersionString) {
2023 compatibleVersionCString = compatibleVersionString->getCStringNoCopy();
2024 compatibleVersion = OSKextParseVersionString(compatibleVersionCString);
2025 if (compatibleVersion < 0) {
2026 OSKextLog(this,
2027 kOSKextLogErrorLevel |
2028 kOSKextLogValidationFlag,
2029 "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
2030 getIdentifierCString(), compatibleVersionCString);
2031 goto finish;
2032 }
2033
2034 if (compatibleVersion > version) {
2035 OSKextLog(this,
2036 kOSKextLogErrorLevel |
2037 kOSKextLogValidationFlag,
2038 "Kext %s error - %s %s > %s %s (must be <=).",
2039 getIdentifierCString(),
2040 kOSBundleCompatibleVersionKey, compatibleVersionCString,
2041 kCFBundleVersionKey, versionCString);
2042 goto finish;
2043 }
2044 }
2045
2046 /* Set flags for later use if the infoDict gets flushed. We only
2047 * check for true values, not false ones(!)
2048 */
2049 scratchBool = OSDynamicCast(OSBoolean,
2050 getPropertyForHostArch(kOSBundleIsInterfaceKey));
6d2010ae 2051 if (scratchBool == kOSBooleanTrue) {
b0d623f7
A
2052 flags.interface = 1;
2053 }
2054
2055 scratchBool = OSDynamicCast(OSBoolean,
2056 getPropertyForHostArch(kOSKernelResourceKey));
6d2010ae 2057 if (scratchBool == kOSBooleanTrue) {
b0d623f7
A
2058 flags.kernelComponent = 1;
2059 flags.interface = 1; // xxx - hm. the kernel itself isn't an interface...
2060 flags.started = 1;
2061
2062 /* A kernel component has one implicit dependency on the kernel.
2063 */
2064 flags.hasAllDependencies = 1;
2065 }
2066
6d2010ae
A
2067 /* Make sure common string values in personalities are uniqued to OSSymbols.
2068 */
2069 scratchDict = OSDynamicCast(OSDictionary,
2070 getPropertyForHostArch(kIOKitPersonalitiesKey));
2071 if (scratchDict) {
2072 uniquePersonalityProperties(scratchDict);
2073 }
2074
b0d623f7
A
2075 result = true;
2076
2077finish:
2078
2079 return result;
2080}
2081
2082/*********************************************************************
2083* Not used for prelinked kernel boot as there is no unrelocated
2084* executable.
2085*********************************************************************/
2086bool
2087OSKext::setExecutable(
2088 OSData * anExecutable,
2089 OSData * externalData,
2090 bool externalDataIsMkext)
2091{
2092 bool result = false;
2093 const char * executableKey = NULL; // do not free
2094
2095 if (!anExecutable) {
2096 infoDict->removeObject(_kOSKextExecutableKey);
2097 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
2098 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
2099 result = true;
2100 goto finish;
2101 }
2102
2103 if (infoDict->getObject(_kOSKextExecutableKey) ||
2104 infoDict->getObject(_kOSKextMkextExecutableReferenceKey)) {
2105
2106 panic("Attempt to set an executable on a kext "
2107 "that already has one (%s).",
2108 getIdentifierCString());
2109 goto finish;
2110 }
2111
2112 if (externalDataIsMkext) {
2113 executableKey = _kOSKextMkextExecutableReferenceKey;
2114 } else {
2115 executableKey = _kOSKextExecutableKey;
2116 }
2117
2118 if (anExecutable) {
2119 infoDict->setObject(executableKey, anExecutable);
2120 if (externalData) {
2121 infoDict->setObject(_kOSKextExecutableExternalDataKey, externalData);
2122 }
2123 }
2124
2125 result = true;
2126
2127finish:
2128 return result;
2129}
2130
6d2010ae
A
2131/*********************************************************************
2132*********************************************************************/
2133static void
2134uniqueStringPlistProperty(OSDictionary * dict, const char * key)
2135{
2136 OSString * stringValue = NULL; // do not release
2137 const OSSymbol * symbolValue = NULL; // must release
2138
2139 stringValue = OSDynamicCast(OSString, dict->getObject(key));
2140 if (!stringValue) {
2141 goto finish;
2142 }
2143
2144 symbolValue = OSSymbol::withString(stringValue);
2145 if (!symbolValue) {
2146 goto finish;
2147 }
2148
2149 dict->setObject(key, symbolValue);
2150
2151finish:
2152 if (symbolValue) symbolValue->release();
2153
2154 return;
2155}
2156
2157/*********************************************************************
2158*********************************************************************/
2159static void
2160uniqueStringPlistProperty(OSDictionary * dict, const OSString * key)
2161{
2162 OSString * stringValue = NULL; // do not release
2163 const OSSymbol * symbolValue = NULL; // must release
2164
2165 stringValue = OSDynamicCast(OSString, dict->getObject(key));
2166 if (!stringValue) {
2167 goto finish;
2168 }
2169
2170 symbolValue = OSSymbol::withString(stringValue);
2171 if (!symbolValue) {
2172 goto finish;
2173 }
2174
2175 dict->setObject(key, symbolValue);
2176
2177finish:
2178 if (symbolValue) symbolValue->release();
2179
2180 return;
2181}
2182
2183/*********************************************************************
2184* Replace common personality property values with uniqued instances
2185* to save on wired memory.
2186*********************************************************************/
2187/* static */
2188void
2189OSKext::uniquePersonalityProperties(OSDictionary * personalityDict)
2190{
2191 /* Properties every personality has.
2192 */
2193 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKey);
2194 uniqueStringPlistProperty(personalityDict, kIOProviderClassKey);
2195 uniqueStringPlistProperty(personalityDict, gIOClassKey);
2196
2197 /* Other commonly used properties.
2198 */
2199 uniqueStringPlistProperty(personalityDict, gIOMatchCategoryKey);
2200 uniqueStringPlistProperty(personalityDict, gIOResourceMatchKey);
2201 uniqueStringPlistProperty(personalityDict, gIOUserClientClassKey);
2202
2203 uniqueStringPlistProperty(personalityDict, "HIDDefaultBehavior");
2204 uniqueStringPlistProperty(personalityDict, "HIDPointerAccelerationType");
2205 uniqueStringPlistProperty(personalityDict, "HIDRemoteControlType");
2206 uniqueStringPlistProperty(personalityDict, "HIDScrollAccelerationType");
2207 uniqueStringPlistProperty(personalityDict, "IOPersonalityPublisher");
2208 uniqueStringPlistProperty(personalityDict, "Physical Interconnect");
2209 uniqueStringPlistProperty(personalityDict, "Physical Interconnect Location");
2210 uniqueStringPlistProperty(personalityDict, "Vendor");
2211 uniqueStringPlistProperty(personalityDict, "Vendor Identification");
2212 uniqueStringPlistProperty(personalityDict, "Vendor Name");
2213 uniqueStringPlistProperty(personalityDict, "bConfigurationValue");
2214 uniqueStringPlistProperty(personalityDict, "bInterfaceNumber");
2215 uniqueStringPlistProperty(personalityDict, "idProduct");
2216
2217 return;
2218}
2219
b0d623f7
A
2220/*********************************************************************
2221*********************************************************************/
2222void
2223OSKext::free(void)
2224{
2225 if (isLoaded()) {
2226 panic("Attempt to free loaded kext %s.", getIdentifierCString());
2227 }
2228
2229 OSSafeRelease(infoDict);
2230 OSSafeRelease(bundleID);
2231 OSSafeRelease(path);
6d2010ae 2232 OSSafeRelease(executableRelPath);
b0d623f7 2233 OSSafeRelease(dependencies);
b0d623f7
A
2234 OSSafeRelease(linkedExecutable);
2235 OSSafeRelease(metaClasses);
2236 OSSafeRelease(interfaceUUID);
2237
2238 if (isInterface() && kmod_info) {
2239 kfree(kmod_info, sizeof(kmod_info_t));
2240 }
2241
2242 super::free();
2243 return;
2244}
2245
2246#if PRAGMA_MARK
2247#pragma mark Mkext files
2248#endif
2249/*********************************************************************
2250*********************************************************************/
2251OSReturn
2252OSKext::readMkextArchive(OSData * mkextData,
2253 uint32_t * checksumPtr)
2254{
2255 OSReturn result = kOSKextReturnBadData;
2256 uint32_t mkextLength = 0;
2257 mkext_header * mkextHeader = 0; // do not free
2258 uint32_t mkextVersion = 0;
2259
2260 /* Note default return of kOSKextReturnBadData above.
2261 */
2262 mkextLength = mkextData->getLength();
2263 if (mkextLength < sizeof(mkext_basic_header)) {
2264 OSKextLog(/* kext */ NULL,
2265 kOSKextLogErrorLevel |
2266 kOSKextLogArchiveFlag,
2267 "Mkext archive too small to be valid.");
2268 goto finish;
2269 }
2270
2271 mkextHeader = (mkext_header *)mkextData->getBytesNoCopy();
2272
2273 if (MKEXT_GET_MAGIC(mkextHeader) != MKEXT_MAGIC ||
2274 MKEXT_GET_SIGNATURE(mkextHeader) != MKEXT_SIGN) {
2275 OSKextLog(/* kext */ NULL,
2276 kOSKextLogErrorLevel |
2277 kOSKextLogArchiveFlag,
2278 "Mkext archive has invalid magic or signature.");
2279 goto finish;
2280 }
2281
2282 if (MKEXT_GET_LENGTH(mkextHeader) != mkextLength) {
2283 OSKextLog(/* kext */ NULL,
2284 kOSKextLogErrorLevel |
2285 kOSKextLogArchiveFlag,
2286 "Mkext archive recorded length doesn't match actual file length.");
2287 goto finish;
2288 }
2289
2290 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
2291
2292 if (mkextVersion == MKEXT_VERS_2) {
2293 result = OSKext::readMkext2Archive(mkextData, NULL, checksumPtr);
2294 } else if (mkextVersion == MKEXT_VERS_1) {
2295 result = OSKext::readMkext1Archive(mkextData, checksumPtr);
2296 } else {
2297 OSKextLog(/* kext */ NULL,
2298 kOSKextLogErrorLevel |
2299 kOSKextLogArchiveFlag,
2300 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion);
2301 result = kOSKextReturnUnsupported;
2302 }
2303
2304finish:
2305 return result;
2306}
2307
2308/*********************************************************************
2309* Assumes magic, signature, version, length have been checked.
2310*
2311* Doesn't do as much bounds-checking as it should, but we're dropping
2312* mkext1 support from the kernel for SnowLeopard soon.
2313*
2314* Should keep track of all kexts created so far, and if we hit a
2315* fatal error halfway through, remove those kexts. If we've dropped
2316* an older version that had already been read, whoops! Might want to
2317* add a level of buffering?
2318*********************************************************************/
2319/* static */
2320OSReturn
2321OSKext::readMkext1Archive(
2322 OSData * mkextData,
2323 uint32_t * checksumPtr)
2324{
2325 OSReturn result = kOSReturnError;
2326 uint32_t mkextLength;
2327 mkext1_header * mkextHeader = 0; // do not free
2328 void * mkextEnd = 0; // do not free
2329 uint32_t mkextVersion;
2330 uint8_t * crc_address = 0;
2331 uint32_t checksum;
2332 uint32_t numKexts = 0;
2333
2334 OSData * infoDictDataObject = NULL; // must release
6d2010ae 2335 OSObject * parsedXML = NULL; // must release
b0d623f7
A
2336 OSDictionary * infoDict = NULL; // do not release
2337 OSString * errorString = NULL; // must release
2338 OSData * mkextExecutableInfo = NULL; // must release
2339 OSKext * theKext = NULL; // must release
2340
2341 mkextLength = mkextData->getLength();
2342 mkextHeader = (mkext1_header *)mkextData->getBytesNoCopy();
2343 mkextEnd = (char *)mkextHeader + mkextLength;
2344 mkextVersion = OSSwapBigToHostInt32(mkextHeader->version);
2345
2346 crc_address = (u_int8_t *)&mkextHeader->version;
2347 checksum = mkext_adler32(crc_address,
2348 (uintptr_t)mkextHeader +
2349 OSSwapBigToHostInt32(mkextHeader->length) - (uintptr_t)crc_address);
2350
2351 if (OSSwapBigToHostInt32(mkextHeader->adler32) != checksum) {
2352 OSKextLog(/* kext */ NULL,
2353 kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
2354 "Kext archive has a bad checksum.");
2355 result = kOSKextReturnBadData;
2356 goto finish;
2357 }
2358
2359 if (checksumPtr) {
2360 *checksumPtr = checksum;
2361 }
2362
2363 /* Check that the CPU type & subtype match that of the running kernel. */
2364 if (OSSwapBigToHostInt32(mkextHeader->cputype) != (UInt32)CPU_TYPE_ANY) {
2365 if ((UInt32)_mh_execute_header.cputype !=
2366 OSSwapBigToHostInt32(mkextHeader->cputype)) {
2367
2368 OSKextLog(/* kext */ NULL,
2369 kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
2370 "Kext archive doesn't contain software "
2371 "for this computer's CPU type.");
2372 result = kOSKextReturnArchNotFound;
2373 goto finish;
2374 }
2375 }
2376
2377 numKexts = OSSwapBigToHostInt32(mkextHeader->numkexts);
2378
2379 for (uint32_t i = 0; i < numKexts; i++) {
2380
2381 OSSafeReleaseNULL(infoDictDataObject);
2382 OSSafeReleaseNULL(infoDict);
2383 OSSafeReleaseNULL(mkextExecutableInfo);
2384 OSSafeReleaseNULL(errorString);
2385 OSSafeReleaseNULL(theKext);
2386
2387 mkext_kext * kextEntry = &mkextHeader->kext[i];
2388 mkext_file * infoDictPtr = &kextEntry->plist;
2389 mkext_file * executablePtr = &kextEntry->module;
2390 if (kextEntry >= mkextEnd) {
2391 OSKextLog(/* kext */ NULL,
2392 kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
2393 "Mkext file overrun.");
2394 result = kOSKextReturnBadData;
2395 goto finish;
2396 }
2397
2398 /* Note that we're pretty tolerant of errors in individual entries.
2399 * As long as we can keep processing, we do.
2400 */
2401 infoDictDataObject = OSKext::extractMkext1Entry(
2402 mkextHeader, infoDictPtr);
2403 if (!infoDictDataObject) {
2404 OSKextLog(/* kext */ NULL,
2405 kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
2406 "Can't uncompress info dictionary "
2407 "from mkext archive entry %d.", i);
2408 continue;
2409 }
2410
2411 parsedXML = OSUnserializeXML(
2412 (const char *)infoDictDataObject->getBytesNoCopy(),
2413 &errorString);
2414 if (parsedXML) {
2415 infoDict = OSDynamicCast(OSDictionary, parsedXML);
2416 }
2417 if (!infoDict) {
2418 const char * errorCString = "(unknown error)";
2419
2420 if (errorString && errorString->getCStringNoCopy()) {
2421 errorCString = errorString->getCStringNoCopy();
2422 } else if (parsedXML) {
2423 errorCString = "not a dictionary";
2424 }
2425 OSKextLog(/* kext */ NULL,
2426 kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
2427 "Error: Can't read XML property list "
2428 "for mkext archive entry %d: %s.", i, errorCString);
2429 continue;
2430 }
2431
2432 theKext = new OSKext;
2433 if (!theKext) {
2434 OSKextLog(/* kext */ NULL,
2435 kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
2436 "Kext allocation failure.");
2437 continue;
2438 }
2439
2440 /*****
2441 * Prepare an entry to hold the mkext entry info for the
2442 * compressed binary module, if there is one. If all four fields
2443 * of the module entry are zero, there isn't one.
2444 */
2445 if ((OSSwapBigToHostInt32(executablePtr->offset) ||
2446 OSSwapBigToHostInt32(executablePtr->compsize) ||
2447 OSSwapBigToHostInt32(executablePtr->realsize) ||
2448 OSSwapBigToHostInt32(executablePtr->modifiedsecs))) {
2449
2450 MkextEntryRef entryRef;
2451
2452 mkextExecutableInfo = OSData::withCapacity(sizeof(entryRef));
2453 if (!mkextExecutableInfo) {
2454 panic("Error: Couldn't allocate data object "
2455 "for mkext archive entry %d.\n", i);
2456 }
2457
2458 entryRef.mkext = (mkext_basic_header *)mkextHeader;
2459 entryRef.fileinfo = (uint8_t *)executablePtr;
2460 if (!mkextExecutableInfo->appendBytes(&entryRef,
2461 sizeof(entryRef))) {
2462
2463 OSKextLog(/* kext */ NULL,
2464 kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
2465 "Couldn't record executable info "
2466 "for mkext archive entry %d.", i);
2467 // we might hit a load error later but oh well
2468 // xxx - should probably remove theKext
2469 continue;
2470 }
2471
2472 }
2473
2474 /* Init can fail because of a data/runtime error, or because the
2475 * kext is a dup. Either way, we don't care here.
2476 */
2477 if (!theKext->initWithMkext1Info(infoDict, mkextExecutableInfo,
2478 mkextData)) {
2479
2480 // theKext is released at the top of the loop or in the finish block
2481 continue;
2482 }
2483
2484 /* If we got even one kext out of the mkext archive,
2485 * we have successfully read the archive, in that we
2486 * have data references into its mapped memory.
2487 */
2488 result = kOSReturnSuccess;
2489 }
2490
2491finish:
2492
2493 OSSafeRelease(infoDictDataObject);
2494 OSSafeRelease(parsedXML);
2495 OSSafeRelease(errorString);
2496 OSSafeRelease(mkextExecutableInfo);
2497 OSSafeRelease(theKext);
2498
2499 return result;
2500}
2501
2502/*********************************************************************
2503*********************************************************************/
2504bool
2505OSKext::initWithMkext1Info(
2506 OSDictionary * anInfoDict,
2507 OSData * executableWrapper,
2508 OSData * mkextData)
2509{
2510 bool result = false;
2511
2512 // mkext1 doesn't allow for path (might stuff in info dict)
2513 if (!setInfoDictionaryAndPath(anInfoDict, /* path */ NULL)) {
2514 goto finish;
2515 }
2516
2517 if (!registerIdentifier()) {
2518 goto finish;
2519 }
2520
2521 if (!setExecutable(executableWrapper, mkextData, true)) {
2522 goto finish;
2523 }
2524
2525 result = true;
2526
2527finish:
2528
2529 /* If we can't init, remove the kext from the lookup dictionary.
2530 * This is safe to call in init because there's an implicit retain.
2531 */
2532 if (!result) {
2533 OSKext::removeKext(this, /* removePersonalities? */ false);
2534 }
2535
2536 return result;
2537}
2538
2539/*********************************************************************
2540* xxx - this should take the input data length
2541*********************************************************************/
2542/* static */
2543OSData *
2544OSKext::extractMkext1Entry(
2545 const void * mkextFileBase,
2546 const void * entry)
2547{
2548 OSData * result = NULL;
2549 OSData * uncompressedData = NULL; // release on error
2550 const char * errmsg = NULL;
2551
2552 mkext_file * fileinfo;
2553 uint8_t * uncompressedDataBuffer = 0; // do not free (panic on alloc. fail)
2554 size_t uncompressed_size = 0;
2555 kern_return_t kern_result;
2556
2557 fileinfo = (mkext_file *)entry;
2558
2559 size_t offset = OSSwapBigToHostInt32(fileinfo->offset);
2560 size_t compressed_size = OSSwapBigToHostInt32(fileinfo->compsize);
2561 size_t expected_size = OSSwapBigToHostInt32(fileinfo->realsize);
2562
2563 // Add 1 for '\0' to terminate XML string (for plists)
2564 // (we really should have the archive format include that).
2565 size_t alloc_size = expected_size + 1;
2566 time_t modifiedsecs = OSSwapBigToHostInt32(fileinfo->modifiedsecs);
2567
2568 /* If these four fields are zero there's no file, but it's up to
2569 * the calling context to decide if that's an error.
2570 */
2571 if (offset == 0 && compressed_size == 0 &&
2572 expected_size == 0 && modifiedsecs == 0) {
2573 goto finish;
2574 }
2575
2576 kern_result = kmem_alloc(kernel_map,
2577 (vm_offset_t *)&uncompressedDataBuffer,
2578 alloc_size);
2579 if (kern_result != KERN_SUCCESS) {
2580 panic(ALLOC_FAIL);
2581 goto finish;
2582 }
2583
2584 uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer,
2585 alloc_size);
2586 if (uncompressedData == NULL) {
2587 /* No need to free uncompressedDataBuffer here, either. */
2588 panic(ALLOC_FAIL);
2589 goto finish;
2590 }
2591 uncompressedData->setDeallocFunction(&osdata_kmem_free);
2592
2593 /* Do the decompression if necessary. Note that even if the file isn't
2594 * compressed, we want to make a copy so that we don't have the tie to
2595 * the larger mkext file buffer any more.
2596 * xxx - need to detect decompression overflow too
2597 */
2598 if (compressed_size != 0) {
2599 errmsg = "OSKext::uncompressMkext - "
2600 "uncompressed file shorter than expected";
2601 uncompressed_size = decompress_lzss(uncompressedDataBuffer,
2602 expected_size,
2603 ((uint8_t *)mkextFileBase) + offset,
2604 compressed_size);
2605 if (uncompressed_size != expected_size) {
2606 goto finish;
2607 }
2608 } else {
2609 memcpy(uncompressedDataBuffer,
2610 ((uint8_t *)mkextFileBase) + offset,
2611 expected_size);
2612 }
2613
2614 // Add a terminating nul character in case the data is XML.
2615 // (we really should have the archive format include that).
2616 uncompressedDataBuffer[expected_size] = '\0';
2617
2618 result = uncompressedData;
2619 errmsg = NULL;
2620
2621finish:
2622 if (!result) {
2623 OSKextLog(/* kext */ NULL,
2624 kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
2625 "%s", errmsg);
2626
2627 if (uncompressedData) {
2628 uncompressedData->release();
2629 }
2630 }
2631 return result;
2632}
2633
2634/*********************************************************************
2635* Assumes magic, signature, version, length have been checked.
2636* xxx - need to add further bounds checking for each file entry
2637*
2638* Should keep track of all kexts created so far, and if we hit a
2639* fatal error halfway through, remove those kexts. If we've dropped
2640* an older version that had already been read, whoops! Might want to
2641* add a level of buffering?
2642*********************************************************************/
2643/* static */
2644OSReturn
2645OSKext::readMkext2Archive(
2646 OSData * mkextData,
2647 OSDictionary ** mkextPlistOut,
2648 uint32_t * checksumPtr)
2649{
2650 OSReturn result = kOSReturnError;
2651 uint32_t mkextLength;
2652 mkext2_header * mkextHeader = NULL; // do not free
2653 void * mkextEnd = NULL; // do not free
2654 uint32_t mkextVersion;
2655 uint8_t * crc_address = NULL;
2656 uint32_t checksum;
2657 uint32_t mkextPlistOffset;
2658 uint32_t mkextPlistCompressedSize;
2659 char * mkextPlistEnd = NULL; // do not free
2660 uint32_t mkextPlistFullSize;
2661 OSString * errorString = NULL; // must release
2662 OSData * mkextPlistUncompressedData = NULL; // must release
2663 const char * mkextPlistDataBuffer = NULL; // do not free
6d2010ae 2664 OSObject * parsedXML = NULL; // must release
b0d623f7
A
2665 OSDictionary * mkextPlist = NULL; // do not release
2666 OSArray * mkextInfoDictArray = NULL; // do not release
2667 uint32_t count, i;
2668
2669 mkextLength = mkextData->getLength();
2670 mkextHeader = (mkext2_header *)mkextData->getBytesNoCopy();
2671 mkextEnd = (char *)mkextHeader + mkextLength;
2672 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
2673
2674 crc_address = (u_int8_t *)&mkextHeader->version;
2675 checksum = mkext_adler32(crc_address,
2676 (uintptr_t)mkextHeader +
2677 MKEXT_GET_LENGTH(mkextHeader) - (uintptr_t)crc_address);
2678
2679 if (MKEXT_GET_CHECKSUM(mkextHeader) != checksum) {
2680 OSKextLog(/* kext */ NULL,
2681 kOSKextLogErrorLevel |
2682 kOSKextLogArchiveFlag,
2683 "Mkext archive has bad checksum.");
2684 result = kOSKextReturnBadData;
2685 goto finish;
2686 }
2687
2688 if (checksumPtr) {
2689 *checksumPtr = checksum;
2690 }
2691
2692 /* Check that the CPU type & subtype match that of the running kernel. */
2693 if (MKEXT_GET_CPUTYPE(mkextHeader) == (UInt32)CPU_TYPE_ANY) {
2694 OSKextLog(/* kext */ NULL,
2695 kOSKextLogErrorLevel |
2696 kOSKextLogArchiveFlag,
2697 "Mkext archive must have a specific CPU type.");
2698 result = kOSKextReturnBadData;
2699 goto finish;
2700 } else {
2701 if ((UInt32)_mh_execute_header.cputype !=
2702 MKEXT_GET_CPUTYPE(mkextHeader)) {
2703
2704 OSKextLog(/* kext */ NULL,
2705 kOSKextLogErrorLevel |
2706 kOSKextLogArchiveFlag,
2707 "Mkext archive does not match the running kernel's CPU type.");
2708 result = kOSKextReturnArchNotFound;
2709 goto finish;
2710 }
2711 }
2712
2713 mkextPlistOffset = MKEXT2_GET_PLIST(mkextHeader);
2714 mkextPlistCompressedSize = MKEXT2_GET_PLIST_COMPSIZE(mkextHeader);
2715 mkextPlistEnd = (char *)mkextHeader + mkextPlistOffset +
2716 mkextPlistCompressedSize;
2717 if (mkextPlistEnd > mkextEnd) {
2718 OSKextLog(/* kext */ NULL,
2719 kOSKextLogErrorLevel |
2720 kOSKextLogArchiveFlag,
2721 "Mkext archive file overrun.");
2722 result = kOSKextReturnBadData;
2723 }
2724
2725 mkextPlistFullSize = MKEXT2_GET_PLIST_FULLSIZE(mkextHeader);
2726 if (mkextPlistCompressedSize) {
2727 mkextPlistUncompressedData = sKernelKext->extractMkext2FileData(
2728 (UInt8 *)mkextHeader + mkextPlistOffset,
2729 "plist",
2730 mkextPlistCompressedSize, mkextPlistFullSize);
2731 if (!mkextPlistUncompressedData) {
2732 goto finish;
2733 }
2734 mkextPlistDataBuffer = (const char *)
2735 mkextPlistUncompressedData->getBytesNoCopy();
2736 } else {
2737 mkextPlistDataBuffer = (const char *)mkextHeader + mkextPlistOffset;
2738 }
2739
2740 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
2741 */
2742 parsedXML = OSUnserializeXML(mkextPlistDataBuffer, &errorString);
2743 if (parsedXML) {
2744 mkextPlist = OSDynamicCast(OSDictionary, parsedXML);
2745 }
2746 if (!mkextPlist) {
2747 const char * errorCString = "(unknown error)";
2748
2749 if (errorString && errorString->getCStringNoCopy()) {
2750 errorCString = errorString->getCStringNoCopy();
2751 } else if (parsedXML) {
2752 errorCString = "not a dictionary";
2753 }
2754 OSKextLog(/* kext */ NULL,
2755 kOSKextLogErrorLevel |
2756 kOSKextLogArchiveFlag,
2757 "Error unserializing mkext plist: %s.", errorCString);
2758 goto finish;
2759 }
2760
2761 /* If the caller needs the plist, hand it back and retain it.
2762 * (This function releases it at the end.)
2763 */
2764 if (mkextPlistOut) {
2765 *mkextPlistOut = mkextPlist;
2766 (*mkextPlistOut)->retain();
2767 }
2768
2769 mkextInfoDictArray = OSDynamicCast(OSArray,
2770 mkextPlist->getObject(kMKEXTInfoDictionariesKey));
2771 if (!mkextInfoDictArray) {
2772 OSKextLog(/* kext */ NULL,
2773 kOSKextLogErrorLevel |
2774 kOSKextLogArchiveFlag,
2775 "Mkext archive contains no kext info dictionaries.");
2776 goto finish;
2777 }
2778
2779 count = mkextInfoDictArray->getCount();
2780 for (i = 0; i < count; i++) {
2781 OSDictionary * infoDict;
2782
2783
2784 infoDict = OSDynamicCast(OSDictionary,
2785 mkextInfoDictArray->getObject(i));
2786
2787 /* Create the kext for the entry, then release it, because the
2788 * kext system keeps them around until explicitly removed.
2789 * Any creation/registration failures are already logged for us.
2790 */
2791 OSKext * newKext = OSKext::withMkext2Info(infoDict, mkextData);
2792 OSSafeRelease(newKext);
2793 }
2794
2795 /* Even if we didn't keep any kexts from the mkext, we may have a load
2796 * request to process, so we are successful (no errors occurred).
2797 */
2798 result = kOSReturnSuccess;
2799
2800finish:
2801
2802 OSSafeRelease(parsedXML);
2803 OSSafeRelease(mkextPlistUncompressedData);
2804 OSSafeRelease(errorString);
2805
2806 return result;
2807}
2808
2809/*********************************************************************
2810*********************************************************************/
2811/* static */
2812OSKext *
2813OSKext::withMkext2Info(
2814 OSDictionary * anInfoDict,
2815 OSData * mkextData)
2816{
2817 OSKext * newKext = new OSKext;
2818
2819 if (newKext && !newKext->initWithMkext2Info(anInfoDict, mkextData)) {
2820 newKext->release();
2821 return NULL;
2822 }
2823
2824 return newKext;
2825}
2826
2827/*********************************************************************
2828*********************************************************************/
2829bool
2830OSKext::initWithMkext2Info(
2831 OSDictionary * anInfoDict,
2832 OSData * mkextData)
2833{
2834 bool result = false;
2835 OSString * kextPath = NULL; // do not release
2836 OSNumber * executableOffsetNum = NULL; // do not release
2837 OSCollectionIterator * iterator = NULL; // must release
2838 OSData * executable = NULL; // must release
2839
2840 if (!super::init()) {
2841 goto finish;
2842 }
2843
2844 /* Get the path. Don't look for an arch-specific path property.
2845 */
2846 kextPath = OSDynamicCast(OSString,
2847 anInfoDict->getObject(kMKEXTBundlePathKey));
2848
2849 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
2850 goto finish;
2851 }
2852
6d2010ae
A
2853 /* If we have a path to the executable, save it.
2854 */
2855 executableRelPath = OSDynamicCast(OSString,
2856 anInfoDict->getObject(kMKEXTExecutableRelativePathKey));
2857 if (executableRelPath) {
2858 executableRelPath->retain();
2859 }
2860
2861 /* Don't need the paths to be in the info dictionary any more.
b0d623f7
A
2862 */
2863 anInfoDict->removeObject(kMKEXTBundlePathKey);
6d2010ae 2864 anInfoDict->removeObject(kMKEXTExecutableRelativePathKey);
b0d623f7
A
2865
2866 executableOffsetNum = OSDynamicCast(OSNumber,
2867 infoDict->getObject(kMKEXTExecutableKey));
2868 if (executableOffsetNum) {
2869 executable = createMkext2FileEntry(mkextData,
2870 executableOffsetNum, "executable");
2871 infoDict->removeObject(kMKEXTExecutableKey);
2872 if (!executable) {
2873 goto finish;
2874 }
2875 if (!setExecutable(executable, mkextData, true)) {
2876 goto finish;
2877 }
2878 }
2879
2880 result = registerIdentifier();
2881
2882finish:
2883
2884 OSSafeRelease(executable);
2885 OSSafeRelease(iterator);
2886 return result;
2887}
2888
2889/*********************************************************************
2890*********************************************************************/
2891OSData *
2892OSKext::createMkext2FileEntry(
2893 OSData * mkextData,
2894 OSNumber * offsetNum,
2895 const char * name)
2896{
2897 OSData * result = NULL;
2898 MkextEntryRef entryRef;
2899 uint8_t * mkextBuffer = (uint8_t *)mkextData->getBytesNoCopy();
2900 uint32_t entryOffset = offsetNum->unsigned32BitValue();
2901
2902 result = OSData::withCapacity(sizeof(entryRef));
2903 if (!result) {
2904 goto finish;
2905 }
2906
2907 entryRef.mkext = (mkext_basic_header *)mkextBuffer;
2908 entryRef.fileinfo = mkextBuffer + entryOffset;
2909 if (!result->appendBytes(&entryRef, sizeof(entryRef))) {
2910 OSSafeReleaseNULL(result);
2911 goto finish;
2912 }
2913
2914finish:
2915 if (!result) {
2916 OSKextLog(this,
2917 kOSKextLogErrorLevel |
2918 kOSKextLogArchiveFlag,
2919 "Can't create wrapper for mkext file entry '%s' of kext %s.",
2920 name, getIdentifierCString());
2921 }
2922 return result;
2923}
2924
2925/*********************************************************************
2926*********************************************************************/
2927extern "C" {
2928static void * z_alloc(void *, u_int items, u_int size);
2929static void z_free(void *, void *ptr);
2930
2931typedef struct z_mem {
2932 uint32_t alloc_size;
2933 uint8_t data[0];
2934} z_mem;
2935
2936/*
2937 * Space allocation and freeing routines for use by zlib routines.
2938 */
2939void *
2940z_alloc(void * notused __unused, u_int num_items, u_int size)
2941{
2942 void * result = NULL;
2943 z_mem * zmem = NULL;
2944 uint32_t total = num_items * size;
2945 uint32_t allocSize = total + sizeof(zmem);
2946
2947 zmem = (z_mem *)kalloc(allocSize);
2948 if (!zmem) {
2949 goto finish;
2950 }
2951 zmem->alloc_size = allocSize;
2952 result = (void *)&(zmem->data);
2953finish:
2954 return result;
2955}
2956
2957void
2958z_free(void * notused __unused, void * ptr)
2959{
2960 uint32_t * skipper = (uint32_t *)ptr - 1;
2961 z_mem * zmem = (z_mem *)skipper;
2962 kfree((void *)zmem, zmem->alloc_size);
2963 return;
2964}
2965};
2966
2967OSData *
2968OSKext::extractMkext2FileData(
2969 UInt8 * data,
2970 const char * name,
2971 uint32_t compressedSize,
2972 uint32_t fullSize)
2973{
2974 OSData * result = NULL;
2975
2976 OSData * uncompressedData = NULL; // release on error
2977
2978 uint8_t * uncompressedDataBuffer = 0; // do not free
2979 unsigned long uncompressedSize;
2980 z_stream zstream;
2981 bool zstream_inited = false;
2982 int zlib_result;
2983
2984 /* If the file isn't compressed, we want to make a copy
2985 * so that we don't have the tie to the larger mkext file buffer any more.
2986 */
2987 if (!compressedSize) {
2988 uncompressedData = OSData::withBytes(data, fullSize);
2989 // xxx - no check for failure?
2990 result = uncompressedData;
2991 goto finish;
2992 }
2993
2994 if (KERN_SUCCESS != kmem_alloc(kernel_map,
2995 (vm_offset_t*)&uncompressedDataBuffer, fullSize)) {
2996
2997 /* How's this for cheesy? The kernel is only asked to extract
2998 * kext plists so we tailor the log messages.
2999 */
6d2010ae 3000 if (isKernel()) {
b0d623f7
A
3001 OSKextLog(this,
3002 kOSKextLogErrorLevel |
3003 kOSKextLogArchiveFlag,
3004 "Allocation failure extracting %s from mkext.", name);
3005 } else {
3006 OSKextLog(this,
3007 kOSKextLogErrorLevel |
3008 kOSKextLogArchiveFlag,
3009 "Allocation failure extracting %s from mkext for kext %s.",
3010 name, getIdentifierCString());
3011 }
3012
3013 goto finish;
3014 }
3015 uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer, fullSize);
3016 if (!uncompressedData) {
6d2010ae 3017 if (isKernel()) {
b0d623f7
A
3018 OSKextLog(this,
3019 kOSKextLogErrorLevel |
3020 kOSKextLogArchiveFlag,
3021 "Allocation failure extracting %s from mkext.", name);
3022 } else {
3023 OSKextLog(this,
3024 kOSKextLogErrorLevel |
3025 kOSKextLogArchiveFlag,
3026 "Allocation failure extracting %s from mkext for kext %s.",
3027 name, getIdentifierCString());
3028 }
3029 goto finish;
3030 }
3031 uncompressedData->setDeallocFunction(&osdata_kmem_free);
3032
6d2010ae 3033 if (isKernel()) {
b0d623f7
A
3034 OSKextLog(this,
3035 kOSKextLogDetailLevel |
3036 kOSKextLogArchiveFlag,
3037 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
3038 name, compressedSize, fullSize);
3039 } else {
3040 OSKextLog(this,
3041 kOSKextLogDetailLevel |
3042 kOSKextLogArchiveFlag,
3043 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
3044 getIdentifierCString(), name, compressedSize, fullSize);
3045 }
3046
3047 bzero(&zstream, sizeof(zstream));
3048 zstream.next_in = (UInt8 *)data;
3049 zstream.avail_in = compressedSize;
3050
3051 zstream.next_out = uncompressedDataBuffer;
3052 zstream.avail_out = fullSize;
3053
3054 zstream.zalloc = z_alloc;
3055 zstream.zfree = z_free;
3056
3057 zlib_result = inflateInit(&zstream);
3058 if (Z_OK != zlib_result) {
6d2010ae 3059 if (isKernel()) {
b0d623f7
A
3060 OSKextLog(this,
3061 kOSKextLogErrorLevel |
3062 kOSKextLogArchiveFlag,
3063 "Mkext error; zlib inflateInit failed (%d) for %s.",
3064 zlib_result, name);
3065 } else {
3066 OSKextLog(this,
3067 kOSKextLogErrorLevel |
3068 kOSKextLogArchiveFlag,
3069 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
3070 getIdentifierCString(), zlib_result, name);
3071 }
3072 goto finish;
3073 } else {
3074 zstream_inited = true;
3075 }
3076
3077 zlib_result = inflate(&zstream, Z_FINISH);
3078
3079 if (zlib_result == Z_STREAM_END || zlib_result == Z_OK) {
3080 uncompressedSize = zstream.total_out;
3081 } else {
6d2010ae 3082 if (isKernel()) {
b0d623f7
A
3083 OSKextLog(this,
3084 kOSKextLogErrorLevel |
3085 kOSKextLogArchiveFlag,
3086 "Mkext error; zlib inflate failed (%d) for %s.",
3087 zlib_result, name);
3088 } else {
3089 OSKextLog(this,
3090 kOSKextLogErrorLevel |
3091 kOSKextLogArchiveFlag,
3092 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
3093 getIdentifierCString(), zlib_result, name);
3094 }
3095 if (zstream.msg) {
3096 OSKextLog(this,
3097 kOSKextLogErrorLevel |
3098 kOSKextLogArchiveFlag,
3099 "zlib error: %s.", zstream.msg);
3100 }
3101 goto finish;
3102 }
3103
3104 if (uncompressedSize != fullSize) {
6d2010ae 3105 if (isKernel()) {
b0d623f7
A
3106 OSKextLog(this,
3107 kOSKextLogErrorLevel |
3108 kOSKextLogArchiveFlag,
3109 "Mkext error; zlib inflate discrepancy for %s, "
3110 "uncompressed size != original size.", name);
3111 } else {
3112 OSKextLog(this,
3113 kOSKextLogErrorLevel |
3114 kOSKextLogArchiveFlag,
3115 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
3116 "uncompressed size != original size.",
3117 getIdentifierCString(), name);
3118 }
3119 goto finish;
3120 }
3121
3122 result = uncompressedData;
3123
3124finish:
3125 /* Don't bother checking return, nothing we can do on fail.
3126 */
3127 if (zstream_inited) inflateEnd(&zstream);
3128
3129 if (!result) {
3130 OSSafeRelease(uncompressedData);
3131 }
3132
3133 return result;
3134}
3135
3136/*********************************************************************
3137*********************************************************************/
3138/* static */
3139OSReturn
3140OSKext::loadFromMkext(
3141 OSKextLogSpec clientLogFilter,
3142 char * mkextBuffer,
3143 uint32_t mkextBufferLength,
3144 char ** logInfoOut,
3145 uint32_t * logInfoLengthOut)
3146{
3147 OSReturn result = kOSReturnError;
3148 OSReturn tempResult = kOSReturnError;
3149
3150 OSData * mkextData = NULL; // must release
3151 OSDictionary * mkextPlist = NULL; // must release
3152
3153 OSArray * logInfoArray = NULL; // must release
3154 OSSerialize * serializer = NULL; // must release
3155
3156 OSString * predicate = NULL; // do not release
3157 OSDictionary * requestArgs = NULL; // do not release
3158
3159 OSString * kextIdentifier = NULL; // do not release
3160 OSNumber * startKextExcludeNum = NULL; // do not release
3161 OSNumber * startMatchingExcludeNum = NULL; // do not release
3162 OSBoolean * delayAutounloadBool = NULL; // do not release
3163 OSArray * personalityNames = NULL; // do not release
3164
3165 /* Default values for these two options: regular autounload behavior,
3166 * load all kexts, send no personalities.
3167 */
3168 Boolean delayAutounload = false;
3169 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
3170 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeAll;
3171
3172 IORecursiveLockLock(sKextLock);
3173
3174 if (logInfoOut) {
3175 *logInfoOut = NULL;
3176 *logInfoLengthOut = 0;
3177 }
3178
3179 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
3180
3181 OSKextLog(/* kext */ NULL,
3182 kOSKextLogDebugLevel |
3183 kOSKextLogIPCFlag,
3184 "Received kext load request from user space.");
3185
3186 /* Regardless of processing, the fact that we have gotten here means some
3187 * user-space program is up and talking to us, so we'll switch our kext
3188 * registration to reflect that.
3189 */
3190 if (!sUserLoadsActive) {
3191 OSKextLog(/* kext */ NULL,
3192 kOSKextLogProgressLevel |
3193 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
3194 "Switching to late startup (user-space) kext loading policy.");
3195
3196 sUserLoadsActive = true;
3197 }
3198
3199 if (!sLoadEnabled) {
3200 OSKextLog(/* kext */ NULL,
3201 kOSKextLogErrorLevel |
3202 kOSKextLogLoadFlag,
3203 "Kext loading is disabled.");
3204 result = kOSKextReturnDisabled;
3205 goto finish;
3206 }
3207
3208 /* Note that we do not set a dealloc function on this OSData
3209 * object! No references to it can remain after the loadFromMkext()
3210 * call since we are in a MIG function, and will vm_deallocate()
3211 * the buffer.
3212 */
3213 mkextData = OSData::withBytesNoCopy(mkextBuffer,
3214 mkextBufferLength);
3215 if (!mkextData) {
3216 OSKextLog(/* kext */ NULL,
3217 kOSKextLogErrorLevel |
3218 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3219 "Failed to create wrapper for kext load request.");
3220 result = kOSKextReturnNoMemory;
3221 goto finish;
3222 }
3223
3224 result = readMkext2Archive(mkextData, &mkextPlist, NULL);
3225 if (result != kOSReturnSuccess) {
3226 OSKextLog(/* kext */ NULL,
3227 kOSKextLogErrorLevel |
3228 kOSKextLogLoadFlag,
3229 "Failed to read kext load request.");
3230 goto finish;
3231 }
3232
3233 predicate = _OSKextGetRequestPredicate(mkextPlist);
3234 if (!predicate || !predicate->isEqualTo(kKextRequestPredicateLoad)) {
3235 OSKextLog(/* kext */ NULL,
3236 kOSKextLogErrorLevel |
3237 kOSKextLogLoadFlag,
3238 "Received kext load request with no predicate; skipping.");
3239 result = kOSKextReturnInvalidArgument;
3240 goto finish;
3241 }
3242
3243 requestArgs = OSDynamicCast(OSDictionary,
3244 mkextPlist->getObject(kKextRequestArgumentsKey));
3245 if (!requestArgs || !requestArgs->getCount()) {
3246 OSKextLog(/* kext */ NULL,
3247 kOSKextLogErrorLevel |
3248 kOSKextLogLoadFlag,
3249 "Received kext load request with no arguments.");
3250 result = kOSKextReturnInvalidArgument;
3251 goto finish;
3252 }
3253
3254 kextIdentifier = OSDynamicCast(OSString,
3255 requestArgs->getObject(kKextRequestArgumentBundleIdentifierKey));
3256 if (!kextIdentifier) {
3257 OSKextLog(/* kext */ NULL,
3258 kOSKextLogErrorLevel |
3259 kOSKextLogLoadFlag,
3260 "Received kext load request with no kext identifier.");
3261 result = kOSKextReturnInvalidArgument;
3262 goto finish;
3263 }
3264
3265 startKextExcludeNum = OSDynamicCast(OSNumber,
6d2010ae 3266 requestArgs->getObject(kKextRequestArgumentStartExcludeKey));
b0d623f7
A
3267 startMatchingExcludeNum = OSDynamicCast(OSNumber,
3268 requestArgs->getObject(kKextRequestArgumentStartMatchingExcludeKey));
3269 delayAutounloadBool = OSDynamicCast(OSBoolean,
3270 requestArgs->getObject(kKextRequestArgumentDelayAutounloadKey));
3271 personalityNames = OSDynamicCast(OSArray,
3272 requestArgs->getObject(kKextRequestArgumentPersonalityNamesKey));
3273
3274 if (delayAutounloadBool) {
3275 delayAutounload = delayAutounloadBool->getValue();
3276 }
3277 if (startKextExcludeNum) {
3278 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
3279 }
3280 if (startMatchingExcludeNum) {
3281 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
3282 }
3283
3284 OSKextLog(/* kext */ NULL,
3285 kOSKextLogProgressLevel |
3286 kOSKextLogIPCFlag,
3287 "Received request from user space to load kext %s.",
3288 kextIdentifier->getCStringNoCopy());
3289
3290 /* Load the kext, with no deferral, since this is a load from outside
3291 * the kernel.
3292 * xxx - Would like a better way to handle the default values for the
3293 * xxx - start/match opt args.
3294 */
3295 result = OSKext::loadKextWithIdentifier(
3296 kextIdentifier,
3297 /* allowDefer */ false,
3298 delayAutounload,
3299 startKextExcludeLevel,
3300 startMatchingExcludeLevel,
3301 personalityNames);
3302 if (result != kOSReturnSuccess) {
3303 goto finish;
3304 }
3305 /* If the load came down from kextd, it will shortly inform IOCatalogue
3306 * for matching via a separate IOKit calldown.
3307 */
3308
3309finish:
3310
3311 /* Gather up the collected log messages for user space. Any
3312 * error messages past this call will not make it up as log messages
3313 * but will be in the system log.
3314 */
3315 logInfoArray = OSKext::clearUserSpaceLogFilter();
3316
3317 if (logInfoArray && logInfoOut && logInfoLengthOut) {
3318 tempResult = OSKext::serializeLogInfo(logInfoArray,
3319 logInfoOut, logInfoLengthOut);
3320 if (tempResult != kOSReturnSuccess) {
3321 result = tempResult;
3322 }
3323 }
3324
3325 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
3326
3327 /* Note: mkextDataObject will have been retained by every kext w/an
3328 * executable in it. That should all have been flushed out at the
3329 * and of the load operation, but you never know....
3330 */
3331 if (mkextData && mkextData->getRetainCount() > 1) {
3332 OSKextLog(/* kext */ NULL,
3333 kOSKextLogErrorLevel |
3334 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3335 "Kext load request buffer from user space still retained by a kext; "
3336 "probable memory leak.");
3337 }
3338
3339 IORecursiveLockUnlock(sKextLock);
3340
3341 OSSafeRelease(mkextData);
3342 OSSafeRelease(mkextPlist);
3343 OSSafeRelease(serializer);
3344 OSSafeRelease(logInfoArray);
3345
3346 return result;
3347}
3348
3349/*********************************************************************
3350*********************************************************************/
3351/* static */
3352OSReturn
3353OSKext::serializeLogInfo(
3354 OSArray * logInfoArray,
3355 char ** logInfoOut,
3356 uint32_t * logInfoLengthOut)
3357{
3358 OSReturn result = kOSReturnError;
3359 char * buffer = NULL;
3360 kern_return_t kmem_result = KERN_FAILURE;
3361 OSSerialize * serializer = NULL; // must release; reused
3362 char * logInfo = NULL; // returned by reference
3363 uint32_t logInfoLength = 0;
3364
3365 if (!logInfoArray || !logInfoOut || !logInfoLengthOut) {
3366 OSKextLog(/* kext */ NULL,
3367 kOSKextLogErrorLevel |
3368 kOSKextLogIPCFlag,
3369 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
3370 /* Bad programmer. */
3371 result = kOSKextReturnInvalidArgument;
3372 goto finish;
3373 }
3374
3375 serializer = OSSerialize::withCapacity(0);
3376 if (!serializer) {
3377 OSKextLog(/* kext */ NULL,
3378 kOSKextLogErrorLevel |
3379 kOSKextLogIPCFlag,
3380 "Failed to create serializer on log info for request from user space.");
3381 /* Incidental error; we're going to (try to) allow the request
3382 * itself to succeed. */
3383 }
3384
3385 if (!logInfoArray->serialize(serializer)) {
3386 OSKextLog(/* kext */ NULL,
3387 kOSKextLogErrorLevel |
3388 kOSKextLogIPCFlag,
3389 "Failed to serialize log info for request from user space.");
3390 /* Incidental error; we're going to (try to) allow the request
3391 * itself to succeed. */
3392 } else {
3393 logInfo = serializer->text();
3394 logInfoLength = serializer->getLength();
3395
3396 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer, logInfoLength);
3397 if (kmem_result != KERN_SUCCESS) {
3398 OSKextLog(/* kext */ NULL,
3399 kOSKextLogErrorLevel |
3400 kOSKextLogIPCFlag,
3401 "Failed to copy log info for request from user space.");
3402 /* Incidental error; we're going to (try to) allow the request
3403 * to succeed. */
3404 } else {
3405 memcpy(buffer, logInfo, logInfoLength);
3406 *logInfoOut = buffer;
3407 *logInfoLengthOut = logInfoLength;
3408 }
3409 }
3410
3411 result = kOSReturnSuccess;
3412finish:
3413 OSSafeRelease(serializer);
3414 return result;
3415}
3416
3417#if PRAGMA_MARK
3418#pragma mark Instance Management Methods
3419#endif
3420/*********************************************************************
3421*********************************************************************/
3422OSKext *
3423OSKext::lookupKextWithIdentifier(const char * kextIdentifier)
3424{
3425 OSKext * foundKext = NULL;
3426
3427 IORecursiveLockLock(sKextLock);
3428 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
3429 if (foundKext) {
3430 foundKext->retain();
3431 }
3432 IORecursiveLockUnlock(sKextLock);
3433
3434 return foundKext;
3435}
3436
3437/*********************************************************************
3438*********************************************************************/
3439OSKext *
3440OSKext::lookupKextWithIdentifier(OSString * kextIdentifier)
3441{
3442 return OSKext::lookupKextWithIdentifier(kextIdentifier->getCStringNoCopy());
3443}
3444
3445/*********************************************************************
3446*********************************************************************/
3447OSKext *
3448OSKext::lookupKextWithLoadTag(uint32_t aTag)
3449{
3450 OSKext * foundKext = NULL; // returned
3451 uint32_t count, i;
3452
3453 IORecursiveLockLock(sKextLock);
3454
3455 count = sLoadedKexts->getCount();
3456 for (i = 0; i < count; i++) {
3457 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
3458 if (thisKext->getLoadTag() == aTag) {
3459 foundKext = thisKext;
3460 foundKext->retain();
3461 goto finish;
3462 }
3463 }
3464
3465finish:
3466 IORecursiveLockUnlock(sKextLock);
3467
3468 return foundKext;
3469}
3470
3471/*********************************************************************
3472*********************************************************************/
3473OSKext *
3474OSKext::lookupKextWithAddress(vm_address_t address)
3475{
3476 OSKext * foundKext = NULL; // returned
3477 uint32_t count, i;
3478
3479 IORecursiveLockLock(sKextLock);
3480
3481 count = sLoadedKexts->getCount();
3482 for (i = 0; i < count; i++) {
3483 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
3484 if (thisKext->linkedExecutable) {
3485 vm_address_t kext_start =
3486 (vm_address_t)thisKext->linkedExecutable->getBytesNoCopy();
3487 vm_address_t kext_end = kext_start +
3488 thisKext->linkedExecutable->getLength();
3489
3490 if ((kext_start <= address) && (address < kext_end)) {
3491 foundKext = thisKext;
3492 foundKext->retain();
3493 goto finish;
3494 }
3495 }
3496 }
3497
3498finish:
3499 IORecursiveLockUnlock(sKextLock);
3500
3501 return foundKext;
3502}
3503
3504/*********************************************************************
3505*********************************************************************/
3506/* static */
3507bool OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
3508{
3509 bool result = false;
3510 OSKext * foundKext = NULL; // returned
3511
3512 IORecursiveLockLock(sKextLock);
3513
3514 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
3515 if (foundKext && foundKext->isLoaded()) {
3516 result = true;
3517 }
3518
3519 IORecursiveLockUnlock(sKextLock);
3520
3521 return result;
3522}
3523
3524/*********************************************************************
3525* xxx - should spawn a separate thread so a kext can safely have
3526* xxx - itself unloaded.
3527*********************************************************************/
3528/* static */
3529OSReturn
3530OSKext::removeKext(
3531 OSKext * aKext,
3532 bool terminateServicesAndRemovePersonalitiesFlag)
3533 {
3534 OSReturn result = kOSKextReturnInUse;
3535 OSKext * checkKext = NULL; // do not release
3536
3537 IORecursiveLockLock(sKextLock);
3538
3539 /* If the kext has no identifier, it failed to init
3540 * so isn't in sKextsByID and it isn't loaded.
3541 */
3542 if (!aKext->getIdentifier()) {
3543 result = kOSReturnSuccess;
3544 goto finish;
3545 }
3546
3547 checkKext = OSDynamicCast(OSKext,
3548 sKextsByID->getObject(aKext->getIdentifier()));
3549 if (checkKext != aKext) {
3550 result = kOSKextReturnNotFound;
3551 goto finish;
3552 }
3553
3554 if (aKext->isLoaded()) {
6d2010ae 3555
b0d623f7
A
3556 /* If we are terminating, send the request to the IOCatalogue
3557 * (which will actually call us right back but that's ok we have
3558 * a recursive lock don't you know) but do not ask the IOCatalogue
3559 * to call back with an unload, we'll do that right here.
3560 */
3561 if (terminateServicesAndRemovePersonalitiesFlag) {
3562 result = gIOCatalogue->terminateDriversForModule(
3563 aKext->getIdentifierCString(), /* unload */ false);
3564 if (result != kOSReturnSuccess) {
3565 OSKextLog(aKext,
6d2010ae 3566 kOSKextLogErrorLevel |
b0d623f7
A
3567 kOSKextLogKextBookkeepingFlag,
3568 "Can't remove kext %s; services failed to terminate - 0x%x.",
3569 aKext->getIdentifierCString(), result);
3570 goto finish;
3571 }
3572 }
3573
3574 result = aKext->unload();
3575 if (result != kOSReturnSuccess) {
3576 goto finish;
3577 }
3578 }
3579
3580 /* Remove personalities as requested. This is a bit redundant for a loaded
3581 * kext as IOCatalogue::terminateDriversForModule() removes driver
3582 * personalities, but it doesn't restart matching, which we always want
3583 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
3584 * that happens.
3585 */
3586 if (terminateServicesAndRemovePersonalitiesFlag) {
3587 aKext->removePersonalitiesFromCatalog();
3588 }
3589
3590 OSKextLog(aKext,
3591 kOSKextLogProgressLevel |
3592 kOSKextLogKextBookkeepingFlag,
3593 "Removing kext %s.",
3594 aKext->getIdentifierCString());
3595
3596 sKextsByID->removeObject(aKext->getIdentifier());
3597 result = kOSReturnSuccess;
3598
3599finish:
3600 IORecursiveLockUnlock(sKextLock);
3601 return result;
3602 }
3603
3604/*********************************************************************
3605*********************************************************************/
3606/* static */
3607OSReturn
3608OSKext::removeKextWithIdentifier(
3609 const char * kextIdentifier,
3610 bool terminateServicesAndRemovePersonalitiesFlag)
3611{
3612 OSReturn result = kOSReturnError;
3613
3614 IORecursiveLockLock(sKextLock);
3615
3616 OSKext * aKext = OSDynamicCast(OSKext,
3617 sKextsByID->getObject(kextIdentifier));
3618 if (!aKext) {
3619 result = kOSKextReturnNotFound;
3620 OSKextLog(/* kext */ NULL,
3621 kOSKextLogErrorLevel |
3622 kOSKextLogKextBookkeepingFlag,
3623 "Can't remove kext %s - not found.",
3624 kextIdentifier);
3625 goto finish;
3626 }
3627
3628 result = OSKext::removeKext(aKext,
3629 terminateServicesAndRemovePersonalitiesFlag);
3630
3631finish:
3632 IORecursiveLockUnlock(sKextLock);
3633
3634 return result;
3635}
3636
3637/*********************************************************************
3638*********************************************************************/
3639/* static */
3640OSReturn
3641OSKext::removeKextWithLoadTag(
3642 OSKextLoadTag loadTag,
3643 bool terminateServicesAndRemovePersonalitiesFlag)
3644{
3645 OSReturn result = kOSReturnError;
3646 OSKext * foundKext = NULL;
3647 uint32_t count, i;
3648
3649 IORecursiveLockLock(sKextLock);
3650
3651 count = sLoadedKexts->getCount();
3652 for (i = 0; i < count; i++) {
3653 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
3654 if (thisKext->loadTag == loadTag) {
3655 foundKext = thisKext;
3656 break;
3657 }
3658 }
3659
3660 if (!foundKext) {
3661 result = kOSKextReturnNotFound;
3662 OSKextLog(/* kext */ NULL,
3663 kOSKextLogErrorLevel |
3664 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
3665 "Can't remove kext with load tag %d - not found.",
3666 loadTag);
3667 goto finish;
3668 }
3669
3670 result = OSKext::removeKext(foundKext,
3671 terminateServicesAndRemovePersonalitiesFlag);
3672
3673finish:
3674 IORecursiveLockUnlock(sKextLock);
3675
3676 return result;
3677 }
3678
3679/*********************************************************************
3680*********************************************************************/
3681OSDictionary *
3682OSKext::copyKexts(void)
3683{
3684 OSDictionary * result;
3685
3686 IORecursiveLockLock(sKextLock);
3687 result = OSDynamicCast(OSDictionary, sKextsByID->copyCollection());
3688 IORecursiveLockUnlock(sKextLock);
3689
3690 return result;
3691}
3692
3693#if PRAGMA_MARK
3694#pragma mark Accessors
3695#endif
3696/*********************************************************************
3697*********************************************************************/
3698const OSSymbol *
3699OSKext::getIdentifier(void)
3700{
3701 return bundleID;
3702}
3703
3704/*********************************************************************
3705* A kext must have a bundle identifier to even survive initialization;
3706* this is guaranteed to exist past then.
3707*********************************************************************/
3708const char *
3709OSKext::getIdentifierCString(void)
3710{
3711 return bundleID->getCStringNoCopy();
3712}
3713
3714/*********************************************************************
3715*********************************************************************/
3716OSKextVersion
3717OSKext::getVersion(void)
3718{
3719 return version;
3720}
3721
3722/*********************************************************************
3723*********************************************************************/
3724OSKextVersion
3725OSKext::getCompatibleVersion(void)
3726{
3727 return compatibleVersion;
3728}
3729
6d2010ae
A
3730/*********************************************************************
3731*********************************************************************/
3732bool
3733OSKext::isLibrary(void)
3734{
3735 return (getCompatibleVersion() > 0);
3736}
3737
b0d623f7
A
3738/*********************************************************************
3739*********************************************************************/
3740bool
3741OSKext::isCompatibleWithVersion(OSKextVersion aVersion)
3742{
3743 if ((compatibleVersion > -1 && version > -1) &&
3744 (compatibleVersion <= version && aVersion <= version)) {
3745 return true;
3746 }
3747 return false;
3748}
3749
3750/*********************************************************************
3751*********************************************************************/
3752bool
3753OSKext::declaresExecutable(void)
3754{
6d2010ae 3755 return (getPropertyForHostArch(kCFBundleExecutableKey) != NULL);
b0d623f7
A
3756}
3757
3758/*********************************************************************
3759*********************************************************************/
3760OSData *
3761OSKext::getExecutable(void)
3762{
3763 OSData * result = NULL;
3764 OSData * extractedExecutable = NULL; // must release
3765 OSData * mkextExecutableRef = NULL; // do not release
3766
3767 result = OSDynamicCast(OSData, infoDict->getObject(_kOSKextExecutableKey));
3768 if (result) {
3769 goto finish;
3770 }
3771
3772 mkextExecutableRef = OSDynamicCast(OSData,
3773 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey));
3774
3775 if (mkextExecutableRef) {
3776
3777 MkextEntryRef * mkextEntryRef = (MkextEntryRef *)
3778 mkextExecutableRef->getBytesNoCopy();
3779 uint32_t mkextVersion = MKEXT_GET_VERSION(mkextEntryRef->mkext);
3780 if (mkextVersion == MKEXT_VERS_2) {
3781 mkext2_file_entry * fileinfo =
3782 (mkext2_file_entry *)mkextEntryRef->fileinfo;
3783 uint32_t compressedSize = MKEXT2_GET_ENTRY_COMPSIZE(fileinfo);
3784 uint32_t fullSize = MKEXT2_GET_ENTRY_FULLSIZE(fileinfo);
3785 extractedExecutable = extractMkext2FileData(
3786 MKEXT2_GET_ENTRY_DATA(fileinfo), "executable",
3787 compressedSize, fullSize);
3788 } else if (mkextVersion == MKEXT_VERS_1) {
3789 extractedExecutable = extractMkext1Entry(
3790 mkextEntryRef->mkext, mkextEntryRef->fileinfo);
3791 } else {
3792 OSKextLog(this, kOSKextLogErrorLevel |
3793 kOSKextLogArchiveFlag,
3794 "Kext %s - unknown mkext version 0x%x for executable.",
3795 getIdentifierCString(), mkextVersion);
3796 }
3797
3798 /* Regardless of success, remove the mkext executable,
3799 * and drop one reference on the mkext. (setExecutable() does not
3800 * replace, it removes, or panics if asked to replace.)
3801 */
3802 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
3803 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
3804
3805 if (extractedExecutable && extractedExecutable->getLength()) {
3806 if (!setExecutable(extractedExecutable)) {
3807 goto finish;
3808 }
3809 result = extractedExecutable;
3810 } else {
3811 goto finish;
3812 }
3813 }
3814
3815finish:
3816
3817 OSSafeRelease(extractedExecutable);
3818
3819 return result;
3820}
3821
3822/*********************************************************************
3823*********************************************************************/
3824bool
3825OSKext::isInterface(void)
3826{
3827 return flags.interface;
3828}
3829
6d2010ae
A
3830/*********************************************************************
3831*********************************************************************/
3832bool
3833OSKext::isKernel(void)
3834{
3835 return (this == sKernelKext);
3836}
3837
b0d623f7
A
3838/*********************************************************************
3839*********************************************************************/
3840bool
3841OSKext::isKernelComponent(void)
3842{
3843 return flags.kernelComponent ? true : false;
3844}
3845
6d2010ae
A
3846/*********************************************************************
3847*********************************************************************/
3848bool
3849OSKext::isExecutable(void)
3850{
3851 return (!isKernel() && !isInterface() && declaresExecutable());
3852}
3853
b0d623f7
A
3854/*********************************************************************
3855* We might want to check this recursively for all dependencies,
3856* since a subtree of dependencies could get loaded before we hit
3857* a dependency that isn't safe-boot-loadable.
3858*
3859* xxx - Might want to return false if OSBundleEnableKextLogging or
3860* OSBundleDebugLevel
3861* or IOKitDebug is nonzero too (we used to do that, but I don't see
3862* the point except it's usually development drivers, which might
3863* cause panics on startup, that have those properties). Heh; could
3864* use a "kx" boot-arg!
3865*********************************************************************/
3866bool
3867OSKext::isLoadableInSafeBoot(void)
3868{
3869 bool result = false;
3870 OSString * required = NULL; // do not release
3871
6d2010ae
A
3872 if (isKernel()) {
3873 result = true;
3874 goto finish;
3875 }
b0d623f7
A
3876
3877 required = OSDynamicCast(OSString,
3878 getPropertyForHostArch(kOSBundleRequiredKey));
3879 if (!required) {
3880 goto finish;
3881 }
3882 if (required->isEqualTo(kOSBundleRequiredRoot) ||
3883 required->isEqualTo(kOSBundleRequiredLocalRoot) ||
3884 required->isEqualTo(kOSBundleRequiredNetworkRoot) ||
3885 required->isEqualTo(kOSBundleRequiredSafeBoot) ||
3886 required->isEqualTo(kOSBundleRequiredConsole)) {
3887
3888 result = true;
3889 }
3890
3891finish:
3892 return result;
3893}
3894
3895/*********************************************************************
3896*********************************************************************/
3897bool
3898OSKext::isPrelinked(void)
3899{
3900 return flags.prelinked ? true : false;
3901}
3902
3903/*********************************************************************
3904*********************************************************************/
3905bool OSKext::isLoaded(void)
3906{
3907 return flags.loaded ? true : false;
3908}
3909
3910/*********************************************************************
3911*********************************************************************/
3912bool
3913OSKext::isStarted(void)
3914{
3915 return flags.started ? true : false;
3916}
3917
3918/*********************************************************************
3919*********************************************************************/
3920bool
3921OSKext::isCPPInitialized(void)
3922{
3923 return flags.CPPInitialized;
3924}
3925
3926/*********************************************************************
3927*********************************************************************/
3928void
3929OSKext::setCPPInitialized(bool initialized)
3930{
3931 flags.CPPInitialized = initialized;
3932}
3933
3934/*********************************************************************
3935*********************************************************************/
3936uint32_t
3937OSKext::getLoadTag(void)
3938{
3939 return loadTag;
3940}
3941
6d2010ae
A
3942/*********************************************************************
3943 *********************************************************************/
3944void OSKext::getSizeInfo(uint32_t *loadSize, uint32_t *wiredSize)
3945{
316670eb
A
3946 if (linkedExecutable) {
3947 *loadSize = linkedExecutable->getLength();
6d2010ae 3948
316670eb
A
3949 /* If we have a kmod_info struct, calculated the wired size
3950 * from that. Otherwise it's the full load size.
3951 */
3952 if (kmod_info) {
3953 *wiredSize = *loadSize - kmod_info->hdr_size;
3954 } else {
3955 *wiredSize = *loadSize;
3956 }
3957 }
3958 else {
3959 *wiredSize = 0;
3960 *loadSize = 0;
3961 }
6d2010ae
A
3962}
3963
b0d623f7
A
3964/*********************************************************************
3965*********************************************************************/
3966OSData *
3967OSKext::copyUUID(void)
3968{
3969 OSData * result = NULL;
3970 OSData * theExecutable = NULL; // do not release
3971 const kernel_mach_header_t * header = NULL;
3972 const struct load_command * load_cmd = NULL;
3973 const struct uuid_command * uuid_cmd = NULL;
3974 uint32_t i;
3975
3976 /* An interface kext doesn't have a linked executable with an LC_UUID,
3977 * we create one when it's linked.
3978 */
3979 if (interfaceUUID) {
3980 result = interfaceUUID;
3981 result->retain();
3982 goto finish;
3983 }
3984
3985 /* For real kexts, try to get the UUID from the linked executable,
3986 * or if is hasn't been linked yet, the unrelocated executable.
3987 */
3988 theExecutable = linkedExecutable;
3989 if (!theExecutable) {
3990 theExecutable = getExecutable();
3991 }
3992 if (!theExecutable) {
3993 goto finish;
3994 }
3995
3996 header = (const kernel_mach_header_t *)theExecutable->getBytesNoCopy();
3997 load_cmd = (const struct load_command *)&header[1];
3998
3999 for (i = 0; i < header->ncmds; i++) {
4000 if (load_cmd->cmd == LC_UUID) {
4001 uuid_cmd = (struct uuid_command *)load_cmd;
4002 result = OSData::withBytes(uuid_cmd->uuid, sizeof(uuid_cmd->uuid));
4003 goto finish;
4004 }
4005 load_cmd = (struct load_command *)((caddr_t)load_cmd + load_cmd->cmdsize);
4006 }
4007
4008finish:
4009 return result;
4010}
4011
4012/*********************************************************************
4013*********************************************************************/
316670eb 4014
6d2010ae 4015#if defined (__i386__)
b0d623f7
A
4016#define ARCHNAME "i386"
4017#elif defined (__x86_64__)
4018#define ARCHNAME "x86_64"
4019#else
4020#error architecture not supported
4021#endif
4022
4023#define ARCH_SEPARATOR_CHAR '_'
4024
4025static char * makeHostArchKey(const char * key, uint32_t * keySizeOut)
4026{
4027 char * result = NULL;
4028 uint32_t keyLength = strlen(key);
4029 uint32_t keySize;
4030
4031 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
4032 */
4033 keySize = 1 + 1 + strlen(key) + strlen(ARCHNAME);
4034 result = (char *)kalloc(keySize);
4035 if (!result) {
4036 goto finish;
4037 }
4038 strlcpy(result, key, keySize);
4039 result[keyLength++] = ARCH_SEPARATOR_CHAR;
4040 result[keyLength] = '\0';
4041 strlcat(result, ARCHNAME, keySize);
4042 *keySizeOut = keySize;
4043
4044finish:
4045 return result;
4046}
4047
4048/*********************************************************************
4049*********************************************************************/
4050OSObject *
4051OSKext::getPropertyForHostArch(const char * key)
4052{
4053 OSObject * result = NULL; // do not release
4054 uint32_t hostArchKeySize = 0;
4055 char * hostArchKey = NULL; // must kfree
4056
4057 if (!key || !infoDict) {
4058 goto finish;
4059 }
4060
4061 /* Some properties are not allowed to be arch-variant:
4062 * - Any CFBundle... property.
4063 * - OSBundleIsInterface.
4064 * - OSKernelResource.
4065 */
4066 if (STRING_HAS_PREFIX(key, "OS") ||
4067 STRING_HAS_PREFIX(key, "IO")) {
4068
4069 hostArchKey = makeHostArchKey(key, &hostArchKeySize);
4070 if (!hostArchKey) {
4071 OSKextLog(/* kext (this isn't about a kext) */ NULL,
4072 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4073 "Allocation failure.");
4074 goto finish;
4075 }
4076 result = infoDict->getObject(hostArchKey);
4077 }
4078
4079 if (!result) {
4080 result = infoDict->getObject(key);
4081 }
4082
4083finish:
4084 if (hostArchKey) kfree(hostArchKey, hostArchKeySize);
4085 return result;
4086}
4087
4088#if PRAGMA_MARK
4089#pragma mark Load/Start/Stop/Unload
4090#endif
4091/*********************************************************************
4092*********************************************************************/
6d2010ae 4093/* static */
b0d623f7
A
4094OSReturn
4095OSKext::loadKextWithIdentifier(
4096 const char * kextIdentifierCString,
4097 Boolean allowDeferFlag,
4098 Boolean delayAutounloadFlag,
4099 OSKextExcludeLevel startOpt,
4100 OSKextExcludeLevel startMatchingOpt,
4101 OSArray * personalityNames)
4102{
4103 OSReturn result = kOSReturnError;
4104 OSString * kextIdentifier = NULL; // must release
4105
4106 kextIdentifier = OSString::withCString(kextIdentifierCString);
4107 if (!kextIdentifier) {
4108 result = kOSKextReturnNoMemory;
4109 goto finish;
4110 }
4111 result = OSKext::loadKextWithIdentifier(kextIdentifier,
4112 allowDeferFlag, delayAutounloadFlag,
4113 startOpt, startMatchingOpt, personalityNames);
4114
4115finish:
4116 OSSafeRelease(kextIdentifier);
4117 return result;
4118}
4119
b0d623f7
A
4120/*********************************************************************
4121*********************************************************************/
4122OSReturn
4123OSKext::loadKextWithIdentifier(
4124 OSString * kextIdentifier,
4125 Boolean allowDeferFlag,
4126 Boolean delayAutounloadFlag,
4127 OSKextExcludeLevel startOpt,
4128 OSKextExcludeLevel startMatchingOpt,
4129 OSArray * personalityNames)
4130{
4131 OSReturn result = kOSReturnError;
6d2010ae 4132 OSReturn pingResult = kOSReturnError;
b0d623f7
A
4133 OSKext * theKext = NULL; // do not release
4134 OSDictionary * loadRequest = NULL; // must release
4135 const OSSymbol * kextIdentifierSymbol = NULL; // must release
4136
4137 IORecursiveLockLock(sKextLock);
4138
4139 if (!kextIdentifier) {
4140 result = kOSKextReturnInvalidArgument;
4141 goto finish;
4142 }
4143
4144 OSKext::recordIdentifierRequest(kextIdentifier);
4145
4146 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
4147 if (!theKext) {
4148 if (!allowDeferFlag) {
4149 OSKextLog(/* kext */ NULL,
4150 kOSKextLogErrorLevel |
4151 kOSKextLogLoadFlag,
4152 "Can't load kext %s - not found.",
4153 kextIdentifier->getCStringNoCopy());
4154 goto finish;
4155 }
4156
4157 if (!sKernelRequestsEnabled) {
4158 OSKextLog(theKext,
4159 kOSKextLogErrorLevel |
4160 kOSKextLogLoadFlag,
4161 "Can't load kext %s - requests to user space are disabled.",
4162 kextIdentifier->getCStringNoCopy());
4163 result = kOSKextReturnDisabled;
4164 goto finish;
4165 }
4166
4167 /* Create a new request unless one is already sitting
4168 * in sKernelRequests for this bundle identifier
4169 */
4170 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
4171 if (!sPostedKextLoadIdentifiers->containsObject(kextIdentifierSymbol)) {
4172 result = _OSKextCreateRequest(kKextRequestPredicateRequestLoad,
4173 &loadRequest);
4174 if (result != kOSReturnSuccess) {
4175 goto finish;
4176 }
4177 if (!_OSKextSetRequestArgument(loadRequest,
4178 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
4179
4180 result = kOSKextReturnNoMemory;
4181 goto finish;
4182 }
4183 if (!sKernelRequests->setObject(loadRequest)) {
4184 result = kOSKextReturnNoMemory;
4185 goto finish;
4186 }
4187
4188 if (!sPostedKextLoadIdentifiers->setObject(kextIdentifierSymbol)) {
4189 result = kOSKextReturnNoMemory;
4190 goto finish;
4191 }
4192
4193 OSKextLog(theKext,
4194 kOSKextLogDebugLevel |
4195 kOSKextLogLoadFlag,
4196 "Kext %s not found; queued load request to user space.",
4197 kextIdentifier->getCStringNoCopy());
4198 }
4199
6d2010ae
A
4200 pingResult = OSKext::pingKextd();
4201 if (pingResult == kOSKextReturnDisabled) {
b0d623f7
A
4202 OSKextLog(/* kext */ NULL,
4203 ((sPrelinkBoot) ? kOSKextLogDebugLevel : kOSKextLogErrorLevel) |
4204 kOSKextLogLoadFlag,
6d2010ae 4205 "Kext %s might not load - kextd is currently unavailable.",
b0d623f7
A
4206 kextIdentifier->getCStringNoCopy());
4207 }
4208
4209 result = kOSKextReturnDeferred;
4210 goto finish;
4211 }
4212
4213 result = theKext->load(startOpt, startMatchingOpt, personalityNames);
4214
4215 if (result != kOSReturnSuccess) {
4216 OSKextLog(theKext,
4217 kOSKextLogErrorLevel |
4218 kOSKextLogLoadFlag,
4219 "Failed to load kext %s (error 0x%x).",
4220 kextIdentifier->getCStringNoCopy(), (int)result);
4221
4222 OSKext::removeKext(theKext,
4223 /* terminateService/removePersonalities */ true);
4224 goto finish;
4225 }
4226
4227 if (delayAutounloadFlag) {
4228 OSKextLog(theKext,
4229 kOSKextLogProgressLevel |
4230 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4231 "Setting delayed autounload for %s.",
4232 kextIdentifier->getCStringNoCopy());
4233 theKext->flags.delayAutounload = 1;
4234 }
4235
4236finish:
4237 OSSafeRelease(loadRequest);
4238 OSSafeRelease(kextIdentifierSymbol);
4239
4240 IORecursiveLockUnlock(sKextLock);
4241
4242 return result;
4243}
4244
4245/*********************************************************************
4246*********************************************************************/
4247/* static */
4248void
4249OSKext::recordIdentifierRequest(
4250 OSString * kextIdentifier)
4251{
4252 const OSSymbol * kextIdentifierSymbol = NULL; // must release
4253 bool fail = false;
4254
4255 if (!sAllKextLoadIdentifiers || !kextIdentifier) {
4256 goto finish;
4257 }
4258
4259 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
4260 if (!kextIdentifierSymbol) {
4261 // xxx - this is really a basic alloc failure
4262 fail = true;
4263 goto finish;
4264 }
4265
4266 if (!sAllKextLoadIdentifiers->containsObject(kextIdentifierSymbol)) {
4267 if (!sAllKextLoadIdentifiers->setObject(kextIdentifierSymbol)) {
4268 fail = true;
4269 } else {
4270 // xxx - need to find a way to associate this whole func w/the kext
4271 OSKextLog(/* kext */ NULL,
4272 // xxx - check level
4273 kOSKextLogStepLevel |
4274 kOSKextLogArchiveFlag,
4275 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
4276 kextIdentifier->getCStringNoCopy());
4277 }
4278 }
4279finish:
4280
4281 if (fail) {
4282 OSKextLog(/* kext */ NULL,
4283 kOSKextLogErrorLevel |
4284 kOSKextLogArchiveFlag,
4285 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
4286 kextIdentifier->getCStringNoCopy());
4287 }
4288 OSSafeRelease(kextIdentifierSymbol);
4289 return;
4290}
4291
4292/*********************************************************************
4293*********************************************************************/
4294OSReturn
4295OSKext::load(
4296 OSKextExcludeLevel startOpt,
4297 OSKextExcludeLevel startMatchingOpt,
4298 OSArray * personalityNames)
4299{
4300 OSReturn result = kOSReturnError;
4301 kern_return_t kxldResult;
4302 OSKextExcludeLevel dependenciesStartOpt = startOpt;
4303 OSKextExcludeLevel dependenciesStartMatchingOpt = startMatchingOpt;
4304 unsigned int i, count;
4305 Boolean alreadyLoaded = false;
4306 OSKext * lastLoadedKext = NULL;
4307
b0d623f7
A
4308 if (isLoaded()) {
4309 alreadyLoaded = true;
4310 result = kOSReturnSuccess;
4311
4312 OSKextLog(this,
4313 kOSKextLogDebugLevel |
4314 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4315 "Kext %s is already loaded.",
4316 getIdentifierCString());
4317 goto loaded;
4318 }
4319
b7266188
A
4320 if (!sLoadEnabled) {
4321 OSKextLog(this,
4322 kOSKextLogErrorLevel |
4323 kOSKextLogLoadFlag,
4324 "Kext loading is disabled (attempt to load kext %s).",
4325 getIdentifierCString());
4326 result = kOSKextReturnDisabled;
4327 goto finish;
4328 }
4329
b0d623f7
A
4330 /* If we've pushed the next available load tag to the invalid value,
4331 * we can't load any more kexts.
4332 */
4333 if (sNextLoadTag == kOSKextInvalidLoadTag) {
4334 OSKextLog(this,
4335 kOSKextLogErrorLevel |
4336 kOSKextLogLoadFlag,
4337 "Can't load kext %s - no more load tags to assign.",
4338 getIdentifierCString());
4339 result = kOSKextReturnNoResources;
4340 goto finish;
4341 }
4342
4343 /* This is a bit of a hack, because we shouldn't be handling
4344 * personalities within the load function.
4345 */
4346 if (!declaresExecutable()) {
4347 result = kOSReturnSuccess;
4348 goto loaded;
4349 }
4350
4351 /* Are we in safe boot?
4352 */
4353 if (sSafeBoot && !isLoadableInSafeBoot()) {
4354 OSKextLog(this,
4355 kOSKextLogErrorLevel |
4356 kOSKextLogLoadFlag,
4357 "Can't load kext %s - not loadable during safe boot.",
4358 getIdentifierCString());
4359 result = kOSKextReturnBootLevel;
4360 goto finish;
4361 }
4362
4363 OSKextLog(this,
4364 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
4365 "Loading kext %s.",
4366 getIdentifierCString());
4367
4368
4369 if (!sKxldContext) {
4370 kxldResult = kxld_create_context(&sKxldContext, &kern_allocate,
4371 &kxld_log_callback, /* Flags */ (KXLDFlags) 0,
4372 /* cputype */ 0, /* cpusubtype */ 0);
4373 if (kxldResult) {
4374 OSKextLog(this,
4375 kOSKextLogErrorLevel |
4376 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
4377 "Can't load kext %s - failed to create link context.",
4378 getIdentifierCString());
4379 result = kOSKextReturnNoMemory;
4380 goto finish;
4381 }
4382 }
4383
4384 /* We only need to resolve dependencies once for the whole graph, but
4385 * resolveDependencies will just return if there's no work to do, so it's
4386 * safe to call it more than once.
4387 */
4388 if (!resolveDependencies()) {
4389 // xxx - check resolveDependencies() for log msg
4390 OSKextLog(this,
4391 kOSKextLogErrorLevel |
4392 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4393 "Can't load kext %s - failed to resolve library dependencies.",
4394 getIdentifierCString());
4395 result = kOSKextReturnDependencies;
4396 goto finish;
4397 }
4398
4399 /* If we are excluding just the kext being loaded now (and not its
4400 * dependencies), drop the exclusion level to none so dependencies
4401 * start and/or add their personalities.
4402 */
4403 if (dependenciesStartOpt == kOSKextExcludeKext) {
4404 dependenciesStartOpt = kOSKextExcludeNone;
4405 }
4406
4407 if (dependenciesStartMatchingOpt == kOSKextExcludeKext) {
4408 dependenciesStartMatchingOpt = kOSKextExcludeNone;
4409 }
4410
4411 /* Load the dependencies, recursively.
4412 */
4413 count = getNumDependencies();
4414 for (i = 0; i < count; i++) {
4415 OSKext * dependency = OSDynamicCast(OSKext,
4416 dependencies->getObject(i));
4417 if (dependency == NULL) {
4418 OSKextLog(this,
4419 kOSKextLogErrorLevel |
4420 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4421 "Internal error loading kext %s; dependency disappeared.",
4422 getIdentifierCString());
4423 result = kOSKextReturnInternalError;
4424 goto finish;
4425 }
4426
4427 /* Dependencies must be started accorting to the opt,
4428 * but not given the personality names of the main kext.
4429 */
4430 result = dependency->load(dependenciesStartOpt,
4431 dependenciesStartMatchingOpt,
4432 /* personalityNames */ NULL);
4433 if (result != KERN_SUCCESS) {
4434 OSKextLog(this,
4435 kOSKextLogErrorLevel |
4436 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4437 "Dependency %s of kext %s failed to load.",
4438 dependency->getIdentifierCString(),
4439 getIdentifierCString());
4440
4441 OSKext::removeKext(dependency,
4442 /* terminateService/removePersonalities */ true);
4443 result = kOSKextReturnDependencyLoadError;
4444
4445 goto finish;
4446 }
4447 }
4448
4449 result = loadExecutable();
4450 if (result != KERN_SUCCESS) {
4451 goto finish;
4452 }
4453
4454 flags.loaded = true;
4455
4456 /* Add the kext to the list of loaded kexts and update the kmod_info
4457 * struct to point to that of the last loaded kext (which is the way
4458 * it's always been done, though I'd rather do them in order now).
4459 */
4460 lastLoadedKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
4461 sLoadedKexts->setObject(this);
4462
4463 /* Keep the kernel itself out of the kmod list.
4464 */
6d2010ae 4465 if (lastLoadedKext->isKernel()) {
b0d623f7
A
4466 lastLoadedKext = NULL;
4467 }
4468
4469 if (lastLoadedKext) {
4470 kmod_info->next = lastLoadedKext->kmod_info;
4471 }
4472
6d2010ae
A
4473 notifyKextLoadObservers(this, kmod_info);
4474
b0d623f7
A
4475 /* Make the global kmod list point at the just-loaded kext. Note that the
4476 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
4477 * although we do report it in kextstat these days by using the newer
4478 * OSArray of loaded kexts, which does contain it.
4479 *
4480 * (The OSKext object representing the kernel doesn't even have a kmod_info
4481 * struct, though I suppose we could stick a pointer to it from the
4482 * static struct in OSRuntime.cpp.)
4483 */
4484 kmod = kmod_info;
4485
4486 /* Save the list of loaded kexts in case we panic.
4487 */
b0d623f7
A
4488 OSKext::saveLoadedKextPanicList();
4489
6d2010ae
A
4490 if (isExecutable()) {
4491 OSKext::updateLoadedKextSummaries();
4492 savePanicString(/* isLoading */ true);
b7266188 4493
6d2010ae
A
4494#if CONFIG_DTRACE
4495 registerWithDTrace();
4496#else
4497 jettisonLinkeditSegment();
4498#endif /* CONFIG_DTRACE */
4499 }
4500
4501loaded:
4502 if (isExecutable() && !flags.started) {
4503 if (startOpt == kOSKextExcludeNone) {
4504 result = start();
4505 if (result != kOSReturnSuccess) {
4506 OSKextLog(this,
4507 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
4508 "Kext %s start failed (result 0x%x).",
4509 getIdentifierCString(), result);
4510 result = kOSKextReturnStartStopError;
4511 }
b0d623f7
A
4512 }
4513 }
4514
4515 /* If not excluding matching, send the personalities to the kernel.
4516 * This never affects the result of the load operation.
b7266188
A
4517 * This is a bit of a hack, because we shouldn't be handling
4518 * personalities within the load function.
b0d623f7
A
4519 */
4520 if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
b7266188 4521 result = sendPersonalitiesToCatalog(true, personalityNames);
b0d623f7 4522 }
6d2010ae 4523
b0d623f7 4524finish:
b7266188
A
4525
4526 /* More hack! If the kext doesn't declare an executable, even if we
4527 * "loaded" it, we have to remove any personalities naming it, or we'll
4528 * never see the registry go quiet. Errors here do not count for the
4529 * load operation itself.
4530 *
4531 * Note that in every other regard it's perfectly ok for a kext to
4532 * not declare an executable and serve only as a package for personalities
4533 * naming another kext, so we do have to allow such kexts to be "loaded"
4534 * so that those other personalities get added & matched.
4535 */
4536 if (!declaresExecutable()) {
4537 OSKextLog(this,
4538 kOSKextLogStepLevel | kOSKextLogLoadFlag,
4539 "Kext %s has no executable; removing any personalities naming it.",
4540 getIdentifierCString());
4541 removePersonalitiesFromCatalog();
4542 }
4543
b0d623f7
A
4544 if (result != kOSReturnSuccess) {
4545 OSKextLog(this,
4546 kOSKextLogErrorLevel |
4547 kOSKextLogLoadFlag,
4548 "Kext %s failed to load (0x%x).",
4549 getIdentifierCString(), (int)result);
4550 } else if (!alreadyLoaded) {
4551 OSKextLog(this,
4552 kOSKextLogProgressLevel |
4553 kOSKextLogLoadFlag,
4554 "Kext %s loaded.",
4555 getIdentifierCString());
6d2010ae
A
4556
4557 queueKextNotification(kKextRequestPredicateLoadNotification,
4558 OSDynamicCast(OSString, bundleID));
b0d623f7
A
4559 }
4560 return result;
4561}
4562
6d2010ae
A
4563/*********************************************************************
4564*
4565*********************************************************************/
4566static char * strdup(const char * string)
4567{
4568 char * result = NULL;
4569 size_t size;
4570
4571 if (!string) {
4572 goto finish;
4573 }
4574
4575 size = 1 + strlen(string);
4576 result = (char *)kalloc(size);
4577 if (!result) {
4578 goto finish;
4579 }
4580
4581 memcpy(result, string, size);
4582
4583finish:
4584 return result;
4585}
4586
316670eb
A
4587/*********************************************************************
4588*
4589*********************************************************************/
4590OSReturn
4591OSKext::slidePrelinkedExecutable()
4592{
4593 OSReturn result = kOSKextReturnBadData;
4594 kernel_mach_header_t * mh = NULL;
4595 kernel_segment_command_t * seg = NULL;
4596 kernel_segment_command_t * linkeditSeg = NULL;
4597 kernel_section_t * sec = NULL;
4598 char * linkeditBase = NULL;
4599 bool haveLinkeditBase = false;
4600 char * relocBase = NULL;
4601 bool haveRelocBase = false;
4602 struct dysymtab_command * dysymtab = NULL;
4603 struct symtab_command * symtab = NULL;
4604 kernel_nlist_t * sym = NULL;
4605 struct relocation_info * reloc = NULL;
4606 uint32_t i = 0;
4607 int reloc_size;
4608 vm_offset_t new_kextsize;
4609
4610 if (linkedExecutable == NULL || vm_kernel_slide == 0) {
4611 result = kOSReturnSuccess;
4612 goto finish;
4613 }
4614
4615 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
4616
4617 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
4618 seg->vmaddr += vm_kernel_slide;
4619
4620#if KASLR_KEXT_DEBUG
4621 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
4622 seg->segname,
4623 (unsigned long)VM_KERNEL_UNSLIDE(seg->vmaddr),
4624 (unsigned long)seg->vmaddr);
4625#endif
4626
4627 if (!haveRelocBase) {
4628 relocBase = (char *) seg->vmaddr;
4629 haveRelocBase = true;
4630 }
4631 if (!strcmp(seg->segname, "__LINKEDIT")) {
4632 linkeditBase = (char *) seg->vmaddr - seg->fileoff;
4633 haveLinkeditBase = true;
4634 linkeditSeg = seg;
4635 }
4636 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
4637 sec->addr += vm_kernel_slide;
4638
4639#if KASLR_KEXT_DEBUG
4640 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
4641 sec->sectname,
4642 (unsigned long)VM_KERNEL_UNSLIDE(sec->addr),
4643 (unsigned long)sec->addr);
4644#endif
4645 }
4646 }
4647
4648 dysymtab = (struct dysymtab_command *) getcommandfromheader(mh, LC_DYSYMTAB);
4649
4650 symtab = (struct symtab_command *) getcommandfromheader(mh, LC_SYMTAB);
4651
4652 if (symtab != NULL) {
4653 /* Some pseudo-kexts have symbol tables without segments.
4654 * Ignore them. */
4655 if (symtab->nsyms > 0 && haveLinkeditBase) {
4656 sym = (kernel_nlist_t *) (linkeditBase + symtab->symoff);
4657 for (i = 0; i < symtab->nsyms; i++) {
4658 if (sym[i].n_type & N_STAB) {
4659 continue;
4660 }
4661 sym[i].n_value += vm_kernel_slide;
4662
4663#if KASLR_KEXT_DEBUG
4664#define MAX_SYMS_TO_LOG 5
4665 if ( i < MAX_SYMS_TO_LOG ) {
4666 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
4667 (unsigned long)VM_KERNEL_UNSLIDE(sym[i].n_value),
4668 (unsigned long)sym[i].n_value);
4669 }
4670#endif
4671 }
4672 }
4673 }
4674
4675 if (dysymtab != NULL) {
4676 if (dysymtab->nextrel > 0) {
4677 OSKextLog(this,
4678 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
4679 kOSKextLogLinkFlag,
4680 "Sliding kext %s: External relocations found.",
4681 getIdentifierCString());
4682 goto finish;
4683 }
4684
4685 if (dysymtab->nlocrel > 0) {
4686 if (!haveLinkeditBase) {
4687 OSKextLog(this,
4688 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
4689 kOSKextLogLinkFlag,
4690 "Sliding kext %s: No linkedit segment.",
4691 getIdentifierCString());
4692 goto finish;
4693 }
4694
4695 if (!haveRelocBase) {
4696 OSKextLog(this,
4697 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
4698 kOSKextLogLinkFlag,
4699#if __x86_64__
4700 "Sliding kext %s: No writable segments.",
4701#else
4702 "Sliding kext %s: No segments.",
4703#endif
4704 getIdentifierCString());
4705 goto finish;
4706 }
4707
4708 reloc = (struct relocation_info *) (linkeditBase + dysymtab->locreloff);
4709 reloc_size = dysymtab->nlocrel * sizeof(struct relocation_info);
4710
4711 for (i = 0; i < dysymtab->nlocrel; i++) {
4712 if ( reloc[i].r_extern != 0
4713 || reloc[i].r_type != 0
4714 || reloc[i].r_length != (sizeof(void *) == 8 ? 3 : 2)
4715#if __i386__
4716 || (reloc[i].r_address & R_SCATTERED)
4717#endif
4718 ) {
4719 OSKextLog(this,
4720 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
4721 kOSKextLogLinkFlag,
4722 "Sliding kext %s: Unexpected relocation found.",
4723 getIdentifierCString());
4724 goto finish;
4725 }
4726 if (reloc[i].r_pcrel != 0) {
4727 continue;
4728 }
4729 *((uintptr_t *)(relocBase + reloc[i].r_address)) += vm_kernel_slide;
4730
4731#if KASLR_KEXT_DEBUG
4732#define MAX_DYSYMS_TO_LOG 5
4733 if ( i < MAX_DYSYMS_TO_LOG ) {
4734 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
4735 (unsigned long)VM_KERNEL_UNSLIDE(*((uintptr_t *)(relocBase + reloc[i].r_address))),
4736 (unsigned long)*((uintptr_t *)(relocBase + reloc[i].r_address)));
4737 }
4738#endif
4739 }
4740
4741 /* We should free these relocations, not just delete the reference to them.
4742 * <rdar://problem/10535549> Free relocations from PIE kexts.
4743 */
4744 new_kextsize = round_page(kmod_info->size - reloc_size);
4745
4746 if ((kmod_info->size - new_kextsize) > PAGE_SIZE) {
4747 vm_offset_t endofkext = kmod_info->address + kmod_info->size;
4748 vm_offset_t new_endofkext = kmod_info->address + new_kextsize;
4749 vm_offset_t endofrelocInfo = (vm_offset_t) (((uint8_t *)reloc) + reloc_size);
4750 int bytes_remaining = endofkext - endofrelocInfo;
4751 OSData * new_osdata = NULL;
4752
4753 /* fix up symbol offsets if they are after the dsymtab local relocs */
4754 if (symtab) {
4755 if (dysymtab->locreloff < symtab->symoff){
4756 symtab->symoff -= reloc_size;
4757 }
4758 if (dysymtab->locreloff < symtab->stroff) {
4759 symtab->stroff -= reloc_size;
4760 }
4761 }
4762 if (dysymtab->locreloff < dysymtab->extreloff) {
4763 dysymtab->extreloff -= reloc_size;
4764 }
4765
4766 /* move data behind reloc info down to new offset */
4767 if (endofrelocInfo < endofkext) {
4768 memcpy(reloc, (void *)endofrelocInfo, bytes_remaining);
4769 }
4770
4771 /* Create a new OSData for the smaller kext object and reflect
4772 * new linkedit segment size.
4773 */
4774 linkeditSeg->vmsize = round_page(linkeditSeg->vmsize - reloc_size);
4775 linkeditSeg->filesize = linkeditSeg->vmsize;
4776
4777 new_osdata = OSData::withBytesNoCopy((void *)kmod_info->address, new_kextsize);
4778 if (new_osdata) {
4779 /* Fix up kmod info and linkedExecutable.
4780 */
4781 kmod_info->size = new_kextsize;
4782 linkedExecutable->setDeallocFunction(NULL);
4783 linkedExecutable->release();
4784 linkedExecutable = new_osdata;
4785
4786#if VM_MAPPED_KEXTS
4787 kext_free(new_endofkext, (endofkext - new_endofkext));
4788#else
4789 ml_static_mfree(new_endofkext, (endofkext - new_endofkext));
4790#endif
4791 }
4792 }
4793 dysymtab->nlocrel = 0;
4794 dysymtab->locreloff = 0;
4795 }
4796 }
4797
4798 result = kOSReturnSuccess;
4799finish:
4800 return result;
4801}
4802
b0d623f7
A
4803/*********************************************************************
4804* called only by load()
4805*********************************************************************/
4806OSReturn
4807OSKext::loadExecutable()
4808{
4809 OSReturn result = kOSReturnError;
4810 kern_return_t kxldResult;
6d2010ae 4811 KXLDDependency * kxlddeps = NULL; // must kfree
b0d623f7 4812 uint32_t num_kxlddeps = 0;
6d2010ae
A
4813 OSArray * linkDependencies = NULL; // must release
4814 uint32_t numDirectDependencies = 0;
b0d623f7 4815 uint32_t num_kmod_refs = 0;
b0d623f7
A
4816 struct mach_header ** kxldHeaderPtr = NULL; // do not free
4817 struct mach_header * kxld_header = NULL; // xxx - need to free here?
4818 OSData * theExecutable = NULL; // do not release
4819 OSString * versString = NULL; // do not release
4820 const char * versCString = NULL; // do not free
4821 const char * string = NULL; // do not free
4822 unsigned int i;
4823
4824 /* We need the version string for a variety of bits below.
4825 */
4826 versString = OSDynamicCast(OSString,
4827 getPropertyForHostArch(kCFBundleVersionKey));
4828 if (!versString) {
4829 goto finish;
4830 }
4831 versCString = versString->getCStringNoCopy();
4832
4833 if (isKernelComponent()) {
4834 if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
6d2010ae 4835
b0d623f7
A
4836 if (strncmp(versCString, KERNEL6_VERSION, strlen(KERNEL6_VERSION))) {
4837 OSKextLog(this,
4838 kOSKextLogErrorLevel |
4839 kOSKextLogLoadFlag,
4840 "Kernel component %s has incorrect version %s; "
4841 "expected %s.",
4842 getIdentifierCString(),
4843 versCString, KERNEL6_VERSION);
4844 result = kOSKextReturnInternalError;
4845 goto finish;
4846 } else if (strcmp(versCString, osrelease)) {
4847 OSKextLog(this,
4848 kOSKextLogErrorLevel |
4849 kOSKextLogLoadFlag,
4850 "Kernel component %s has incorrect version %s; "
4851 "expected %s.",
4852 getIdentifierCString(),
4853 versCString, osrelease);
4854 result = kOSKextReturnInternalError;
4855 goto finish;
4856 }
4857 }
4858 }
4859
4860 if (isPrelinked()) {
316670eb
A
4861 result = slidePrelinkedExecutable();
4862 if (result != kOSReturnSuccess) {
4863 goto finish;
4864 }
b0d623f7
A
4865 goto register_kmod;
4866 }
4867
4868 theExecutable = getExecutable();
4869 if (!theExecutable) {
4870 if (declaresExecutable()) {
4871 OSKextLog(this,
4872 kOSKextLogErrorLevel |
4873 kOSKextLogLoadFlag,
4874 "Can't load kext %s - executable is missing.",
4875 getIdentifierCString());
4876 result = kOSKextReturnValidation;
4877 goto finish;
4878 }
4879 goto register_kmod;
4880 }
4881
6d2010ae
A
4882 if (isInterface()) {
4883 OSData *executableCopy = OSData::withData(theExecutable);
4884 setLinkedExecutable(executableCopy);
4885 executableCopy->release();
4886 goto register_kmod;
b0d623f7 4887 }
6d2010ae
A
4888
4889 numDirectDependencies = getNumDependencies();
4890
4891 if (flags.hasBleedthrough) {
4892 linkDependencies = dependencies;
4893 linkDependencies->retain();
4894 } else {
4895 linkDependencies = OSArray::withArray(dependencies);
4896 if (!linkDependencies) {
4897 OSKextLog(this,
4898 kOSKextLogErrorLevel |
4899 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
4900 "Can't allocate link dependencies to load kext %s.",
4901 getIdentifierCString());
4902 goto finish;
4903 }
4904
4905 for (i = 0; i < numDirectDependencies; ++i) {
4906 OSKext * dependencyKext = OSDynamicCast(OSKext,
4907 dependencies->getObject(i));
4908 dependencyKext->addBleedthroughDependencies(linkDependencies);
4909 }
4910 }
4911
4912 num_kxlddeps = linkDependencies->getCount();
b0d623f7
A
4913 if (!num_kxlddeps) {
4914 OSKextLog(this,
4915 kOSKextLogErrorLevel |
4916 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4917 "Can't load kext %s - it has no library dependencies.",
4918 getIdentifierCString());
4919 goto finish;
4920 }
6d2010ae
A
4921
4922 kxlddeps = (KXLDDependency *)kalloc(num_kxlddeps * sizeof(*kxlddeps));
b0d623f7
A
4923 if (!kxlddeps) {
4924 OSKextLog(this,
4925 kOSKextLogErrorLevel |
4926 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
4927 "Can't allocate link context to load kext %s.",
4928 getIdentifierCString());
4929 goto finish;
4930 }
6d2010ae
A
4931 bzero(kxlddeps, num_kxlddeps * sizeof(*kxlddeps));
4932
4933 for (i = 0; i < num_kxlddeps; ++i ) {
4934 OSKext * dependency = OSDynamicCast(OSKext, linkDependencies->getObject(i));
4935
4936 if (dependency->isInterface()) {
4937 OSKext *interfaceTargetKext = NULL;
4938 OSData * interfaceTarget = NULL;
4939
4940 if (dependency->isKernelComponent()) {
4941 interfaceTargetKext = sKernelKext;
4942 interfaceTarget = sKernelKext->linkedExecutable;
4943 } else {
4944 interfaceTargetKext = OSDynamicCast(OSKext,
4945 dependency->dependencies->getObject(0));
4946
4947 interfaceTarget = interfaceTargetKext->linkedExecutable;
4948 }
4949
4950 if (!interfaceTarget) {
4951 // panic?
4952 goto finish;
4953 }
4954
4955 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
4956 * it will be useful to have them in the debugger.
4957 * strdup() failing isn't critical right here so we don't check that.
4958 */
4959 kxlddeps[i].kext = (u_char *) interfaceTarget->getBytesNoCopy();
4960 kxlddeps[i].kext_size = interfaceTarget->getLength();
4961 kxlddeps[i].kext_name = strdup(interfaceTargetKext->getIdentifierCString());
4962
4963 kxlddeps[i].interface = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
4964 kxlddeps[i].interface_size = dependency->linkedExecutable->getLength();
4965 kxlddeps[i].interface_name = strdup(dependency->getIdentifierCString());
4966 } else {
4967 kxlddeps[i].kext = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
4968 kxlddeps[i].kext_size = dependency->linkedExecutable->getLength();
4969 kxlddeps[i].kext_name = strdup(dependency->getIdentifierCString());
b0d623f7 4970 }
b0d623f7 4971
6d2010ae 4972 kxlddeps[i].is_direct_dependency = (i < numDirectDependencies);
b0d623f7
A
4973 }
4974
6d2010ae 4975 kxldHeaderPtr = &kxld_header;
b0d623f7
A
4976
4977#if DEBUG
4978 OSKextLog(this,
4979 kOSKextLogExplicitLevel |
4980 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
4981 "Kext %s - calling kxld_link_file:\n"
4982 " kxld_context: %p\n"
4983 " executable: %p executable_length: %d\n"
4984 " user_data: %p\n"
4985 " kxld_dependencies: %p num_dependencies: %d\n"
6d2010ae
A
4986 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
4987 getIdentifierCString(), sKxldContext,
b0d623f7
A
4988 theExecutable->getBytesNoCopy(), theExecutable->getLength(),
4989 this, kxlddeps, num_kxlddeps,
6d2010ae 4990 kxldHeaderPtr, &kmod_info);
b0d623f7
A
4991#endif
4992
4993 /* After this call, the linkedExecutable instance variable
4994 * should exist.
4995 */
4996 kxldResult = kxld_link_file(sKxldContext,
4997 (u_char *)theExecutable->getBytesNoCopy(),
4998 theExecutable->getLength(),
4999 getIdentifierCString(), this, kxlddeps, num_kxlddeps,
6d2010ae 5000 (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info);
b0d623f7
A
5001
5002 if (kxldResult != KERN_SUCCESS) {
5003 // xxx - add kxldResult here?
5004 OSKextLog(this,
5005 kOSKextLogErrorLevel |
5006 kOSKextLogLoadFlag,
5007 "Can't load kext %s - link failed.",
5008 getIdentifierCString());
5009 result = kOSKextReturnLinkError;
5010 goto finish;
5011 }
b0d623f7 5012
6d2010ae
A
5013 /* We've written data & instructions into kernel memory, so flush the data
5014 * cache and invalidate the instruction cache.
5015 * I/D caches are coherent on x86
b0d623f7 5016 */
316670eb 5017#if !defined(__i386__) && !defined(__x86_64__)
6d2010ae
A
5018 flush_dcache(kmod_info->address, kmod_info->size, false);
5019 invalidate_icache(kmod_info->address, kmod_info->size, false);
5020#endif
b0d623f7
A
5021register_kmod:
5022
5023 if (isInterface()) {
5024
5025 /* Whip up a fake kmod_info entry for the interface kext.
5026 */
5027 kmod_info = (kmod_info_t *)kalloc(sizeof(kmod_info_t));
5028 if (!kmod_info) {
5029 result = KERN_MEMORY_ERROR;
5030 goto finish;
5031 }
5032
5033 /* A pseudokext has almost nothing in its kmod_info struct.
5034 */
5035 bzero(kmod_info, sizeof(kmod_info_t));
5036
5037 kmod_info->info_version = KMOD_INFO_VERSION;
5038
5039 /* An interface kext doesn't have a linkedExecutable, so save a
5040 * copy of the UUID out of the original executable via copyUUID()
5041 * while we still have the original executable.
5042 */
5043 interfaceUUID = copyUUID();
5044 }
5045
5046 kmod_info->id = loadTag = sNextLoadTag++;
5047 kmod_info->reference_count = 0; // KMOD_DECL... sets it to -1 (invalid).
5048
5049 /* Stamp the bundle ID and version from the OSKext over anything
5050 * resident inside the kmod_info.
5051 */
5052 string = getIdentifierCString();
5053 strlcpy(kmod_info->name, string, sizeof(kmod_info->name));
5054
5055 string = versCString;
5056 strlcpy(kmod_info->version, string, sizeof(kmod_info->version));
5057
5058 /* Add the dependencies' kmod_info structs as kmod_references.
5059 */
5060 num_kmod_refs = getNumDependencies();
5061 if (num_kmod_refs) {
5062 kmod_info->reference_list = (kmod_reference_t *)kalloc(
5063 num_kmod_refs * sizeof(kmod_reference_t));
5064 if (!kmod_info->reference_list) {
5065 result = KERN_MEMORY_ERROR;
5066 goto finish;
5067 }
5068 bzero(kmod_info->reference_list,
5069 num_kmod_refs * sizeof(kmod_reference_t));
5070 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
5071 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
5072 OSKext * refKext = OSDynamicCast(OSKext, dependencies->getObject(refIndex));
5073 ref->info = refKext->kmod_info;
5074 ref->info->reference_count++;
5075
5076 if (refIndex + 1 < num_kmod_refs) {
5077 ref->next = kmod_info->reference_list + refIndex + 1;
5078 }
5079 }
5080 }
5081
5082 if (!isInterface() && linkedExecutable) {
5083 OSKextLog(this,
5084 kOSKextLogProgressLevel |
5085 kOSKextLogLoadFlag,
5086 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
5087 kmod_info->name,
5088 (unsigned)kmod_info->size / PAGE_SIZE,
316670eb 5089 (unsigned long)VM_KERNEL_UNSLIDE(kmod_info->address),
b0d623f7
A
5090 (unsigned)kmod_info->id);
5091 }
5092
5093 result = setVMProtections();
5094 if (result != KERN_SUCCESS) {
5095 goto finish;
5096 }
5097
5098 result = kOSReturnSuccess;
5099
5100finish:
6d2010ae
A
5101 OSSafeRelease(linkDependencies);
5102
5103 /* Clear up locally allocated dependency info.
5104 */
5105 for (i = 0; i < num_kxlddeps; ++i ) {
5106 size_t size;
5107
5108 if (kxlddeps[i].kext_name) {
5109 size = 1 + strlen(kxlddeps[i].kext_name);
5110 kfree(kxlddeps[i].kext_name, size);
5111 }
5112 if (kxlddeps[i].interface_name) {
5113 size = 1 + strlen(kxlddeps[i].interface_name);
5114 kfree(kxlddeps[i].interface_name, size);
5115 }
5116 }
5117 if (kxlddeps) kfree(kxlddeps, (num_kxlddeps * sizeof(*kxlddeps)));
b0d623f7
A
5118
5119 /* We no longer need the unrelocated executable (which the linker
5120 * has altered anyhow).
5121 */
5122 setExecutable(NULL);
5123
5124 if (result != kOSReturnSuccess) {
5125 OSKextLog(this,
5126 kOSKextLogErrorLevel |
5127 kOSKextLogLoadFlag,
5128 "Failed to load executable for kext %s.",
5129 getIdentifierCString());
5130
5131 if (kmod_info && kmod_info->reference_list) {
5132 kfree(kmod_info->reference_list,
5133 num_kmod_refs * sizeof(kmod_reference_t));
5134 }
5135 if (isInterface()) {
5136 kfree(kmod_info, sizeof(kmod_info_t));
5137 }
5138 kmod_info = NULL;
5139 if (linkedExecutable) {
5140 linkedExecutable->release();
5141 linkedExecutable = NULL;
5142 }
5143 }
5144
5145 return result;
5146}
5147
5148/*********************************************************************
6d2010ae
A
5149* The linkedit segment is used by the kext linker for dependency
5150* resolution, and by dtrace for probe initialization. We can free it
5151* for non-library kexts, since no kexts depend on non-library kexts
5152* by definition, once dtrace has been initialized.
5153*********************************************************************/
5154void
5155OSKext::jettisonLinkeditSegment(void)
5156{
5157 kernel_mach_header_t * machhdr = (kernel_mach_header_t *)kmod_info->address;
5158 kernel_segment_command_t * linkedit = NULL;
316670eb 5159 vm_offset_t start;
6d2010ae
A
5160 vm_size_t linkeditsize, kextsize;
5161 OSData * data = NULL;
316670eb
A
5162
5163#if NO_KEXTD
5164 /* We can free symbol tables for all embedded kexts because we don't
5165 * support runtime kext linking.
5166 */
5167 if (sKeepSymbols || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
5168#else
5169 if (sKeepSymbols || isLibrary() || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
5170#endif
6d2010ae
A
5171 goto finish;
5172 }
5173
5174 /* Find the linkedit segment. If it's not the last segment, then freeing
5175 * it will fragment the kext into multiple VM regions, which OSKext is not
5176 * designed to handle, so we'll have to skip it.
5177 */
5178 linkedit = getsegbynamefromheader(machhdr, SEG_LINKEDIT);
5179 if (!linkedit) {
5180 goto finish;
5181 }
5182
5183 if (round_page(kmod_info->address + kmod_info->size) !=
5184 round_page(linkedit->vmaddr + linkedit->vmsize))
5185 {
5186 goto finish;
5187 }
5188
5189 /* Create a new OSData for the smaller kext object.
5190 */
5191 linkeditsize = round_page(linkedit->vmsize);
5192 kextsize = kmod_info->size - linkeditsize;
316670eb
A
5193 start = linkedit->vmaddr;
5194
6d2010ae
A
5195 data = OSData::withBytesNoCopy((void *)kmod_info->address, kextsize);
5196 if (!data) {
5197 goto finish;
5198 }
6d2010ae
A
5199
5200 /* Fix the kmod info and linkedExecutable.
5201 */
5202 kmod_info->size = kextsize;
5203 linkedExecutable->setDeallocFunction(NULL);
5204 linkedExecutable->release();
5205 linkedExecutable = data;
316670eb
A
5206 flags.jettisonLinkeditSeg = 1;
5207
6d2010ae
A
5208 /* Free the linkedit segment.
5209 */
316670eb
A
5210#if VM_MAPPED_KEXTS
5211 kext_free(start, linkeditsize);
5212#else
5213 ml_static_mfree(start, linkeditsize);
5214#endif
6d2010ae
A
5215
5216finish:
5217 return;
5218}
5219
6d2010ae 5220/*********************************************************************
b0d623f7
A
5221*********************************************************************/
5222void
5223OSKext::setLinkedExecutable(OSData * anExecutable)
5224{
5225 if (linkedExecutable) {
5226 panic("Attempt to set linked executable on kext "
5227 "that already has one (%s).\n",
5228 getIdentifierCString());
5229 }
5230 linkedExecutable = anExecutable;
5231 linkedExecutable->retain();
5232 return;
5233}
5234
6d2010ae
A
5235#if CONFIG_DTRACE
5236/*********************************************************************
5237* Go through all loaded kexts and tell them to register with dtrace.
5238* The instance method only registers if necessary.
5239*********************************************************************/
5240/* static */
5241void
5242OSKext::registerKextsWithDTrace(void)
5243{
5244 uint32_t count = sLoadedKexts->getCount();
5245 uint32_t i;
5246
5247 IORecursiveLockLock(sKextLock);
5248
5249 for (i = 0; i < count; i++) {
5250 OSKext * thisKext = NULL; // do not release
5251
5252 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
5253 if (!thisKext || !thisKext->isExecutable()) {
5254 continue;
5255 }
5256
5257 thisKext->registerWithDTrace();
5258 }
5259
5260 IORecursiveLockUnlock(sKextLock);
5261
5262 return;
5263}
5264
5265extern "C" {
316670eb 5266 extern int (*dtrace_modload)(struct kmod_info *, uint32_t);
6d2010ae
A
5267 extern int (*dtrace_modunload)(struct kmod_info *);
5268};
5269
5270/*********************************************************************
5271*********************************************************************/
5272void
5273OSKext::registerWithDTrace(void)
5274{
5275 /* Register kext with dtrace. A dtrace_modload failure should not
5276 * prevent a kext from loading, so we ignore the return code.
5277 */
5278 if (!flags.dtraceInitialized && (dtrace_modload != NULL)) {
316670eb
A
5279 uint32_t modflag = 0;
5280 OSObject * forceInit = getPropertyForHostArch("OSBundleForceDTraceInit");
5281 if (forceInit == kOSBooleanTrue) {
5282 modflag |= KMOD_DTRACE_FORCE_INIT;
5283 }
5284
5285 (void)(*dtrace_modload)(kmod_info, modflag);
6d2010ae
A
5286 flags.dtraceInitialized = true;
5287 jettisonLinkeditSegment();
5288 }
5289 return;
5290}
5291/*********************************************************************
5292*********************************************************************/
5293void
5294OSKext::unregisterWithDTrace(void)
5295{
5296 /* Unregister kext with dtrace. A dtrace_modunload failure should not
5297 * prevent a kext from loading, so we ignore the return code.
5298 */
5299 if (flags.dtraceInitialized && (dtrace_modunload != NULL)) {
5300 (void)(*dtrace_modunload)(kmod_info);
5301 flags.dtraceInitialized = false;
5302 }
5303 return;
5304}
5305#endif /* CONFIG_DTRACE */
5306
5307
b0d623f7
A
5308/*********************************************************************
5309* called only by loadExecutable()
5310*********************************************************************/
316670eb
A
5311#if !VM_MAPPED_KEXTS
5312#error Unrecognized architecture
5313#else
5314static inline kern_return_t
5315OSKext_protect(
5316 vm_map_t map,
5317 vm_map_offset_t start,
5318 vm_map_offset_t end,
5319 vm_prot_t new_prot,
5320 boolean_t set_max)
5321{
5322 if (start == end) { // 10538581
5323 return(KERN_SUCCESS);
5324 }
5325 return vm_map_protect(map, start, end, new_prot, set_max);
5326}
5327
5328static inline kern_return_t
5329OSKext_wire(
5330 vm_map_t map,
5331 vm_map_offset_t start,
5332 vm_map_offset_t end,
5333 vm_prot_t access_type,
5334 boolean_t user_wire)
5335{
5336 return vm_map_wire(map, start, end, access_type, user_wire);
5337}
5338#endif
5339
b0d623f7
A
5340OSReturn
5341OSKext::setVMProtections(void)
5342{
5343 vm_map_t kext_map = NULL;
5344 kernel_segment_command_t * seg = NULL;
5345 vm_map_offset_t start = 0;
5346 vm_map_offset_t end = 0;
5347 OSReturn result = kOSReturnError;
5348
5349 if (!kmod_info->address && !kmod_info->size) {
5350 result = kOSReturnSuccess;
5351 goto finish;
5352 }
5353
5354 /* Get the kext's vm map */
5355 kext_map = kext_get_vm_map(kmod_info);
5356 if (!kext_map) {
5357 result = KERN_MEMORY_ERROR;
5358 goto finish;
5359 }
5360
b0d623f7 5361 /* Protect the headers as read-only; they do not need to be wired */
316670eb 5362 result = OSKext_protect(kext_map, kmod_info->address,
b0d623f7
A
5363 kmod_info->address + kmod_info->hdr_size, VM_PROT_READ, TRUE);
5364 if (result != KERN_SUCCESS) {
5365 goto finish;
5366 }
5367
5368 /* Set the VM protections and wire down each of the segments */
5369 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
5370 while (seg) {
5371 start = round_page(seg->vmaddr);
5372 end = trunc_page(seg->vmaddr + seg->vmsize);
5373
316670eb 5374 result = OSKext_protect(kext_map, start, end, seg->maxprot, TRUE);
b0d623f7
A
5375 if (result != KERN_SUCCESS) {
5376 OSKextLog(this,
5377 kOSKextLogErrorLevel |
5378 kOSKextLogLoadFlag,
5379 "Kext %s failed to set maximum VM protections "
5380 "for segment %s - 0x%x.",
5381 getIdentifierCString(), seg->segname, (int)result);
5382 goto finish;
5383 }
5384
316670eb 5385 result = OSKext_protect(kext_map, start, end, seg->initprot, FALSE);
b0d623f7
A
5386 if (result != KERN_SUCCESS) {
5387 OSKextLog(this,
5388 kOSKextLogErrorLevel |
5389 kOSKextLogLoadFlag,
5390 "Kext %s failed to set initial VM protections "
5391 "for segment %s - 0x%x.",
5392 getIdentifierCString(), seg->segname, (int)result);
5393 goto finish;
5394 }
5395
6d2010ae 5396 if (segmentShouldBeWired(seg)) {
316670eb 5397 result = OSKext_wire(kext_map, start, end, seg->initprot, FALSE);
6d2010ae
A
5398 if (result != KERN_SUCCESS) {
5399 goto finish;
5400 }
b0d623f7
A
5401 }
5402
5403 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
5404 }
5405
5406finish:
5407 return result;
5408}
5409
6d2010ae
A
5410/*********************************************************************
5411*********************************************************************/
5412boolean_t
5413OSKext::segmentShouldBeWired(kernel_segment_command_t *seg)
5414{
5415 return (sKeepSymbols || strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)));
5416}
5417
b0d623f7
A
5418/*********************************************************************
5419*********************************************************************/
5420OSReturn
5421OSKext::validateKextMapping(bool startFlag)
5422{
5423 OSReturn result = kOSReturnError;
5424 const char * whichOp = startFlag ? "start" : "stop";
5425 kern_return_t kern_result = 0;
5426 vm_map_t kext_map = NULL;
6d2010ae 5427 kernel_segment_command_t * seg = NULL;
b0d623f7
A
5428 mach_vm_address_t address = 0;
5429 mach_vm_size_t size = 0;
5430 uint32_t depth = 0;
5431 mach_msg_type_number_t count;
5432 vm_region_submap_short_info_data_64_t info;
5433
5434 count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
5435 bzero(&info, sizeof(info));
5436
5437 // xxx - do we need a distinct OSReturn value for these or is "bad data"
5438 // xxx - sufficient?
5439
5440 /* Verify that the kmod_info and start/stop pointers are non-NULL.
5441 */
5442 if (!kmod_info) {
5443 OSKextLog(this,
5444 kOSKextLogErrorLevel |
5445 kOSKextLogLoadFlag,
5446 "Kext %s - NULL kmod_info pointer.",
5447 getIdentifierCString());
5448 result = kOSKextReturnBadData;
5449 goto finish;
5450 }
5451
5452 if (startFlag) {
5453 address = (mach_vm_address_t)kmod_info->start;
5454 } else {
5455 address = (mach_vm_address_t)kmod_info->stop;
5456 }
5457
5458 if (!address) {
5459 OSKextLog(this,
5460 kOSKextLogErrorLevel |
5461 kOSKextLogLoadFlag,
5462 "Kext %s - NULL module %s pointer.",
5463 getIdentifierCString(), whichOp);
5464 result = kOSKextReturnBadData;
5465 goto finish;
5466 }
5467
5468 kext_map = kext_get_vm_map(kmod_info);
5469 depth = (kernel_map == kext_map) ? 1 : 2;
5470
5471 /* Verify that the start/stop function lies within the kext's address range.
5472 */
5473 if (address < kmod_info->address + kmod_info->hdr_size ||
5474 kmod_info->address + kmod_info->size <= address)
5475 {
5476 OSKextLog(this,
5477 kOSKextLogErrorLevel |
5478 kOSKextLogLoadFlag,
5479 "Kext %s module %s pointer is outside of kext range "
5480 "(%s %p - kext at %p-%p)..",
5481 getIdentifierCString(),
5482 whichOp,
5483 whichOp,
316670eb
A
5484 (void *)VM_KERNEL_UNSLIDE(address),
5485 (void *)VM_KERNEL_UNSLIDE(kmod_info->address),
5486 (void *)(VM_KERNEL_UNSLIDE(kmod_info->address) + kmod_info->size));
b0d623f7
A
5487 result = kOSKextReturnBadData;
5488 goto finish;
5489 }
5490
5491 /* Only do these checks before calling the start function;
5492 * If anything goes wrong with the mapping while the kext is running,
5493 * we'll likely have panicked well before any attempt to stop the kext.
5494 */
5495 if (startFlag) {
5496
5497 /* Verify that the start/stop function is executable.
5498 */
5499 kern_result = mach_vm_region_recurse(kernel_map, &address, &size, &depth,
5500 (vm_region_recurse_info_t)&info, &count);
5501 if (kern_result != KERN_SUCCESS) {
5502 OSKextLog(this,
5503 kOSKextLogErrorLevel |
5504 kOSKextLogLoadFlag,
5505 "Kext %s - bad %s pointer %p.",
5506 getIdentifierCString(),
316670eb 5507 whichOp, (void *)VM_KERNEL_UNSLIDE(address));
b0d623f7
A
5508 result = kOSKextReturnBadData;
5509 goto finish;
5510 }
5511
316670eb 5512#if VM_MAPPED_KEXTS
b0d623f7
A
5513 if (!(info.protection & VM_PROT_EXECUTE)) {
5514 OSKextLog(this,
5515 kOSKextLogErrorLevel |
5516 kOSKextLogLoadFlag,
5517 "Kext %s - memory region containing module %s function "
5518 "is not executable.",
5519 getIdentifierCString(), whichOp);
5520 result = kOSKextReturnBadData;
5521 goto finish;
5522 }
316670eb 5523#endif
b0d623f7 5524
6d2010ae 5525 /* Verify that the kext's segments are backed by physical memory.
b0d623f7 5526 */
6d2010ae
A
5527 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
5528 while (seg) {
5529 if (!verifySegmentMapping(seg)) {
b0d623f7
A
5530 result = kOSKextReturnBadData;
5531 goto finish;
5532 }
6d2010ae
A
5533
5534 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
b0d623f7 5535 }
6d2010ae 5536
b0d623f7
A
5537 }
5538
5539 result = kOSReturnSuccess;
5540finish:
5541 return result;
5542}
5543
6d2010ae
A
5544/*********************************************************************
5545*********************************************************************/
5546boolean_t
5547OSKext::verifySegmentMapping(kernel_segment_command_t *seg)
5548{
5549 mach_vm_address_t address = 0;
5550
5551 if (!segmentShouldBeWired(seg)) return true;
5552
5553 for (address = seg->vmaddr;
5554 address < round_page(seg->vmaddr + seg->vmsize);
5555 address += PAGE_SIZE)
5556 {
5557 if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
5558 OSKextLog(this,
5559 kOSKextLogErrorLevel |
5560 kOSKextLogLoadFlag,
5561 "Kext %s - page %p is not backed by physical memory.",
5562 getIdentifierCString(),
5563 (void *)address);
5564 return false;
5565 }
5566 }
5567
5568 return true;
5569}
5570
b0d623f7
A
5571/*********************************************************************
5572*********************************************************************/
5573OSReturn
5574OSKext::start(bool startDependenciesFlag)
5575{
5576 OSReturn result = kOSReturnError;
5577 kern_return_t (* startfunc)(kmod_info_t *, void *);
5578 unsigned int i, count;
316670eb 5579 void * kmodStartData = NULL;
b0d623f7
A
5580
5581 if (isStarted() || isInterface() || isKernelComponent()) {
5582 result = kOSReturnSuccess;
5583 goto finish;
5584 }
5585
5586 if (!isLoaded()) {
5587 OSKextLog(this,
5588 kOSKextLogErrorLevel |
5589 kOSKextLogLoadFlag,
5590 "Attempt to start nonloaded kext %s.",
5591 getIdentifierCString());
5592 result = kOSKextReturnInvalidArgument;
5593 goto finish;
5594 }
5595
b7266188
A
5596 if (!sLoadEnabled) {
5597 OSKextLog(this,
5598 kOSKextLogErrorLevel |
5599 kOSKextLogLoadFlag,
5600 "Kext loading is disabled (attempt to start kext %s).",
5601 getIdentifierCString());
5602 result = kOSKextReturnDisabled;
5603 goto finish;
5604 }
5605
b0d623f7
A
5606 result = validateKextMapping(/* start? */ true);
5607 if (result != kOSReturnSuccess) {
5608 goto finish;
5609 }
5610
5611 startfunc = kmod_info->start;
5612
5613 count = getNumDependencies();
5614 for (i = 0; i < count; i++) {
5615 OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
5616 if (dependency == NULL) {
5617 OSKextLog(this,
5618 kOSKextLogErrorLevel |
5619 kOSKextLogLoadFlag,
5620 "Kext %s start - internal error, dependency disappeared.",
5621 getIdentifierCString());
5622 goto finish;
5623 }
5624 if (!dependency->isStarted()) {
5625 if (startDependenciesFlag) {
5626 OSReturn dependencyResult =
5627 dependency->start(startDependenciesFlag);
5628 if (dependencyResult != KERN_SUCCESS) {
5629 OSKextLog(this,
5630 kOSKextLogErrorLevel |
5631 kOSKextLogLoadFlag,
5632 "Kext %s start - dependency %s failed to start (error 0x%x).",
5633 getIdentifierCString(),
5634 dependency->getIdentifierCString(),
5635 dependencyResult);
5636 goto finish;
5637 }
5638 } else {
5639 OSKextLog(this,
5640 kOSKextLogErrorLevel |
5641 kOSKextLogLoadFlag,
5642 "Not starting %s - dependency %s not started yet.",
5643 getIdentifierCString(),
5644 dependency->getIdentifierCString());
5645 result = kOSKextReturnStartStopError; // xxx - make new return?
5646 goto finish;
5647 }
5648 }
5649 }
5650
b0d623f7
A
5651 OSKextLog(this,
5652 kOSKextLogDetailLevel |
5653 kOSKextLogLoadFlag,
5654 "Kext %s calling module start function.",
5655 getIdentifierCString());
5656
5657 flags.starting = 1;
5658
6d2010ae 5659#if !CONFIG_STATIC_CPPINIT
b0d623f7
A
5660 result = OSRuntimeInitializeCPP(kmod_info, NULL);
5661 if (result == KERN_SUCCESS) {
5662#endif
5663
316670eb
A
5664#if CONFIG_KEC_FIPS
5665 kmodStartData = GetAppleTEXTHashForKext(this, this->infoDict);
5666
5667#if 0
5668 if (kmodStartData) {
5669 OSKextLog(this,
5670 kOSKextLogErrorLevel |
5671 kOSKextLogGeneralFlag,
5672 "Kext %s calling module start function. kmodStartData %p. arch %s",
5673 getIdentifierCString(), kmodStartData, ARCHNAME);
5674 }
5675#endif
5676#endif // CONFIG_KEC_FIPS
5677
b0d623f7
A
5678 result = startfunc(kmod_info, kmodStartData);
5679
6d2010ae 5680#if !CONFIG_STATIC_CPPINIT
b0d623f7
A
5681 if (result != KERN_SUCCESS) {
5682 (void) OSRuntimeFinalizeCPP(kmod_info, NULL);
5683 }
5684 }
5685#endif
5686
5687 flags.starting = 0;
5688
5689 /* On success overlap the setting of started/starting. On failure just
5690 * clear starting.
5691 */
5692 if (result == KERN_SUCCESS) {
5693 flags.started = 1;
5694
5695 // xxx - log start error from kernel?
5696 OSKextLog(this,
5697 kOSKextLogProgressLevel |
5698 kOSKextLogLoadFlag,
5699 "Kext %s is now started.",
5700 getIdentifierCString());
5701 } else {
5702 invokeOrCancelRequestCallbacks(
5703 /* result not actually used */ kOSKextReturnStartStopError,
5704 /* invokeFlag */ false);
5705 OSKextLog(this,
5706 kOSKextLogProgressLevel |
5707 kOSKextLogLoadFlag,
5708 "Kext %s did not start (return code 0x%x).",
5709 getIdentifierCString(), result);
5710 }
5711
5712finish:
b0d623f7
A
5713 return result;
5714}
5715
5716/*********************************************************************
5717*********************************************************************/
5718/* static */
5719bool OSKext::canUnloadKextWithIdentifier(
5720 OSString * kextIdentifier,
5721 bool checkClassesFlag)
5722{
5723 bool result = false;
5724 OSKext * aKext = NULL; // do not release
5725
5726 IORecursiveLockLock(sKextLock);
5727
5728 aKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
5729
5730 if (!aKext) {
5731 goto finish; // can't unload what's not loaded
5732 }
5733
5734 if (aKext->isLoaded()) {
5735 if (aKext->getRetainCount() > kOSKextMinLoadedRetainCount) {
5736 goto finish;
5737 }
5738 if (checkClassesFlag && aKext->hasOSMetaClassInstances()) {
5739 goto finish;
5740 }
5741 }
5742
5743 result = true;
5744
5745finish:
5746 IORecursiveLockUnlock(sKextLock);
5747 return result;
5748}
5749
5750/*********************************************************************
5751*********************************************************************/
5752OSReturn
5753OSKext::stop(void)
5754{
5755 OSReturn result = kOSReturnError;
5756 kern_return_t (*stopfunc)(kmod_info_t *, void *);
5757
5758 if (!isStarted() || isInterface()) {
5759 result = kOSReturnSuccess;
5760 goto finish;
5761 }
5762
5763 if (!isLoaded()) {
5764 OSKextLog(this,
5765 kOSKextLogErrorLevel |
5766 kOSKextLogLoadFlag,
5767 "Attempt to stop nonloaded kext %s.",
5768 getIdentifierCString());
5769 result = kOSKextReturnInvalidArgument;
5770 goto finish;
5771 }
5772
5773 /* Refuse to stop if we have clients or instances. It is up to
5774 * the caller to make sure those aren't true.
5775 */
5776 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
5777 OSKextLog(this,
5778 kOSKextLogErrorLevel |
5779 kOSKextLogLoadFlag,
5780 "Kext %s - C++ instances; can't stop.",
5781 getIdentifierCString());
5782 result = kOSKextReturnInUse;
5783 goto finish;
5784 }
5785
5786 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
5787
5788 OSKextLog(this,
5789 kOSKextLogErrorLevel |
5790 kOSKextLogLoadFlag,
5791 "Kext %s - has references (linkage or tracking object); "
5792 "can't stop.",
5793 getIdentifierCString());
5794 result = kOSKextReturnInUse;
5795 goto finish;
5796 }
5797
5798 /* Note: If validateKextMapping fails on the stop & unload path,
5799 * we are in serious trouble and a kernel panic is likely whether
5800 * we stop & unload the kext or not.
5801 */
5802 result = validateKextMapping(/* start? */ false);
5803 if (result != kOSReturnSuccess) {
5804 goto finish;
5805 }
5806
b0d623f7
A
5807 stopfunc = kmod_info->stop;
5808 if (stopfunc) {
5809 OSKextLog(this,
5810 kOSKextLogDetailLevel |
5811 kOSKextLogLoadFlag,
5812 "Kext %s calling module stop function.",
5813 getIdentifierCString());
5814
5815 flags.stopping = 1;
5816
5817 result = stopfunc(kmod_info, /* userData */ NULL);
6d2010ae 5818#if !CONFIG_STATIC_CPPINIT
b0d623f7
A
5819 if (result == KERN_SUCCESS) {
5820 result = OSRuntimeFinalizeCPP(kmod_info, NULL);
5821 }
5822#endif
5823
5824 flags.stopping = 0;
5825
5826 if (result == KERN_SUCCESS) {
5827 flags.started = 0;
5828
5829 OSKextLog(this,
5830 kOSKextLogDetailLevel |
5831 kOSKextLogLoadFlag,
5832 "Kext %s is now stopped and ready to unload.",
5833 getIdentifierCString());
5834 } else {
5835 OSKextLog(this,
5836 kOSKextLogErrorLevel |
5837 kOSKextLogLoadFlag,
5838 "Kext %s did not stop (return code 0x%x).",
5839 getIdentifierCString(), result);
5840 result = kOSKextReturnStartStopError;
5841 }
5842 }
5843
5844finish:
5845 return result;
5846}
5847
5848/*********************************************************************
5849*********************************************************************/
5850OSReturn
5851OSKext::unload(void)
5852{
5853 OSReturn result = kOSReturnError;
5854 unsigned int index;
5855 uint32_t num_kmod_refs = 0;
5856
5857 if (!sUnloadEnabled) {
5858 OSKextLog(this,
5859 kOSKextLogErrorLevel |
5860 kOSKextLogLoadFlag,
5861 "Kext unloading is disabled (%s).",
5862 this->getIdentifierCString());
5863
5864 result = kOSKextReturnDisabled;
5865 goto finish;
5866 }
5867
5868 /* Refuse to unload if we have clients or instances. It is up to
5869 * the caller to make sure those aren't true.
5870 */
5871 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
5872 // xxx - Don't log under errors? this is more of an info thing
5873 OSKextLog(this,
5874 kOSKextLogErrorLevel |
5875 kOSKextLogKextBookkeepingFlag,
5876 "Can't unload kext %s; outstanding references (linkage or tracking object).",
5877 getIdentifierCString());
5878 result = kOSKextReturnInUse;
5879 goto finish;
5880 }
5881
b0d623f7
A
5882 if (hasOSMetaClassInstances()) {
5883 OSKextLog(this,
5884 kOSKextLogErrorLevel |
5885 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5886 "Can't unload kext %s; classes have instances:",
5887 getIdentifierCString());
5888 reportOSMetaClassInstances(kOSKextLogErrorLevel |
5889 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag);
5890 result = kOSKextReturnInUse;
5891 goto finish;
5892 }
5893
5894 if (!isLoaded()) {
5895 result = kOSReturnSuccess;
5896 goto finish;
5897 }
5898
5899 if (isKernelComponent()) {
5900 result = kOSKextReturnInvalidArgument;
5901 goto finish;
5902 }
5903
5904 /* Note that the kext is unloading before running any code that
5905 * might be in the kext (request callbacks, module stop function).
5906 * We will deny certain requests made against a kext in the process
5907 * of unloading.
5908 */
5909 flags.unloading = 1;
6d2010ae
A
5910
5911 /* Update the string describing the last kext to unload in case we panic.
5912 */
5913 savePanicString(/* isLoading */ false);
b0d623f7
A
5914
5915 if (isStarted()) {
5916 result = stop();
5917 if (result != KERN_SUCCESS) {
5918 OSKextLog(this,
5919 kOSKextLogErrorLevel |
5920 kOSKextLogLoadFlag,
5921 "Kext %s can't unload - module stop returned 0x%x.",
5922 getIdentifierCString(), (unsigned)result);
5923 result = kOSKextReturnStartStopError;
5924 goto finish;
5925 }
5926 }
5927
5928 OSKextLog(this,
5929 kOSKextLogProgressLevel |
5930 kOSKextLogLoadFlag,
5931 "Kext %s unloading.",
5932 getIdentifierCString());
5933
5934 /* Even if we don't call the stop function, we want to be sure we
5935 * have no OSMetaClass references before unloading the kext executable
5936 * from memory. OSMetaClasses may have pointers into the kext executable
5937 * and that would cause a panic on OSKext::free() when metaClasses is freed.
5938 */
5939 if (metaClasses) {
5940 metaClasses->flushCollection();
5941 }
5942
5943 /* Remove the kext from the list of loaded kexts, patch the gap
5944 * in the kmod_info_t linked list, and reset "kmod" to point to the
5945 * last loaded kext that isn't the fake kernel kext (sKernelKext).
5946 */
5947 index = sLoadedKexts->getNextIndexOfObject(this, 0);
5948 if (index != (unsigned int)-1) {
5949
5950 sLoadedKexts->removeObject(index);
5951
5952 OSKext * nextKext = OSDynamicCast(OSKext,
5953 sLoadedKexts->getObject(index));
5954
5955 if (nextKext) {
5956 if (index > 0) {
5957 OSKext * gapKext = OSDynamicCast(OSKext,
5958 sLoadedKexts->getObject(index - 1));
5959
5960 nextKext->kmod_info->next = gapKext->kmod_info;
5961
5962 } else /* index == 0 */ {
5963 nextKext->kmod_info->next = NULL;
5964 }
5965 }
5966
5967 OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
6d2010ae 5968 if (lastKext && !lastKext->isKernel()) {
b0d623f7
A
5969 kmod = lastKext->kmod_info;
5970 } else {
5971 kmod = NULL; // clear the global kmod variable
5972 }
5973 }
5974
5975 /* Clear out the kmod references that we're keeping for compatibility
5976 * with current panic backtrace code & kgmacros.
5977 * xxx - will want to update those bits sometime and remove this.
5978 */
5979 num_kmod_refs = getNumDependencies();
5980 if (num_kmod_refs && kmod_info && kmod_info->reference_list) {
5981 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
5982 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
5983 ref->info->reference_count--;
5984 }
5985 kfree(kmod_info->reference_list,
5986 num_kmod_refs * sizeof(kmod_reference_t));
5987 }
5988
6d2010ae
A
5989#if CONFIG_DTRACE
5990 unregisterWithDTrace();
5991#endif /* CONFIG_DTRACE */
5992
5993 notifyKextUnloadObservers(this);
5994
5995 /* Unwire and free the linked executable.
5996 */
b0d623f7 5997 if (linkedExecutable) {
316670eb 5998#if VM_MAPPED_KEXTS
6d2010ae
A
5999 if (!isInterface()) {
6000 kernel_segment_command_t *seg = NULL;
6001 vm_map_t kext_map = kext_get_vm_map(kmod_info);
b0d623f7 6002
6d2010ae
A
6003 if (!kext_map) {
6004 OSKextLog(this,
6005 kOSKextLogErrorLevel |
6006 kOSKextLogLoadFlag,
6007 "Failed to free kext %s; couldn't find the kext map.",
6008 getIdentifierCString());
6009 result = kOSKextReturnInternalError;
6010 goto finish;
6011 }
b0d623f7 6012
6d2010ae
A
6013 OSKextLog(this,
6014 kOSKextLogProgressLevel |
6015 kOSKextLogLoadFlag,
6016 "Kext %s unwiring and unmapping linked executable.",
6017 getIdentifierCString());
6018
6019 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
6020 while (seg) {
6021 if (segmentShouldBeWired(seg)) {
6022 result = vm_map_unwire(kext_map, seg->vmaddr,
6023 seg->vmaddr + seg->vmsize, FALSE);
6024 if (result != KERN_SUCCESS) {
6025 OSKextLog(this,
6026 kOSKextLogErrorLevel |
6027 kOSKextLogLoadFlag,
6028 "Failed to unwire kext %s.",
6029 getIdentifierCString());
6030 result = kOSKextReturnInternalError;
6031 goto finish;
6032 }
6033 }
b0d623f7 6034
6d2010ae 6035 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
b0d623f7
A
6036 }
6037 }
316670eb 6038#endif
6d2010ae 6039 OSSafeReleaseNULL(linkedExecutable);
b0d623f7
A
6040 }
6041
6042 /* An interface kext has a fake kmod_info that was allocated,
6043 * so we have to free it.
6044 */
6045 if (isInterface()) {
6046 kfree(kmod_info, sizeof(kmod_info_t));
6047 }
6048
6049 kmod_info = NULL;
6050
6051 flags.loaded = false;
6052 flushDependencies();
6053
6d2010ae
A
6054 /* save a copy of the bundle ID for us to check when deciding to
6055 * rebuild the kernel cache file. If a kext was already in the kernel
6056 * cache and unloaded then later loaded we do not need to rebuild the
6057 * kernel cache. 9055303
6058 */
6059 if (isPrelinked()) {
316670eb
A
6060 if (!_OSKextInUnloadedPrelinkedKexts(bundleID)) {
6061 IORecursiveLockLock(sKextLock);
6062 if (sUnloadedPrelinkedKexts) {
6063 sUnloadedPrelinkedKexts->setObject(bundleID);
6064 }
6065 IORecursiveLockUnlock(sKextLock);
6066 }
6d2010ae
A
6067 }
6068
b0d623f7
A
6069 OSKextLog(this,
6070 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
6071 "Kext %s unloaded.", getIdentifierCString());
6072
6d2010ae
A
6073 queueKextNotification(kKextRequestPredicateUnloadNotification,
6074 OSDynamicCast(OSString, bundleID));
6075
b0d623f7
A
6076finish:
6077 OSKext::saveLoadedKextPanicList();
6d2010ae 6078 OSKext::updateLoadedKextSummaries();
b0d623f7
A
6079
6080 flags.unloading = 0;
6081 return result;
6082}
6083
6d2010ae
A
6084/*********************************************************************
6085* Assumes sKextLock is held.
6086*********************************************************************/
6087/* static */
6088OSReturn
6089OSKext::queueKextNotification(
6090 const char * notificationName,
6091 OSString * kextIdentifier)
6092{
6093 OSReturn result = kOSReturnError;
6094 OSDictionary * loadRequest = NULL; // must release
6095
6096 if (!kextIdentifier) {
6097 result = kOSKextReturnInvalidArgument;
6098 goto finish;
6099 }
6100
6101 /* Create a new request unless one is already sitting
6102 * in sKernelRequests for this bundle identifier
6103 */
6104 result = _OSKextCreateRequest(notificationName, &loadRequest);
6105 if (result != kOSReturnSuccess) {
6106 goto finish;
6107 }
6108 if (!_OSKextSetRequestArgument(loadRequest,
6109 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
6110
6111 result = kOSKextReturnNoMemory;
6112 goto finish;
6113 }
6114 if (!sKernelRequests->setObject(loadRequest)) {
6115 result = kOSKextReturnNoMemory;
6116 goto finish;
6117 }
6118
6119 /* We might want to only queue the notification if kextd is active,
6120 * but that wouldn't work for embedded. Note that we don't care if
6121 * the ping immediately succeeds here so don't do anything with the
6122 * result of this call.
6123 */
6124 OSKext::pingKextd();
6125
6126 result = kOSReturnSuccess;
6127
6128finish:
6129 OSSafeRelease(loadRequest);
6130
6131 return result;
6132}
6133
b0d623f7
A
6134/*********************************************************************
6135*********************************************************************/
6136static void
6137_OSKextConsiderDestroyingLinkContext(
6138 __unused thread_call_param_t p0,
6139 __unused thread_call_param_t p1)
6140{
6d2010ae 6141 /* Take multiple locks in the correct order.
b0d623f7
A
6142 */
6143 IORecursiveLockLock(sKextLock);
6144 IORecursiveLockLock(sKextInnerLock);
6145
6146 /* The first time we destroy the kxldContext is in the first
6147 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
6148 * before calling this function. Thereafter any call to this function
6149 * will actually destroy the context.
6150 */
6151 if (sConsiderUnloadsCalled && sKxldContext) {
6152 kxld_destroy_context(sKxldContext);
6153 sKxldContext = NULL;
6154 }
6155
6156 /* Free the thread_call that was allocated to execute this function.
6157 */
6158 if (sDestroyLinkContextThread) {
6159 if (!thread_call_free(sDestroyLinkContextThread)) {
6160 OSKextLog(/* kext */ NULL,
6161 kOSKextLogErrorLevel |
6162 kOSKextLogGeneralFlag,
6163 "thread_call_free() failed for kext link context.");
6164 }
6165 sDestroyLinkContextThread = 0;
6166 }
6167
6168 IORecursiveLockUnlock(sKextInnerLock);
6169 IORecursiveLockUnlock(sKextLock);
6170
6171 return;
6172}
6173
6174/*********************************************************************
6175* Destroying the kxldContext requires checking variables under both
6176* sKextInnerLock and sKextLock, so we do it on a separate thread
6177* to avoid deadlocks with IOService, with which OSKext has a reciprocal
6178* call relationship.
6179*
6d2010ae
A
6180* This function must be invoked with sKextInnerLock held.
6181* Do not call any function that takes sKextLock here!
b0d623f7
A
6182*********************************************************************/
6183/* static */
6184void
6185OSKext::considerDestroyingLinkContext(void)
6186{
6187 IORecursiveLockLock(sKextInnerLock);
6188
6189 /* If we have already queued a thread to destroy the link context,
6190 * don't bother resetting; that thread will take care of it.
6191 */
6192 if (sDestroyLinkContextThread) {
6193 goto finish;
6194 }
6195
6196 /* The function to be invoked in the thread will deallocate
6197 * this thread_call, so don't share it around.
6198 */
6199 sDestroyLinkContextThread = thread_call_allocate(
6200 &_OSKextConsiderDestroyingLinkContext, 0);
6201 if (!sDestroyLinkContextThread) {
6202 OSKextLog(/* kext */ NULL,
6203 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogLinkFlag,
6204 "Can't create thread to destroy kext link context.");
6205 goto finish;
6206 }
6207
6d2010ae 6208 thread_call_enter(sDestroyLinkContextThread);
b0d623f7
A
6209
6210finish:
6d2010ae
A
6211 IORecursiveLockUnlock(sKextInnerLock);
6212 return;
b0d623f7
A
6213}
6214
6215#if PRAGMA_MARK
6216#pragma mark Autounload
6217#endif
6218/*********************************************************************
6219* This is a static method because the kext will be deallocated if it
6220* does unload!
6221*********************************************************************/
6d2010ae 6222/* static */
b0d623f7
A
6223OSReturn
6224OSKext::autounloadKext(OSKext * aKext)
6225{
6226 OSReturn result = kOSKextReturnInUse;
6227
6228 /* Check for external references to this kext (usu. dependents),
6229 * instances of defined classes (or classes derived from them),
6230 * outstanding requests.
6231 */
6232 if ((aKext->getRetainCount() > kOSKextMinLoadedRetainCount) ||
6233 !aKext->flags.autounloadEnabled ||
6234 aKext->isKernelComponent()) {
6235
6236 goto finish;
6237 }
6238
6239 /* Skip a delay-autounload kext, once.
6240 */
6241 if (aKext->flags.delayAutounload) {
6242 OSKextLog(aKext,
6243 kOSKextLogProgressLevel |
6244 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6245 "Kext %s has delayed autounload set; skipping and clearing flag.",
6246 aKext->getIdentifierCString());
6247 aKext->flags.delayAutounload = 0;
6248 goto finish;
6249 }
6250
6251 if (aKext->hasOSMetaClassInstances() ||
6252 aKext->countRequestCallbacks()) {
6253 goto finish;
6254 }
6255
6256 result = OSKext::removeKext(aKext);
6257
6258finish:
6259
6260 return result;
6261}
6262
6263/*********************************************************************
6264*********************************************************************/
6265void
6266_OSKextConsiderUnloads(
6267 __unused thread_call_param_t p0,
6268 __unused thread_call_param_t p1)
6269{
6270 bool didUnload = false;
6271 unsigned int count, i;
6272
6d2010ae
A
6273 /* Take multiple locks in the correct order
6274 * (note also sKextSummaries lock further down).
b0d623f7
A
6275 */
6276 IORecursiveLockLock(sKextLock);
6277 IORecursiveLockLock(sKextInnerLock);
6278
6279 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
6280
6d2010ae
A
6281 IOLockLock(sKextSummariesLock);
6282
6283 /* If there is an old kext summary, free that now.
6284 */
6285 if (sPrevLoadedKextSummaries) {
6286 kmem_free(kernel_map, (vm_offset_t)sPrevLoadedKextSummaries,
6287 sPrevLoadedKextSummariesAllocSize);
6288 sPrevLoadedKextSummaries = NULL;
6289 sPrevLoadedKextSummariesAllocSize = 0;
6290 }
6291
6292 IOLockUnlock(sKextSummariesLock);
6293
b0d623f7
A
6294 /* If the system is powering down, don't try to unload anything.
6295 */
6296 if (sSystemSleep) {
6297 goto finish;
6298 }
6299
6300 OSKextLog(/* kext */ NULL,
6301 kOSKextLogProgressLevel |
6302 kOSKextLogLoadFlag,
6303 "Checking for unused kexts to autounload.");
6304
6305 /*****
6306 * Remove any request callbacks marked as stale,
6307 * and mark as stale any currently in flight.
6308 */
6309 count = sRequestCallbackRecords->getCount();
6310 if (count) {
6311 i = count - 1;
6312 do {
6313 OSDictionary * callbackRecord = OSDynamicCast(OSDictionary,
6314 sRequestCallbackRecords->getObject(i));
6315 OSBoolean * stale = OSDynamicCast(OSBoolean,
6316 callbackRecord->getObject(kKextRequestStaleKey));
6317
6d2010ae 6318 if (stale == kOSBooleanTrue) {
b0d623f7
A
6319 OSKext::invokeRequestCallback(callbackRecord,
6320 kOSKextReturnTimeout);
6321 } else {
6322 callbackRecord->setObject(kKextRequestStaleKey,
6323 kOSBooleanTrue);
6324 }
6325 } while (i--);
6326 }
6327
6328 /*****
6329 * Make multiple passes through the array of loaded kexts until
6330 * we don't unload any. This handles unwinding of dependency
6331 * chains. We have to go *backwards* through the array because
6332 * kexts are removed from it when unloaded, and we cannot make
6333 * a copy or we'll mess up the retain counts we rely on to
6334 * check whether a kext will unload. If only we could have
6335 * nonretaining collections like CF has....
6336 */
6337 do {
6338 didUnload = false;
6339
6340 count = sLoadedKexts->getCount();
6341 if (count) {
6342 i = count - 1;
6343 do {
6344 OSKext * thisKext = OSDynamicCast(OSKext,
6345 sLoadedKexts->getObject(i));
6346 didUnload = (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
6347 } while (i--);
6348 }
6349 } while (didUnload);
6350
6351finish:
6352 sConsiderUnloadsPending = false;
6353 sConsiderUnloadsExecuted = true;
6354
316670eb 6355 (void) OSKext::considerRebuildOfPrelinkedKernel();
6d2010ae 6356
b0d623f7
A
6357 IORecursiveLockUnlock(sKextInnerLock);
6358 IORecursiveLockUnlock(sKextLock);
6359
6360 return;
6361}
6362
6363/*********************************************************************
6364* Do not call any function that takes sKextLock here!
6365*********************************************************************/
6366void OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
6367{
6368 AbsoluteTime when;
6369
6370 IORecursiveLockLock(sKextInnerLock);
6371
6372 if (!sUnloadCallout) {
6373 sUnloadCallout = thread_call_allocate(&_OSKextConsiderUnloads, 0);
6374 }
6375
6d2010ae
A
6376 /* we only reset delay value for unloading if we already have something
6377 * pending. rescheduleOnlyFlag should not start the count down.
6378 */
b0d623f7
A
6379 if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
6380 goto finish;
6381 }
6382
6383 thread_call_cancel(sUnloadCallout);
6384 if (OSKext::getAutounloadEnabled() && !sSystemSleep) {
6385 clock_interval_to_deadline(sConsiderUnloadDelay,
6386 1000 * 1000 * 1000, &when);
6387
6388 OSKextLog(/* kext */ NULL,
6389 kOSKextLogProgressLevel |
6390 kOSKextLogLoadFlag,
6391 "%scheduling %sscan for unused kexts in %lu seconds.",
6392 sConsiderUnloadsPending ? "Res" : "S",
6393 sConsiderUnloadsCalled ? "" : "initial ",
6394 (unsigned long)sConsiderUnloadDelay);
6395
6396 sConsiderUnloadsPending = true;
6397 thread_call_enter_delayed(sUnloadCallout, when);
6398 }
6399
6400finish:
6401 /* The kxld context should be reused throughout boot. We mark the end of
6402 * period as the first time considerUnloads() is called, and we destroy
6403 * the first kxld context in that function. Afterwards, it will be
6404 * destroyed in flushNonloadedKexts.
6405 */
6406 if (!sConsiderUnloadsCalled) {
6407 sConsiderUnloadsCalled = true;
6408 OSKext::considerDestroyingLinkContext();
6409 }
6410
6411 IORecursiveLockUnlock(sKextInnerLock);
6412 return;
6413}
6414
6415/*********************************************************************
6416* Do not call any function that takes sKextLock here!
6417*********************************************************************/
6418extern "C" {
6419
6420IOReturn OSKextSystemSleepOrWake(UInt32 messageType)
6421{
6422 IORecursiveLockLock(sKextInnerLock);
6423
6424 /* If the system is going to sleep, cancel the reaper thread timer,
6425 * and note that we're in a sleep state in case it just fired but hasn't
6426 * taken the lock yet. If we are coming back from sleep, just
6427 * clear the sleep flag; IOService's normal operation will cause
6428 * unloads to be considered soon enough.
6429 */
6430 if (messageType == kIOMessageSystemWillSleep) {
6431 if (sUnloadCallout) {
6432 thread_call_cancel(sUnloadCallout);
6433 }
6434 sSystemSleep = true;
316670eb 6435 AbsoluteTime_to_scalar(&sLastWakeTime) = 0;
b0d623f7
A
6436 } else if (messageType == kIOMessageSystemHasPoweredOn) {
6437 sSystemSleep = false;
316670eb
A
6438 clock_get_uptime(&sLastWakeTime);
6439 }
b0d623f7
A
6440 IORecursiveLockUnlock(sKextInnerLock);
6441
6442 return kIOReturnSuccess;
6443}
6444
6445};
6446
6447
6448#if PRAGMA_MARK
6449#pragma mark Prelinked Kernel
6450#endif
6451/*********************************************************************
6452* Do not access sConsiderUnloads... variables other than
6453* sConsiderUnloadsExecuted in this function. They are guarded by a
6454* different lock.
6455*********************************************************************/
6456/* static */
6457void
316670eb
A
6458OSKext::considerRebuildOfPrelinkedKernel(void)
6459{
6460 static bool requestedPrelink = false;
6461 OSReturn checkResult = kOSReturnError;
6462 OSDictionary * prelinkRequest = NULL; // must release
6463 OSCollectionIterator * kextIterator = NULL; // must release
6464 const OSSymbol * thisID = NULL; // do not release
6465 bool doRebuild = false;
6466 AbsoluteTime my_abstime;
6467 UInt64 my_ns;
6468 SInt32 delta_secs;
6469
6470 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
6471 if (requestedPrelink || !sPrelinkBoot) {
6472 return;
6473 }
6474
6475 /* no direct return from this point */
b0d623f7 6476 IORecursiveLockLock(sKextLock);
6d2010ae 6477
316670eb
A
6478 /* We need to wait for kextd to get up and running with unloads already done
6479 * and any new startup kexts loaded.
6d2010ae 6480 */
316670eb
A
6481 if (!sConsiderUnloadsExecuted ||
6482 !sDeferredLoadSucceeded) {
6483 goto finish;
6484 }
6485
6486 /* we really only care about boot / system start up related kexts so bail
6487 * if we're here after REBUILD_MAX_TIME.
6488 */
6489 if (!_OSKextInPrelinkRebuildWindow()) {
6490 OSKextLog(/* kext */ NULL,
6491 kOSKextLogArchiveFlag,
6492 "%s prebuild rebuild has expired",
6493 __FUNCTION__);
6494 requestedPrelink = true;
6495 goto finish;
6496 }
6497
6498 /* we do not want to trigger a rebuild if we get here too close to waking
6499 * up. (see radar 10233768)
6500 */
6501 IORecursiveLockLock(sKextInnerLock);
6502
6503 clock_get_uptime(&my_abstime);
6504 delta_secs = MINIMUM_WAKEUP_SECONDS + 1;
6505 if (AbsoluteTime_to_scalar(&sLastWakeTime) != 0) {
6506 SUB_ABSOLUTETIME(&my_abstime, &sLastWakeTime);
6507 absolutetime_to_nanoseconds(my_abstime, &my_ns);
6508 delta_secs = (SInt32)(my_ns / NSEC_PER_SEC);
6509 }
6510 IORecursiveLockUnlock(sKextInnerLock);
6511
6512 if (delta_secs < MINIMUM_WAKEUP_SECONDS) {
6513 /* too close to time of last wake from sleep */
6514 goto finish;
6515 }
6516 requestedPrelink = true;
6517
6518 /* Now it's time to see if we have a reason to rebuild. We may have done
6519 * some loads and unloads but the kernel cache didn't actually change.
6520 * We will rebuild if any kext is not marked prelinked AND is not in our
6521 * list of prelinked kexts that got unloaded. (see radar 9055303)
6522 */
6523 kextIterator = OSCollectionIterator::withCollection(sKextsByID);
6524 if (!kextIterator) {
6525 goto finish;
6526 }
6527
6528 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
6529 OSKext * thisKext; // do not release
6530
6531 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
6532 if (!thisKext || thisKext->isPrelinked() || thisKext->isKernel()) {
6533 continue;
6534 }
6535
6536 if (_OSKextInUnloadedPrelinkedKexts(thisKext->bundleID)) {
6537 continue;
6d2010ae 6538 }
316670eb
A
6539 /* kext is loaded and was not in current kernel cache so let's rebuild
6540 */
6541 doRebuild = true;
6542 OSKextLog(/* kext */ NULL,
6543 kOSKextLogArchiveFlag,
6544 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
6545 thisKext->bundleID->getCStringNoCopy());
6546 break;
6d2010ae 6547 }
316670eb
A
6548 sUnloadedPrelinkedKexts->flushCollection();
6549
6550 if (!doRebuild) {
b0d623f7
A
6551 goto finish;
6552 }
316670eb 6553
b0d623f7 6554 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
316670eb 6555 &prelinkRequest);
b0d623f7
A
6556 if (checkResult != kOSReturnSuccess) {
6557 goto finish;
6558 }
316670eb 6559
b0d623f7
A
6560 if (!sKernelRequests->setObject(prelinkRequest)) {
6561 goto finish;
6562 }
316670eb 6563
6d2010ae 6564 OSKext::pingKextd();
316670eb 6565
b0d623f7
A
6566finish:
6567 IORecursiveLockUnlock(sKextLock);
6568 OSSafeRelease(prelinkRequest);
316670eb
A
6569 OSSafeRelease(kextIterator);
6570
b0d623f7
A
6571 return;
6572}
6573
6574#if PRAGMA_MARK
6575#pragma mark Dependencies
6576#endif
6577/*********************************************************************
6578*********************************************************************/
6579bool
6580OSKext::resolveDependencies(
6581 OSArray * loopStack)
6582{
6583 bool result = false;
6584 OSArray * localLoopStack = NULL; // must release
6585 bool addedToLoopStack = false;
6586 OSDictionary * libraries = NULL; // do not release
6587 OSCollectionIterator * libraryIterator = NULL; // must release
6588 OSString * libraryID = NULL; // do not release
6589 OSString * infoString = NULL; // do not release
6590 OSString * readableString = NULL; // do not release
6591 OSKext * libraryKext = NULL; // do not release
6592 bool hasRawKernelDependency = false;
6593 bool hasKernelDependency = false;
6594 bool hasKPIDependency = false;
6595 bool hasPrivateKPIDependency = false;
6596 unsigned int count;
6597
6598 /* A kernel component will automatically have this flag set,
6599 * and a loaded kext should also have it set (as should all its
6600 * loaded dependencies).
6601 */
6602 if (flags.hasAllDependencies) {
6603 result = true;
6604 goto finish;
6605 }
6606
6607 /* Check for loops in the dependency graph.
6608 */
6609 if (loopStack) {
6610 if (loopStack->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
6611 OSKextLog(this,
6612 kOSKextLogErrorLevel |
6613 kOSKextLogDependenciesFlag,
6614 "Kext %s has a dependency loop; can't resolve dependencies.",
6615 getIdentifierCString());
6616 goto finish;
6617 }
6618 } else {
6619 OSKextLog(this,
6620 kOSKextLogStepLevel |
6621 kOSKextLogDependenciesFlag,
6622 "Kext %s resolving dependencies.",
6623 getIdentifierCString());
6624
6625 loopStack = OSArray::withCapacity(6); // any small capacity will do
6626 if (!loopStack) {
6627 OSKextLog(this,
6628 kOSKextLogErrorLevel |
6629 kOSKextLogDependenciesFlag,
6630 "Kext %s can't create bookkeeping stack to resolve dependencies.",
6631 getIdentifierCString());
6632 goto finish;
6633 }
6634 localLoopStack = loopStack;
6635 }
6636 if (!loopStack->setObject(this)) {
6637 OSKextLog(this,
6638 kOSKextLogErrorLevel |
6639 kOSKextLogDependenciesFlag,
6640 "Kext %s - internal error resolving dependencies.",
6641 getIdentifierCString());
6642 goto finish;
6643 }
6644 addedToLoopStack = true;
6645
6646 /* Purge any existing kexts in the dependency list and start over.
6647 */
6648 flushDependencies();
6649 if (dependencies) {
6650 OSKextLog(this,
6651 kOSKextLogErrorLevel |
6652 kOSKextLogDependenciesFlag,
6653 "Kext %s - internal error resolving dependencies.",
6654 getIdentifierCString());
6655 }
6656
6657 libraries = OSDynamicCast(OSDictionary,
6658 getPropertyForHostArch(kOSBundleLibrariesKey));
6659 if (libraries == NULL || libraries->getCount() == 0) {
6660 OSKextLog(this,
6661 kOSKextLogErrorLevel |
6662 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
6663 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
6664 getIdentifierCString(), kOSBundleLibrariesKey);
6665 goto finish;
6666 }
6667
6668 /* Make a new array to hold the dependencies (flush freed the old one).
6669 */
6670 dependencies = OSArray::withCapacity(libraries->getCount());
6671 if (!dependencies) {
6672 OSKextLog(this,
6673 kOSKextLogErrorLevel |
6674 kOSKextLogDependenciesFlag,
6675 "Kext %s - can't allocate dependencies array.",
6676 getIdentifierCString());
6677 goto finish;
6678 }
6679
6680 // xxx - compat: We used to add an implicit dependency on kernel 6.0
6681 // xxx - compat: if none were declared.
6682
6683 libraryIterator = OSCollectionIterator::withCollection(libraries);
6684 if (!libraryIterator) {
6685 OSKextLog(this,
6686 kOSKextLogErrorLevel |
6687 kOSKextLogDependenciesFlag,
6688 "Kext %s - can't allocate dependencies iterator.",
6689 getIdentifierCString());
6690 goto finish;
6691 }
6692
6693 while ((libraryID = OSDynamicCast(OSString,
6694 libraryIterator->getNextObject()))) {
6695
6696 const char * library_id = libraryID->getCStringNoCopy();
6697
6698 OSString * libraryVersion = OSDynamicCast(OSString,
6699 libraries->getObject(libraryID));
6700 if (libraryVersion == NULL) {
6701 OSKextLog(this,
6702 kOSKextLogErrorLevel |
6703 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
6704 "Kext %s - illegal type in OSBundleLibraries.",
6705 getIdentifierCString());
6706 goto finish;
6707 }
6708
6709 OSKextVersion libraryVers =
6710 OSKextParseVersionString(libraryVersion->getCStringNoCopy());
6711 if (libraryVers == -1) {
6712 OSKextLog(this,
6713 kOSKextLogErrorLevel |
6714 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
6715 "Kext %s - invalid library version %s.",
6716 getIdentifierCString(),
6717 libraryVersion->getCStringNoCopy());
6718 goto finish;
6719 }
6720
6721 libraryKext = OSDynamicCast(OSKext, sKextsByID->getObject(libraryID));
6722 if (libraryKext == NULL) {
6723 OSKextLog(this,
6724 kOSKextLogErrorLevel |
6725 kOSKextLogDependenciesFlag,
6726 "Kext %s - library kext %s not found.",
6727 getIdentifierCString(), library_id);
6728 goto finish;
6729 }
6730
6731 if (!libraryKext->isCompatibleWithVersion(libraryVers)) {
6732 OSKextLog(this,
6733 kOSKextLogErrorLevel |
6734 kOSKextLogDependenciesFlag,
6735 "Kext %s - library kext %s not compatible "
6736 "with requested version %s.",
6737 getIdentifierCString(), library_id,
6738 libraryVersion->getCStringNoCopy());
6739 goto finish;
6740 }
6d2010ae
A
6741
6742 /* If a nonprelinked library somehow got into the mix for a
6743 * prelinked kext, at any point in the chain, we must fail
6744 * because the prelinked relocs for the library will be all wrong.
6745 */
6746 if (this->isPrelinked() &&
6747 libraryKext->declaresExecutable() &&
6748 !libraryKext->isPrelinked()) {
6749
6750 OSKextLog(this,
6751 kOSKextLogErrorLevel |
6752 kOSKextLogDependenciesFlag,
6753 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
6754 getIdentifierCString(), library_id,
6755 libraryVersion->getCStringNoCopy());
6756 goto finish;
6757 }
6758
b0d623f7
A
6759 if (!libraryKext->resolveDependencies(loopStack)) {
6760 goto finish;
6761 }
6762
6763 /* Add the library directly only if it has an executable to link.
6764 * Otherwise it's just used to collect other dependencies, so put
6765 * *its* dependencies on the list for this kext.
6766 */
6767 // xxx - We are losing info here; would like to make fake entries or
6768 // xxx - keep these in the dependency graph for loaded kexts.
6769 // xxx - I really want to make kernel components not a special case!
6770 if (libraryKext->declaresExecutable() ||
6771 libraryKext->isInterface()) {
6772
6773 if (dependencies->getNextIndexOfObject(libraryKext, 0) == (unsigned)-1) {
6774 dependencies->setObject(libraryKext);
6775
6776 OSKextLog(this,
6777 kOSKextLogDetailLevel |
6778 kOSKextLogDependenciesFlag,
6779 "Kext %s added dependency %s.",
6780 getIdentifierCString(),
6781 libraryKext->getIdentifierCString());
6782 }
6783 } else {
6784 int numLibDependencies = libraryKext->getNumDependencies();
6785 OSArray * libraryDependencies = libraryKext->getDependencies();
6786 int index;
6787
6788 if (numLibDependencies) {
6789 // xxx - this msg level should be 1 lower than the per-kext one
6790 OSKextLog(this,
6791 kOSKextLogDetailLevel |
6792 kOSKextLogDependenciesFlag,
6793 "Kext %s pulling %d dependencies from codeless library %s.",
6794 getIdentifierCString(),
6795 numLibDependencies,
6796 libraryKext->getIdentifierCString());
6797 }
6798 for (index = 0; index < numLibDependencies; index++) {
6799 OSKext * thisLibDependency = OSDynamicCast(OSKext,
6800 libraryDependencies->getObject(index));
6801 if (dependencies->getNextIndexOfObject(thisLibDependency, 0) == (unsigned)-1) {
6802 dependencies->setObject(thisLibDependency);
6803 OSKextLog(this,
6804 kOSKextLogDetailLevel |
6805 kOSKextLogDependenciesFlag,
6806 "Kext %s added dependency %s from codeless library %s.",
6807 getIdentifierCString(),
6808 thisLibDependency->getIdentifierCString(),
6809 libraryKext->getIdentifierCString());
6810 }
6811 }
6812 }
6813
6814 if ((strlen(library_id) == strlen(KERNEL_LIB)) &&
6815 0 == strncmp(library_id, KERNEL_LIB, sizeof(KERNEL_LIB)-1)) {
6816
6817 hasRawKernelDependency = true;
6818 } else if (STRING_HAS_PREFIX(library_id, KERNEL_LIB_PREFIX)) {
6819 hasKernelDependency = true;
6820 } else if (STRING_HAS_PREFIX(library_id, KPI_LIB_PREFIX)) {
6821 hasKPIDependency = true;
6822 if (!strncmp(library_id, PRIVATE_KPI, sizeof(PRIVATE_KPI)-1)) {
6823 hasPrivateKPIDependency = true;
6824 }
6825 }
6826 }
6827
6d2010ae
A
6828 if (hasRawKernelDependency) {
6829 OSKextLog(this,
6830 kOSKextLogErrorLevel |
6831 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
6832 "Error - kext %s declares a dependency on %s, which is not permitted.",
6833 getIdentifierCString(), KERNEL_LIB);
6834 goto finish;
6835 }
b0d623f7 6836#if __LP64__
6d2010ae 6837 if (hasKernelDependency) {
b0d623f7
A
6838 OSKextLog(this,
6839 kOSKextLogErrorLevel |
6840 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
6841 "Error - kext %s declares %s dependencies. "
6842 "Only %s* dependencies are supported for 64-bit kexts.",
6843 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
6844 goto finish;
6845 }
6846 if (!hasKPIDependency) {
6847 OSKextLog(this,
6848 kOSKextLogWarningLevel |
6849 kOSKextLogDependenciesFlag,
6850 "Warning - kext %s declares no %s* dependencies. "
6851 "If it uses any KPIs, the link may fail with undefined symbols.",
6852 getIdentifierCString(), KPI_LIB_PREFIX);
6853 }
6854#else /* __LP64__ */
6855 // xxx - will change to flatly disallow "kernel" dependencies at some point
6856 // xxx - is it invalid to do both "com.apple.kernel" and any
6857 // xxx - "com.apple.kernel.*"?
6858
6d2010ae 6859 if (hasKernelDependency && hasKPIDependency) {
b0d623f7
A
6860 OSKextLog(this,
6861 kOSKextLogWarningLevel |
6862 kOSKextLogDependenciesFlag,
6863 "Warning - kext %s has immediate dependencies on both "
6864 "%s* and %s* components; use only one style.",
6865 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
6866 }
6867
6d2010ae 6868 if (!hasKernelDependency && !hasKPIDependency) {
b0d623f7
A
6869 // xxx - do we want to use validation flag for these too?
6870 OSKextLog(this,
6871 kOSKextLogWarningLevel |
6872 kOSKextLogDependenciesFlag,
6873 "Warning - %s declares no kernel dependencies; using %s.",
6874 getIdentifierCString(), KERNEL6_LIB);
6875 OSKext * kernelKext = OSDynamicCast(OSKext,
6876 sKextsByID->getObject(KERNEL6_LIB));
6877 if (kernelKext) {
6878 dependencies->setObject(kernelKext);
6879 } else {
6880 OSKextLog(this,
6881 kOSKextLogErrorLevel |
6882 kOSKextLogDependenciesFlag,
6883 "Error - Library %s not found for %s.",
6884 KERNEL6_LIB, getIdentifierCString());
6885 }
6886 }
6887
6888 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
6889 * its indirect dependencies to simulate old-style linking. XXX - Should
6890 * check for duplicates.
6891 */
6d2010ae 6892 if (!hasKPIDependency) {
b0d623f7
A
6893 unsigned int i;
6894
6d2010ae
A
6895 flags.hasBleedthrough = true;
6896
b0d623f7
A
6897 count = getNumDependencies();
6898
6899 /* We add to the dependencies array in this loop, but do not iterate
6900 * past its original count.
6901 */
6902 for (i = 0; i < count; i++) {
6903 OSKext * dependencyKext = OSDynamicCast(OSKext,
6904 dependencies->getObject(i));
6905 dependencyKext->addBleedthroughDependencies(dependencies);
6906 }
6907 }
6908#endif /* __LP64__ */
6909
6910 if (hasPrivateKPIDependency) {
6911 bool hasApplePrefix = false;
6912 bool infoCopyrightIsValid = false;
6913 bool readableCopyrightIsValid = false;
6914
6915 hasApplePrefix = STRING_HAS_PREFIX(getIdentifierCString(),
6916 APPLE_KEXT_PREFIX);
6917
6918 infoString = OSDynamicCast(OSString,
6919 getPropertyForHostArch("CFBundleGetInfoString"));
6920 if (infoString) {
6921 infoCopyrightIsValid =
6922 kxld_validate_copyright_string(infoString->getCStringNoCopy());
6923 }
6924
6925 readableString = OSDynamicCast(OSString,
6926 getPropertyForHostArch("NSHumanReadableCopyright"));
6927 if (readableString) {
6928 readableCopyrightIsValid =
6929 kxld_validate_copyright_string(readableString->getCStringNoCopy());
6930 }
6931
6932 if (!hasApplePrefix || (!infoCopyrightIsValid && !readableCopyrightIsValid)) {
6933 OSKextLog(this,
6934 kOSKextLogErrorLevel |
6935 kOSKextLogDependenciesFlag,
6936 "Error - kext %s declares a dependency on %s. "
6937 "Only Apple kexts may declare a dependency on %s.",
6938 getIdentifierCString(), PRIVATE_KPI, PRIVATE_KPI);
6939 goto finish;
6940 }
6941 }
6942
6943 result = true;
6944 flags.hasAllDependencies = 1;
6945
6946finish:
6947
6948 if (addedToLoopStack) {
6949 count = loopStack->getCount();
6950 if (count > 0 && (this == loopStack->getObject(count - 1))) {
6951 loopStack->removeObject(count - 1);
6952 } else {
6953 OSKextLog(this,
6954 kOSKextLogErrorLevel |
6955 kOSKextLogDependenciesFlag,
6956 "Kext %s - internal error resolving dependencies.",
6957 getIdentifierCString());
6958 }
6959 }
6960
6961 if (result && localLoopStack) {
6962 OSKextLog(this,
6963 kOSKextLogStepLevel |
6964 kOSKextLogDependenciesFlag,
6965 "Kext %s successfully resolved dependencies.",
6966 getIdentifierCString());
6967 }
6968
6969 OSSafeRelease(localLoopStack);
6970 OSSafeRelease(libraryIterator);
6971
6972 return result;
6973}
6974
6975/*********************************************************************
6976*********************************************************************/
6977bool
6978OSKext::addBleedthroughDependencies(OSArray * anArray)
6979{
6980 bool result = false;
6981 unsigned int dependencyIndex, dependencyCount;
6982
6983 dependencyCount = getNumDependencies();
6984
6985 for (dependencyIndex = 0;
6986 dependencyIndex < dependencyCount;
6987 dependencyIndex++) {
6988
6989 OSKext * dependency = OSDynamicCast(OSKext,
6990 dependencies->getObject(dependencyIndex));
6991 if (!dependency) {
6992 OSKextLog(this,
6993 kOSKextLogErrorLevel |
6994 kOSKextLogDependenciesFlag,
6995 "Kext %s - internal error propagating compatibility dependencies.",
6996 getIdentifierCString());
6997 goto finish;
6998 }
6999 if (anArray->getNextIndexOfObject(dependency, 0) == (unsigned int)-1) {
7000 anArray->setObject(dependency);
7001 }
7002 dependency->addBleedthroughDependencies(anArray);
7003 }
7004
7005 result = true;
7006
7007finish:
7008 return result;
7009}
7010
7011/*********************************************************************
7012*********************************************************************/
7013bool
7014OSKext::flushDependencies(bool forceFlag)
7015{
7016 bool result = false;
7017
7018 /* Only clear the dependencies if the kext isn't loaded;
7019 * we need the info for loaded kexts to track references.
7020 */
7021 if (!isLoaded() || forceFlag) {
7022 if (dependencies) {
7023 // xxx - check level
7024 OSKextLog(this,
7025 kOSKextLogProgressLevel |
7026 kOSKextLogDependenciesFlag,
7027 "Kext %s flushing dependencies.",
7028 getIdentifierCString());
7029 OSSafeReleaseNULL(dependencies);
7030
7031 }
7032 if (!isKernelComponent()) {
7033 flags.hasAllDependencies = 0;
7034 }
7035 result = true;
7036 }
7037
7038 return result;
7039}
7040
7041/*********************************************************************
7042*********************************************************************/
7043uint32_t
7044OSKext::getNumDependencies(void)
7045{
7046 if (!dependencies) {
7047 return 0;
7048 }
7049 return dependencies->getCount();
7050}
7051
7052/*********************************************************************
7053*********************************************************************/
7054OSArray *
7055OSKext::getDependencies(void)
7056{
7057 return dependencies;
7058}
7059
7060#if PRAGMA_MARK
7061#pragma mark OSMetaClass Support
7062#endif
7063/*********************************************************************
7064*********************************************************************/
7065OSReturn
7066OSKext::addClass(
7067 OSMetaClass * aClass,
7068 uint32_t numClasses)
7069{
7070 OSReturn result = kOSMetaClassNoInsKModSet;
7071
7072 if (!metaClasses) {
7073 metaClasses = OSSet::withCapacity(numClasses);
7074 if (!metaClasses) {
7075 goto finish;
7076 }
7077 }
7078
7079 if (metaClasses->containsObject(aClass)) {
7080 OSKextLog(this,
7081 kOSKextLogWarningLevel |
7082 kOSKextLogLoadFlag,
7083 "Notice - kext %s has already registered class %s.",
7084 getIdentifierCString(),
7085 aClass->getClassName());
7086 result = kOSReturnSuccess;
7087 goto finish;
7088 }
7089
7090 if (!metaClasses->setObject(aClass)) {
7091 goto finish;
7092 } else {
7093 OSKextLog(this,
7094 kOSKextLogDetailLevel |
7095 kOSKextLogLoadFlag,
7096 "Kext %s registered class %s.",
7097 getIdentifierCString(),
7098 aClass->getClassName());
7099 }
7100
7101 if (!flags.autounloadEnabled) {
7102 const OSMetaClass * metaScan = NULL; // do not release
7103
7104 for (metaScan = aClass; metaScan; metaScan = metaScan->getSuperClass()) {
7105 if (metaScan == OSTypeID(IOService)) {
7106
7107 OSKextLog(this,
7108 kOSKextLogProgressLevel |
7109 kOSKextLogLoadFlag,
7110 "Kext %s has IOService subclass %s; enabling autounload.",
7111 getIdentifierCString(),
7112 aClass->getClassName());
7113
7114 flags.autounloadEnabled = 1;
7115 break;
7116 }
7117 }
7118 }
7119
6d2010ae
A
7120 notifyAddClassObservers(this, aClass, flags);
7121
b0d623f7
A
7122 result = kOSReturnSuccess;
7123
7124finish:
7125 if (result != kOSReturnSuccess) {
7126 OSKextLog(this,
7127 kOSKextLogErrorLevel |
7128 kOSKextLogLoadFlag,
7129 "Kext %s failed to register class %s.",
7130 getIdentifierCString(),
7131 aClass->getClassName());
7132 }
7133
7134 return result;
7135}
7136
7137/*********************************************************************
7138*********************************************************************/
7139OSReturn
7140OSKext::removeClass(
7141 OSMetaClass * aClass)
7142{
7143 OSReturn result = kOSMetaClassNoKModSet;
7144
7145 if (!metaClasses) {
7146 goto finish;
7147 }
7148
7149 if (!metaClasses->containsObject(aClass)) {
7150 OSKextLog(this,
7151 kOSKextLogWarningLevel |
7152 kOSKextLogLoadFlag,
7153 "Notice - kext %s asked to unregister unknown class %s.",
7154 getIdentifierCString(),
7155 aClass->getClassName());
7156 result = kOSReturnSuccess;
7157 goto finish;
7158 }
7159
7160 OSKextLog(this,
7161 kOSKextLogDetailLevel |
7162 kOSKextLogLoadFlag,
7163 "Kext %s unregistering class %s.",
7164 getIdentifierCString(),
7165 aClass->getClassName());
7166
7167 metaClasses->removeObject(aClass);
7168
6d2010ae
A
7169 notifyRemoveClassObservers(this, aClass, flags);
7170
b0d623f7
A
7171 result = kOSReturnSuccess;
7172
7173finish:
7174 if (result != kOSReturnSuccess) {
7175 OSKextLog(this,
7176 kOSKextLogErrorLevel |
7177 kOSKextLogLoadFlag,
7178 "Failed to unregister kext %s class %s.",
7179 getIdentifierCString(),
7180 aClass->getClassName());
7181 }
7182 return result;
7183}
7184
7185/*********************************************************************
7186*********************************************************************/
7187OSSet *
7188OSKext::getMetaClasses(void)
7189{
7190 return metaClasses;
7191}
7192
7193/*********************************************************************
7194*********************************************************************/
7195bool
7196OSKext::hasOSMetaClassInstances(void)
7197{
7198 bool result = false;
7199 OSCollectionIterator * classIterator = NULL; // must release
7200 OSMetaClass * checkClass = NULL; // do not release
7201
7202 if (!metaClasses) {
7203 goto finish;
7204 }
7205
7206 classIterator = OSCollectionIterator::withCollection(metaClasses);
7207 if (!classIterator) {
7208 // xxx - log alloc failure?
7209 goto finish;
7210 }
7211 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
7212 if (checkClass->getInstanceCount()) {
7213 result = true;
7214 goto finish;
7215 }
7216 }
7217
7218finish:
7219
7220 OSSafeRelease(classIterator);
7221 return result;
7222}
7223
7224/*********************************************************************
7225*********************************************************************/
7226/* static */
7227void
7228OSKext::reportOSMetaClassInstances(
7229 const char * kextIdentifier,
7230 OSKextLogSpec msgLogSpec)
7231{
7232 OSKext * theKext = NULL; // must release
7233
7234 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
7235 if (!theKext) {
7236 goto finish;
7237 }
7238
7239 theKext->reportOSMetaClassInstances(msgLogSpec);
7240finish:
7241 OSSafeRelease(theKext);
7242 return;
7243}
7244
7245/*********************************************************************
7246*********************************************************************/
7247void
7248OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
7249{
7250 OSCollectionIterator * classIterator = NULL; // must release
7251 OSMetaClass * checkClass = NULL; // do not release
7252
7253 if (!metaClasses) {
7254 goto finish;
7255 }
7256
7257 classIterator = OSCollectionIterator::withCollection(metaClasses);
7258 if (!classIterator) {
7259 goto finish;
7260 }
7261 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
7262 if (checkClass->getInstanceCount()) {
7263 OSKextLog(this,
7264 msgLogSpec,
7265 " Kext %s class %s has %d instance%s.",
7266 getIdentifierCString(),
7267 checkClass->getClassName(),
7268 checkClass->getInstanceCount(),
7269 checkClass->getInstanceCount() == 1 ? "" : "s");
7270 }
7271 }
7272
7273finish:
7274 OSSafeRelease(classIterator);
7275 return;
7276}
7277
7278#if PRAGMA_MARK
7279#pragma mark User-Space Requests
7280#endif
7281/*********************************************************************
7282* XXX - this function is a big ugly mess
7283*********************************************************************/
7284/* static */
7285OSReturn
7286OSKext::handleRequest(
7287 host_priv_t hostPriv,
7288 OSKextLogSpec clientLogFilter,
7289 char * requestBuffer,
7290 uint32_t requestLength,
7291 char ** responseOut,
7292 uint32_t * responseLengthOut,
7293 char ** logInfoOut,
7294 uint32_t * logInfoLengthOut)
7295{
7296 OSReturn result = kOSReturnError;
7297 kern_return_t kmem_result = KERN_FAILURE;
7298
7299 char * response = NULL; // returned by reference
7300 uint32_t responseLength = 0;
7301
6d2010ae 7302 OSObject * parsedXML = NULL; // must release
b0d623f7
A
7303 OSDictionary * requestDict = NULL; // do not release
7304 OSString * errorString = NULL; // must release
7305
7306 OSData * responseData = NULL; // must release
6d2010ae 7307 OSObject * responseObject = NULL; // must release
b0d623f7
A
7308
7309 OSSerialize * serializer = NULL; // must release
7310
7311 OSArray * logInfoArray = NULL; // must release
7312
7313 OSString * predicate = NULL; // do not release
7314 OSString * kextIdentifier = NULL; // do not release
7315 OSArray * kextIdentifiers = NULL; // do not release
7316 OSKext * theKext = NULL; // do not release
7317 OSBoolean * boolArg = NULL; // do not release
7318
316670eb
A
7319 bool hideTheSlide = false;
7320
b0d623f7
A
7321 IORecursiveLockLock(sKextLock);
7322
7323 if (responseOut) {
7324 *responseOut = NULL;
7325 *responseLengthOut = 0;
7326 }
7327 if (logInfoOut) {
7328 *logInfoOut = NULL;
7329 *logInfoLengthOut = 0;
7330 }
7331
7332 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
7333
7334 /* XML must be nul-terminated.
7335 */
7336 if (requestBuffer[requestLength - 1] != '\0') {
7337 OSKextLog(/* kext */ NULL,
7338 kOSKextLogErrorLevel |
7339 kOSKextLogIPCFlag,
7340 "Invalid request from user space (not nul-terminated).");
7341 result = kOSKextReturnBadData;
7342 goto finish;
7343 }
7344 parsedXML = OSUnserializeXML((const char *)requestBuffer, &errorString);
7345 if (parsedXML) {
7346 requestDict = OSDynamicCast(OSDictionary, parsedXML);
7347 }
7348 if (!requestDict) {
7349 const char * errorCString = "(unknown error)";
7350
7351 if (errorString && errorString->getCStringNoCopy()) {
7352 errorCString = errorString->getCStringNoCopy();
7353 } else if (parsedXML) {
7354 errorCString = "not a dictionary";
7355 }
7356 OSKextLog(/* kext */ NULL,
7357 kOSKextLogErrorLevel |
7358 kOSKextLogIPCFlag,
7359 "Error unserializing request from user space: %s.",
7360 errorCString);
7361 result = kOSKextReturnSerialization;
7362 goto finish;
7363 }
7364
7365 predicate = _OSKextGetRequestPredicate(requestDict);
7366 if (!predicate) {
7367 OSKextLog(/* kext */ NULL,
7368 kOSKextLogErrorLevel |
7369 kOSKextLogIPCFlag,
7370 "Recieved kext request from user space with no predicate.");
7371 result = kOSKextReturnInvalidArgument;
7372 goto finish;
7373 }
7374
7375 OSKextLog(/* kext */ NULL,
7376 kOSKextLogDebugLevel |
7377 kOSKextLogIPCFlag,
7378 "Received '%s' request from user space.",
7379 predicate->getCStringNoCopy());
7380
7381 result = kOSKextReturnNotPrivileged;
7382 if (hostPriv == HOST_PRIV_NULL) {
316670eb
A
7383 if (sPrelinkBoot) {
7384 hideTheSlide = true;
7385
7386 /* must be root to use these kext requests */
7387 if (predicate->isEqualTo(kKextRequestPredicateGetKernelLoadAddress) ) {
7388 OSKextLog(/* kext */ NULL,
7389 kOSKextLogErrorLevel |
7390 kOSKextLogIPCFlag,
7391 "Access Failure - must be root user.");
7392 goto finish;
7393 }
7394 }
7395 }
b0d623f7
A
7396
7397 /* Get common args in anticipation of use.
7398 */
7399 kextIdentifier = OSDynamicCast(OSString, _OSKextGetRequestArgument(
7400 requestDict, kKextRequestArgumentBundleIdentifierKey));
7401 kextIdentifiers = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
7402 requestDict, kKextRequestArgumentBundleIdentifierKey));
7403 if (kextIdentifier) {
7404 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
7405 }
7406 boolArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
7407 requestDict, kKextRequestArgumentValueKey));
7408
7409 result = kOSKextReturnInvalidArgument;
7410
7411 if (predicate->isEqualTo(kKextRequestPredicateStart)) {
7412 if (!kextIdentifier) {
7413 OSKextLog(/* kext */ NULL,
7414 kOSKextLogErrorLevel |
7415 kOSKextLogIPCFlag,
7416 "Invalid arguments to kext start request.");
7417 } else if (!theKext) {
7418 OSKextLog(/* kext */ NULL,
7419 kOSKextLogErrorLevel |
7420 kOSKextLogIPCFlag,
7421 "Kext %s not found for start request.",
7422 kextIdentifier->getCStringNoCopy());
7423 result = kOSKextReturnNotFound;
7424 } else {
7425 result = theKext->start();
7426 }
7427
7428 } else if (predicate->isEqualTo(kKextRequestPredicateStop)) {
7429 if (!kextIdentifier) {
7430 OSKextLog(/* kext */ NULL,
7431 kOSKextLogErrorLevel |
7432 kOSKextLogIPCFlag,
7433 "Invalid arguments to kext stop request.");
7434 } else if (!theKext) {
7435 OSKextLog(/* kext */ NULL,
7436 kOSKextLogErrorLevel |
7437 kOSKextLogIPCFlag,
7438 "Kext %s not found for stop request.",
7439 kextIdentifier->getCStringNoCopy());
7440 result = kOSKextReturnNotFound;
7441 } else {
7442 result = theKext->stop();
7443 }
7444
7445 } else if (predicate->isEqualTo(kKextRequestPredicateUnload)) {
7446 if (!kextIdentifier) {
7447 OSKextLog(/* kext */ NULL,
7448 kOSKextLogErrorLevel |
7449 kOSKextLogIPCFlag,
7450 "Invalid arguments to kext unload request.");
7451 } else if (!theKext) {
7452 OSKextLog(/* kext */ NULL,
7453 kOSKextLogErrorLevel |
7454 kOSKextLogIPCFlag,
7455 "Kext %s not found for unload request.",
7456 kextIdentifier->getCStringNoCopy());
7457 result = kOSKextReturnNotFound;
7458 } else {
7459 OSBoolean * terminateFlag = OSDynamicCast(OSBoolean,
7460 _OSKextGetRequestArgument(requestDict,
7461 kKextRequestArgumentTerminateIOServicesKey));
7462 result = OSKext::removeKext(theKext, terminateFlag == kOSBooleanTrue);
7463 }
7464
7465 } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
7466 result = OSKext::dispatchResource(requestDict);
7467
7468 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
6d2010ae
A
7469 OSBoolean * delayAutounloadBool = NULL;
7470 OSObject * infoKeysRaw = NULL;
7471 OSArray * infoKeys = NULL;
7472 uint32_t infoKeysCount = 0;
b0d623f7
A
7473
7474 delayAutounloadBool = OSDynamicCast(OSBoolean,
7475 _OSKextGetRequestArgument(requestDict,
7476 kKextRequestArgumentDelayAutounloadKey));
7477
7478 /* If asked to delay autounload, reset the timer if it's currently set.
7479 * (That is, don't schedule an unload if one isn't already pending.
7480 */
7481 if (delayAutounloadBool == kOSBooleanTrue) {
7482 OSKext::considerUnloads(/* rescheduleOnly? */ true);
7483 }
7484
6d2010ae
A
7485 infoKeysRaw = _OSKextGetRequestArgument(requestDict,
7486 kKextRequestArgumentInfoKeysKey);
7487 infoKeys = OSDynamicCast(OSArray, infoKeysRaw);
7488 if (infoKeysRaw && !infoKeys) {
7489 OSKextLog(/* kext */ NULL,
7490 kOSKextLogErrorLevel |
7491 kOSKextLogIPCFlag,
7492 "Invalid arguments to kext info request.");
7493 goto finish;
7494 }
7495
7496 if (infoKeys) {
7497 infoKeysCount = infoKeys->getCount();
7498 for (uint32_t i = 0; i < infoKeysCount; i++) {
7499 if (!OSDynamicCast(OSString, infoKeys->getObject(i))) {
7500 OSKextLog(/* kext */ NULL,
7501 kOSKextLogErrorLevel |
7502 kOSKextLogIPCFlag,
7503 "Invalid arguments to kext info request.");
7504 goto finish;
7505 }
7506 }
7507 }
7508
7509 responseObject = OSKext::copyLoadedKextInfo(kextIdentifiers, infoKeys);
b0d623f7
A
7510 if (!responseObject) {
7511 result = kOSKextReturnInternalError;
7512 } else {
7513 OSKextLog(/* kext */ NULL,
7514 kOSKextLogDebugLevel |
7515 kOSKextLogIPCFlag,
7516 "Returning loaded kext info.");
7517 result = kOSReturnSuccess;
7518 }
7519
7520 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelLoadAddress)) {
7521 OSNumber * addressNum = NULL; // released as responseObject
7522 kernel_segment_command_t * textseg = getsegbyname("__TEXT");
7523
7524 if (!textseg) {
7525 OSKextLog(/* kext */ NULL,
7526 kOSKextLogErrorLevel |
7527 kOSKextLogGeneralFlag | kOSKextLogIPCFlag,
7528 "Can't find text segment for kernel load address.");
7529 result = kOSReturnError;
7530 goto finish;
7531 }
7532
7533 OSKextLog(/* kext */ NULL,
7534 kOSKextLogDebugLevel |
7535 kOSKextLogIPCFlag,
7536 "Returning kernel load address 0x%llx.",
316670eb
A
7537 (unsigned long long) textseg->vmaddr );
7538
b0d623f7
A
7539 addressNum = OSNumber::withNumber((long long unsigned int)textseg->vmaddr,
7540 8 * sizeof(long long unsigned int));
6d2010ae 7541 responseObject = addressNum;
b0d623f7
A
7542 result = kOSReturnSuccess;
7543
b0d623f7
A
7544 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
7545
7546 /* Hand the current sKernelRequests array to the caller
7547 * (who must release it), and make a new one.
7548 */
6d2010ae 7549 responseObject = sKernelRequests;
b0d623f7
A
7550 sKernelRequests = OSArray::withCapacity(0);
7551 sPostedKextLoadIdentifiers->flushCollection();
7552 OSKextLog(/* kext */ NULL,
7553 kOSKextLogDebugLevel |
7554 kOSKextLogIPCFlag,
7555 "Returning kernel requests.");
7556 result = kOSReturnSuccess;
7557
7558 } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
7559
7560 /* Return the set of all requested bundle identifiers */
6d2010ae 7561 responseObject = sAllKextLoadIdentifiers;
b0d623f7
A
7562 responseObject->retain();
7563 OSKextLog(/* kext */ NULL,
7564 kOSKextLogDebugLevel |
7565 kOSKextLogIPCFlag,
7566 "Returning load requests.");
7567 result = kOSReturnSuccess;
7568 }
7569
7570 /**********
7571 * Now we have handle the request, or not. Gather up the response & logging
7572 * info to ship to user space.
7573 *********/
7574
7575 /* Note: Nothing in OSKext is supposed to retain requestDict,
7576 * but you never know....
7577 */
7578 if (requestDict->getRetainCount() > 1) {
7579 OSKextLog(/* kext */ NULL,
7580 kOSKextLogWarningLevel |
7581 kOSKextLogIPCFlag,
7582 "Request from user space still retained by a kext; "
7583 "probable memory leak.");
7584 }
7585
7586 if (responseData && responseObject) {
7587 OSKextLog(/* kext */ NULL,
7588 kOSKextLogErrorLevel |
7589 kOSKextLogIPCFlag,
7590 "Mistakenly generated both data & plist responses to user request "
7591 "(returning only data).");
7592 }
7593
7594 if (responseData && responseData->getLength() && responseOut) {
7595
7596 response = (char *)responseData->getBytesNoCopy();
7597 responseLength = responseData->getLength();
7598 } else if (responseOut && responseObject) {
7599 serializer = OSSerialize::withCapacity(0);
7600 if (!serializer) {
7601 result = kOSKextReturnNoMemory;
7602 goto finish;
7603 }
7604
7605 if (!responseObject->serialize(serializer)) {
7606 OSKextLog(/* kext */ NULL,
7607 kOSKextLogErrorLevel |
7608 kOSKextLogIPCFlag,
7609 "Failed to serialize response to request from user space.");
7610 result = kOSKextReturnSerialization;
7611 goto finish;
7612 }
7613
7614 response = (char *)serializer->text();
7615 responseLength = serializer->getLength();
7616 }
7617
7618 if (responseOut && response) {
7619 char * buffer;
7620
7621 /* This kmem_alloc sets the return value of the function.
7622 */
7623 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer,
7624 responseLength);
7625 if (kmem_result != KERN_SUCCESS) {
7626 OSKextLog(/* kext */ NULL,
7627 kOSKextLogErrorLevel |
7628 kOSKextLogIPCFlag,
7629 "Failed to copy response to request from user space.");
7630 result = kmem_result;
7631 goto finish;
7632 } else {
7633 memcpy(buffer, response, responseLength);
7634 *responseOut = buffer;
7635 *responseLengthOut = responseLength;
7636 }
7637 }
7638
7639finish:
7640
7641 /* Gather up the collected log messages for user space. Any messages
7642 * messages past this call will not make it up as log messages but
7643 * will be in the system log. Note that we ignore the return of the
7644 * serialize; it has no bearing on the operation at hand even if we
7645 * fail to get the log messages.
7646 */
7647 logInfoArray = OSKext::clearUserSpaceLogFilter();
7648
7649 if (logInfoArray && logInfoOut && logInfoLengthOut) {
7650 (void)OSKext::serializeLogInfo(logInfoArray,
7651 logInfoOut, logInfoLengthOut);
7652 }
7653
7654 IORecursiveLockUnlock(sKextLock);
7655
6d2010ae 7656 OSSafeRelease(parsedXML);
b0d623f7
A
7657 OSSafeRelease(errorString);
7658 OSSafeRelease(responseData);
7659 OSSafeRelease(responseObject);
7660 OSSafeRelease(serializer);
7661 OSSafeRelease(logInfoArray);
7662
7663 return result;
7664}
7665
7666/*********************************************************************
7667*********************************************************************/
7668/* static */
6d2010ae
A
7669OSDictionary *
7670OSKext::copyLoadedKextInfo(
7671 OSArray * kextIdentifiers,
316670eb 7672 OSArray * infoKeys)
b0d623f7 7673{
6d2010ae 7674 OSDictionary * result = NULL;
b0d623f7
A
7675 OSDictionary * kextInfo = NULL; // must release
7676 uint32_t count, i;
7677 uint32_t idCount = 0;
7678 uint32_t idIndex = 0;
7679
7680 IORecursiveLockLock(sKextLock);
7681
7682 /* Empty list of bundle ids is equivalent to no list (get all).
7683 */
7684 if (kextIdentifiers && !kextIdentifiers->getCount()) {
7685 kextIdentifiers = NULL;
7686 } else if (kextIdentifiers) {
7687 idCount = kextIdentifiers->getCount();
7688 }
7689
6d2010ae
A
7690 /* Same for keys.
7691 */
7692 if (infoKeys && !infoKeys->getCount()) {
7693 infoKeys = NULL;
7694 }
7695
b0d623f7 7696 count = sLoadedKexts->getCount();
6d2010ae 7697 result = OSDictionary::withCapacity(count);
b0d623f7
A
7698 if (!result) {
7699 goto finish;
7700 }
7701 for (i = 0; i < count; i++) {
7702 OSKext * thisKext = NULL; // do not release
7703 Boolean includeThis = true;
7704
7705 if (kextInfo) {
7706 kextInfo->release();
7707 kextInfo = NULL;
7708 }
7709 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
7710 if (!thisKext) {
7711 continue;
7712 }
7713
7714 /* Skip current kext if we have a list of bundle IDs and
7715 * it isn't in the list.
7716 */
7717 if (kextIdentifiers) {
7718 const OSString * thisKextID = thisKext->getIdentifier();
7719
7720 includeThis = false;
7721
7722 for (idIndex = 0; idIndex < idCount; idIndex++) {
7723 const OSString * thisRequestID = OSDynamicCast(OSString,
7724 kextIdentifiers->getObject(idIndex));
7725 if (thisKextID->isEqualTo(thisRequestID)) {
7726 includeThis = true;
7727 break;
7728 }
7729 }
7730 }
7731
7732 if (!includeThis) {
7733 continue;
7734 }
7735
6d2010ae
A
7736 kextInfo = thisKext->copyInfo(infoKeys);
7737 if (kextInfo) {
7738 result->setObject(thisKext->getIdentifier(), kextInfo);
7739 }
b0d623f7
A
7740 }
7741
7742finish:
7743 IORecursiveLockUnlock(sKextLock);
7744
7745 if (kextInfo) kextInfo->release();
7746
7747 return result;
7748}
7749
7750/*********************************************************************
6d2010ae
A
7751* Any info that needs to do allocations must goto finish on alloc
7752* failure. Info that is just a lookup should just not set the object
7753* if the info does not exist.
b0d623f7
A
7754*********************************************************************/
7755#define _OSKextLoadInfoDictCapacity (12)
7756
7757OSDictionary *
6d2010ae
A
7758OSKext::copyInfo(OSArray * infoKeys)
7759{
7760 OSDictionary * result = NULL;
7761 bool success = false;
7762 OSData * headerData = NULL; // must release
7763 OSNumber * cpuTypeNumber = NULL; // must release
7764 OSNumber * cpuSubtypeNumber = NULL; // must release
7765 OSString * versionString = NULL; // do not release
7766 uint32_t executablePathCStringSize = 0;
7767 char * executablePathCString = NULL; // must release
7768 OSString * executablePathString = NULL; // must release
7769 OSData * uuid = NULL; // must release
7770 OSNumber * scratchNumber = NULL; // must release
7771 OSArray * dependencyLoadTags = NULL; // must release
7772 OSCollectionIterator * metaClassIterator = NULL; // must release
7773 OSArray * metaClassInfo = NULL; // must release
7774 OSDictionary * metaClassDict = NULL; // must release
7775 OSMetaClass * thisMetaClass = NULL; // do not release
7776 OSString * metaClassName = NULL; // must release
7777 OSString * superclassName = NULL; // must release
b0d623f7
A
7778 uint32_t count, i;
7779
7780 result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
7781 if (!result) {
7782 goto finish;
7783 }
7784
6d2010ae
A
7785
7786 /* Empty keys means no keys, but NULL is quicker to check.
7787 */
7788 if (infoKeys && !infoKeys->getCount()) {
7789 infoKeys = NULL;
7790 }
7791
7792 /* Headers, CPU type, and CPU subtype.
b0d623f7 7793 */
6d2010ae
A
7794 if (!infoKeys ||
7795 _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey) ||
7796 _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey) ||
7797 _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey))
7798 {
7799
7800 if (linkedExecutable && !isInterface()) {
7801
7802 kernel_mach_header_t *kext_mach_hdr = (kernel_mach_header_t *)
7803 linkedExecutable->getBytesNoCopy();
7804
7805 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey)) {
316670eb
A
7806 kernel_mach_header_t * temp_kext_mach_hdr;
7807 struct load_command * lcp;
7808
6d2010ae
A
7809 headerData = OSData::withBytes(kext_mach_hdr,
7810 (u_int) (sizeof(*kext_mach_hdr) + kext_mach_hdr->sizeofcmds));
7811 if (!headerData) {
7812 goto finish;
7813 }
316670eb
A
7814
7815 // unslide any vmaddrs we return to userspace - 10726716
7816 temp_kext_mach_hdr = (kernel_mach_header_t *)
7817 headerData->getBytesNoCopy();
7818 if (temp_kext_mach_hdr == NULL) {
7819 goto finish;
7820 }
7821
7822 lcp = (struct load_command *) (temp_kext_mach_hdr + 1);
7823 for (i = 0; i < temp_kext_mach_hdr->ncmds; i++) {
7824 if (lcp->cmd == LC_SEGMENT_KERNEL) {
7825 kernel_segment_command_t * scp;
7826
7827 scp = (kernel_segment_command_t *) lcp;
7828 // 10543468 - if we jettisoned __LINKEDIT clear size info
7829 if (flags.jettisonLinkeditSeg) {
7830 if (strncmp(scp->segname, SEG_LINKEDIT, sizeof(scp->segname)) == 0) {
7831 scp->vmsize = 0;
7832 scp->fileoff = 0;
7833 scp->filesize = 0;
7834 }
7835 }
7836#if 0
7837 OSKextLog(/* kext */ NULL,
7838 kOSKextLogErrorLevel |
7839 kOSKextLogGeneralFlag,
7840 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
7841 __FUNCTION__, scp->segname, scp->vmaddr,
7842 VM_KERNEL_UNSLIDE(scp->vmaddr),
7843 scp->vmsize, scp->nsects);
7844#endif
7845 scp->vmaddr = VM_KERNEL_UNSLIDE(scp->vmaddr);
7846 }
7847 lcp = (struct load_command *)((caddr_t)lcp + lcp->cmdsize);
7848 }
6d2010ae
A
7849 result->setObject(kOSBundleMachOHeadersKey, headerData);
7850 }
7851
7852 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey)) {
7853 cpuTypeNumber = OSNumber::withNumber(
7854 (uint64_t) kext_mach_hdr->cputype,
7855 8 * sizeof(kext_mach_hdr->cputype));
7856 if (!cpuTypeNumber) {
7857 goto finish;
7858 }
7859 result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber);
7860 }
b0d623f7 7861
6d2010ae
A
7862 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
7863 cpuSubtypeNumber = OSNumber::withNumber(
7864 (uint64_t) kext_mach_hdr->cpusubtype,
7865 8 * sizeof(kext_mach_hdr->cpusubtype));
7866 if (!cpuSubtypeNumber) {
7867 goto finish;
7868 }
7869 result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber);
7870 }
b0d623f7
A
7871 }
7872 }
7873
6d2010ae 7874 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
b0d623f7
A
7875 */
7876 result->setObject(kCFBundleIdentifierKey, bundleID);
7877
7878 /* CFBundleVersion.
7879 */
6d2010ae
A
7880 if (!infoKeys || _OSArrayContainsCString(infoKeys, kCFBundleVersionKey)) {
7881 versionString = OSDynamicCast(OSString,
7882 getPropertyForHostArch(kCFBundleVersionKey));
7883 if (versionString) {
7884 result->setObject(kCFBundleVersionKey, versionString);
7885 }
b0d623f7
A
7886 }
7887
7888 /* OSBundleCompatibleVersion.
7889 */
6d2010ae
A
7890 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCompatibleVersionKey)) {
7891 versionString = OSDynamicCast(OSString,
7892 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
7893 if (versionString) {
7894 result->setObject(kOSBundleCompatibleVersionKey, versionString);
7895 }
b0d623f7
A
7896 }
7897
7898 /* Path.
7899 */
6d2010ae
A
7900 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePathKey)) {
7901 if (path) {
7902 result->setObject(kOSBundlePathKey, path);
7903 }
b0d623f7
A
7904 }
7905
6d2010ae
A
7906
7907 /* OSBundleExecutablePath.
b0d623f7 7908 */
6d2010ae
A
7909 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecutablePathKey)) {
7910 if (path && executableRelPath) {
7911
7912 uint32_t pathLength = path->getLength(); // gets incremented below
7913
7914 // +1 for slash, +1 for \0
7915 executablePathCStringSize = pathLength + executableRelPath->getLength() + 2;
7916
7917 executablePathCString = (char *)kalloc((executablePathCStringSize) *
7918 sizeof(char)); // +1 for \0
7919 if (!executablePathCString) {
7920 goto finish;
7921 }
7922 strlcpy(executablePathCString, path->getCStringNoCopy(),
7923 executablePathCStringSize);
7924 executablePathCString[pathLength++] = '/';
7925 executablePathCString[pathLength++] = '\0';
7926 strlcat(executablePathCString, executableRelPath->getCStringNoCopy(),
7927 executablePathCStringSize);
7928
7929 executablePathString = OSString::withCString(executablePathCString);
7930
7931 if (!executablePathCString) {
7932 goto finish;
7933 }
7934
7935 result->setObject(kOSBundleExecutablePathKey, executablePathString);
7936 }
7937 }
7938
7939 /* UUID, if the kext has one.
7940 */
7941 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleUUIDKey)) {
7942 uuid = copyUUID();
7943 if (uuid) {
7944 result->setObject(kOSBundleUUIDKey, uuid);
7945 }
b0d623f7
A
7946 }
7947
7948 /*****
7949 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
7950 */
6d2010ae
A
7951 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleUUIDKey)) {
7952 result->setObject(kOSKernelResourceKey,
7953 isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
7954 }
b0d623f7 7955
6d2010ae
A
7956 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleIsInterfaceKey)) {
7957 result->setObject(kOSBundleIsInterfaceKey,
7958 isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
7959 }
b0d623f7 7960
6d2010ae
A
7961 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePrelinkedKey)) {
7962 result->setObject(kOSBundlePrelinkedKey,
7963 isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
7964 }
b0d623f7 7965
6d2010ae
A
7966 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleStartedKey)) {
7967 result->setObject(kOSBundleStartedKey,
7968 isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
7969 }
b0d623f7
A
7970
7971 /* LoadTag (Index).
7972 */
6d2010ae
A
7973 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadTagKey)) {
7974 scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
7975 /* numBits */ 8 * sizeof(loadTag));
7976 if (!scratchNumber) {
7977 goto finish;
7978 }
b0d623f7
A
7979 result->setObject(kOSBundleLoadTagKey, scratchNumber);
7980 OSSafeReleaseNULL(scratchNumber);
7981 }
7982
7983 /* LoadAddress, LoadSize.
7984 */
6d2010ae
A
7985 if (!infoKeys ||
7986 _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey) ||
7987 _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey) ||
7988 _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey))
7989 {
7990 if (isInterface() || linkedExecutable) {
7991 /* These go to userspace via serialization, so we don't want any doubts
7992 * about their size.
b0d623f7 7993 */
6d2010ae
A
7994 uint64_t loadAddress = 0;
7995 uint32_t loadSize = 0;
7996 uint32_t wiredSize = 0;
7997
7998 /* Interfaces always report 0 load address & size.
7999 * Just the way they roll.
8000 *
8001 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
8002 * xxx - shouldn't have one!
8003 */
8004 if (linkedExecutable /* && !isInterface() */) {
8005 loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
316670eb 8006 loadAddress = VM_KERNEL_UNSLIDE(loadAddress);
6d2010ae
A
8007 loadSize = linkedExecutable->getLength();
8008
8009 /* If we have a kmod_info struct, calculated the wired size
8010 * from that. Otherwise it's the full load size.
8011 */
8012 if (kmod_info) {
8013 wiredSize = loadSize - kmod_info->hdr_size;
8014 } else {
8015 wiredSize = loadSize;
8016 }
b0d623f7 8017 }
b0d623f7 8018
6d2010ae
A
8019 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey)) {
8020 scratchNumber = OSNumber::withNumber(
8021 (unsigned long long)(loadAddress),
8022 /* numBits */ 8 * sizeof(loadAddress));
8023 if (!scratchNumber) {
8024 goto finish;
8025 }
8026 result->setObject(kOSBundleLoadAddressKey, scratchNumber);
8027 OSSafeReleaseNULL(scratchNumber);
8028 }
8029 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey)) {
8030 scratchNumber = OSNumber::withNumber(
8031 (unsigned long long)(loadSize),
8032 /* numBits */ 8 * sizeof(loadSize));
8033 if (!scratchNumber) {
8034 goto finish;
8035 }
8036 result->setObject(kOSBundleLoadSizeKey, scratchNumber);
8037 OSSafeReleaseNULL(scratchNumber);
8038 }
8039 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
8040 scratchNumber = OSNumber::withNumber(
8041 (unsigned long long)(wiredSize),
8042 /* numBits */ 8 * sizeof(wiredSize));
8043 if (!scratchNumber) {
8044 goto finish;
8045 }
8046 result->setObject(kOSBundleWiredSizeKey, scratchNumber);
8047 OSSafeReleaseNULL(scratchNumber);
8048 }
b0d623f7
A
8049 }
8050 }
6d2010ae 8051
b0d623f7
A
8052 /* OSBundleDependencies. In descending order for
8053 * easy compatibility with kextstat(8).
8054 */
6d2010ae
A
8055 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleDependenciesKey)) {
8056 if ((count = getNumDependencies())) {
8057 dependencyLoadTags = OSArray::withCapacity(count);
8058 result->setObject(kOSBundleDependenciesKey, dependencyLoadTags);
b0d623f7 8059
6d2010ae
A
8060 i = count - 1;
8061 do {
8062 OSKext * dependency = OSDynamicCast(OSKext,
8063 dependencies->getObject(i));
b0d623f7 8064
6d2010ae
A
8065 OSSafeReleaseNULL(scratchNumber);
8066
8067 if (!dependency) {
8068 continue;
8069 }
8070 scratchNumber = OSNumber::withNumber(
8071 (unsigned long long)dependency->getLoadTag(),
8072 /* numBits*/ 8 * sizeof(loadTag));
8073 if (!scratchNumber) {
8074 goto finish;
8075 }
b0d623f7 8076 dependencyLoadTags->setObject(scratchNumber);
6d2010ae
A
8077 } while (i--);
8078 }
b0d623f7
A
8079 }
8080
8081 OSSafeReleaseNULL(scratchNumber);
8082
8083 /* OSBundleMetaClasses.
8084 */
6d2010ae
A
8085 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleClassesKey)) {
8086 if (metaClasses && metaClasses->getCount()) {
8087 metaClassIterator = OSCollectionIterator::withCollection(metaClasses);
8088 metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
8089 if (!metaClassIterator || !metaClassInfo) {
8090 goto finish;
8091 }
8092 result->setObject(kOSBundleClassesKey, metaClassInfo);
b0d623f7 8093
6d2010ae
A
8094 while ( (thisMetaClass = OSDynamicCast(OSMetaClass,
8095 metaClassIterator->getNextObject())) ) {
b0d623f7 8096
316670eb
A
8097 OSSafeReleaseNULL(metaClassDict);
8098 OSSafeReleaseNULL(scratchNumber);
8099 OSSafeReleaseNULL(metaClassName);
8100 OSSafeReleaseNULL(superclassName);
b0d623f7 8101
6d2010ae
A
8102 metaClassDict = OSDictionary::withCapacity(3);
8103 if (!metaClassDict) {
8104 goto finish;
8105 }
b0d623f7 8106
6d2010ae
A
8107 metaClassName = OSString::withCString(thisMetaClass->getClassName());
8108 if (thisMetaClass->getSuperClass()) {
8109 superclassName = OSString::withCString(
8110 thisMetaClass->getSuperClass()->getClassName());
8111 }
8112 scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
8113 8 * sizeof(unsigned int));
8114
8115 /* Bail if any of the essentials is missing. The root class lacks a superclass,
8116 * of course.
8117 */
8118 if (!metaClassDict || !metaClassName || !scratchNumber) {
8119 goto finish;
8120 }
b0d623f7 8121
6d2010ae
A
8122 metaClassInfo->setObject(metaClassDict);
8123 metaClassDict->setObject(kOSMetaClassNameKey, metaClassName);
8124 if (superclassName) {
8125 metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName);
8126 }
8127 metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber);
b0d623f7 8128 }
b0d623f7
A
8129 }
8130 }
8131
8132 /* OSBundleRetainCount.
8133 */
6d2010ae
A
8134 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleRetainCountKey)) {
8135 OSSafeReleaseNULL(scratchNumber);
8136 {
8137 int kextRetainCount = getRetainCount() - 1;
8138 if (isLoaded()) {
8139 kextRetainCount--;
8140 }
8141 scratchNumber = OSNumber::withNumber(
8142 (int)kextRetainCount,
8143 /* numBits*/ 8 * sizeof(int));
8144 if (scratchNumber) {
8145 result->setObject(kOSBundleRetainCountKey, scratchNumber);
8146 }
b0d623f7
A
8147 }
8148 }
8149
8150 success = true;
6d2010ae 8151
b0d623f7 8152finish:
6d2010ae 8153 OSSafeRelease(headerData);
b0d623f7
A
8154 OSSafeRelease(cpuTypeNumber);
8155 OSSafeRelease(cpuSubtypeNumber);
6d2010ae
A
8156 OSSafeRelease(executablePathString);
8157 if (executablePathString) kfree(executablePathCString, executablePathCStringSize);
b0d623f7
A
8158 OSSafeRelease(uuid);
8159 OSSafeRelease(scratchNumber);
8160 OSSafeRelease(dependencyLoadTags);
8161 OSSafeRelease(metaClassIterator);
8162 OSSafeRelease(metaClassInfo);
8163 OSSafeRelease(metaClassDict);
8164 OSSafeRelease(metaClassName);
8165 OSSafeRelease(superclassName);
8166 if (!success) {
8167 OSSafeReleaseNULL(result);
8168 }
8169 return result;
8170}
8171
6d2010ae 8172/*********************************************************************
316670eb 8173 *********************************************************************/
b0d623f7
A
8174/* static */
8175OSReturn
8176OSKext::requestResource(
8177 const char * kextIdentifierCString,
8178 const char * resourceNameCString,
8179 OSKextRequestResourceCallback callback,
8180 void * context,
8181 OSKextRequestTag * requestTagOut)
8182{
8183 OSReturn result = kOSReturnError;
8184 OSKext * callbackKext = NULL; // must release (looked up)
8185
8186 OSKextRequestTag requestTag = -1;
8187 OSNumber * requestTagNum = NULL; // must release
8188
8189 OSDictionary * requestDict = NULL; // must release
8190 OSString * kextIdentifier = NULL; // must release
8191 OSString * resourceName = NULL; // must release
8192
8193 OSDictionary * callbackRecord = NULL; // must release
8194 OSData * callbackWrapper = NULL; // must release
8195
8196 OSData * contextWrapper = NULL; // must release
8197
8198 IORecursiveLockLock(sKextLock);
8199
8200 if (requestTagOut) {
8201 *requestTagOut = kOSKextRequestTagInvalid;
8202 }
8203
6d2010ae
A
8204 /* If requests to user space are disabled, don't go any further */
8205 if (!sKernelRequestsEnabled) {
8206 OSKextLog(/* kext */ NULL,
8207 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
8208 "Can't request resource %s for %s - requests to user space are disabled.",
316670eb
A
8209 resourceNameCString,
8210 kextIdentifierCString);
6d2010ae
A
8211 result = kOSKextReturnDisabled;
8212 goto finish;
8213 }
8214
b0d623f7
A
8215 if (!kextIdentifierCString || !resourceNameCString || !callback) {
8216 result = kOSKextReturnInvalidArgument;
8217 goto finish;
8218 }
8219
8220 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
8221 if (!callbackKext) {
8222 OSKextLog(/* kext */ NULL,
8223 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
8224 "Resource request has bad callback address.");
8225 result = kOSKextReturnInvalidArgument;
8226 goto finish;
8227 }
8228 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
8229 OSKextLog(/* kext */ NULL,
8230 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
8231 "Resource request callback is in a kext that is not started.");
8232 result = kOSKextReturnInvalidArgument;
8233 goto finish;
8234 }
8235
8236 /* Do not allow any new requests to be made on a kext that is unloading.
8237 */
8238 if (callbackKext->flags.stopping) {
8239 result = kOSKextReturnStopping;
8240 goto finish;
8241 }
8242
8243 /* If we're wrapped the next available request tag around to the negative
8244 * numbers, we can't service any more requests.
8245 */
8246 if (sNextRequestTag == kOSKextRequestTagInvalid) {
8247 OSKextLog(/* kext */ NULL,
8248 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
8249 "No more request tags available; restart required.");
8250 result = kOSKextReturnNoResources;
8251 goto finish;
8252 }
8253 requestTag = sNextRequestTag++;
8254
8255 result = _OSKextCreateRequest(kKextRequestPredicateRequestResource,
8256 &requestDict);
8257 if (result != kOSReturnSuccess) {
8258 goto finish;
8259 }
8260
8261 kextIdentifier = OSString::withCString(kextIdentifierCString);
8262 resourceName = OSString::withCString(resourceNameCString);
8263 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
8264 8 * sizeof(requestTag));
8265 if (!kextIdentifier ||
8266 !resourceName ||
8267 !requestTagNum ||
8268 !_OSKextSetRequestArgument(requestDict,
8269 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
8270 !_OSKextSetRequestArgument(requestDict,
8271 kKextRequestArgumentNameKey, resourceName) ||
8272 !_OSKextSetRequestArgument(requestDict,
8273 kKextRequestArgumentRequestTagKey, requestTagNum)) {
8274
8275 result = kOSKextReturnNoMemory;
8276 goto finish;
8277 }
8278
8279 callbackRecord = OSDynamicCast(OSDictionary, requestDict->copyCollection());
8280 if (!callbackRecord) {
8281 result = kOSKextReturnNoMemory;
8282 goto finish;
8283 }
8284 // we validate callback address at call time
8285 callbackWrapper = OSData::withBytes((void *)&callback, sizeof(void *));
8286 if (context) {
8287 contextWrapper = OSData::withBytes((void *)&context, sizeof(void *));
8288 }
8289 if (!callbackWrapper || !_OSKextSetRequestArgument(callbackRecord,
8290 kKextRequestArgumentCallbackKey, callbackWrapper)) {
8291
8292 result = kOSKextReturnNoMemory;
8293 goto finish;
8294 }
8295
8296 if (context) {
8297 if (!contextWrapper || !_OSKextSetRequestArgument(callbackRecord,
8298 kKextRequestArgumentContextKey, contextWrapper)) {
8299
8300 result = kOSKextReturnNoMemory;
8301 goto finish;
8302 }
8303 }
8304
8305 /* Only post the requests after all the other potential failure points
8306 * have been passed.
8307 */
8308 if (!sKernelRequests->setObject(requestDict) ||
8309 !sRequestCallbackRecords->setObject(callbackRecord)) {
8310
8311 result = kOSKextReturnNoMemory;
8312 goto finish;
8313 }
8314
6d2010ae 8315 OSKext::pingKextd();
b0d623f7
A
8316
8317 result = kOSReturnSuccess;
8318 if (requestTagOut) {
8319 *requestTagOut = requestTag;
8320 }
8321
8322finish:
8323
8324 /* If we didn't succeed, yank the request & callback
8325 * from their holding arrays.
8326 */
8327 if (result != kOSReturnSuccess) {
8328 unsigned int index;
8329
8330 index = sKernelRequests->getNextIndexOfObject(requestDict, 0);
8331 if (index != (unsigned int)-1) {
8332 sKernelRequests->removeObject(index);
8333 }
8334 index = sRequestCallbackRecords->getNextIndexOfObject(callbackRecord, 0);
8335 if (index != (unsigned int)-1) {
8336 sRequestCallbackRecords->removeObject(index);
8337 }
8338 }
8339
8340 OSKext::considerUnloads(/* rescheduleOnly? */ true);
8341
8342 IORecursiveLockUnlock(sKextLock);
8343
8344 if (callbackKext) callbackKext->release();
8345 if (requestTagNum) requestTagNum->release();
8346
8347 if (requestDict) requestDict->release();
8348 if (kextIdentifier) kextIdentifier->release();
8349 if (resourceName) resourceName->release();
8350
8351 if (callbackRecord) callbackRecord->release();
8352 if (callbackWrapper) callbackWrapper->release();
8353 if (contextWrapper) contextWrapper->release();
8354
8355 return result;
8356}
8357
8358/*********************************************************************
6d2010ae 8359* Assumes sKextLock is held.
b0d623f7
A
8360*********************************************************************/
8361/* static */
8362OSReturn
8363OSKext::dequeueCallbackForRequestTag(
8364 OSKextRequestTag requestTag,
8365 OSDictionary ** callbackRecordOut)
8366{
8367 OSReturn result = kOSReturnError;
8368 OSNumber * requestTagNum = NULL; // must release
8369
8370 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
8371 8 * sizeof(requestTag));
8372 if (!requestTagNum) {
8373 goto finish;
8374 }
8375
8376 result = OSKext::dequeueCallbackForRequestTag(requestTagNum,
8377 callbackRecordOut);
8378
8379finish:
8380 OSSafeRelease(requestTagNum);
8381
8382 return result;
8383}
8384
8385/*********************************************************************
6d2010ae 8386* Assumes sKextLock is held.
b0d623f7
A
8387*********************************************************************/
8388/* static */
8389OSReturn
8390OSKext::dequeueCallbackForRequestTag(
8391 OSNumber * requestTagNum,
8392 OSDictionary ** callbackRecordOut)
8393{
8394 OSReturn result = kOSKextReturnInvalidArgument;
8395 OSDictionary * callbackRecord = NULL; // retain if matched!
8396 OSNumber * callbackTagNum = NULL; // do not release
8397 unsigned int count, i;
8398
b0d623f7
A
8399 result = kOSReturnError;
8400 count = sRequestCallbackRecords->getCount();
8401 for (i = 0; i < count; i++) {
8402 callbackRecord = OSDynamicCast(OSDictionary,
8403 sRequestCallbackRecords->getObject(i));
8404 if (!callbackRecord) {
8405 goto finish;
8406 }
8407
8408 /* If we don't find a tag, we basically have a leak here. Maybe
8409 * we should just remove it.
8410 */
8411 callbackTagNum = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(
8412 callbackRecord, kKextRequestArgumentRequestTagKey));
8413 if (!callbackTagNum) {
8414 goto finish;
8415 }
8416
8417 /* We could be even more paranoid and check that all the incoming
8418 * args match what's in the callback record.
8419 */
8420 if (callbackTagNum->isEqualTo(requestTagNum)) {
8421 if (callbackRecordOut) {
8422 *callbackRecordOut = callbackRecord;
8423 callbackRecord->retain();
8424 }
8425 sRequestCallbackRecords->removeObject(i);
8426 result = kOSReturnSuccess;
8427 goto finish;
8428 }
8429 }
8430 result = kOSKextReturnNotFound;
8431
8432finish:
b0d623f7
A
8433 return result;
8434}
8435
8436/*********************************************************************
6d2010ae 8437* Assumes sKextLock is held.
b0d623f7
A
8438*********************************************************************/
8439/* static */
8440OSReturn
8441OSKext::dispatchResource(OSDictionary * requestDict)
8442{
8443 OSReturn result = kOSReturnError;
8444 OSDictionary * callbackRecord = NULL; // must release
8445 OSNumber * requestTag = NULL; // do not release
8446 OSNumber * requestResult = NULL; // do not release
8447 OSData * dataObj = NULL; // do not release
8448 uint32_t dataLength = 0;
8449 const void * dataPtr = NULL; // do not free
8450 OSData * callbackWrapper = NULL; // do not release
8451 OSKextRequestResourceCallback callback = NULL;
8452 OSData * contextWrapper = NULL; // do not release
8453 void * context = NULL; // do not free
8454 OSKext * callbackKext = NULL; // must release (looked up)
8455
b0d623f7
A
8456 /* Get the args from the request. Right now we need the tag
8457 * to look up the callback record, and the result for invoking the callback.
8458 */
8459 requestTag = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
8460 kKextRequestArgumentRequestTagKey));
8461 requestResult = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
8462 kKextRequestArgumentResultKey));
8463 if (!requestTag || !requestResult) {
8464 result = kOSKextReturnInvalidArgument;
8465 goto finish;
8466 }
8467
8468 /* Look for a callback record matching this request's tag.
8469 */
8470 result = dequeueCallbackForRequestTag(requestTag, &callbackRecord);
8471 if (result != kOSReturnSuccess) {
8472 goto finish;
8473 }
8474
8475 /*****
8476 * Get the context pointer of the callback record (if there is one).
8477 */
8478 contextWrapper = OSDynamicCast(OSData, _OSKextGetRequestArgument(callbackRecord,
8479 kKextRequestArgumentContextKey));
8480 context = _OSKextExtractPointer(contextWrapper);
8481 if (contextWrapper && !context) {
8482 goto finish;
8483 }
8484
8485 callbackWrapper = OSDynamicCast(OSData,
8486 _OSKextGetRequestArgument(callbackRecord,
8487 kKextRequestArgumentCallbackKey));
8488 callback = (OSKextRequestResourceCallback)
8489 _OSKextExtractPointer(callbackWrapper);
8490 if (!callback) {
8491 goto finish;
8492 }
8493
8494 /* Check for a data obj. We might not have one and that's ok, that means
8495 * we didn't find the requested resource, and we still have to tell the
8496 * caller that via the callback.
8497 */
8498 dataObj = OSDynamicCast(OSData, _OSKextGetRequestArgument(requestDict,
8499 kKextRequestArgumentValueKey));
8500 if (dataObj) {
8501 dataPtr = dataObj->getBytesNoCopy();
8502 dataLength = dataObj->getLength();
8503 }
8504
8505 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
8506 if (!callbackKext) {
8507 OSKextLog(/* kext */ NULL,
8508 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
316670eb 8509 "Can't invoke callback for resource request; ");
b0d623f7
A
8510 goto finish;
8511 }
8512 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
8513 OSKextLog(/* kext */ NULL,
8514 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
316670eb 8515 "Can't invoke kext resource callback; ");
b0d623f7
A
8516 goto finish;
8517 }
8518
8519 (void)callback(requestTag->unsigned32BitValue(),
8520 (OSReturn)requestResult->unsigned32BitValue(),
8521 dataPtr, dataLength, context);
8522
8523 result = kOSReturnSuccess;
8524
8525finish:
8526 if (callbackKext) callbackKext->release();
8527 if (callbackRecord) callbackRecord->release();
8528
b0d623f7
A
8529 return result;
8530}
8531
8532/*********************************************************************
8533*********************************************************************/
8534/* static */
8535void
8536OSKext::invokeRequestCallback(
8537 OSDictionary * callbackRecord,
8538 OSReturn callbackResult)
8539{
8540 OSString * predicate = _OSKextGetRequestPredicate(callbackRecord);
8541 OSNumber * resultNum = NULL; // must release
8542
8543 if (!predicate) {
8544 goto finish;
8545 }
8546
8547 resultNum = OSNumber::withNumber((long long unsigned int)callbackResult,
8548 8 * sizeof(callbackResult));
8549 if (!resultNum) {
8550 goto finish;
8551 }
8552
8553 /* Insert the result into the callback record and dispatch it as if it
8554 * were the reply coming down from user space.
8555 */
8556 _OSKextSetRequestArgument(callbackRecord, kKextRequestArgumentResultKey,
8557 resultNum);
8558
8559 if (predicate->isEqualTo(kKextRequestPredicateRequestResource)) {
8560 /* This removes the pending callback record.
8561 */
8562 OSKext::dispatchResource(callbackRecord);
8563 }
8564
8565finish:
8566 if (resultNum) resultNum->release();
8567 return;
8568}
8569
8570/*********************************************************************
6d2010ae 8571* Assumes sKextLock is held.
b0d623f7
A
8572*********************************************************************/
8573/* static */
8574OSReturn
8575OSKext::cancelRequest(
8576 OSKextRequestTag requestTag,
8577 void ** contextOut)
8578{
8579 OSReturn result = kOSKextReturnNoMemory;
8580 OSDictionary * callbackRecord = NULL; // must release
8581 OSData * contextWrapper = NULL; // do not release
8582
6d2010ae 8583 IORecursiveLockLock(sKextLock);
b0d623f7
A
8584 result = OSKext::dequeueCallbackForRequestTag(requestTag,
8585 &callbackRecord);
6d2010ae
A
8586 IORecursiveLockUnlock(sKextLock);
8587
b0d623f7
A
8588 if (result == kOSReturnSuccess && contextOut) {
8589 contextWrapper = OSDynamicCast(OSData,
8590 _OSKextGetRequestArgument(callbackRecord,
8591 kKextRequestArgumentContextKey));
8592 *contextOut = _OSKextExtractPointer(contextWrapper);
8593 }
8594
8595 if (callbackRecord) callbackRecord->release();
8596
8597 return result;
8598}
8599
8600/*********************************************************************
6d2010ae 8601* Assumes sKextLock is held.
b0d623f7
A
8602*********************************************************************/
8603void
8604OSKext::invokeOrCancelRequestCallbacks(
8605 OSReturn callbackResult,
8606 bool invokeFlag)
8607{
8608 unsigned int count, i;
8609
b0d623f7
A
8610 count = sRequestCallbackRecords->getCount();
8611 if (!count) {
8612 goto finish;
8613 }
8614
8615 i = count - 1;
8616 do {
8617 OSDictionary * request = OSDynamicCast(OSDictionary,
8618 sRequestCallbackRecords->getObject(i));
8619
8620 if (!request) {
8621 continue;
8622 }
8623 OSData * callbackWrapper = OSDynamicCast(OSData,
8624 _OSKextGetRequestArgument(request,
8625 kKextRequestArgumentCallbackKey));
8626
8627 if (!callbackWrapper) {
8628 sRequestCallbackRecords->removeObject(i);
8629 continue;
8630 }
8631
8632 vm_address_t callbackAddress = (vm_address_t)
8633 _OSKextExtractPointer(callbackWrapper);
8634
8635 if ((kmod_info->address <= callbackAddress) &&
8636 (callbackAddress < (kmod_info->address + kmod_info->size))) {
8637
8638 if (invokeFlag) {
8639 /* This removes the callback record.
8640 */
8641 invokeRequestCallback(request, callbackResult);
8642 } else {
8643 sRequestCallbackRecords->removeObject(i);
8644 }
8645 }
8646 } while (i--);
8647
8648finish:
b0d623f7
A
8649 return;
8650}
8651
8652/*********************************************************************
6d2010ae 8653* Assumes sKextLock is held.
b0d623f7
A
8654*********************************************************************/
8655uint32_t
8656OSKext::countRequestCallbacks(void)
8657{
8658 uint32_t result = 0;
8659 unsigned int count, i;
8660
b0d623f7
A
8661 count = sRequestCallbackRecords->getCount();
8662 if (!count) {
8663 goto finish;
8664 }
8665
8666 i = count - 1;
8667 do {
8668 OSDictionary * request = OSDynamicCast(OSDictionary,
8669 sRequestCallbackRecords->getObject(i));
8670
8671 if (!request) {
8672 continue;
8673 }
8674 OSData * callbackWrapper = OSDynamicCast(OSData,
8675 _OSKextGetRequestArgument(request,
8676 kKextRequestArgumentCallbackKey));
8677
8678 if (!callbackWrapper) {
8679 continue;
8680 }
8681
8682 vm_address_t callbackAddress = (vm_address_t)
8683 _OSKextExtractPointer(callbackWrapper);
8684
8685 if ((kmod_info->address <= callbackAddress) &&
8686 (callbackAddress < (kmod_info->address + kmod_info->size))) {
8687
8688 result++;
8689 }
8690 } while (i--);
8691
8692finish:
b0d623f7
A
8693 return result;
8694}
8695
8696/*********************************************************************
8697*********************************************************************/
8698static OSReturn _OSKextCreateRequest(
8699 const char * predicate,
8700 OSDictionary ** requestP)
8701{
8702 OSReturn result = kOSKextReturnNoMemory;
8703 OSDictionary * request = NULL; // must release on error
8704 OSDictionary * args = NULL; // must release
8705
8706 request = OSDictionary::withCapacity(2);
8707 if (!request) {
8708 goto finish;
8709 }
8710 result = _OSDictionarySetCStringValue(request,
8711 kKextRequestPredicateKey, predicate);
8712 if (result != kOSReturnSuccess) {
8713 goto finish;
8714 }
8715 result = kOSReturnSuccess;
8716
8717finish:
8718 if (result != kOSReturnSuccess) {
8719 if (request) request->release();
8720 } else {
8721 *requestP = request;
8722 }
8723 if (args) args->release();
8724
8725 return result;
8726}
8727
8728/*********************************************************************
8729*********************************************************************/
8730static OSString * _OSKextGetRequestPredicate(OSDictionary * requestDict)
8731{
8732 return OSDynamicCast(OSString,
8733 requestDict->getObject(kKextRequestPredicateKey));
8734}
8735
8736/*********************************************************************
8737*********************************************************************/
8738static OSObject * _OSKextGetRequestArgument(
8739 OSDictionary * requestDict,
8740 const char * argName)
8741{
8742 OSDictionary * args = OSDynamicCast(OSDictionary,
8743 requestDict->getObject(kKextRequestArgumentsKey));
8744 if (args) {
8745 return args->getObject(argName);
8746 }
8747 return NULL;
8748}
8749
8750/*********************************************************************
8751*********************************************************************/
8752static bool _OSKextSetRequestArgument(
8753 OSDictionary * requestDict,
8754 const char * argName,
8755 OSObject * value)
8756{
8757 OSDictionary * args = OSDynamicCast(OSDictionary,
8758 requestDict->getObject(kKextRequestArgumentsKey));
8759 if (!args) {
8760 args = OSDictionary::withCapacity(2);
8761 if (!args) {
8762 goto finish;
8763 }
8764 requestDict->setObject(kKextRequestArgumentsKey, args);
8765 args->release();
8766 }
8767 if (args) {
8768 return args->setObject(argName, value);
8769 }
8770finish:
8771 return false;
8772}
8773
8774/*********************************************************************
8775*********************************************************************/
8776static void * _OSKextExtractPointer(OSData * wrapper)
8777{
8778 void * result = NULL;
8779 const void * resultPtr = NULL;
8780
8781 if (!wrapper) {
8782 goto finish;
8783 }
8784 resultPtr = wrapper->getBytesNoCopy();
8785 result = *(void **)resultPtr;
8786finish:
8787 return result;
8788}
8789
8790/*********************************************************************
8791*********************************************************************/
8792static OSReturn _OSDictionarySetCStringValue(
8793 OSDictionary * dict,
8794 const char * cKey,
8795 const char * cValue)
8796{
8797 OSReturn result = kOSKextReturnNoMemory;
8798 const OSSymbol * key = NULL; // must release
8799 OSString * value = NULL; // must release
8800
8801 key = OSSymbol::withCString(cKey);
8802 value = OSString::withCString(cValue);
8803 if (!key || !value) {
8804 goto finish;
8805 }
8806 if (dict->setObject(key, value)) {
8807 result = kOSReturnSuccess;
8808 }
8809
8810finish:
8811 if (key) key->release();
8812 if (value) value->release();
8813
8814 return result;
8815}
8816
6d2010ae
A
8817/*********************************************************************
8818*********************************************************************/
8819static bool _OSArrayContainsCString(
8820 OSArray * array,
8821 const char * cString)
8822{
8823 bool result = false;
8824 const OSSymbol * symbol = NULL;
8825 uint32_t count, i;
8826
8827 if (!array || !cString) {
8828 goto finish;
8829 }
8830
8831 symbol = OSSymbol::withCStringNoCopy(cString);
8832 if (!symbol) {
8833 goto finish;
8834 }
8835
8836 count = array->getCount();
8837 for (i = 0; i < count; i++) {
8838 OSObject * thisObject = array->getObject(i);
8839 if (symbol->isEqualTo(thisObject)) {
8840 result = true;
8841 goto finish;
8842 }
8843 }
8844
8845finish:
8846 if (symbol) symbol->release();
8847 return result;
8848}
8849
316670eb
A
8850/*********************************************************************
8851 * We really only care about boot / system start up related kexts.
8852 * We return true if we're less than REBUILD_MAX_TIME since start up,
8853 * otherwise return false.
8854 *********************************************************************/
8855bool _OSKextInPrelinkRebuildWindow(void)
8856{
8857 static bool outside_the_window = false;
8858 AbsoluteTime my_abstime;
8859 UInt64 my_ns;
8860 SInt32 my_secs;
8861
8862 if (outside_the_window) {
8863 return(false);
8864 }
8865 clock_get_uptime(&my_abstime);
8866 absolutetime_to_nanoseconds(my_abstime, &my_ns);
8867 my_secs = (SInt32)(my_ns / NSEC_PER_SEC);
8868 if (my_secs > REBUILD_MAX_TIME) {
8869 outside_the_window = true;
8870 return(false);
8871 }
8872 return(true);
8873}
8874
8875/*********************************************************************
8876 *********************************************************************/
8877bool _OSKextInUnloadedPrelinkedKexts( const OSSymbol * theBundleID )
8878{
8879 int unLoadedCount, i;
8880 bool result = false;
8881
8882 IORecursiveLockLock(sKextLock);
8883
8884 if (sUnloadedPrelinkedKexts == NULL) {
8885 goto finish;
8886 }
8887 unLoadedCount = sUnloadedPrelinkedKexts->getCount();
8888 if (unLoadedCount == 0) {
8889 goto finish;
8890 }
8891
8892 for (i = 0; i < unLoadedCount; i++) {
8893 const OSSymbol * myBundleID; // do not release
8894
8895 myBundleID = OSDynamicCast(OSSymbol, sUnloadedPrelinkedKexts->getObject(i));
8896 if (!myBundleID) continue;
8897 if (theBundleID->isEqualTo(myBundleID->getCStringNoCopy())) {
8898 result = true;
8899 break;
8900 }
8901 }
8902finish:
8903 IORecursiveLockUnlock(sKextLock);
8904 return(result);
8905}
8906
b0d623f7
A
8907#if PRAGMA_MARK
8908#pragma mark Personalities (IOKit Drivers)
8909#endif
8910/*********************************************************************
8911*********************************************************************/
8912/* static */
8913OSArray *
8914OSKext::copyAllKextPersonalities(bool filterSafeBootFlag)
8915{
8916 OSArray * result = NULL; // returned
8917 OSCollectionIterator * kextIterator = NULL; // must release
8918 OSArray * personalities = NULL; // must release
8919 OSCollectionIterator * personalitiesIterator = NULL; // must release
8920
8921 OSString * kextID = NULL; // do not release
8922 OSKext * theKext = NULL; // do not release
8923
8924 IORecursiveLockLock(sKextLock);
8925
8926 /* Let's conservatively guess that any given kext has around 3
8927 * personalities for now.
8928 */
8929 result = OSArray::withCapacity(sKextsByID->getCount() * 3);
8930 if (!result) {
8931 goto finish;
8932 }
8933
8934 kextIterator = OSCollectionIterator::withCollection(sKextsByID);
8935 if (!kextIterator) {
8936 goto finish;
8937 }
8938
8939 while ((kextID = OSDynamicCast(OSString, kextIterator->getNextObject()))) {
8940 if (personalitiesIterator) {
8941 personalitiesIterator->release();
8942 personalitiesIterator = NULL;
8943 }
8944 if (personalities) {
8945 personalities->release();
8946 personalities = NULL;
8947 }
8948
8949 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextID));
8950 if (!sSafeBoot || !filterSafeBootFlag || theKext->isLoadableInSafeBoot()) {
8951 personalities = theKext->copyPersonalitiesArray();
8952 if (!personalities) {
8953 continue;
8954 }
8955 result->merge(personalities);
8956 } else {
8957 // xxx - check for better place to put this log msg
8958 OSKextLog(theKext,
8959 kOSKextLogWarningLevel |
8960 kOSKextLogLoadFlag,
8961 "Kext %s is not loadable during safe boot; "
8962 "omitting its personalities.",
8963 theKext->getIdentifierCString());
8964 }
8965
8966 }
8967
8968finish:
8969 IORecursiveLockUnlock(sKextLock);
8970
8971 if (kextIterator) kextIterator->release();
8972 if (personalitiesIterator) personalitiesIterator->release();
8973 if (personalities) personalities->release();
8974
8975 return result;
8976}
8977
b0d623f7
A
8978/*********************************************************************
8979*********************************************************************/
8980/* static */
8981void
8982OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching)
8983{
8984 int numPersonalities = 0;
8985
8986 OSKextLog(/* kext */ NULL,
8987 kOSKextLogStepLevel |
8988 kOSKextLogLoadFlag,
8989 "Sending all eligible registered kexts' personalities "
8990 "to the IOCatalogue %s.",
8991 startMatching ? "and starting matching" : "but not starting matching");
8992
8993 OSArray * personalities = OSKext::copyAllKextPersonalities(
8994 /* filterSafeBootFlag */ true);
8995
8996 if (personalities) {
8997 gIOCatalogue->addDrivers(personalities, startMatching);
8998 numPersonalities = personalities->getCount();
8999 personalities->release();
9000 }
9001
9002 OSKextLog(/* kext */ NULL,
9003 kOSKextLogStepLevel |
9004 kOSKextLogLoadFlag,
9005 "%d kext personalit%s sent to the IOCatalogue; %s.",
9006 numPersonalities, numPersonalities > 0 ? "ies" : "y",
9007 startMatching ? "matching started" : "matching not started");
9008 return;
9009}
9010
9011/*********************************************************************
9012* Do not make a deep copy, just convert the IOKitPersonalities dict
9013* to an array for sending to the IOCatalogue.
9014*********************************************************************/
9015OSArray *
9016OSKext::copyPersonalitiesArray(void)
9017{
9018 OSArray * result = NULL;
9019 OSDictionary * personalities = NULL; // do not release
9020 OSCollectionIterator * personalitiesIterator = NULL; // must release
9021
9022 OSString * personalityName = NULL; // do not release
9023 OSString * personalityBundleIdentifier = NULL; // do not release
9024
9025 personalities = OSDynamicCast(OSDictionary,
9026 getPropertyForHostArch(kIOKitPersonalitiesKey));
9027 if (!personalities) {
9028 goto finish;
9029 }
9030
9031 result = OSArray::withCapacity(personalities->getCount());
9032 if (!result) {
9033 goto finish;
9034 }
9035
9036 personalitiesIterator =
9037 OSCollectionIterator::withCollection(personalities);
9038 if (!personalitiesIterator) {
9039 goto finish;
9040 }
9041 while ((personalityName = OSDynamicCast(OSString,
9042 personalitiesIterator->getNextObject()))) {
9043
9044 OSDictionary * personality = OSDynamicCast(OSDictionary,
9045 personalities->getObject(personalityName));
9046
9047 /******
9048 * If the personality doesn't have a CFBundleIdentifier, or if it
9049 * differs from the kext's, insert the kext's ID so we can find it.
9050 * The publisher ID is used to remove personalities from bundles
9051 * correctly.
9052 */
9053 personalityBundleIdentifier = OSDynamicCast(OSString,
9054 personality->getObject(kCFBundleIdentifierKey));
9055
9056 if (!personalityBundleIdentifier) {
9057 personality->setObject(kCFBundleIdentifierKey, bundleID);
9058 } else if (!personalityBundleIdentifier->isEqualTo(bundleID)) {
9059 personality->setObject(kIOPersonalityPublisherKey, bundleID);
9060 }
9061
9062 result->setObject(personality);
9063 }
9064
9065finish:
9066 if (personalitiesIterator) personalitiesIterator->release();
9067
9068 return result;
9069}
9070
9071/*********************************************************************
9072Might want to change this to a bool return?
9073*********************************************************************/
b7266188 9074OSReturn
b0d623f7
A
9075OSKext::sendPersonalitiesToCatalog(
9076 bool startMatching,
9077 OSArray * personalityNames)
9078{
b7266188
A
9079 OSReturn result = kOSReturnSuccess;
9080 OSArray * personalitiesToSend = NULL; // must release
9081 OSDictionary * kextPersonalities = NULL; // do not release
b0d623f7
A
9082 int count, i;
9083
b7266188
A
9084 if (!sLoadEnabled) {
9085 OSKextLog(this,
9086 kOSKextLogErrorLevel |
9087 kOSKextLogLoadFlag,
9088 "Kext loading is disabled (attempt to start matching for kext %s).",
9089 getIdentifierCString());
9090 result = kOSKextReturnDisabled;
9091 goto finish;
9092 }
9093
b0d623f7
A
9094 if (sSafeBoot && !isLoadableInSafeBoot()) {
9095 OSKextLog(this,
9096 kOSKextLogErrorLevel |
9097 kOSKextLogLoadFlag,
9098 "Kext %s is not loadable during safe boot; "
9099 "not sending personalities to the IOCatalogue.",
9100 getIdentifierCString());
b7266188
A
9101 result = kOSKextReturnNotLoadable;
9102 goto finish;
b0d623f7
A
9103 }
9104
9105 if (!personalityNames || !personalityNames->getCount()) {
9106 personalitiesToSend = copyPersonalitiesArray();
9107 } else {
9108 kextPersonalities = OSDynamicCast(OSDictionary,
9109 getPropertyForHostArch(kIOKitPersonalitiesKey));
9110 if (!kextPersonalities || !kextPersonalities->getCount()) {
b7266188 9111 // not an error
b0d623f7
A
9112 goto finish;
9113 }
9114 personalitiesToSend = OSArray::withCapacity(0);
9115 if (!personalitiesToSend) {
b7266188 9116 result = kOSKextReturnNoMemory;
b0d623f7
A
9117 goto finish;
9118 }
9119 count = personalityNames->getCount();
9120 for (i = 0; i < count; i++) {
9121 OSString * name = OSDynamicCast(OSString,
9122 personalityNames->getObject(i));
9123 if (!name) {
9124 continue;
9125 }
9126 OSDictionary * personality = OSDynamicCast(OSDictionary,
9127 kextPersonalities->getObject(name));
9128 if (personality) {
9129 personalitiesToSend->setObject(personality);
9130 }
9131 }
9132 }
9133 if (personalitiesToSend) {
9134 unsigned numPersonalities = personalitiesToSend->getCount();
9135 OSKextLog(this,
9136 kOSKextLogStepLevel |
9137 kOSKextLogLoadFlag,
9138 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
9139 getIdentifierCString(),
9140 numPersonalities,
9141 numPersonalities > 1 ? "ies" : "y",
9142 startMatching ? " and starting matching" : " but not starting matching");
9143 gIOCatalogue->addDrivers(personalitiesToSend, startMatching);
9144 }
9145finish:
9146 if (personalitiesToSend) {
9147 personalitiesToSend->release();
9148 }
b7266188 9149 return result;
b0d623f7
A
9150}
9151
9152/*********************************************************************
b7266188
A
9153* xxx - We should allow removing the kext's declared personalities,
9154* xxx - even with other bundle identifiers.
b0d623f7
A
9155*********************************************************************/
9156void
9157OSKext::removePersonalitiesFromCatalog(void)
9158{
9159 OSDictionary * personality = NULL; // do not release
9160
9161 personality = OSDictionary::withCapacity(1);
9162 if (!personality) {
9163 goto finish;
9164 }
9165 personality->setObject(kCFBundleIdentifierKey, getIdentifier());
9166
9167 OSKextLog(this,
9168 kOSKextLogStepLevel |
9169 kOSKextLogLoadFlag,
9170 "Kext %s removing all personalities naming it from the IOCatalogue.",
9171 getIdentifierCString());
9172
9173 /* Have the IOCatalog remove all personalities matching this kext's
9174 * bundle ID and trigger matching anew.
9175 */
9176 gIOCatalogue->removeDrivers(personality, /* startMatching */ true);
9177
9178 finish:
9179 if (personality) personality->release();
9180
9181 return;
9182}
9183
9184
9185#if PRAGMA_MARK
9186#pragma mark Logging
9187#endif
9188/*********************************************************************
9189* Do not call any function that takes sKextLock here!
9190*********************************************************************/
9191/* static */
9192OSKextLogSpec
9193OSKext::setUserSpaceLogFilter(
6d2010ae 9194 OSKextLogSpec newUserLogFilter,
b0d623f7
A
9195 bool captureFlag)
9196{
9197 OSKextLogSpec result;
6d2010ae 9198 bool allocError = false;
b0d623f7 9199
6d2010ae
A
9200 /* Do not call any function that takes sKextLoggingLock during
9201 * this critical block. That means do logging after.
9202 */
9203 IOLockLock(sKextLoggingLock);
b0d623f7
A
9204
9205 result = sUserSpaceKextLogFilter;
6d2010ae 9206 sUserSpaceKextLogFilter = newUserLogFilter;
b0d623f7 9207
6d2010ae 9208 if (newUserLogFilter && captureFlag &&
b0d623f7
A
9209 !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
9210
9211 // xxx - do some measurements for a good initial capacity?
9212 sUserSpaceLogSpecArray = OSArray::withCapacity(0);
9213 sUserSpaceLogMessageArray = OSArray::withCapacity(0);
9214
9215 if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
b0d623f7
A
9216 OSSafeReleaseNULL(sUserSpaceLogSpecArray);
9217 OSSafeReleaseNULL(sUserSpaceLogMessageArray);
6d2010ae 9218 allocError = true;
b0d623f7
A
9219 }
9220 }
9221
6d2010ae
A
9222 IOLockUnlock(sKextLoggingLock);
9223
9224 /* If the config flag itself is changing, log the state change
9225 * going both ways, before setting up the user-space log arrays,
9226 * so that this is only logged in the kernel.
9227 */
9228 if (result != newUserLogFilter) {
9229 OSKextLog(/* kext */ NULL,
9230 kOSKextLogDebugLevel |
9231 kOSKextLogGeneralFlag,
9232 "User-space log flags changed from 0x%x to 0x%x.",
9233 result, newUserLogFilter);
9234 }
9235 if (allocError) {
9236 OSKextLog(/* kext */ NULL,
9237 kOSKextLogErrorLevel |
9238 kOSKextLogGeneralFlag,
9239 "Failed to allocate user-space log message arrays.");
9240 }
b0d623f7
A
9241
9242 return result;
9243}
9244
9245/*********************************************************************
9246* Do not call any function that takes sKextLock here!
9247*********************************************************************/
9248/* static */
9249OSArray *
9250OSKext::clearUserSpaceLogFilter(void)
9251{
6d2010ae 9252 OSArray * result = NULL;
b0d623f7 9253 OSKextLogSpec oldLogFilter;
6d2010ae 9254 OSKextLogSpec newLogFilter = kOSKextLogSilentFilter;
b0d623f7 9255
6d2010ae
A
9256 /* Do not call any function that takes sKextLoggingLock during
9257 * this critical block. That means do logging after.
9258 */
9259 IOLockLock(sKextLoggingLock);
b0d623f7
A
9260
9261 result = OSArray::withCapacity(2);
9262 if (result) {
9263 result->setObject(sUserSpaceLogSpecArray);
9264 result->setObject(sUserSpaceLogMessageArray);
9265 }
9266 OSSafeReleaseNULL(sUserSpaceLogSpecArray);
9267 OSSafeReleaseNULL(sUserSpaceLogMessageArray);
9268
9269 oldLogFilter = sUserSpaceKextLogFilter;
6d2010ae
A
9270 sUserSpaceKextLogFilter = newLogFilter;
9271
9272 IOLockUnlock(sKextLoggingLock);
b0d623f7
A
9273
9274 /* If the config flag itself is changing, log the state change
9275 * going both ways, after tearing down the user-space log
9276 * arrays, so this is only logged within the kernel.
9277 */
6d2010ae 9278 if (oldLogFilter != newLogFilter) {
b0d623f7
A
9279 OSKextLog(/* kext */ NULL,
9280 kOSKextLogDebugLevel |
9281 kOSKextLogGeneralFlag,
9282 "User-space log flags changed from 0x%x to 0x%x.",
6d2010ae 9283 oldLogFilter, newLogFilter);
b0d623f7
A
9284 }
9285
b0d623f7
A
9286 return result;
9287}
9288
6d2010ae 9289
b0d623f7
A
9290/*********************************************************************
9291* Do not call any function that takes sKextLock here!
9292*********************************************************************/
9293/* static */
9294OSKextLogSpec
9295OSKext::getUserSpaceLogFilter(void)
9296{
9297 OSKextLogSpec result;
9298
6d2010ae 9299 IOLockLock(sKextLoggingLock);
b0d623f7 9300 result = sUserSpaceKextLogFilter;
6d2010ae 9301 IOLockUnlock(sKextLoggingLock);
b0d623f7
A
9302
9303 return result;
9304}
9305
9306/*********************************************************************
9307* This function is called by OSMetaClass during kernel C++ setup.
9308* Be careful what you access here; assume only OSKext::initialize()
9309* has been called.
9310*
9311* Do not call any function that takes sKextLock here!
9312*********************************************************************/
9313#define VTRESET "\033[0m"
9314
9315#define VTBOLD "\033[1m"
9316#define VTUNDER "\033[4m"
9317
9318#define VTRED "\033[31m"
9319#define VTGREEN "\033[32m"
9320#define VTYELLOW "\033[33m"
9321#define VTBLUE "\033[34m"
9322#define VTMAGENTA "\033[35m"
9323#define VTCYAN "\033[36m"
9324
9325inline const char * colorForFlags(OSKextLogSpec flags)
9326{
9327 OSKextLogSpec logLevel = flags & kOSKextLogLevelMask;
9328
9329 switch (logLevel) {
9330 case kOSKextLogErrorLevel:
9331 return VTRED VTBOLD;
9332 break;
9333 case kOSKextLogWarningLevel:
9334 return VTRED;
9335 break;
9336 case kOSKextLogBasicLevel:
9337 return VTYELLOW VTUNDER;
9338 break;
9339 case kOSKextLogProgressLevel:
9340 return VTYELLOW;
9341 break;
9342 case kOSKextLogStepLevel:
9343 return VTGREEN;
9344 break;
9345 case kOSKextLogDetailLevel:
9346 return VTCYAN;
9347 break;
9348 case kOSKextLogDebugLevel:
9349 return VTMAGENTA;
9350 break;
9351 default:
9352 return ""; // white
9353 break;
9354 }
9355 return "";
9356}
9357
9358inline bool logSpecMatch(
9359 OSKextLogSpec msgLogSpec,
9360 OSKextLogSpec logFilter)
9361{
9362 OSKextLogSpec filterKextGlobal = logFilter & kOSKextLogKextOrGlobalMask;
9363 OSKextLogSpec filterLevel = logFilter & kOSKextLogLevelMask;
9364 OSKextLogSpec filterFlags = logFilter & kOSKextLogFlagsMask;
9365
9366 OSKextLogSpec msgKextGlobal = msgLogSpec & kOSKextLogKextOrGlobalMask;
9367 OSKextLogSpec msgLevel = msgLogSpec & kOSKextLogLevelMask;
9368 OSKextLogSpec msgFlags = msgLogSpec & kOSKextLogFlagsMask;
9369
9370 /* Explicit messages always get logged.
9371 */
9372 if (msgLevel == kOSKextLogExplicitLevel) {
9373 return true;
9374 }
9375
9376 /* Warnings and errors are logged regardless of the flags.
9377 */
9378 if (msgLevel <= kOSKextLogBasicLevel && (msgLevel <= filterLevel)) {
9379 return true;
9380 }
9381
9382 /* A verbose message that isn't for a logging-enabled kext and isn't global
9383 * does *not* get logged.
9384 */
9385 if (!msgKextGlobal && !filterKextGlobal) {
9386 return false;
9387 }
9388
9389 /* Warnings and errors are logged regardless of the flags.
9390 * All other messages must fit the flags and
9391 * have a level at or below the filter.
9392 *
9393 */
9394 if ((msgFlags & filterFlags) && (msgLevel <= filterLevel)) {
9395 return true;
9396 }
9397 return false;
9398}
9399
9400extern "C" {
9401
9402void
9403OSKextLog(
9404 OSKext * aKext,
9405 OSKextLogSpec msgLogSpec,
9406 const char * format, ...)
9407{
9408 va_list argList;
9409
9410 va_start(argList, format);
9411 OSKextVLog(aKext, msgLogSpec, format, argList);
9412 va_end(argList);
9413}
9414
9415void
9416OSKextVLog(
9417 OSKext * aKext,
9418 OSKextLogSpec msgLogSpec,
9419 const char * format,
6d2010ae 9420 va_list srcArgList)
b0d623f7
A
9421{
9422 extern int disableConsoleOutput;
9423
9424 bool logForKernel = false;
9425 bool logForUser = false;
9426 va_list argList;
9427 char stackBuffer[120];
9428 uint32_t length = 0;
9429 char * allocBuffer = NULL; // must kfree
9430 OSNumber * logSpecNum = NULL; // must release
9431 OSString * logString = NULL; // must release
9432 char * buffer = stackBuffer; // do not free
9433
6d2010ae 9434 IOLockLock(sKextLoggingLock);
b0d623f7
A
9435
9436 /* Set the kext/global bit in the message spec if we have no
9437 * kext or if the kext requests logging.
9438 */
9439 if (!aKext || aKext->flags.loggingEnabled) {
9440 msgLogSpec = msgLogSpec | kOSKextLogKextOrGlobalMask;
9441 }
9442
9443 logForKernel = logSpecMatch(msgLogSpec, sKernelLogFilter);
9444 if (sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
9445 logForUser = logSpecMatch(msgLogSpec, sUserSpaceKextLogFilter);
9446 }
9447
9448 if (! (logForKernel || logForUser) ) {
9449 goto finish;
9450 }
9451
9452 /* No goto from here until past va_end()!
9453 */
9454 va_copy(argList, srcArgList);
9455 length = vsnprintf(stackBuffer, sizeof(stackBuffer), format, argList);
9456 va_end(argList);
9457
9458 if (length + 1 >= sizeof(stackBuffer)) {
9459 allocBuffer = (char *)kalloc((length + 1) * sizeof(char));
9460 if (!allocBuffer) {
9461 goto finish;
9462 }
9463
9464 /* No goto from here until past va_end()!
9465 */
9466 va_copy(argList, srcArgList);
9467 vsnprintf(allocBuffer, length + 1, format, argList);
9468 va_end(argList);
9469
9470 buffer = allocBuffer;
9471 }
9472
9473 /* If user space wants the log message, queue it up.
9474 */
9475 if (logForUser && sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
9476 logSpecNum = OSNumber::withNumber(msgLogSpec, 8 * sizeof(msgLogSpec));
9477 logString = OSString::withCString(buffer);
9478 if (logSpecNum && logString) {
9479 sUserSpaceLogSpecArray->setObject(logSpecNum);
9480 sUserSpaceLogMessageArray->setObject(logString);
9481 }
9482 }
9483
9484 /* Always log messages from the kernel according to the kernel's
9485 * log flags.
9486 */
9487 if (logForKernel) {
9488
9489 /* If we are in console mode and have a custom log filter,
9490 * colorize the log message.
9491 */
9492 if (!disableConsoleOutput && sBootArgLogFilterFound) {
9493 const char * color = ""; // do not free
9494 color = colorForFlags(msgLogSpec);
9495 printf("%s%s%s\n", colorForFlags(msgLogSpec),
9496 buffer, color[0] ? VTRESET : "");
9497 } else {
9498 printf("%s\n", buffer);
9499 }
9500 }
9501
9502finish:
6d2010ae
A
9503 IOLockUnlock(sKextLoggingLock);
9504
b0d623f7
A
9505 if (allocBuffer) {
9506 kfree(allocBuffer, (length + 1) * sizeof(char));
9507 }
9508 OSSafeRelease(logString);
9509 OSSafeRelease(logSpecNum);
b0d623f7
A
9510 return;
9511}
9512
316670eb
A
9513#if KASLR_IOREG_DEBUG
9514
9515#define IOLOG_INDENT( the_indention ) \
9516{ \
9517 int i; \
9518 for ( i = 0; i < (the_indention); i++ ) { \
9519 IOLog(" "); \
9520 } \
9521}
9522
9523extern vm_offset_t vm_kernel_stext;
9524extern vm_offset_t vm_kernel_etext;
9525extern mach_vm_offset_t kext_alloc_base;
9526extern mach_vm_offset_t kext_alloc_max;
9527
9528bool ScanForAddrInObject(OSObject * theObject,
9529 int indent );
9530
9531bool ScanForAddrInObject(OSObject * theObject,
9532 int indent)
9533{
9534 const OSMetaClass * myTypeID;
9535 OSCollectionIterator * myIter;
9536 OSSymbol * myKey;
9537 OSObject * myValue;
9538 bool myResult = false;
9539
9540 if ( theObject == NULL ) {
9541 IOLog("%s: theObject is NULL \n",
9542 __FUNCTION__);
9543 return myResult;
9544 }
9545
9546 myTypeID = OSTypeIDInst(theObject);
9547
9548 if ( myTypeID == OSTypeID(OSDictionary) ) {
9549 OSDictionary * myDictionary;
9550
9551 myDictionary = OSDynamicCast(OSDictionary, theObject);
9552 myIter = OSCollectionIterator::withCollection( myDictionary );
9553 if ( myIter == NULL )
9554 return myResult;
9555 myIter->reset();
9556
9557 while ( (myKey = OSDynamicCast(OSSymbol, myIter->getNextObject())) ) {
9558 bool myTempResult;
9559
9560 myValue = myDictionary->getObject(myKey);
9561 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
9562 if (myTempResult) {
9563 // if we ever get a true result return true
9564 myResult = true;
9565 IOLOG_INDENT(indent);
9566 IOLog("OSDictionary key \"%s\" \n", myKey->getCStringNoCopy());
9567 }
9568 }
9569 myIter->release();
9570 }
9571 else if ( myTypeID == OSTypeID(OSArray) ) {
9572 OSArray * myArray;
9573
9574 myArray = OSDynamicCast(OSArray, theObject);
9575 myIter = OSCollectionIterator::withCollection(myArray);
9576 if ( myIter == NULL )
9577 return myResult;
9578 myIter->reset();
9579
9580 while ( (myValue = myIter->getNextObject()) ) {
9581 bool myTempResult;
9582 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
9583 if (myTempResult) {
9584 // if we ever get a true result return true
9585 myResult = true;
9586 IOLOG_INDENT(indent);
9587 IOLog("OSArray: \n");
9588 }
9589 }
9590 myIter->release();
9591 }
9592 else if ( myTypeID == OSTypeID(OSString) || myTypeID == OSTypeID(OSSymbol) ) {
9593
9594 // should we look for addresses in strings?
9595 }
9596 else if ( myTypeID == OSTypeID(OSData) ) {
9597
9598 void * * myPtrPtr;
9599 unsigned int myLen;
9600 OSData * myDataObj;
9601
9602 myDataObj = OSDynamicCast(OSData, theObject);
9603 myPtrPtr = (void * *) myDataObj->getBytesNoCopy();
9604 myLen = myDataObj->getLength();
9605
9606 if (myPtrPtr && myLen && myLen > 7) {
9607 int i;
9608 int myPtrCount = (myLen / sizeof(void *));
9609
9610 for (i = 0; i < myPtrCount; i++) {
9611 UInt64 numberValue = (UInt64) *(myPtrPtr);
9612
9613 if ( kext_alloc_max != 0 &&
9614 numberValue >= kext_alloc_base &&
9615 numberValue < kext_alloc_max ) {
9616
9617 OSKext * myKext = NULL; // must release (looked up)
9618 // IOLog("found OSData %p in kext map %p to %p \n",
9619 // *(myPtrPtr),
9620 // (void *) kext_alloc_base,
9621 // (void *) kext_alloc_max);
9622
9623 myKext = OSKext::lookupKextWithAddress( (vm_address_t) *(myPtrPtr) );
9624 if (myKext) {
9625 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
9626 *(myPtrPtr),
9627 myKext->getIdentifierCString());
9628 myKext->release();
9629 }
9630 myResult = true;
9631 }
9632 if ( vm_kernel_etext != 0 &&
9633 numberValue >= vm_kernel_stext &&
9634 numberValue < vm_kernel_etext ) {
9635 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
9636 *(myPtrPtr),
9637 (void *) vm_kernel_stext,
9638 (void *) vm_kernel_etext);
9639 myResult = true;
9640 }
9641 myPtrPtr++;
9642 }
9643 }
9644 }
9645 else if ( myTypeID == OSTypeID(OSBoolean) ) {
9646
9647 // do nothing here...
9648 }
9649 else if ( myTypeID == OSTypeID(OSNumber) ) {
9650
9651 OSNumber * number = OSDynamicCast(OSNumber, theObject);
9652
9653 UInt64 numberValue = number->unsigned64BitValue();
9654
9655 if ( kext_alloc_max != 0 &&
9656 numberValue >= kext_alloc_base &&
9657 numberValue < kext_alloc_max ) {
9658
9659 OSKext * myKext = NULL; // must release (looked up)
9660 IOLog("found OSNumber in kext map %p to %p \n",
9661 (void *) kext_alloc_base,
9662 (void *) kext_alloc_max);
9663 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
9664
9665 myKext = OSKext::lookupKextWithAddress( (vm_address_t) numberValue );
9666 if (myKext) {
9667 IOLog("found in kext \"%s\" \n",
9668 myKext->getIdentifierCString());
9669 myKext->release();
9670 }
9671
9672 myResult = true;
9673 }
9674 if ( vm_kernel_etext != 0 &&
9675 numberValue >= vm_kernel_stext &&
9676 numberValue < vm_kernel_etext ) {
9677 IOLog("found OSNumber in kernel text segment %p to %p \n",
9678 (void *) vm_kernel_stext,
9679 (void *) vm_kernel_etext);
9680 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
9681 myResult = true;
9682 }
9683 }
9684#if 0
9685 else {
9686 const OSMetaClass* myMetaClass = NULL;
9687
9688 myMetaClass = theObject->getMetaClass();
9689 if ( myMetaClass ) {
9690 IOLog("class %s \n", myMetaClass->getClassName() );
9691 }
9692 else {
9693 IOLog("Unknown object \n" );
9694 }
9695 }
9696#endif
9697
9698 return myResult;
9699}
9700#endif // KASLR_KEXT_DEBUG
9701
b0d623f7
A
9702}; /* extern "C" */
9703
9704#if PRAGMA_MARK
9705#pragma mark Backtrace Dump & kmod_get_info() support
9706#endif
9707/*********************************************************************
6d2010ae 9708* This function must be safe to call in panic context.
b0d623f7
A
9709*********************************************************************/
9710/* static */
9711void
9712OSKext::printKextsInBacktrace(
9713 vm_offset_t * addr,
9714 unsigned int cnt,
9715 int (* printf_func)(const char *fmt, ...),
9716 bool lockFlag)
9717{
6d2010ae
A
9718 addr64_t summary_page = 0;
9719 addr64_t last_summary_page = 0;
9720 bool found_kmod = false;
9721 u_int i = 0;
b0d623f7
A
9722
9723 if (lockFlag) {
6d2010ae 9724 IOLockLock(sKextSummariesLock);
b0d623f7
A
9725 }
9726
6d2010ae
A
9727 if (!gLoadedKextSummaries) {
9728 (*printf_func)(" can't perform kext scan: no kext summary");
9729 goto finish;
9730 }
9731
9732 summary_page = trunc_page((addr64_t)(uintptr_t)gLoadedKextSummaries);
9733 last_summary_page = round_page(summary_page + sLoadedKextSummariesAllocSize);
9734 for (; summary_page < last_summary_page; summary_page += PAGE_SIZE) {
9735 if (pmap_find_phys(kernel_pmap, summary_page) == 0) {
9736 (*printf_func)(" can't perform kext scan: "
9737 "missing kext summary page %p", summary_page);
9738 goto finish;
9739 }
9740 }
9741
9742 for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
9743 OSKextLoadedKextSummary * summary;
9744
9745 summary = gLoadedKextSummaries->summaries + i;
9746 if (!summary->address) {
9747 continue;
b0d623f7 9748 }
6d2010ae
A
9749
9750 if (!summaryIsInBacktrace(summary, addr, cnt)) {
9751 continue;
b0d623f7 9752 }
b0d623f7 9753
6d2010ae
A
9754 if (!found_kmod) {
9755 (*printf_func)(" Kernel Extensions in backtrace:\n");
9756 found_kmod = true;
9757 }
b0d623f7 9758
6d2010ae
A
9759 printSummary(summary, printf_func);
9760 }
b0d623f7 9761
6d2010ae
A
9762finish:
9763 if (lockFlag) {
9764 IOLockUnlock(sKextSummariesLock);
9765 }
b0d623f7 9766
6d2010ae
A
9767 return;
9768}
b0d623f7 9769
6d2010ae
A
9770/*********************************************************************
9771* This function must be safe to call in panic context.
9772*********************************************************************/
9773/* static */
9774boolean_t
9775OSKext::summaryIsInBacktrace(
9776 OSKextLoadedKextSummary * summary,
9777 vm_offset_t * addr,
9778 unsigned int cnt)
9779{
9780 u_int i = 0;
9781
9782 for (i = 0; i < cnt; i++) {
9783 vm_offset_t kscan_addr = addr[i];
9784 if ((kscan_addr >= summary->address) &&
9785 (kscan_addr < (summary->address + summary->size)))
9786 {
9787 return TRUE;
9788 }
9789 }
b0d623f7 9790
6d2010ae
A
9791 return FALSE;
9792}
b0d623f7 9793
6d2010ae
A
9794/*********************************************************************
9795 * scan list of loaded kext summaries looking for a load address match and if
9796 * found return the UUID C string. If not found then set empty string.
9797 *********************************************************************/
9798static void findSummaryUUID(
9799 uint32_t tag_ID,
9800 uuid_string_t uuid);
b0d623f7 9801
6d2010ae
A
9802static void findSummaryUUID(
9803 uint32_t tag_ID,
9804 uuid_string_t uuid)
9805{
9806 u_int i;
9807
9808 uuid[0] = 0x00; // default to no UUID
9809
9810 for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
9811 OSKextLoadedKextSummary * summary;
9812
9813 summary = gLoadedKextSummaries->summaries + i;
9814
9815 if (summary->loadTag == tag_ID) {
9816 (void) uuid_unparse(summary->uuid, uuid);
9817 break;
b0d623f7
A
9818 }
9819 }
6d2010ae
A
9820 return;
9821}
b0d623f7 9822
6d2010ae
A
9823/*********************************************************************
9824* This function must be safe to call in panic context.
9825*********************************************************************/
9826void OSKext::printSummary(
9827 OSKextLoadedKextSummary * summary,
9828 int (* printf_func)(const char *fmt, ...))
9829{
9830 kmod_reference_t * kmod_ref = NULL;
9831 uuid_string_t uuid;
9832 char version[kOSKextVersionMaxLength];
9833
9834 if (!OSKextVersionGetString(summary->version, version, sizeof(version))) {
9835 strlcpy(version, "unknown version", sizeof(version));
b0d623f7 9836 }
6d2010ae 9837 (void) uuid_unparse(summary->uuid, uuid);
b0d623f7 9838
6d2010ae
A
9839 (*printf_func)(" %s(%s)[%s]@0x%llx->0x%llx\n",
9840 summary->name, version, uuid,
9841 summary->address, summary->address + summary->size - 1);
9842
9843 /* print dependency info */
9844 for (kmod_ref = (kmod_reference_t *) summary->reference_list;
9845 kmod_ref;
9846 kmod_ref = kmod_ref->next) {
9847 kmod_info_t * rinfo;
9848
9849 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_ref)) == 0) {
9850 (*printf_func)(" kmod dependency scan stopped "
9851 "due to missing dependency page: %p\n", kmod_ref);
9852 break;
9853 }
9854 rinfo = kmod_ref->info;
9855
9856 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
9857 (*printf_func)(" kmod dependency scan stopped "
9858 "due to missing kmod page: %p\n", rinfo);
9859 break;
9860 }
9861
9862 if (!rinfo->address) {
9863 continue; // skip fake entries for built-ins
9864 }
9865
9866 /* locate UUID in gLoadedKextSummaries */
9867 findSummaryUUID(rinfo->id, uuid);
9868
9869 (*printf_func)(" dependency: %s(%s)[%s]@%p\n",
9870 rinfo->name, rinfo->version, uuid, rinfo->address);
9871 }
b0d623f7
A
9872 return;
9873}
9874
6d2010ae 9875
b0d623f7
A
9876/*******************************************************************************
9877* substitute() looks at an input string (a pointer within a larger buffer)
9878* for a match to a substring, and on match it writes the marker & substitution
9879* character to an output string, updating the scan (from) and
9880* output (to) indexes as appropriate.
9881*******************************************************************************/
9882static int substitute(
9883 const char * scan_string,
9884 char * string_out,
9885 uint32_t * to_index,
9886 uint32_t * from_index,
9887 const char * substring,
9888 char marker,
9889 char substitution);
9890
9891/* string_out must be at least KMOD_MAX_NAME bytes.
9892 */
9893static int
9894substitute(
9895 const char * scan_string,
9896 char * string_out,
9897 uint32_t * to_index,
9898 uint32_t * from_index,
9899 const char * substring,
9900 char marker,
9901 char substitution)
9902{
9903 uint32_t substring_length = strnlen(substring, KMOD_MAX_NAME - 1);
9904
9905 /* On a substring match, append the marker (if there is one) and then
9906 * the substitution character, updating the output (to) index accordingly.
9907 * Then update the input (from) length by the length of the substring
9908 * that got replaced.
9909 */
9910 if (!strncmp(scan_string, substring, substring_length)) {
9911 if (marker) {
9912 string_out[(*to_index)++] = marker;
9913 }
9914 string_out[(*to_index)++] = substitution;
9915 (*from_index) += substring_length;
9916 return 1;
9917 }
9918 return 0;
9919}
9920
9921/*******************************************************************************
9922* compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
9923* KMOD_MAX_NAME characters and performs various substitutions of common
9924* prefixes & substrings as defined by tables in kext_panic_report.h.
9925*******************************************************************************/
9926static void compactIdentifier(
9927 const char * identifier,
9928 char * identifier_out,
9929 char ** identifier_out_end);
9930
9931static void
9932compactIdentifier(
9933 const char * identifier,
9934 char * identifier_out,
9935 char ** identifier_out_end)
9936{
9937 uint32_t from_index, to_index;
9938 uint32_t scan_from_index = 0;
9939 uint32_t scan_to_index = 0;
9940 subs_entry_t * subs_entry = NULL;
9941 int did_sub = 0;
9942
9943 from_index = to_index = 0;
9944 identifier_out[0] = '\0';
9945
9946 /* Replace certain identifier prefixes with shorter @+character sequences.
9947 * Check the return value of substitute() so we only replace the prefix.
9948 */
9949 for (subs_entry = &kext_identifier_prefix_subs[0];
9950 subs_entry->substring && !did_sub;
9951 subs_entry++) {
9952
9953 did_sub = substitute(identifier, identifier_out,
9954 &scan_to_index, &scan_from_index,
9955 subs_entry->substring, /* marker */ '\0', subs_entry->substitute);
9956 }
9957 did_sub = 0;
9958
9959 /* Now scan through the identifier looking for the common substrings
9960 * and replacing them with shorter !+character sequences via substitute().
9961 */
9962 for (/* see above */;
9963 scan_from_index < KMOD_MAX_NAME - 1 && identifier[scan_from_index];
9964 /* see loop */) {
9965
9966 const char * scan_string = &identifier[scan_from_index];
9967
9968 did_sub = 0;
9969
9970 if (scan_from_index) {
9971 for (subs_entry = &kext_identifier_substring_subs[0];
9972 subs_entry->substring && !did_sub;
9973 subs_entry++) {
9974
9975 did_sub = substitute(scan_string, identifier_out,
9976 &scan_to_index, &scan_from_index,
9977 subs_entry->substring, '!', subs_entry->substitute);
9978 }
9979 }
9980
9981 /* If we didn't substitute, copy the input character to the output.
9982 */
9983 if (!did_sub) {
9984 identifier_out[scan_to_index++] = identifier[scan_from_index++];
9985 }
9986 }
9987
9988 identifier_out[scan_to_index] = '\0';
9989 if (identifier_out_end) {
9990 *identifier_out_end = &identifier_out[scan_to_index];
9991 }
9992
9993 return;
9994}
9995
9996/*******************************************************************************
9997* assemble_identifier_and_version() adds to a string buffer a compacted
9998* bundle identifier followed by a version string.
9999*******************************************************************************/
10000
10001/* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
10002 */
10003static int assemble_identifier_and_version(
10004 kmod_info_t * kmod_info,
10005 char * identPlusVers);
10006static int
10007assemble_identifier_and_version(
10008 kmod_info_t * kmod_info,
10009 char * identPlusVers)
10010{
10011 int result = 0;
10012
10013 compactIdentifier(kmod_info->name, identPlusVers, NULL);
10014 result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
10015 identPlusVers[result++] = '\t'; // increment for real char
10016 identPlusVers[result] = '\0'; // don't increment for nul char
10017 result = strlcat(identPlusVers, kmod_info->version, KMOD_MAX_NAME);
10018
10019 return result;
10020}
10021
10022/*******************************************************************************
6d2010ae 10023* Assumes sKextLock is held.
b0d623f7 10024*******************************************************************************/
b0d623f7
A
10025/* static */
10026uint32_t
10027OSKext::saveLoadedKextPanicListTyped(
10028 const char * prefix,
10029 int invertFlag,
10030 int libsFlag,
10031 char * paniclist,
10032 uint32_t list_size,
10033 uint32_t * list_length_ptr)
10034{
10035 uint32_t result = 0;
10036 int error = 0;
10037 unsigned int count, i;
10038
10039 count = sLoadedKexts->getCount();
10040 if (!count) {
10041 goto finish;
10042 }
10043
10044 i = count - 1;
10045 do {
6d2010ae
A
10046 OSObject * rawKext = sLoadedKexts->getObject(i);
10047 OSKext * theKext = OSDynamicCast(OSKext, rawKext);
b0d623f7
A
10048 int match;
10049 char identPlusVers[2*KMOD_MAX_NAME];
10050 uint32_t identPlusVersLength;
6d2010ae
A
10051
10052 if (!rawKext) {
10053 printf("OSKext::saveLoadedKextPanicListTyped - "
10054 "NULL kext in loaded kext list; continuing\n");
10055 continue;
10056 }
10057
10058 if (!theKext) {
10059 printf("OSKext::saveLoadedKextPanicListTyped - "
10060 "Kext type cast failed in loaded kext list; continuing\n");
10061 continue;
10062 }
b0d623f7
A
10063
10064 /* Skip all built-in kexts.
10065 */
10066 if (theKext->isKernelComponent()) {
10067 continue;
10068 }
10069
6d2010ae
A
10070 kmod_info_t * kmod_info = theKext->kmod_info;
10071
b0d623f7
A
10072 /* Filter for kmod name (bundle identifier).
10073 */
10074 match = !strncmp(kmod_info->name, prefix, strnlen(prefix, KMOD_MAX_NAME));
10075 if ((match && invertFlag) || (!match && !invertFlag)) {
10076 continue;
10077 }
10078
10079 /* Filter for libraries (kexts that have a compatible version).
10080 */
10081 if ((libsFlag == 0 && theKext->getCompatibleVersion() > 1) ||
10082 (libsFlag == 1 && theKext->getCompatibleVersion() < 1)) {
10083
10084 continue;
10085 }
10086
10087 if (!kmod_info ||
10088 !pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_info))) {
10089
10090 printf("kext scan stopped due to missing kmod_info page: %p\n",
10091 kmod_info);
10092 error = 1;
10093 goto finish;
10094 }
10095
10096 identPlusVersLength = assemble_identifier_and_version(kmod_info,
10097 identPlusVers);
10098 if (!identPlusVersLength) {
10099 printf("error saving loaded kext info\n");
10100 goto finish;
10101 }
10102
b0d623f7
A
10103 /* Adding 1 for the newline.
10104 */
10105 if (*list_length_ptr + identPlusVersLength + 1 >= list_size) {
10106 goto finish;
10107 }
10108
10109 *list_length_ptr = strlcat(paniclist, identPlusVers, list_size);
b0d623f7
A
10110 *list_length_ptr = strlcat(paniclist, "\n", list_size);
10111
10112 } while (i--);
10113
10114finish:
10115 if (!error) {
10116 if (*list_length_ptr + 1 <= list_size) {
10117 result = list_size - (*list_length_ptr + 1);
10118 }
10119 }
10120
10121 return result;
10122}
10123
10124/*********************************************************************
10125*********************************************************************/
10126/* static */
10127void
10128OSKext::saveLoadedKextPanicList(void)
10129{
10130 char * newlist = NULL;
10131 uint32_t newlist_size = 0;
10132 uint32_t newlist_length = 0;
10133
b0d623f7
A
10134 newlist_length = 0;
10135 newlist_size = KEXT_PANICLIST_SIZE;
10136 newlist = (char *)kalloc(newlist_size);
10137
10138 if (!newlist) {
10139 OSKextLog(/* kext */ NULL,
10140 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
10141 "Couldn't allocate kext panic log buffer.");
10142 goto finish;
10143 }
10144
10145 newlist[0] = '\0';
10146
10147 // non-"com.apple." kexts
10148 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
10149 /* libs? */ -1, newlist, newlist_size, &newlist_length)) {
10150
10151 goto finish;
10152 }
10153 // "com.apple." nonlibrary kexts
10154 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
10155 /* libs? */ 0, newlist, newlist_size, &newlist_length)) {
10156
10157 goto finish;
10158 }
10159 // "com.apple." library kexts
10160 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
10161 /* libs? */ 1, newlist, newlist_size, &newlist_length)) {
10162
10163 goto finish;
10164 }
10165
10166 if (loaded_kext_paniclist) {
10167 kfree(loaded_kext_paniclist, loaded_kext_paniclist_size);
10168 }
10169 loaded_kext_paniclist = newlist;
10170 loaded_kext_paniclist_size = newlist_size;
10171 loaded_kext_paniclist_length = newlist_length;
10172
10173finish:
b0d623f7
A
10174 return;
10175}
10176
10177/*********************************************************************
6d2010ae 10178* Assumes sKextLock is held.
b0d623f7 10179*********************************************************************/
b0d623f7 10180void
6d2010ae 10181OSKext::savePanicString(bool isLoading)
b0d623f7 10182{
6d2010ae 10183 u_long len;
b0d623f7 10184
6d2010ae 10185 if (!kmod_info) {
b0d623f7
A
10186 return; // do not goto finish here b/c of lock
10187 }
10188
6d2010ae
A
10189 len = assemble_identifier_and_version(kmod_info,
10190 (isLoading) ? last_loaded_str : last_unloaded_str);
10191 if (!len) {
b0d623f7
A
10192 printf("error saving unloaded kext info\n");
10193 goto finish;
10194 }
10195
6d2010ae
A
10196 if (isLoading) {
10197 last_loaded_strlen = len;
10198 last_loaded_address = (void *)kmod_info->address;
10199 last_loaded_size = kmod_info->size;
10200 clock_get_uptime(&last_loaded_timestamp);
10201 } else {
10202 last_unloaded_strlen = len;
10203 last_unloaded_address = (void *)kmod_info->address;
10204 last_unloaded_size = kmod_info->size;
10205 clock_get_uptime(&last_unloaded_timestamp);
b0d623f7 10206 }
b0d623f7
A
10207
10208finish:
b0d623f7
A
10209 return;
10210}
10211
10212/*********************************************************************
10213*********************************************************************/
b0d623f7
A
10214/* static */
10215void
10216OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
10217{
6d2010ae
A
10218 if (last_loaded_strlen) {
10219 printf_func("last loaded kext at %llu: %.*s (addr %p, size %lu)\n",
10220 AbsoluteTime_to_scalar(&last_loaded_timestamp),
10221 last_loaded_strlen, last_loaded_str,
10222 last_loaded_address, last_loaded_size);
10223 }
b0d623f7 10224
6d2010ae
A
10225 if (last_unloaded_strlen) {
10226 printf_func("last unloaded kext at %llu: %.*s (addr %p, size %lu)\n",
10227 AbsoluteTime_to_scalar(&last_unloaded_timestamp),
10228 last_unloaded_strlen, last_unloaded_str,
10229 last_unloaded_address, last_unloaded_size);
b0d623f7 10230 }
6d2010ae 10231
b0d623f7
A
10232 printf_func("loaded kexts:\n");
10233 if (loaded_kext_paniclist &&
10234 pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
10235 loaded_kext_paniclist[0]) {
10236
10237 printf_func("%.*s", loaded_kext_paniclist_length, loaded_kext_paniclist);
10238 } else {
10239 printf_func("(none)\n");
10240 }
10241 return;
10242}
10243
6d2010ae
A
10244/*********************************************************************
10245* Assumes sKextLock is held.
10246*********************************************************************/
10247/* static */
10248void
10249OSKext::updateLoadedKextSummaries(void)
10250{
10251 kern_return_t result = KERN_FAILURE;
10252 OSKextLoadedKextSummaryHeader *summaryHeader = NULL;
10253 OSKextLoadedKextSummaryHeader *summaryHeaderAlloc = NULL;
10254 OSKext *aKext;
10255 vm_map_offset_t start, end;
10256 size_t summarySize = 0;
10257 size_t size;
10258 u_int count;
10259 u_int numKexts;
10260 u_int i, j;
10261
10262 IOLockLock(sKextSummariesLock);
10263
10264 count = sLoadedKexts->getCount();
10265 for (i = 0, numKexts = 0; i < count; ++i) {
10266 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
10267 numKexts += (aKext && aKext->isExecutable());
10268 }
10269
10270 if (!numKexts) goto finish;
10271
10272 /* Calculate the size needed for the new summary headers.
10273 */
10274
10275 size = sizeof(*gLoadedKextSummaries);
10276 size += numKexts * sizeof(*gLoadedKextSummaries->summaries);
10277 size = round_page(size);
10278
10279 /* If the previous summary is large enough, use it (and be sure to make
10280 * it writable). If it's too small, free it and allocate a new buffer.
10281 */
10282
10283 if (sPrevLoadedKextSummariesAllocSize < size) {
10284 if (sPrevLoadedKextSummaries) {
10285 kmem_free(kernel_map, (vm_offset_t)sPrevLoadedKextSummaries,
10286 sPrevLoadedKextSummariesAllocSize);
10287 sPrevLoadedKextSummaries = NULL;
10288 sPrevLoadedKextSummariesAllocSize = 0;
10289 }
10290
10291 result = kmem_alloc(kernel_map,
10292 (vm_offset_t*)&summaryHeaderAlloc, size);
10293 if (result != KERN_SUCCESS) goto finish;
10294
10295 summaryHeader = summaryHeaderAlloc;
10296 summarySize = size;
10297 } else {
10298 summaryHeader = sPrevLoadedKextSummaries;
10299 summarySize = sPrevLoadedKextSummariesAllocSize;
10300
10301 start = (vm_map_offset_t) summaryHeader;
10302 end = start + summarySize;
6d2010ae
A
10303 }
10304
10305 /* Populate the summary header.
10306 */
10307
10308 bzero(summaryHeader, summarySize);
10309 summaryHeader->version = kOSKextLoadedKextSummaryVersion;
10310 summaryHeader->entry_size = sizeof(OSKextLoadedKextSummary);
10311 summaryHeader->numSummaries = numKexts;
10312
10313 /* Populate each kext summary.
10314 */
10315
10316 count = sLoadedKexts->getCount();
10317 for (i = 0, j = 0; i < count; ++i) {
10318 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
10319 if (!aKext || !aKext->isExecutable()) continue;
10320
10321 aKext->updateLoadedKextSummary(&summaryHeader->summaries[j++]);
10322 }
10323
10324 /* Write protect the buffer and move it into place.
10325 */
10326
10327 start = (vm_map_offset_t) summaryHeader;
10328 end = start + summarySize;
6d2010ae
A
10329
10330 sPrevLoadedKextSummaries = gLoadedKextSummaries;
10331 sPrevLoadedKextSummariesAllocSize = sLoadedKextSummariesAllocSize;
10332
10333 gLoadedKextSummaries = summaryHeader;
10334 sLoadedKextSummariesAllocSize = summarySize;
10335
10336 summaryHeaderAlloc = NULL;
10337
10338 /* Call the magic breakpoint function through a static function pointer so
10339 * the compiler can't optimize the function away.
10340 */
10341 if (sLoadedKextSummariesUpdated) (*sLoadedKextSummariesUpdated)();
10342
10343finish:
10344 IOLockUnlock(sKextSummariesLock);
10345
10346 /* If we had to allocate a new buffer but failed to generate the summaries,
10347 * free that now.
10348 */
10349 if (summaryHeaderAlloc) {
10350 kmem_free(kernel_map, (vm_offset_t)summaryHeaderAlloc, summarySize);
10351 }
10352
10353 return;
10354}
10355
10356/*********************************************************************
10357*********************************************************************/
10358void
10359OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary *summary)
10360{
10361 OSData *uuid;
10362
10363 strlcpy(summary->name, getIdentifierCString(),
10364 sizeof(summary->name));
10365
10366 uuid = copyUUID();
10367 if (uuid) {
10368 memcpy(summary->uuid, uuid->getBytesNoCopy(), sizeof(summary->uuid));
10369 OSSafeRelease(uuid);
10370 }
10371
10372 summary->address = kmod_info->address;
10373 summary->size = kmod_info->size;
10374 summary->version = getVersion();
10375 summary->loadTag = kmod_info->id;
10376 summary->flags = 0;
10377 summary->reference_list = (uint64_t) kmod_info->reference_list;
10378
10379 return;
10380}
10381
b0d623f7
A
10382/*********************************************************************
10383*********************************************************************/
6d2010ae 10384#if __i386__
b0d623f7
A
10385/* static */
10386kern_return_t
10387OSKext::getKmodInfo(
10388 kmod_info_array_t * kmodList,
10389 mach_msg_type_number_t * kmodCount)
10390{
6d2010ae
A
10391 kern_return_t result = KERN_FAILURE;
10392 vm_offset_t data = 0;
10393 kmod_info_t * k, * kmod_info_scan_ptr;
b0d623f7 10394 kmod_reference_t * r, * ref_scan_ptr;
6d2010ae
A
10395 int ref_count;
10396 unsigned size = 0;
b0d623f7
A
10397
10398 *kmodList = (kmod_info_t *)0;
10399 *kmodCount = 0;
10400
10401 IORecursiveLockLock(sKextLock);
10402
10403 k = kmod;
10404 while (k) {
10405 size += sizeof(kmod_info_t);
10406 r = k->reference_list;
10407 while (r) {
10408 size +=sizeof(kmod_reference_t);
10409 r = r->next;
10410 }
10411 k = k->next;
10412 }
10413 if (!size) {
10414 result = KERN_SUCCESS;
10415 goto finish;
10416 }
10417
10418 result = kmem_alloc(kernel_map, &data, size);
10419 if (result != KERN_SUCCESS) {
10420 goto finish;
10421 }
10422
10423 /* Copy each kmod_info struct sequentially into the data buffer.
10424 * Set each struct's nonzero 'next' pointer back to itself as a sentinel;
10425 * the kernel space address is used to match refs, and a zero 'next' flags
10426 * the end of kmod_infos in the data buffer and the beginning of references.
10427 */
10428 k = kmod;
10429 kmod_info_scan_ptr = (kmod_info_t *)data;
10430 while (k) {
10431 *kmod_info_scan_ptr = *k;
10432 if (k->next) {
10433 kmod_info_scan_ptr->next = k;
10434 }
10435 kmod_info_scan_ptr++;
10436 k = k->next;
10437 }
10438
10439 /* Now add references after the kmod_info structs in the same buffer.
10440 * Update each kmod_info with the ref_count so we can associate
10441 * references with kmod_info structs.
10442 */
10443 k = kmod;
10444 ref_scan_ptr = (kmod_reference_t *)kmod_info_scan_ptr;
10445 kmod_info_scan_ptr = (kmod_info_t *)data;
10446 while (k) {
10447 r = k->reference_list;
10448 ref_count = 0;
10449 while (r) {
10450 /* Note the last kmod_info in the data buffer has its next == 0.
10451 * Since there can only be one like that,
10452 * this case is handled by the caller.
10453 */
10454 *ref_scan_ptr = *r;
10455 ref_scan_ptr++;
10456 r = r->next;
10457 ref_count++;
10458 }
10459 /* Stuff the # of refs into the 'reference_list' field of the kmod_info
10460 * struct for the client to interpret.
10461 */
10462 kmod_info_scan_ptr->reference_list = (kmod_reference_t *)(long)ref_count;
10463 kmod_info_scan_ptr++;
10464 k = k->next;
10465 }
10466
10467 result = vm_map_copyin(kernel_map, data, size, TRUE, (vm_map_copy_t *)kmodList);
10468 if (result != KERN_SUCCESS) {
10469 goto finish;
10470 }
10471
10472 *kmodCount = size;
10473 result = KERN_SUCCESS;
10474
10475finish:
10476 IORecursiveLockUnlock(sKextLock);
10477
10478 if (result != KERN_SUCCESS && data) {
10479 kmem_free(kernel_map, data, size);
10480 *kmodList = (kmod_info_t *)0;
10481 *kmodCount = 0;
10482 }
10483 return result;
10484}
6d2010ae 10485#endif /* __i386__ */
316670eb
A
10486
10487#if CONFIG_KEC_FIPS
10488
b0d623f7 10489#if PRAGMA_MARK
316670eb 10490#pragma mark Kernel External Components for FIPS compliance
b0d623f7 10491#endif
316670eb 10492
b0d623f7 10493/*********************************************************************
316670eb
A
10494 * Kernel External Components for FIPS compliance (KEC_FIPS)
10495 *********************************************************************/
10496static void *
10497GetAppleTEXTHashForKext(OSKext * theKext, OSDictionary *theInfoDict)
b0d623f7 10498{
316670eb
A
10499 AppleTEXTHash_t my_ath = {1, 0, NULL};
10500 AppleTEXTHash_t * my_athp = NULL; // do not release
10501 OSDictionary * textHashDict = NULL; // do not release
10502 OSData * segmentHash = NULL; // do not release
b0d623f7 10503
316670eb
A
10504 if (theKext == NULL || theInfoDict == NULL) {
10505 return(NULL);
b0d623f7
A
10506 }
10507
316670eb
A
10508 textHashDict = OSDynamicCast(OSDictionary, theInfoDict->getObject(kAppleTextHashesKey));
10509 if (textHashDict == NULL) {
10510 return(NULL);
b0d623f7 10511 }
316670eb
A
10512
10513 segmentHash = OSDynamicCast(OSData,
10514 textHashDict->getObject(ARCHNAME));
10515 if (segmentHash == NULL) {
10516 return(NULL);
b0d623f7
A
10517 }
10518
316670eb
A
10519 // KEC_FIPS type kexts never unload so we don't have to clean up our
10520 // AppleTEXTHash_t
10521 if (kmem_alloc(kernel_map, (vm_offset_t *) &my_athp,
10522 sizeof(AppleTEXTHash_t)) != KERN_SUCCESS) {
10523 return(NULL);
b0d623f7 10524 }
b0d623f7 10525
316670eb
A
10526 memcpy(my_athp, &my_ath, sizeof(my_ath));
10527 my_athp->ath_length = segmentHash->getLength();
10528 if (my_athp->ath_length > 0) {
10529 my_athp->ath_hash = (void *)segmentHash->getBytesNoCopy();
10530 }
b0d623f7 10531
316670eb
A
10532#if 0
10533 OSKextLog(theKext,
10534 kOSKextLogErrorLevel |
10535 kOSKextLogGeneralFlag,
10536 "Kext %s ath_version %d ath_length %d ath_hash %p",
10537 theKext->getIdentifierCString(),
10538 my_athp->ath_version,
10539 my_athp->ath_length,
10540 my_athp->ath_hash);
10541#endif
b0d623f7 10542
316670eb 10543 return( (void *) my_athp );
b0d623f7 10544}
b0d623f7 10545
316670eb 10546#endif // CONFIG_KEC_FIPS
b0d623f7 10547