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