]> git.saurik.com Git - apple/xnu.git/blob - libkern/c++/OSKext.cpp
xnu-3789.31.2.tar.gz
[apple/xnu.git] / libkern / c++ / OSKext.cpp
1 /*
2 * Copyright (c) 2008-2016 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 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 IORecursiveLockLock(sKextLock);
4425 if (!sAllKextLoadIdentifiers->containsObject(kextIdentifierSymbol)) {
4426 if (!sAllKextLoadIdentifiers->setObject(kextIdentifierSymbol)) {
4427 fail = true;
4428 } else {
4429 // xxx - need to find a way to associate this whole func w/the kext
4430 OSKextLog(/* kext */ NULL,
4431 // xxx - check level
4432 kOSKextLogStepLevel |
4433 kOSKextLogArchiveFlag,
4434 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
4435 kextIdentifier->getCStringNoCopy());
4436 }
4437 }
4438 IORecursiveLockUnlock(sKextLock);
4439
4440 finish:
4441
4442 if (fail) {
4443 OSKextLog(/* kext */ NULL,
4444 kOSKextLogErrorLevel |
4445 kOSKextLogArchiveFlag,
4446 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
4447 kextIdentifier->getCStringNoCopy());
4448 }
4449 OSSafeReleaseNULL(kextIdentifierSymbol);
4450 return;
4451 }
4452
4453 /*********************************************************************
4454 *********************************************************************/
4455 OSReturn
4456 OSKext::load(
4457 OSKextExcludeLevel startOpt,
4458 OSKextExcludeLevel startMatchingOpt,
4459 OSArray * personalityNames)
4460 {
4461 OSReturn result = kOSReturnError;
4462 kern_return_t kxldResult;
4463 OSKextExcludeLevel dependenciesStartOpt = startOpt;
4464 OSKextExcludeLevel dependenciesStartMatchingOpt = startMatchingOpt;
4465 unsigned int i, count;
4466 Boolean alreadyLoaded = false;
4467 OSKext * lastLoadedKext = NULL;
4468
4469 if (isInExcludeList()) {
4470 OSKextLog(this,
4471 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
4472 kOSKextLogLoadFlag,
4473 "Kext %s is in exclude list, not loadable",
4474 getIdentifierCString());
4475
4476 result = kOSKextReturnNotLoadable;
4477 goto finish;
4478 }
4479
4480 if (isLoaded()) {
4481 alreadyLoaded = true;
4482 result = kOSReturnSuccess;
4483
4484 OSKextLog(this,
4485 kOSKextLogDebugLevel |
4486 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4487 "Kext %s is already loaded.",
4488 getIdentifierCString());
4489 goto loaded;
4490 }
4491
4492 #if CONFIG_MACF
4493 if (current_task() != kernel_task) {
4494 int macCheckResult = 0;
4495 kauth_cred_t cred = NULL;
4496
4497 cred = kauth_cred_get_with_ref();
4498 macCheckResult = mac_kext_check_load(cred, getIdentifierCString());
4499 kauth_cred_unref(&cred);
4500
4501 if (macCheckResult != 0) {
4502 result = kOSReturnError;
4503 OSKextLog(this,
4504 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
4505 "Failed to load kext %s (MAC policy error 0x%x).",
4506 getIdentifierCString(), macCheckResult);
4507 goto finish;
4508 }
4509 }
4510 #endif
4511
4512 if (!sLoadEnabled) {
4513 OSKextLog(this,
4514 kOSKextLogErrorLevel |
4515 kOSKextLogLoadFlag,
4516 "Kext loading is disabled (attempt to load kext %s).",
4517 getIdentifierCString());
4518 result = kOSKextReturnDisabled;
4519 goto finish;
4520 }
4521
4522 /* If we've pushed the next available load tag to the invalid value,
4523 * we can't load any more kexts.
4524 */
4525 if (sNextLoadTag == kOSKextInvalidLoadTag) {
4526 OSKextLog(this,
4527 kOSKextLogErrorLevel |
4528 kOSKextLogLoadFlag,
4529 "Can't load kext %s - no more load tags to assign.",
4530 getIdentifierCString());
4531 result = kOSKextReturnNoResources;
4532 goto finish;
4533 }
4534
4535 /* This is a bit of a hack, because we shouldn't be handling
4536 * personalities within the load function.
4537 */
4538 if (!declaresExecutable()) {
4539 result = kOSReturnSuccess;
4540 goto loaded;
4541 }
4542
4543 /* Are we in safe boot?
4544 */
4545 if (sSafeBoot && !isLoadableInSafeBoot()) {
4546 OSKextLog(this,
4547 kOSKextLogErrorLevel |
4548 kOSKextLogLoadFlag,
4549 "Can't load kext %s - not loadable during safe boot.",
4550 getIdentifierCString());
4551 result = kOSKextReturnBootLevel;
4552 goto finish;
4553 }
4554
4555 OSKextLog(this,
4556 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
4557 "Loading kext %s.",
4558 getIdentifierCString());
4559
4560 if (!sKxldContext) {
4561 kxldResult = kxld_create_context(&sKxldContext, &kern_allocate,
4562 &kxld_log_callback, /* Flags */ (KXLDFlags) 0,
4563 /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
4564 if (kxldResult) {
4565 OSKextLog(this,
4566 kOSKextLogErrorLevel |
4567 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
4568 "Can't load kext %s - failed to create link context.",
4569 getIdentifierCString());
4570 result = kOSKextReturnNoMemory;
4571 goto finish;
4572 }
4573 }
4574
4575 /* We only need to resolve dependencies once for the whole graph, but
4576 * resolveDependencies will just return if there's no work to do, so it's
4577 * safe to call it more than once.
4578 */
4579 if (!resolveDependencies()) {
4580 // xxx - check resolveDependencies() for log msg
4581 OSKextLog(this,
4582 kOSKextLogErrorLevel |
4583 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4584 "Can't load kext %s - failed to resolve library dependencies.",
4585 getIdentifierCString());
4586 result = kOSKextReturnDependencies;
4587 goto finish;
4588 }
4589
4590 /* If we are excluding just the kext being loaded now (and not its
4591 * dependencies), drop the exclusion level to none so dependencies
4592 * start and/or add their personalities.
4593 */
4594 if (dependenciesStartOpt == kOSKextExcludeKext) {
4595 dependenciesStartOpt = kOSKextExcludeNone;
4596 }
4597
4598 if (dependenciesStartMatchingOpt == kOSKextExcludeKext) {
4599 dependenciesStartMatchingOpt = kOSKextExcludeNone;
4600 }
4601
4602 /* Load the dependencies, recursively.
4603 */
4604 count = getNumDependencies();
4605 for (i = 0; i < count; i++) {
4606 OSKext * dependency = OSDynamicCast(OSKext,
4607 dependencies->getObject(i));
4608 if (dependency == NULL) {
4609 OSKextLog(this,
4610 kOSKextLogErrorLevel |
4611 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4612 "Internal error loading kext %s; dependency disappeared.",
4613 getIdentifierCString());
4614 result = kOSKextReturnInternalError;
4615 goto finish;
4616 }
4617
4618 /* Dependencies must be started accorting to the opt,
4619 * but not given the personality names of the main kext.
4620 */
4621 result = dependency->load(dependenciesStartOpt,
4622 dependenciesStartMatchingOpt,
4623 /* personalityNames */ NULL);
4624 if (result != KERN_SUCCESS) {
4625 OSKextLog(this,
4626 kOSKextLogErrorLevel |
4627 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4628 "Dependency %s of kext %s failed to load.",
4629 dependency->getIdentifierCString(),
4630 getIdentifierCString());
4631
4632 OSKext::removeKext(dependency,
4633 /* terminateService/removePersonalities */ true);
4634 result = kOSKextReturnDependencyLoadError;
4635
4636 goto finish;
4637 }
4638 }
4639
4640 result = loadExecutable();
4641 if (result != KERN_SUCCESS) {
4642 goto finish;
4643 }
4644
4645 pendingPgoHead.next = &pendingPgoHead;
4646 pendingPgoHead.prev = &pendingPgoHead;
4647
4648 uuid_generate(instance_uuid);
4649 account = IONew(OSKextAccount, 1);
4650 if (!account) {
4651 result = KERN_MEMORY_ERROR;
4652 goto finish;
4653 }
4654 bzero(account, sizeof(*account));
4655 account->loadTag = kmod_info->id;
4656 account->site.flags = VM_TAG_KMOD;
4657 account->kext = this;
4658
4659 flags.loaded = true;
4660
4661 /* Add the kext to the list of loaded kexts and update the kmod_info
4662 * struct to point to that of the last loaded kext (which is the way
4663 * it's always been done, though I'd rather do them in order now).
4664 */
4665 lastLoadedKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
4666 sLoadedKexts->setObject(this);
4667
4668 /* Keep the kernel itself out of the kmod list.
4669 */
4670 if (lastLoadedKext->isKernel()) {
4671 lastLoadedKext = NULL;
4672 }
4673
4674 if (lastLoadedKext) {
4675 kmod_info->next = lastLoadedKext->kmod_info;
4676 }
4677
4678 notifyKextLoadObservers(this, kmod_info);
4679
4680 /* Make the global kmod list point at the just-loaded kext. Note that the
4681 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
4682 * although we do report it in kextstat these days by using the newer
4683 * OSArray of loaded kexts, which does contain it.
4684 *
4685 * (The OSKext object representing the kernel doesn't even have a kmod_info
4686 * struct, though I suppose we could stick a pointer to it from the
4687 * static struct in OSRuntime.cpp.)
4688 */
4689 kmod = kmod_info;
4690
4691 /* Save the list of loaded kexts in case we panic.
4692 */
4693 OSKext::saveLoadedKextPanicList();
4694
4695 if (isExecutable()) {
4696 OSKext::updateLoadedKextSummaries();
4697 savePanicString(/* isLoading */ true);
4698
4699 #if CONFIG_DTRACE
4700 registerWithDTrace();
4701 #else
4702 jettisonLinkeditSegment();
4703 #endif /* CONFIG_DTRACE */
4704
4705 #if !VM_MAPPED_KEXTS
4706 /* If there is a page (or more) worth of padding after the end
4707 * of the last data section but before the end of the data segment
4708 * then free it in the same manner the LinkeditSegment is freed
4709 */
4710 jettisonDATASegmentPadding();
4711 #endif
4712 }
4713
4714 loaded:
4715 if (isExecutable() && !flags.started) {
4716 if (startOpt == kOSKextExcludeNone) {
4717 result = start();
4718 if (result != kOSReturnSuccess) {
4719 OSKextLog(this,
4720 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
4721 "Kext %s start failed (result 0x%x).",
4722 getIdentifierCString(), result);
4723 result = kOSKextReturnStartStopError;
4724 }
4725 }
4726 }
4727
4728 /* If not excluding matching, send the personalities to the kernel.
4729 * This never affects the result of the load operation.
4730 * This is a bit of a hack, because we shouldn't be handling
4731 * personalities within the load function.
4732 */
4733 if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
4734 result = sendPersonalitiesToCatalog(true, personalityNames);
4735 }
4736
4737 finish:
4738
4739 /* More hack! If the kext doesn't declare an executable, even if we
4740 * "loaded" it, we have to remove any personalities naming it, or we'll
4741 * never see the registry go quiet. Errors here do not count for the
4742 * load operation itself.
4743 *
4744 * Note that in every other regard it's perfectly ok for a kext to
4745 * not declare an executable and serve only as a package for personalities
4746 * naming another kext, so we do have to allow such kexts to be "loaded"
4747 * so that those other personalities get added & matched.
4748 */
4749 if (!declaresExecutable()) {
4750 OSKextLog(this,
4751 kOSKextLogStepLevel | kOSKextLogLoadFlag,
4752 "Kext %s has no executable; removing any personalities naming it.",
4753 getIdentifierCString());
4754 removePersonalitiesFromCatalog();
4755 }
4756
4757 if (result != kOSReturnSuccess) {
4758 OSKextLog(this,
4759 kOSKextLogErrorLevel |
4760 kOSKextLogLoadFlag,
4761 "Kext %s failed to load (0x%x).",
4762 getIdentifierCString(), (int)result);
4763 } else if (!alreadyLoaded) {
4764 OSKextLog(this,
4765 kOSKextLogProgressLevel |
4766 kOSKextLogLoadFlag,
4767 "Kext %s loaded.",
4768 getIdentifierCString());
4769
4770 queueKextNotification(kKextRequestPredicateLoadNotification,
4771 OSDynamicCast(OSString, bundleID));
4772 }
4773 return result;
4774 }
4775
4776 /*********************************************************************
4777 *
4778 *********************************************************************/
4779 static char * strdup(const char * string)
4780 {
4781 char * result = NULL;
4782 size_t size;
4783
4784 if (!string) {
4785 goto finish;
4786 }
4787
4788 size = 1 + strlen(string);
4789 result = (char *)kalloc_tag(size, VM_KERN_MEMORY_OSKEXT);
4790 if (!result) {
4791 goto finish;
4792 }
4793
4794 memcpy(result, string, size);
4795
4796 finish:
4797 return result;
4798 }
4799
4800 /*********************************************************************
4801 *
4802 *********************************************************************/
4803
4804 kernel_section_t *
4805 OSKext::lookupSection(const char *segname, const char *secname)
4806 {
4807 kernel_section_t * found_section = NULL;
4808 kernel_mach_header_t * mh = NULL;
4809 kernel_segment_command_t * seg = NULL;
4810 kernel_section_t * sec = NULL;
4811
4812 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
4813
4814 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
4815
4816 if (0 != strcmp(seg->segname, segname)) {
4817 continue;
4818 }
4819
4820 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
4821
4822 if (0 == strcmp(sec->sectname, secname)) {
4823 found_section = sec;
4824 goto out;
4825 }
4826 }
4827 }
4828
4829 out:
4830 return found_section;
4831 }
4832
4833 /*********************************************************************
4834 *
4835 *********************************************************************/
4836
4837 OSReturn
4838 OSKext::slidePrelinkedExecutable(bool doCoalesedSlides)
4839 {
4840 OSReturn result = kOSKextReturnBadData;
4841 kernel_mach_header_t * mh = NULL;
4842 kernel_segment_command_t * seg = NULL;
4843 kernel_segment_command_t * linkeditSeg = NULL;
4844 kernel_section_t * sec = NULL;
4845 char * linkeditBase = NULL;
4846 bool haveLinkeditBase = false;
4847 char * relocBase = NULL;
4848 bool haveRelocBase = false;
4849 struct dysymtab_command * dysymtab = NULL;
4850 struct linkedit_data_command * segmentSplitInfo = NULL;
4851 struct symtab_command * symtab = NULL;
4852 kernel_nlist_t * sym = NULL;
4853 struct relocation_info * reloc = NULL;
4854 uint32_t i = 0;
4855 int reloc_size;
4856 vm_offset_t new_kextsize;
4857
4858 if (linkedExecutable == NULL || vm_kernel_slide == 0) {
4859 result = kOSReturnSuccess;
4860 goto finish;
4861 }
4862
4863 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
4864 segmentSplitInfo = (struct linkedit_data_command *) getcommandfromheader(mh, LC_SEGMENT_SPLIT_INFO);
4865
4866 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
4867 if (!seg->vmaddr) {
4868 continue;
4869 }
4870 seg->vmaddr += vm_kernel_slide;
4871
4872 #if KASLR_KEXT_DEBUG
4873 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
4874 seg->segname,
4875 (unsigned long)VM_KERNEL_UNSLIDE(seg->vmaddr),
4876 (unsigned long)seg->vmaddr);
4877 #endif
4878
4879 if (!haveRelocBase) {
4880 relocBase = (char *) seg->vmaddr;
4881 haveRelocBase = true;
4882 }
4883 if (!strcmp(seg->segname, "__LINKEDIT")) {
4884 linkeditBase = (char *) seg->vmaddr - seg->fileoff;
4885 haveLinkeditBase = true;
4886 linkeditSeg = seg;
4887 }
4888 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
4889 sec->addr += vm_kernel_slide;
4890
4891 #if KASLR_KEXT_DEBUG
4892 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
4893 sec->sectname,
4894 (unsigned long)VM_KERNEL_UNSLIDE(sec->addr),
4895 (unsigned long)sec->addr);
4896 #endif
4897 }
4898 }
4899
4900 dysymtab = (struct dysymtab_command *) getcommandfromheader(mh, LC_DYSYMTAB);
4901
4902 symtab = (struct symtab_command *) getcommandfromheader(mh, LC_SYMTAB);
4903
4904 if (symtab != NULL && doCoalesedSlides == false) {
4905 /* Some pseudo-kexts have symbol tables without segments.
4906 * Ignore them. */
4907 if (symtab->nsyms > 0 && haveLinkeditBase) {
4908 sym = (kernel_nlist_t *) (linkeditBase + symtab->symoff);
4909 for (i = 0; i < symtab->nsyms; i++) {
4910 if (sym[i].n_type & N_STAB) {
4911 continue;
4912 }
4913 sym[i].n_value += vm_kernel_slide;
4914
4915 #if KASLR_KEXT_DEBUG
4916 #define MAX_SYMS_TO_LOG 5
4917 if ( i < MAX_SYMS_TO_LOG ) {
4918 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
4919 (unsigned long)VM_KERNEL_UNSLIDE(sym[i].n_value),
4920 (unsigned long)sym[i].n_value);
4921 }
4922 #endif
4923 }
4924 }
4925 }
4926
4927 if (dysymtab != NULL && doCoalesedSlides == false) {
4928 if (dysymtab->nextrel > 0) {
4929 OSKextLog(this,
4930 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
4931 kOSKextLogLinkFlag,
4932 "Sliding kext %s: External relocations found.",
4933 getIdentifierCString());
4934 goto finish;
4935 }
4936
4937 if (dysymtab->nlocrel > 0) {
4938 if (!haveLinkeditBase) {
4939 OSKextLog(this,
4940 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
4941 kOSKextLogLinkFlag,
4942 "Sliding kext %s: No linkedit segment.",
4943 getIdentifierCString());
4944 goto finish;
4945 }
4946
4947 if (!haveRelocBase) {
4948 OSKextLog(this,
4949 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
4950 kOSKextLogLinkFlag,
4951 #if __x86_64__
4952 "Sliding kext %s: No writable segments.",
4953 #else
4954 "Sliding kext %s: No segments.",
4955 #endif
4956 getIdentifierCString());
4957 goto finish;
4958 }
4959
4960 reloc = (struct relocation_info *) (linkeditBase + dysymtab->locreloff);
4961 reloc_size = dysymtab->nlocrel * sizeof(struct relocation_info);
4962
4963 for (i = 0; i < dysymtab->nlocrel; i++) {
4964 if ( reloc[i].r_extern != 0
4965 || reloc[i].r_type != 0
4966 || reloc[i].r_length != (sizeof(void *) == 8 ? 3 : 2)
4967 ) {
4968 OSKextLog(this,
4969 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
4970 kOSKextLogLinkFlag,
4971 "Sliding kext %s: Unexpected relocation found.",
4972 getIdentifierCString());
4973 goto finish;
4974 }
4975 if (reloc[i].r_pcrel != 0) {
4976 continue;
4977 }
4978 *((uintptr_t *)(relocBase + reloc[i].r_address)) += vm_kernel_slide;
4979
4980 #if KASLR_KEXT_DEBUG
4981 #define MAX_DYSYMS_TO_LOG 5
4982 if ( i < MAX_DYSYMS_TO_LOG ) {
4983 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
4984 (unsigned long)VM_KERNEL_UNSLIDE(*((uintptr_t *)(relocBase + reloc[i].r_address))),
4985 (unsigned long)*((uintptr_t *)(relocBase + reloc[i].r_address)));
4986 }
4987 #endif
4988 }
4989
4990 /* We should free these relocations, not just delete the reference to them.
4991 * <rdar://problem/10535549> Free relocations from PIE kexts.
4992 *
4993 * For now, we do not free LINKEDIT for kexts with split segments.
4994 */
4995 new_kextsize = round_page(kmod_info->size - reloc_size);
4996 if (((kmod_info->size - new_kextsize) > PAGE_SIZE) && (!segmentSplitInfo)) {
4997 vm_offset_t endofkext = kmod_info->address + kmod_info->size;
4998 vm_offset_t new_endofkext = kmod_info->address + new_kextsize;
4999 vm_offset_t endofrelocInfo = (vm_offset_t) (((uint8_t *)reloc) + reloc_size);
5000 int bytes_remaining = endofkext - endofrelocInfo;
5001 OSData * new_osdata = NULL;
5002
5003 /* fix up symbol offsets if they are after the dsymtab local relocs */
5004 if (symtab) {
5005 if (dysymtab->locreloff < symtab->symoff){
5006 symtab->symoff -= reloc_size;
5007 }
5008 if (dysymtab->locreloff < symtab->stroff) {
5009 symtab->stroff -= reloc_size;
5010 }
5011 }
5012 if (dysymtab->locreloff < dysymtab->extreloff) {
5013 dysymtab->extreloff -= reloc_size;
5014 }
5015
5016 /* move data behind reloc info down to new offset */
5017 if (endofrelocInfo < endofkext) {
5018 memcpy(reloc, (void *)endofrelocInfo, bytes_remaining);
5019 }
5020
5021 /* Create a new OSData for the smaller kext object and reflect
5022 * new linkedit segment size.
5023 */
5024 linkeditSeg->vmsize = round_page(linkeditSeg->vmsize - reloc_size);
5025 linkeditSeg->filesize = linkeditSeg->vmsize;
5026
5027 new_osdata = OSData::withBytesNoCopy((void *)kmod_info->address, new_kextsize);
5028 if (new_osdata) {
5029 /* Fix up kmod info and linkedExecutable.
5030 */
5031 kmod_info->size = new_kextsize;
5032 #if VM_MAPPED_KEXTS
5033 new_osdata->setDeallocFunction(osdata_kext_free);
5034 #else
5035 new_osdata->setDeallocFunction(osdata_phys_free);
5036 #endif
5037 linkedExecutable->setDeallocFunction(NULL);
5038 linkedExecutable->release();
5039 linkedExecutable = new_osdata;
5040
5041 #if VM_MAPPED_KEXTS
5042 kext_free(new_endofkext, (endofkext - new_endofkext));
5043 #else
5044 ml_static_mfree(new_endofkext, (endofkext - new_endofkext));
5045 #endif
5046 }
5047 }
5048 dysymtab->nlocrel = 0;
5049 dysymtab->locreloff = 0;
5050 }
5051 }
5052
5053 result = kOSReturnSuccess;
5054 finish:
5055 return result;
5056 }
5057
5058 /*********************************************************************
5059 * called only by load()
5060 *********************************************************************/
5061 OSReturn
5062 OSKext::loadExecutable()
5063 {
5064 OSReturn result = kOSReturnError;
5065 kern_return_t kxldResult;
5066 KXLDDependency * kxlddeps = NULL; // must kfree
5067 uint32_t num_kxlddeps = 0;
5068 OSArray * linkDependencies = NULL; // must release
5069 uint32_t numDirectDependencies = 0;
5070 uint32_t num_kmod_refs = 0;
5071 struct mach_header ** kxldHeaderPtr = NULL; // do not free
5072 struct mach_header * kxld_header = NULL; // xxx - need to free here?
5073 OSData * theExecutable = NULL; // do not release
5074 OSString * versString = NULL; // do not release
5075 const char * versCString = NULL; // do not free
5076 const char * string = NULL; // do not free
5077 unsigned int i;
5078
5079 /* We need the version string for a variety of bits below.
5080 */
5081 versString = OSDynamicCast(OSString,
5082 getPropertyForHostArch(kCFBundleVersionKey));
5083 if (!versString) {
5084 goto finish;
5085 }
5086 versCString = versString->getCStringNoCopy();
5087
5088 if (isKernelComponent()) {
5089 if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
5090
5091 if (strncmp(versCString, KERNEL6_VERSION, strlen(KERNEL6_VERSION))) {
5092 OSKextLog(this,
5093 kOSKextLogErrorLevel |
5094 kOSKextLogLoadFlag,
5095 "Kernel component %s has incorrect version %s; "
5096 "expected %s.",
5097 getIdentifierCString(),
5098 versCString, KERNEL6_VERSION);
5099 result = kOSKextReturnInternalError;
5100 goto finish;
5101 } else if (strcmp(versCString, osrelease)) {
5102 OSKextLog(this,
5103 kOSKextLogErrorLevel |
5104 kOSKextLogLoadFlag,
5105 "Kernel component %s has incorrect version %s; "
5106 "expected %s.",
5107 getIdentifierCString(),
5108 versCString, osrelease);
5109 result = kOSKextReturnInternalError;
5110 goto finish;
5111 }
5112 }
5113 }
5114
5115 if (isPrelinked()) {
5116 goto register_kmod;
5117 }
5118
5119 /* <rdar://problem/21444003> all callers must be entitled */
5120 if (FALSE == IOTaskHasEntitlement(current_task(), "com.apple.rootless.kext-management")) {
5121 OSKextLog(this,
5122 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5123 "Not entitled to link kext '%s'",
5124 getIdentifierCString());
5125 result = kOSKextReturnNotPrivileged;
5126 goto finish;
5127 }
5128
5129 theExecutable = getExecutable();
5130 if (!theExecutable) {
5131 if (declaresExecutable()) {
5132 OSKextLog(this,
5133 kOSKextLogErrorLevel |
5134 kOSKextLogLoadFlag,
5135 "Can't load kext %s - executable is missing.",
5136 getIdentifierCString());
5137 result = kOSKextReturnValidation;
5138 goto finish;
5139 }
5140 goto register_kmod;
5141 }
5142
5143 if (isInterface()) {
5144 OSData *executableCopy = OSData::withData(theExecutable);
5145 setLinkedExecutable(executableCopy);
5146 executableCopy->release();
5147 goto register_kmod;
5148 }
5149
5150 numDirectDependencies = getNumDependencies();
5151
5152 if (flags.hasBleedthrough) {
5153 linkDependencies = dependencies;
5154 linkDependencies->retain();
5155 } else {
5156 linkDependencies = OSArray::withArray(dependencies);
5157 if (!linkDependencies) {
5158 OSKextLog(this,
5159 kOSKextLogErrorLevel |
5160 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
5161 "Can't allocate link dependencies to load kext %s.",
5162 getIdentifierCString());
5163 goto finish;
5164 }
5165
5166 for (i = 0; i < numDirectDependencies; ++i) {
5167 OSKext * dependencyKext = OSDynamicCast(OSKext,
5168 dependencies->getObject(i));
5169 dependencyKext->addBleedthroughDependencies(linkDependencies);
5170 }
5171 }
5172
5173 num_kxlddeps = linkDependencies->getCount();
5174 if (!num_kxlddeps) {
5175 OSKextLog(this,
5176 kOSKextLogErrorLevel |
5177 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5178 "Can't load kext %s - it has no library dependencies.",
5179 getIdentifierCString());
5180 goto finish;
5181 }
5182
5183 kxlddeps = (KXLDDependency *)kalloc_tag(num_kxlddeps * sizeof(*kxlddeps), VM_KERN_MEMORY_OSKEXT);
5184 if (!kxlddeps) {
5185 OSKextLog(this,
5186 kOSKextLogErrorLevel |
5187 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
5188 "Can't allocate link context to load kext %s.",
5189 getIdentifierCString());
5190 goto finish;
5191 }
5192 bzero(kxlddeps, num_kxlddeps * sizeof(*kxlddeps));
5193
5194 for (i = 0; i < num_kxlddeps; ++i ) {
5195 OSKext * dependency = OSDynamicCast(OSKext, linkDependencies->getObject(i));
5196
5197 if (dependency->isInterface()) {
5198 OSKext *interfaceTargetKext = NULL;
5199 OSData * interfaceTarget = NULL;
5200
5201 if (dependency->isKernelComponent()) {
5202 interfaceTargetKext = sKernelKext;
5203 interfaceTarget = sKernelKext->linkedExecutable;
5204 } else {
5205 interfaceTargetKext = OSDynamicCast(OSKext,
5206 dependency->dependencies->getObject(0));
5207
5208 interfaceTarget = interfaceTargetKext->linkedExecutable;
5209 }
5210
5211 if (!interfaceTarget) {
5212 // panic?
5213 goto finish;
5214 }
5215
5216 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
5217 * it will be useful to have them in the debugger.
5218 * strdup() failing isn't critical right here so we don't check that.
5219 */
5220 kxlddeps[i].kext = (u_char *) interfaceTarget->getBytesNoCopy();
5221 kxlddeps[i].kext_size = interfaceTarget->getLength();
5222 kxlddeps[i].kext_name = strdup(interfaceTargetKext->getIdentifierCString());
5223
5224 kxlddeps[i].interface = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
5225 kxlddeps[i].interface_size = dependency->linkedExecutable->getLength();
5226 kxlddeps[i].interface_name = strdup(dependency->getIdentifierCString());
5227 } else {
5228 kxlddeps[i].kext = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
5229 kxlddeps[i].kext_size = dependency->linkedExecutable->getLength();
5230 kxlddeps[i].kext_name = strdup(dependency->getIdentifierCString());
5231 }
5232
5233 kxlddeps[i].is_direct_dependency = (i < numDirectDependencies);
5234 }
5235
5236 kxldHeaderPtr = &kxld_header;
5237
5238 #if DEBUG
5239 OSKextLog(this,
5240 kOSKextLogExplicitLevel |
5241 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
5242 "Kext %s - calling kxld_link_file:\n"
5243 " kxld_context: %p\n"
5244 " executable: %p executable_length: %d\n"
5245 " user_data: %p\n"
5246 " kxld_dependencies: %p num_dependencies: %d\n"
5247 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
5248 getIdentifierCString(), sKxldContext,
5249 theExecutable->getBytesNoCopy(), theExecutable->getLength(),
5250 this, kxlddeps, num_kxlddeps,
5251 kxldHeaderPtr, &kmod_info);
5252 #endif
5253
5254 /* After this call, the linkedExecutable instance variable
5255 * should exist.
5256 */
5257 kxldResult = kxld_link_file(sKxldContext,
5258 (u_char *)theExecutable->getBytesNoCopy(),
5259 theExecutable->getLength(),
5260 getIdentifierCString(), this, kxlddeps, num_kxlddeps,
5261 (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info);
5262
5263 if (kxldResult != KERN_SUCCESS) {
5264 // xxx - add kxldResult here?
5265 OSKextLog(this,
5266 kOSKextLogErrorLevel |
5267 kOSKextLogLoadFlag,
5268 "Can't load kext %s - link failed.",
5269 getIdentifierCString());
5270 result = kOSKextReturnLinkError;
5271 goto finish;
5272 }
5273
5274 /* We've written data & instructions into kernel memory, so flush the data
5275 * cache and invalidate the instruction cache.
5276 * I/D caches are coherent on x86
5277 */
5278 #if !defined(__i386__) && !defined(__x86_64__)
5279 flush_dcache(kmod_info->address, kmod_info->size, false);
5280 invalidate_icache(kmod_info->address, kmod_info->size, false);
5281 #endif
5282 register_kmod:
5283
5284 if (isInterface()) {
5285
5286 /* Whip up a fake kmod_info entry for the interface kext.
5287 */
5288 kmod_info = (kmod_info_t *)kalloc_tag(sizeof(kmod_info_t), VM_KERN_MEMORY_OSKEXT);
5289 if (!kmod_info) {
5290 result = KERN_MEMORY_ERROR;
5291 goto finish;
5292 }
5293
5294 /* A pseudokext has almost nothing in its kmod_info struct.
5295 */
5296 bzero(kmod_info, sizeof(kmod_info_t));
5297
5298 kmod_info->info_version = KMOD_INFO_VERSION;
5299
5300 /* An interface kext doesn't have a linkedExecutable, so save a
5301 * copy of the UUID out of the original executable via copyUUID()
5302 * while we still have the original executable.
5303 */
5304 interfaceUUID = copyUUID();
5305 }
5306
5307 kmod_info->id = loadTag = sNextLoadTag++;
5308 kmod_info->reference_count = 0; // KMOD_DECL... sets it to -1 (invalid).
5309
5310 /* Stamp the bundle ID and version from the OSKext over anything
5311 * resident inside the kmod_info.
5312 */
5313 string = getIdentifierCString();
5314 strlcpy(kmod_info->name, string, sizeof(kmod_info->name));
5315
5316 string = versCString;
5317 strlcpy(kmod_info->version, string, sizeof(kmod_info->version));
5318
5319 /* Add the dependencies' kmod_info structs as kmod_references.
5320 */
5321 num_kmod_refs = getNumDependencies();
5322 if (num_kmod_refs) {
5323 kmod_info->reference_list = (kmod_reference_t *)kalloc_tag(
5324 num_kmod_refs * sizeof(kmod_reference_t), VM_KERN_MEMORY_OSKEXT);
5325 if (!kmod_info->reference_list) {
5326 result = KERN_MEMORY_ERROR;
5327 goto finish;
5328 }
5329 bzero(kmod_info->reference_list,
5330 num_kmod_refs * sizeof(kmod_reference_t));
5331 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
5332 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
5333 OSKext * refKext = OSDynamicCast(OSKext, dependencies->getObject(refIndex));
5334 ref->info = refKext->kmod_info;
5335 ref->info->reference_count++;
5336
5337 if (refIndex + 1 < num_kmod_refs) {
5338 ref->next = kmod_info->reference_list + refIndex + 1;
5339 }
5340 }
5341 }
5342
5343 if (!isInterface() && linkedExecutable) {
5344 OSKextLog(this,
5345 kOSKextLogProgressLevel |
5346 kOSKextLogLoadFlag,
5347 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
5348 kmod_info->name,
5349 (unsigned)kmod_info->size / PAGE_SIZE,
5350 (unsigned long)VM_KERNEL_UNSLIDE(kmod_info->address),
5351 (unsigned)kmod_info->id);
5352 }
5353
5354 /* if prelinked, VM protections are already set */
5355 result = setVMAttributes(!isPrelinked(), true);
5356 if (result != KERN_SUCCESS) {
5357 goto finish;
5358 }
5359
5360 result = kOSReturnSuccess;
5361
5362 finish:
5363 OSSafeReleaseNULL(linkDependencies);
5364
5365 /* Clear up locally allocated dependency info.
5366 */
5367 for (i = 0; i < num_kxlddeps; ++i ) {
5368 size_t size;
5369
5370 if (kxlddeps[i].kext_name) {
5371 size = 1 + strlen(kxlddeps[i].kext_name);
5372 kfree(kxlddeps[i].kext_name, size);
5373 }
5374 if (kxlddeps[i].interface_name) {
5375 size = 1 + strlen(kxlddeps[i].interface_name);
5376 kfree(kxlddeps[i].interface_name, size);
5377 }
5378 }
5379 if (kxlddeps) kfree(kxlddeps, (num_kxlddeps * sizeof(*kxlddeps)));
5380
5381 /* We no longer need the unrelocated executable (which the linker
5382 * has altered anyhow).
5383 */
5384 setExecutable(NULL);
5385
5386 if (result != kOSReturnSuccess) {
5387 OSKextLog(this,
5388 kOSKextLogErrorLevel |
5389 kOSKextLogLoadFlag,
5390 "Failed to load executable for kext %s.",
5391 getIdentifierCString());
5392
5393 if (kmod_info && kmod_info->reference_list) {
5394 kfree(kmod_info->reference_list,
5395 num_kmod_refs * sizeof(kmod_reference_t));
5396 }
5397 if (isInterface()) {
5398 kfree(kmod_info, sizeof(kmod_info_t));
5399 }
5400 kmod_info = NULL;
5401 if (linkedExecutable) {
5402 linkedExecutable->release();
5403 linkedExecutable = NULL;
5404 }
5405 }
5406
5407 return result;
5408 }
5409
5410 /*********************************************************************
5411 * The linkedit segment is used by the kext linker for dependency
5412 * resolution, and by dtrace for probe initialization. We can free it
5413 * for non-library kexts, since no kexts depend on non-library kexts
5414 * by definition, once dtrace has been initialized.
5415 *********************************************************************/
5416 void
5417 OSKext::jettisonLinkeditSegment(void)
5418 {
5419 kernel_mach_header_t * machhdr = (kernel_mach_header_t *)kmod_info->address;
5420 kernel_segment_command_t * linkedit = NULL;
5421 vm_offset_t start;
5422 vm_size_t linkeditsize, kextsize;
5423 OSData * data = NULL;
5424
5425 #if NO_KEXTD
5426 /* We can free symbol tables for all embedded kexts because we don't
5427 * support runtime kext linking.
5428 */
5429 if (sKeepSymbols || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
5430 #else
5431 if (sKeepSymbols || isLibrary() || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
5432 #endif
5433 goto finish;
5434 }
5435
5436 /* Find the linkedit segment. If it's not the last segment, then freeing
5437 * it will fragment the kext into multiple VM regions, which OSKext is not
5438 * designed to handle, so we'll have to skip it.
5439 */
5440 linkedit = getsegbynamefromheader(machhdr, SEG_LINKEDIT);
5441 if (!linkedit) {
5442 goto finish;
5443 }
5444
5445 if (round_page(kmod_info->address + kmod_info->size) !=
5446 round_page(linkedit->vmaddr + linkedit->vmsize))
5447 {
5448 goto finish;
5449 }
5450
5451 /* Create a new OSData for the smaller kext object.
5452 */
5453 linkeditsize = round_page(linkedit->vmsize);
5454 kextsize = kmod_info->size - linkeditsize;
5455 start = linkedit->vmaddr;
5456
5457 data = OSData::withBytesNoCopy((void *)kmod_info->address, kextsize);
5458 if (!data) {
5459 goto finish;
5460 }
5461
5462 /* Fix the kmod info and linkedExecutable.
5463 */
5464 kmod_info->size = kextsize;
5465
5466 #if VM_MAPPED_KEXTS
5467 data->setDeallocFunction(osdata_kext_free);
5468 #else
5469 data->setDeallocFunction(osdata_phys_free);
5470 #endif
5471 linkedExecutable->setDeallocFunction(NULL);
5472 linkedExecutable->release();
5473 linkedExecutable = data;
5474 flags.jettisonLinkeditSeg = 1;
5475
5476 /* Free the linkedit segment.
5477 */
5478 #if VM_MAPPED_KEXTS
5479 kext_free(start, linkeditsize);
5480 #else
5481 ml_static_mfree(start, linkeditsize);
5482 #endif
5483
5484 finish:
5485 return;
5486 }
5487
5488 /*********************************************************************
5489 * If there are whole pages that are unused betweem the last section
5490 * of the DATA segment and the end of the DATA segment then we can free
5491 * them
5492 *********************************************************************/
5493 void
5494 OSKext::jettisonDATASegmentPadding(void)
5495 {
5496 kernel_mach_header_t * mh;
5497 kernel_segment_command_t * dataSeg;
5498 kernel_section_t * sec, * lastSec;
5499 vm_offset_t dataSegEnd, lastSecEnd;
5500 vm_size_t padSize;
5501
5502 mh = (kernel_mach_header_t *)kmod_info->address;
5503
5504 dataSeg = getsegbynamefromheader(mh, SEG_DATA);
5505 if (dataSeg == NULL) {
5506 return;
5507 }
5508
5509 lastSec = NULL;
5510 sec = firstsect(dataSeg);
5511 while (sec != NULL) {
5512 lastSec = sec;
5513 sec = nextsect(dataSeg, sec);
5514 }
5515
5516 if (lastSec == NULL) {
5517 return;
5518 }
5519
5520 if ((dataSeg->vmaddr != round_page(dataSeg->vmaddr)) ||
5521 (dataSeg->vmsize != round_page(dataSeg->vmsize))) {
5522 return;
5523 }
5524
5525 dataSegEnd = dataSeg->vmaddr + dataSeg->vmsize;
5526 lastSecEnd = round_page(lastSec->addr + lastSec->size);
5527
5528 if (dataSegEnd <= lastSecEnd) {
5529 return;
5530 }
5531
5532 padSize = dataSegEnd - lastSecEnd;
5533
5534 if (padSize >= PAGE_SIZE) {
5535 #if VM_MAPPED_KEXTS
5536 kext_free(lastSecEnd, padSize);
5537 #else
5538 ml_static_mfree(lastSecEnd, padSize);
5539 #endif
5540 }
5541 }
5542
5543 /*********************************************************************
5544 *********************************************************************/
5545 void
5546 OSKext::setLinkedExecutable(OSData * anExecutable)
5547 {
5548 if (linkedExecutable) {
5549 panic("Attempt to set linked executable on kext "
5550 "that already has one (%s).\n",
5551 getIdentifierCString());
5552 }
5553 linkedExecutable = anExecutable;
5554 linkedExecutable->retain();
5555 return;
5556 }
5557
5558 #if CONFIG_DTRACE
5559 /*********************************************************************
5560 * Go through all loaded kexts and tell them to register with dtrace.
5561 * The instance method only registers if necessary.
5562 *********************************************************************/
5563 /* static */
5564 void
5565 OSKext::registerKextsWithDTrace(void)
5566 {
5567 uint32_t count = sLoadedKexts->getCount();
5568 uint32_t i;
5569
5570 IORecursiveLockLock(sKextLock);
5571
5572 for (i = 0; i < count; i++) {
5573 OSKext * thisKext = NULL; // do not release
5574
5575 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
5576 if (!thisKext || !thisKext->isExecutable()) {
5577 continue;
5578 }
5579
5580 thisKext->registerWithDTrace();
5581 }
5582
5583 IORecursiveLockUnlock(sKextLock);
5584
5585 return;
5586 }
5587
5588 extern "C" {
5589 extern int (*dtrace_modload)(struct kmod_info *, uint32_t);
5590 extern int (*dtrace_modunload)(struct kmod_info *);
5591 };
5592
5593 /*********************************************************************
5594 *********************************************************************/
5595 void
5596 OSKext::registerWithDTrace(void)
5597 {
5598 /* Register kext with dtrace. A dtrace_modload failure should not
5599 * prevent a kext from loading, so we ignore the return code.
5600 */
5601 if (!flags.dtraceInitialized && (dtrace_modload != NULL)) {
5602 uint32_t modflag = 0;
5603 OSObject * forceInit = getPropertyForHostArch("OSBundleForceDTraceInit");
5604 if (forceInit == kOSBooleanTrue) {
5605 modflag |= KMOD_DTRACE_FORCE_INIT;
5606 }
5607
5608 (void)(*dtrace_modload)(kmod_info, modflag);
5609 flags.dtraceInitialized = true;
5610 jettisonLinkeditSegment();
5611 }
5612 return;
5613 }
5614 /*********************************************************************
5615 *********************************************************************/
5616 void
5617 OSKext::unregisterWithDTrace(void)
5618 {
5619 /* Unregister kext with dtrace. A dtrace_modunload failure should not
5620 * prevent a kext from loading, so we ignore the return code.
5621 */
5622 if (flags.dtraceInitialized && (dtrace_modunload != NULL)) {
5623 (void)(*dtrace_modunload)(kmod_info);
5624 flags.dtraceInitialized = false;
5625 }
5626 return;
5627 }
5628 #endif /* CONFIG_DTRACE */
5629
5630
5631 /*********************************************************************
5632 * called only by loadExecutable()
5633 *********************************************************************/
5634 #if !VM_MAPPED_KEXTS
5635 #error Unrecognized architecture
5636 #else
5637 static inline kern_return_t
5638 OSKext_protect(
5639 vm_map_t map,
5640 vm_map_offset_t start,
5641 vm_map_offset_t end,
5642 vm_prot_t new_prot,
5643 boolean_t set_max)
5644 {
5645 if (start == end) { // 10538581
5646 return(KERN_SUCCESS);
5647 }
5648 return vm_map_protect(map, start, end, new_prot, set_max);
5649 }
5650
5651 static inline kern_return_t
5652 OSKext_wire(
5653 vm_map_t map,
5654 vm_map_offset_t start,
5655 vm_map_offset_t end,
5656 vm_prot_t access_type,
5657 boolean_t user_wire)
5658 {
5659 return vm_map_wire(map, start, end, access_type | VM_PROT_MEMORY_TAG_MAKE(VM_KERN_MEMORY_KEXT), user_wire);
5660 }
5661 #endif
5662
5663 OSReturn
5664 OSKext::setVMAttributes(bool protect, bool wire)
5665 {
5666 vm_map_t kext_map = NULL;
5667 kernel_segment_command_t * seg = NULL;
5668 vm_map_offset_t start = 0;
5669 vm_map_offset_t end = 0;
5670 OSReturn result = kOSReturnError;
5671
5672 if (isInterface() || !declaresExecutable()) {
5673 result = kOSReturnSuccess;
5674 goto finish;
5675 }
5676
5677 /* Get the kext's vm map */
5678 kext_map = kext_get_vm_map(kmod_info);
5679 if (!kext_map) {
5680 result = KERN_MEMORY_ERROR;
5681 goto finish;
5682 }
5683
5684 #if !VM_MAPPED_KEXTS
5685 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
5686 /* This is a split kext in a prelinked kernelcache; we'll let the
5687 * platform code take care of protecting it. It is already wired.
5688 */
5689 /* TODO: Should this still allow protections for the first segment
5690 * to go through, in the event that we have a mix of split and
5691 * unsplit kexts?
5692 */
5693 result = KERN_SUCCESS;
5694 goto finish;
5695 }
5696 #endif
5697
5698 /* Protect the headers as read-only; they do not need to be wired */
5699 result = (protect) ? OSKext_protect(kext_map, kmod_info->address,
5700 kmod_info->address + kmod_info->hdr_size, VM_PROT_READ, TRUE)
5701 : KERN_SUCCESS;
5702 if (result != KERN_SUCCESS) {
5703 goto finish;
5704 }
5705
5706 /* Set the VM protections and wire down each of the segments */
5707 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
5708 while (seg) {
5709
5710
5711 start = round_page(seg->vmaddr);
5712 end = trunc_page(seg->vmaddr + seg->vmsize);
5713
5714 if (protect) {
5715 result = OSKext_protect(kext_map, start, end, seg->maxprot, TRUE);
5716 if (result != KERN_SUCCESS) {
5717 OSKextLog(this,
5718 kOSKextLogErrorLevel |
5719 kOSKextLogLoadFlag,
5720 "Kext %s failed to set maximum VM protections "
5721 "for segment %s - 0x%x.",
5722 getIdentifierCString(), seg->segname, (int)result);
5723 goto finish;
5724 }
5725
5726 result = OSKext_protect(kext_map, start, end, seg->initprot, FALSE);
5727 if (result != KERN_SUCCESS) {
5728 OSKextLog(this,
5729 kOSKextLogErrorLevel |
5730 kOSKextLogLoadFlag,
5731 "Kext %s failed to set initial VM protections "
5732 "for segment %s - 0x%x.",
5733 getIdentifierCString(), seg->segname, (int)result);
5734 goto finish;
5735 }
5736 }
5737
5738 if (segmentShouldBeWired(seg) && wire) {
5739 result = OSKext_wire(kext_map, start, end, seg->initprot, FALSE);
5740 if (result != KERN_SUCCESS) {
5741 goto finish;
5742 }
5743 }
5744
5745 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
5746 }
5747
5748 finish:
5749 return result;
5750 }
5751
5752 /*********************************************************************
5753 *********************************************************************/
5754 boolean_t
5755 OSKext::segmentShouldBeWired(kernel_segment_command_t *seg)
5756 {
5757 return (sKeepSymbols || strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)));
5758 }
5759
5760 /*********************************************************************
5761 *********************************************************************/
5762 OSReturn
5763 OSKext::validateKextMapping(bool startFlag)
5764 {
5765 OSReturn result = kOSReturnError;
5766 const char * whichOp = startFlag ? "start" : "stop";
5767 kern_return_t kern_result = 0;
5768 vm_map_t kext_map = NULL;
5769 kernel_segment_command_t * seg = NULL;
5770 mach_vm_address_t address = 0;
5771 mach_vm_size_t size = 0;
5772 uint32_t depth = 0;
5773 mach_msg_type_number_t count;
5774 vm_region_submap_short_info_data_64_t info;
5775
5776 count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
5777 bzero(&info, sizeof(info));
5778
5779 // xxx - do we need a distinct OSReturn value for these or is "bad data"
5780 // xxx - sufficient?
5781
5782 /* Verify that the kmod_info and start/stop pointers are non-NULL.
5783 */
5784 if (!kmod_info) {
5785 OSKextLog(this,
5786 kOSKextLogErrorLevel |
5787 kOSKextLogLoadFlag,
5788 "Kext %s - NULL kmod_info pointer.",
5789 getIdentifierCString());
5790 result = kOSKextReturnBadData;
5791 goto finish;
5792 }
5793
5794 if (startFlag) {
5795 address = (mach_vm_address_t)kmod_info->start;
5796 } else {
5797 address = (mach_vm_address_t)kmod_info->stop;
5798 }
5799
5800 if (!address) {
5801 OSKextLog(this,
5802 kOSKextLogErrorLevel |
5803 kOSKextLogLoadFlag,
5804 "Kext %s - NULL module %s pointer.",
5805 getIdentifierCString(), whichOp);
5806 result = kOSKextReturnBadData;
5807 goto finish;
5808 }
5809
5810 kext_map = kext_get_vm_map(kmod_info);
5811 depth = (kernel_map == kext_map) ? 1 : 2;
5812
5813 /* Verify that the start/stop function lies within the kext's address range.
5814 */
5815 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
5816 /* This will likely be how we deal with split kexts; walk the segments to
5817 * check that the function lies inside one of the segments of this kext.
5818 */
5819 for (seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
5820 seg != NULL;
5821 seg = nextsegfromheader((kernel_mach_header_t *)kmod_info->address, seg)) {
5822 if ((address >= seg->vmaddr) && address < (seg->vmaddr + seg->vmsize)) {
5823 break;
5824 }
5825 }
5826
5827 if (!seg) {
5828 OSKextLog(this,
5829 kOSKextLogErrorLevel |
5830 kOSKextLogLoadFlag,
5831 "Kext %s module %s pointer is outside of kext range "
5832 "(%s %p - kext starts at %p).",
5833 getIdentifierCString(),
5834 whichOp,
5835 whichOp,
5836 (void *)VM_KERNEL_UNSLIDE(address),
5837 (void *)VM_KERNEL_UNSLIDE(kmod_info->address));
5838 result = kOSKextReturnBadData;
5839 goto finish;
5840 }
5841
5842 seg = NULL;
5843 } else {
5844 if (address < kmod_info->address + kmod_info->hdr_size ||
5845 kmod_info->address + kmod_info->size <= address)
5846 {
5847 OSKextLog(this,
5848 kOSKextLogErrorLevel |
5849 kOSKextLogLoadFlag,
5850 "Kext %s module %s pointer is outside of kext range "
5851 "(%s %p - kext at %p-%p).",
5852 getIdentifierCString(),
5853 whichOp,
5854 whichOp,
5855 (void *)VM_KERNEL_UNSLIDE(address),
5856 (void *)VM_KERNEL_UNSLIDE(kmod_info->address),
5857 (void *)(VM_KERNEL_UNSLIDE(kmod_info->address) + kmod_info->size));
5858 result = kOSKextReturnBadData;
5859 goto finish;
5860 }
5861 }
5862
5863 /* Only do these checks before calling the start function;
5864 * If anything goes wrong with the mapping while the kext is running,
5865 * we'll likely have panicked well before any attempt to stop the kext.
5866 */
5867 if (startFlag) {
5868
5869 /* Verify that the start/stop function is executable.
5870 */
5871 kern_result = mach_vm_region_recurse(kernel_map, &address, &size, &depth,
5872 (vm_region_recurse_info_t)&info, &count);
5873 if (kern_result != KERN_SUCCESS) {
5874 OSKextLog(this,
5875 kOSKextLogErrorLevel |
5876 kOSKextLogLoadFlag,
5877 "Kext %s - bad %s pointer %p.",
5878 getIdentifierCString(),
5879 whichOp, (void *)VM_KERNEL_UNSLIDE(address));
5880 result = kOSKextReturnBadData;
5881 goto finish;
5882 }
5883
5884 #if VM_MAPPED_KEXTS
5885 if (!(info.protection & VM_PROT_EXECUTE)) {
5886 OSKextLog(this,
5887 kOSKextLogErrorLevel |
5888 kOSKextLogLoadFlag,
5889 "Kext %s - memory region containing module %s function "
5890 "is not executable.",
5891 getIdentifierCString(), whichOp);
5892 result = kOSKextReturnBadData;
5893 goto finish;
5894 }
5895 #endif
5896
5897 /* Verify that the kext's segments are backed by physical memory.
5898 */
5899 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
5900 while (seg) {
5901 if (!verifySegmentMapping(seg)) {
5902 result = kOSKextReturnBadData;
5903 goto finish;
5904 }
5905
5906 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
5907 }
5908
5909 }
5910
5911 result = kOSReturnSuccess;
5912 finish:
5913 return result;
5914 }
5915
5916 /*********************************************************************
5917 *********************************************************************/
5918 boolean_t
5919 OSKext::verifySegmentMapping(kernel_segment_command_t *seg)
5920 {
5921 mach_vm_address_t address = 0;
5922
5923 if (!segmentShouldBeWired(seg)) return true;
5924
5925 for (address = seg->vmaddr;
5926 address < round_page(seg->vmaddr + seg->vmsize);
5927 address += PAGE_SIZE)
5928 {
5929 if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
5930 OSKextLog(this,
5931 kOSKextLogErrorLevel |
5932 kOSKextLogLoadFlag,
5933 "Kext %s - page %p is not backed by physical memory.",
5934 getIdentifierCString(),
5935 (void *)address);
5936 return false;
5937 }
5938 }
5939
5940 return true;
5941 }
5942
5943 /*********************************************************************
5944 *********************************************************************/
5945 static void
5946 OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code)
5947 {
5948
5949 uint64_t stamp = 0;
5950 firehose_tracepoint_id_u trace_id;
5951 struct firehose_trace_uuid_info_s uuid_info_s;
5952 firehose_trace_uuid_info_t uuid_info = &uuid_info_s;
5953 size_t uuid_info_len = sizeof(struct firehose_trace_uuid_info_s);
5954 OSData *uuid_data;
5955
5956 stamp = firehose_tracepoint_time(firehose_activity_flags_default);
5957 trace_id.ftid_value = FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata, _firehose_tracepoint_type_metadata_kext, (firehose_tracepoint_flags_t)0, code);
5958
5959 uuid_data = aKext->copyUUID();
5960 if (uuid_data) {
5961 memcpy(uuid_info->ftui_uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_info->ftui_uuid));
5962 OSSafeReleaseNULL(uuid_data);
5963 }
5964
5965 uuid_info->ftui_size = size;
5966 uuid_info->ftui_address = VM_KERNEL_UNSLIDE(address);
5967
5968 firehose_trace_metadata(firehose_stream_metadata, trace_id, stamp, uuid_info, uuid_info_len);
5969 return;
5970 }
5971
5972 /*********************************************************************
5973 *********************************************************************/
5974 OSReturn
5975 OSKext::start(bool startDependenciesFlag)
5976 {
5977 OSReturn result = kOSReturnError;
5978 kern_return_t (* startfunc)(kmod_info_t *, void *);
5979 unsigned int i, count;
5980 void * kmodStartData = NULL;
5981
5982 if (isStarted() || isInterface() || isKernelComponent()) {
5983 result = kOSReturnSuccess;
5984 goto finish;
5985 }
5986
5987 if (!isLoaded()) {
5988 OSKextLog(this,
5989 kOSKextLogErrorLevel |
5990 kOSKextLogLoadFlag,
5991 "Attempt to start nonloaded kext %s.",
5992 getIdentifierCString());
5993 result = kOSKextReturnInvalidArgument;
5994 goto finish;
5995 }
5996
5997 if (!sLoadEnabled) {
5998 OSKextLog(this,
5999 kOSKextLogErrorLevel |
6000 kOSKextLogLoadFlag,
6001 "Kext loading is disabled (attempt to start kext %s).",
6002 getIdentifierCString());
6003 result = kOSKextReturnDisabled;
6004 goto finish;
6005 }
6006
6007 result = validateKextMapping(/* start? */ true);
6008 if (result != kOSReturnSuccess) {
6009 goto finish;
6010 }
6011
6012 startfunc = kmod_info->start;
6013
6014 count = getNumDependencies();
6015 for (i = 0; i < count; i++) {
6016 OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
6017 if (dependency == NULL) {
6018 OSKextLog(this,
6019 kOSKextLogErrorLevel |
6020 kOSKextLogLoadFlag,
6021 "Kext %s start - internal error, dependency disappeared.",
6022 getIdentifierCString());
6023 goto finish;
6024 }
6025 if (!dependency->isStarted()) {
6026 if (startDependenciesFlag) {
6027 OSReturn dependencyResult =
6028 dependency->start(startDependenciesFlag);
6029 if (dependencyResult != KERN_SUCCESS) {
6030 OSKextLog(this,
6031 kOSKextLogErrorLevel |
6032 kOSKextLogLoadFlag,
6033 "Kext %s start - dependency %s failed to start (error 0x%x).",
6034 getIdentifierCString(),
6035 dependency->getIdentifierCString(),
6036 dependencyResult);
6037 goto finish;
6038 }
6039 } else {
6040 OSKextLog(this,
6041 kOSKextLogErrorLevel |
6042 kOSKextLogLoadFlag,
6043 "Not starting %s - dependency %s not started yet.",
6044 getIdentifierCString(),
6045 dependency->getIdentifierCString());
6046 result = kOSKextReturnStartStopError; // xxx - make new return?
6047 goto finish;
6048 }
6049 }
6050 }
6051
6052 OSKextLog(this,
6053 kOSKextLogDetailLevel |
6054 kOSKextLogLoadFlag,
6055 "Kext %s calling module start function.",
6056 getIdentifierCString());
6057
6058 flags.starting = 1;
6059
6060 // Drop a log message so logd can grab the needed information to decode this kext
6061 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_load);
6062
6063 #if !CONFIG_STATIC_CPPINIT
6064 result = OSRuntimeInitializeCPP(kmod_info, NULL);
6065 if (result == KERN_SUCCESS) {
6066 #endif
6067
6068 #if CONFIG_KEC_FIPS
6069 kmodStartData = GetAppleTEXTHashForKext(this, this->infoDict);
6070
6071 #if 0
6072 if (kmodStartData) {
6073 OSKextLog(this,
6074 kOSKextLogErrorLevel |
6075 kOSKextLogGeneralFlag,
6076 "Kext %s calling module start function. kmodStartData %p. arch %s",
6077 getIdentifierCString(), kmodStartData, ARCHNAME);
6078 }
6079 #endif
6080 #endif // CONFIG_KEC_FIPS
6081 result = startfunc(kmod_info, kmodStartData);
6082
6083 #if !CONFIG_STATIC_CPPINIT
6084 if (result != KERN_SUCCESS) {
6085 (void) OSRuntimeFinalizeCPP(kmod_info, NULL);
6086 }
6087 }
6088 #endif
6089
6090 flags.starting = 0;
6091
6092 /* On success overlap the setting of started/starting. On failure just
6093 * clear starting.
6094 */
6095 if (result == KERN_SUCCESS) {
6096 flags.started = 1;
6097
6098 // xxx - log start error from kernel?
6099 OSKextLog(this,
6100 kOSKextLogProgressLevel |
6101 kOSKextLogLoadFlag,
6102 "Kext %s is now started.",
6103 getIdentifierCString());
6104 } else {
6105 invokeOrCancelRequestCallbacks(
6106 /* result not actually used */ kOSKextReturnStartStopError,
6107 /* invokeFlag */ false);
6108 OSKextLog(this,
6109 kOSKextLogProgressLevel |
6110 kOSKextLogLoadFlag,
6111 "Kext %s did not start (return code 0x%x).",
6112 getIdentifierCString(), result);
6113 }
6114
6115 finish:
6116 return result;
6117 }
6118
6119 /*********************************************************************
6120 *********************************************************************/
6121 /* static */
6122 bool OSKext::canUnloadKextWithIdentifier(
6123 OSString * kextIdentifier,
6124 bool checkClassesFlag)
6125 {
6126 bool result = false;
6127 OSKext * aKext = NULL; // do not release
6128
6129 IORecursiveLockLock(sKextLock);
6130
6131 aKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
6132
6133 if (!aKext) {
6134 goto finish; // can't unload what's not loaded
6135 }
6136
6137 if (aKext->isLoaded()) {
6138 if (aKext->getRetainCount() > kOSKextMinLoadedRetainCount) {
6139 goto finish;
6140 }
6141 if (checkClassesFlag && aKext->hasOSMetaClassInstances()) {
6142 goto finish;
6143 }
6144 }
6145
6146 result = true;
6147
6148 finish:
6149 IORecursiveLockUnlock(sKextLock);
6150 return result;
6151 }
6152
6153 /*********************************************************************
6154 *********************************************************************/
6155 OSReturn
6156 OSKext::stop(void)
6157 {
6158 OSReturn result = kOSReturnError;
6159 kern_return_t (*stopfunc)(kmod_info_t *, void *);
6160
6161 if (!isStarted() || isInterface()) {
6162 result = kOSReturnSuccess;
6163 goto finish;
6164 }
6165
6166 if (!isLoaded()) {
6167 OSKextLog(this,
6168 kOSKextLogErrorLevel |
6169 kOSKextLogLoadFlag,
6170 "Attempt to stop nonloaded kext %s.",
6171 getIdentifierCString());
6172 result = kOSKextReturnInvalidArgument;
6173 goto finish;
6174 }
6175
6176 /* Refuse to stop if we have clients or instances. It is up to
6177 * the caller to make sure those aren't true.
6178 */
6179 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
6180 OSKextLog(this,
6181 kOSKextLogErrorLevel |
6182 kOSKextLogLoadFlag,
6183 "Kext %s - C++ instances; can't stop.",
6184 getIdentifierCString());
6185 result = kOSKextReturnInUse;
6186 goto finish;
6187 }
6188
6189 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
6190
6191 OSKextLog(this,
6192 kOSKextLogErrorLevel |
6193 kOSKextLogLoadFlag,
6194 "Kext %s - has references (linkage or tracking object); "
6195 "can't stop.",
6196 getIdentifierCString());
6197 result = kOSKextReturnInUse;
6198 goto finish;
6199 }
6200
6201 /* Note: If validateKextMapping fails on the stop & unload path,
6202 * we are in serious trouble and a kernel panic is likely whether
6203 * we stop & unload the kext or not.
6204 */
6205 result = validateKextMapping(/* start? */ false);
6206 if (result != kOSReturnSuccess) {
6207 goto finish;
6208 }
6209
6210 stopfunc = kmod_info->stop;
6211 if (stopfunc) {
6212 OSKextLog(this,
6213 kOSKextLogDetailLevel |
6214 kOSKextLogLoadFlag,
6215 "Kext %s calling module stop function.",
6216 getIdentifierCString());
6217
6218 flags.stopping = 1;
6219
6220 result = stopfunc(kmod_info, /* userData */ NULL);
6221 #if !CONFIG_STATIC_CPPINIT
6222 if (result == KERN_SUCCESS) {
6223 result = OSRuntimeFinalizeCPP(kmod_info, NULL);
6224 }
6225 #endif
6226
6227 flags.stopping = 0;
6228
6229 if (result == KERN_SUCCESS) {
6230 flags.started = 0;
6231
6232 OSKextLog(this,
6233 kOSKextLogDetailLevel |
6234 kOSKextLogLoadFlag,
6235 "Kext %s is now stopped and ready to unload.",
6236 getIdentifierCString());
6237 } else {
6238 OSKextLog(this,
6239 kOSKextLogErrorLevel |
6240 kOSKextLogLoadFlag,
6241 "Kext %s did not stop (return code 0x%x).",
6242 getIdentifierCString(), result);
6243 result = kOSKextReturnStartStopError;
6244 }
6245 }
6246
6247 finish:
6248 // Drop a log message so logd can update this kext's metadata
6249 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_unload);
6250 return result;
6251 }
6252
6253 /*********************************************************************
6254 *********************************************************************/
6255 OSReturn
6256 OSKext::unload(void)
6257 {
6258 OSReturn result = kOSReturnError;
6259 unsigned int index;
6260 uint32_t num_kmod_refs = 0;
6261 OSKextAccount * freeAccount;
6262
6263 if (!sUnloadEnabled) {
6264 OSKextLog(this,
6265 kOSKextLogErrorLevel |
6266 kOSKextLogLoadFlag,
6267 "Kext unloading is disabled (%s).",
6268 this->getIdentifierCString());
6269
6270 result = kOSKextReturnDisabled;
6271 goto finish;
6272 }
6273
6274 /* Refuse to unload if we have clients or instances. It is up to
6275 * the caller to make sure those aren't true.
6276 */
6277 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
6278 // xxx - Don't log under errors? this is more of an info thing
6279 OSKextLog(this,
6280 kOSKextLogErrorLevel |
6281 kOSKextLogKextBookkeepingFlag,
6282 "Can't unload kext %s; outstanding references (linkage or tracking object).",
6283 getIdentifierCString());
6284 result = kOSKextReturnInUse;
6285 goto finish;
6286 }
6287
6288 if (hasOSMetaClassInstances()) {
6289 OSKextLog(this,
6290 kOSKextLogErrorLevel |
6291 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6292 "Can't unload kext %s; classes have instances:",
6293 getIdentifierCString());
6294 reportOSMetaClassInstances(kOSKextLogErrorLevel |
6295 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag);
6296 result = kOSKextReturnInUse;
6297 goto finish;
6298 }
6299
6300 if (!isLoaded()) {
6301 result = kOSReturnSuccess;
6302 goto finish;
6303 }
6304
6305 if (isKernelComponent()) {
6306 result = kOSKextReturnInvalidArgument;
6307 goto finish;
6308 }
6309
6310 /* Note that the kext is unloading before running any code that
6311 * might be in the kext (request callbacks, module stop function).
6312 * We will deny certain requests made against a kext in the process
6313 * of unloading.
6314 */
6315 flags.unloading = 1;
6316
6317 /* Update the string describing the last kext to unload in case we panic.
6318 */
6319 savePanicString(/* isLoading */ false);
6320
6321 if (isStarted()) {
6322 result = stop();
6323 if (result != KERN_SUCCESS) {
6324 OSKextLog(this,
6325 kOSKextLogErrorLevel |
6326 kOSKextLogLoadFlag,
6327 "Kext %s can't unload - module stop returned 0x%x.",
6328 getIdentifierCString(), (unsigned)result);
6329 result = kOSKextReturnStartStopError;
6330 goto finish;
6331 }
6332 }
6333
6334 OSKextLog(this,
6335 kOSKextLogProgressLevel |
6336 kOSKextLogLoadFlag,
6337 "Kext %s unloading.",
6338 getIdentifierCString());
6339
6340 {
6341 struct list_head *p;
6342 struct list_head *prev;
6343 struct list_head *next;
6344 for (p = pendingPgoHead.next; p != &pendingPgoHead; p = next) {
6345 OSKextGrabPgoStruct *s = container_of(p, OSKextGrabPgoStruct, list_head);
6346 s->err = OSKextGrabPgoDataLocked(this, s->metadata, instance_uuid, s->pSize, s->pBuffer, s->bufferSize);
6347 prev = p->prev;
6348 next = p->next;
6349 prev->next = next;
6350 next->prev = prev;
6351 p->prev = p;
6352 p->next = p;
6353 IORecursiveLockWakeup(sKextLock, s, false);
6354 }
6355 }
6356
6357
6358 /* Even if we don't call the stop function, we want to be sure we
6359 * have no OSMetaClass references before unloading the kext executable
6360 * from memory. OSMetaClasses may have pointers into the kext executable
6361 * and that would cause a panic on OSKext::free() when metaClasses is freed.
6362 */
6363 if (metaClasses) {
6364 metaClasses->flushCollection();
6365 }
6366
6367 /* Remove the kext from the list of loaded kexts, patch the gap
6368 * in the kmod_info_t linked list, and reset "kmod" to point to the
6369 * last loaded kext that isn't the fake kernel kext (sKernelKext).
6370 */
6371 index = sLoadedKexts->getNextIndexOfObject(this, 0);
6372 if (index != (unsigned int)-1) {
6373
6374 sLoadedKexts->removeObject(index);
6375
6376 OSKext * nextKext = OSDynamicCast(OSKext,
6377 sLoadedKexts->getObject(index));
6378
6379 if (nextKext) {
6380 if (index > 0) {
6381 OSKext * gapKext = OSDynamicCast(OSKext,
6382 sLoadedKexts->getObject(index - 1));
6383
6384 nextKext->kmod_info->next = gapKext->kmod_info;
6385
6386 } else /* index == 0 */ {
6387 nextKext->kmod_info->next = NULL;
6388 }
6389 }
6390
6391 OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
6392 if (lastKext && !lastKext->isKernel()) {
6393 kmod = lastKext->kmod_info;
6394 } else {
6395 kmod = NULL; // clear the global kmod variable
6396 }
6397 }
6398
6399 /* Clear out the kmod references that we're keeping for compatibility
6400 * with current panic backtrace code & kgmacros.
6401 * xxx - will want to update those bits sometime and remove this.
6402 */
6403 num_kmod_refs = getNumDependencies();
6404 if (num_kmod_refs && kmod_info && kmod_info->reference_list) {
6405 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
6406 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
6407 ref->info->reference_count--;
6408 }
6409 kfree(kmod_info->reference_list,
6410 num_kmod_refs * sizeof(kmod_reference_t));
6411 }
6412
6413 #if CONFIG_DTRACE
6414 unregisterWithDTrace();
6415 #endif /* CONFIG_DTRACE */
6416
6417 notifyKextUnloadObservers(this);
6418
6419 freeAccount = NULL;
6420 IOSimpleLockLock(sKextAccountsLock);
6421 account->kext = NULL;
6422 if (account->site.tag) account->site.flags |= VM_TAG_UNLOAD;
6423 else freeAccount = account;
6424 IOSimpleLockUnlock(sKextAccountsLock);
6425 if (freeAccount) IODelete(freeAccount, OSKextAccount, 1);
6426
6427 /* Unwire and free the linked executable.
6428 */
6429 if (linkedExecutable) {
6430 #if VM_MAPPED_KEXTS
6431 if (!isInterface()) {
6432 kernel_segment_command_t *seg = NULL;
6433 vm_map_t kext_map = kext_get_vm_map(kmod_info);
6434
6435 if (!kext_map) {
6436 OSKextLog(this,
6437 kOSKextLogErrorLevel |
6438 kOSKextLogLoadFlag,
6439 "Failed to free kext %s; couldn't find the kext map.",
6440 getIdentifierCString());
6441 result = kOSKextReturnInternalError;
6442 goto finish;
6443 }
6444
6445 OSKextLog(this,
6446 kOSKextLogProgressLevel |
6447 kOSKextLogLoadFlag,
6448 "Kext %s unwiring and unmapping linked executable.",
6449 getIdentifierCString());
6450
6451 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
6452 while (seg) {
6453 if (segmentShouldBeWired(seg)) {
6454 result = vm_map_unwire(kext_map, seg->vmaddr,
6455 seg->vmaddr + seg->vmsize, FALSE);
6456 if (result != KERN_SUCCESS) {
6457 OSKextLog(this,
6458 kOSKextLogErrorLevel |
6459 kOSKextLogLoadFlag,
6460 "Failed to unwire kext %s.",
6461 getIdentifierCString());
6462 result = kOSKextReturnInternalError;
6463 goto finish;
6464 }
6465 }
6466
6467 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
6468 }
6469 }
6470 #endif
6471 OSSafeReleaseNULL(linkedExecutable);
6472 }
6473
6474 /* An interface kext has a fake kmod_info that was allocated,
6475 * so we have to free it.
6476 */
6477 if (isInterface()) {
6478 kfree(kmod_info, sizeof(kmod_info_t));
6479 }
6480
6481 kmod_info = NULL;
6482
6483 flags.loaded = false;
6484 flushDependencies();
6485
6486 /* save a copy of the bundle ID for us to check when deciding to
6487 * rebuild the kernel cache file. If a kext was already in the kernel
6488 * cache and unloaded then later loaded we do not need to rebuild the
6489 * kernel cache. 9055303
6490 */
6491 if (isPrelinked()) {
6492 if (!_OSKextInUnloadedPrelinkedKexts(bundleID)) {
6493 IORecursiveLockLock(sKextLock);
6494 if (sUnloadedPrelinkedKexts) {
6495 sUnloadedPrelinkedKexts->setObject(bundleID);
6496 }
6497 IORecursiveLockUnlock(sKextLock);
6498 }
6499 }
6500
6501 OSKextLog(this,
6502 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
6503 "Kext %s unloaded.", getIdentifierCString());
6504
6505 queueKextNotification(kKextRequestPredicateUnloadNotification,
6506 OSDynamicCast(OSString, bundleID));
6507
6508 finish:
6509 OSKext::saveLoadedKextPanicList();
6510 OSKext::updateLoadedKextSummaries();
6511
6512 flags.unloading = 0;
6513 return result;
6514 }
6515
6516 /*********************************************************************
6517 * Assumes sKextLock is held.
6518 *********************************************************************/
6519 /* static */
6520 OSReturn
6521 OSKext::queueKextNotification(
6522 const char * notificationName,
6523 OSString * kextIdentifier)
6524 {
6525 OSReturn result = kOSReturnError;
6526 OSDictionary * loadRequest = NULL; // must release
6527
6528 if (!kextIdentifier) {
6529 result = kOSKextReturnInvalidArgument;
6530 goto finish;
6531 }
6532
6533 /* Create a new request unless one is already sitting
6534 * in sKernelRequests for this bundle identifier
6535 */
6536 result = _OSKextCreateRequest(notificationName, &loadRequest);
6537 if (result != kOSReturnSuccess) {
6538 goto finish;
6539 }
6540 if (!_OSKextSetRequestArgument(loadRequest,
6541 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
6542
6543 result = kOSKextReturnNoMemory;
6544 goto finish;
6545 }
6546 if (!sKernelRequests->setObject(loadRequest)) {
6547 result = kOSKextReturnNoMemory;
6548 goto finish;
6549 }
6550
6551 /* We might want to only queue the notification if kextd is active,
6552 * but that wouldn't work for embedded. Note that we don't care if
6553 * the ping immediately succeeds here so don't do anything with the
6554 * result of this call.
6555 */
6556 OSKext::pingKextd();
6557
6558 result = kOSReturnSuccess;
6559
6560 finish:
6561 OSSafeReleaseNULL(loadRequest);
6562
6563 return result;
6564 }
6565
6566 /*********************************************************************
6567 *********************************************************************/
6568 static void
6569 _OSKextConsiderDestroyingLinkContext(
6570 __unused thread_call_param_t p0,
6571 __unused thread_call_param_t p1)
6572 {
6573 /* Take multiple locks in the correct order.
6574 */
6575 IORecursiveLockLock(sKextLock);
6576 IORecursiveLockLock(sKextInnerLock);
6577
6578 /* The first time we destroy the kxldContext is in the first
6579 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
6580 * before calling this function. Thereafter any call to this function
6581 * will actually destroy the context.
6582 */
6583 if (sConsiderUnloadsCalled && sKxldContext) {
6584 kxld_destroy_context(sKxldContext);
6585 sKxldContext = NULL;
6586 }
6587
6588 /* Free the thread_call that was allocated to execute this function.
6589 */
6590 if (sDestroyLinkContextThread) {
6591 if (!thread_call_free(sDestroyLinkContextThread)) {
6592 OSKextLog(/* kext */ NULL,
6593 kOSKextLogErrorLevel |
6594 kOSKextLogGeneralFlag,
6595 "thread_call_free() failed for kext link context.");
6596 }
6597 sDestroyLinkContextThread = 0;
6598 }
6599
6600 IORecursiveLockUnlock(sKextInnerLock);
6601 IORecursiveLockUnlock(sKextLock);
6602
6603 return;
6604 }
6605
6606 /*********************************************************************
6607 * Destroying the kxldContext requires checking variables under both
6608 * sKextInnerLock and sKextLock, so we do it on a separate thread
6609 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
6610 * call relationship.
6611 *
6612 * This function must be invoked with sKextInnerLock held.
6613 * Do not call any function that takes sKextLock here!
6614 *********************************************************************/
6615 /* static */
6616 void
6617 OSKext::considerDestroyingLinkContext(void)
6618 {
6619 IORecursiveLockLock(sKextInnerLock);
6620
6621 /* If we have already queued a thread to destroy the link context,
6622 * don't bother resetting; that thread will take care of it.
6623 */
6624 if (sDestroyLinkContextThread) {
6625 goto finish;
6626 }
6627
6628 /* The function to be invoked in the thread will deallocate
6629 * this thread_call, so don't share it around.
6630 */
6631 sDestroyLinkContextThread = thread_call_allocate(
6632 &_OSKextConsiderDestroyingLinkContext, 0);
6633 if (!sDestroyLinkContextThread) {
6634 OSKextLog(/* kext */ NULL,
6635 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogLinkFlag,
6636 "Can't create thread to destroy kext link context.");
6637 goto finish;
6638 }
6639
6640 thread_call_enter(sDestroyLinkContextThread);
6641
6642 finish:
6643 IORecursiveLockUnlock(sKextInnerLock);
6644 return;
6645 }
6646
6647 #if PRAGMA_MARK
6648 #pragma mark Autounload
6649 #endif
6650 /*********************************************************************
6651 * This is a static method because the kext will be deallocated if it
6652 * does unload!
6653 *********************************************************************/
6654 /* static */
6655 OSReturn
6656 OSKext::autounloadKext(OSKext * aKext)
6657 {
6658 OSReturn result = kOSKextReturnInUse;
6659
6660 /* Check for external references to this kext (usu. dependents),
6661 * instances of defined classes (or classes derived from them),
6662 * outstanding requests.
6663 */
6664 if ((aKext->getRetainCount() > kOSKextMinLoadedRetainCount) ||
6665 !aKext->flags.autounloadEnabled ||
6666 aKext->isKernelComponent()) {
6667
6668 goto finish;
6669 }
6670
6671 /* Skip a delay-autounload kext, once.
6672 */
6673 if (aKext->flags.delayAutounload) {
6674 OSKextLog(aKext,
6675 kOSKextLogProgressLevel |
6676 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6677 "Kext %s has delayed autounload set; skipping and clearing flag.",
6678 aKext->getIdentifierCString());
6679 aKext->flags.delayAutounload = 0;
6680 goto finish;
6681 }
6682
6683 if (aKext->hasOSMetaClassInstances() ||
6684 aKext->countRequestCallbacks()) {
6685 goto finish;
6686 }
6687
6688 result = OSKext::removeKext(aKext);
6689
6690 finish:
6691 return result;
6692 }
6693
6694 /*********************************************************************
6695 *********************************************************************/
6696 void
6697 _OSKextConsiderUnloads(
6698 __unused thread_call_param_t p0,
6699 __unused thread_call_param_t p1)
6700 {
6701 bool didUnload = false;
6702 unsigned int count, i;
6703
6704 /* Take multiple locks in the correct order
6705 * (note also sKextSummaries lock further down).
6706 */
6707 IORecursiveLockLock(sKextLock);
6708 IORecursiveLockLock(sKextInnerLock);
6709
6710 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
6711
6712 /* If the system is powering down, don't try to unload anything.
6713 */
6714 if (sSystemSleep) {
6715 goto finish;
6716 }
6717
6718 OSKextLog(/* kext */ NULL,
6719 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
6720 "Checking for unused kexts to autounload.");
6721
6722 /*****
6723 * Remove any request callbacks marked as stale,
6724 * and mark as stale any currently in flight.
6725 */
6726 count = sRequestCallbackRecords->getCount();
6727 if (count) {
6728 i = count - 1;
6729 do {
6730 OSDictionary * callbackRecord = OSDynamicCast(OSDictionary,
6731 sRequestCallbackRecords->getObject(i));
6732 OSBoolean * stale = OSDynamicCast(OSBoolean,
6733 callbackRecord->getObject(kKextRequestStaleKey));
6734
6735 if (stale == kOSBooleanTrue) {
6736 OSKext::invokeRequestCallback(callbackRecord,
6737 kOSKextReturnTimeout);
6738 } else {
6739 callbackRecord->setObject(kKextRequestStaleKey,
6740 kOSBooleanTrue);
6741 }
6742 } while (i--);
6743 }
6744
6745 /*****
6746 * Make multiple passes through the array of loaded kexts until
6747 * we don't unload any. This handles unwinding of dependency
6748 * chains. We have to go *backwards* through the array because
6749 * kexts are removed from it when unloaded, and we cannot make
6750 * a copy or we'll mess up the retain counts we rely on to
6751 * check whether a kext will unload. If only we could have
6752 * nonretaining collections like CF has....
6753 */
6754 do {
6755 didUnload = false;
6756
6757 count = sLoadedKexts->getCount();
6758 if (count) {
6759 i = count - 1;
6760 do {
6761 OSKext * thisKext = OSDynamicCast(OSKext,
6762 sLoadedKexts->getObject(i));
6763 didUnload |= (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
6764 } while (i--);
6765 }
6766 } while (didUnload);
6767
6768 finish:
6769 sConsiderUnloadsPending = false;
6770 sConsiderUnloadsExecuted = true;
6771
6772 (void) OSKext::considerRebuildOfPrelinkedKernel();
6773
6774 IORecursiveLockUnlock(sKextInnerLock);
6775 IORecursiveLockUnlock(sKextLock);
6776
6777 return;
6778 }
6779
6780 /*********************************************************************
6781 * Do not call any function that takes sKextLock here!
6782 *********************************************************************/
6783 void OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
6784 {
6785 AbsoluteTime when;
6786
6787 IORecursiveLockLock(sKextInnerLock);
6788
6789 if (!sUnloadCallout) {
6790 sUnloadCallout = thread_call_allocate(&_OSKextConsiderUnloads, 0);
6791 }
6792
6793 /* we only reset delay value for unloading if we already have something
6794 * pending. rescheduleOnlyFlag should not start the count down.
6795 */
6796 if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
6797 goto finish;
6798 }
6799
6800 thread_call_cancel(sUnloadCallout);
6801 if (OSKext::getAutounloadEnabled() && !sSystemSleep) {
6802 clock_interval_to_deadline(sConsiderUnloadDelay,
6803 1000 * 1000 * 1000, &when);
6804
6805 OSKextLog(/* kext */ NULL,
6806 kOSKextLogProgressLevel |
6807 kOSKextLogLoadFlag,
6808 "%scheduling %sscan for unused kexts in %lu seconds.",
6809 sConsiderUnloadsPending ? "Res" : "S",
6810 sConsiderUnloadsCalled ? "" : "initial ",
6811 (unsigned long)sConsiderUnloadDelay);
6812
6813 sConsiderUnloadsPending = true;
6814 thread_call_enter_delayed(sUnloadCallout, when);
6815 }
6816
6817 finish:
6818 /* The kxld context should be reused throughout boot. We mark the end of
6819 * period as the first time considerUnloads() is called, and we destroy
6820 * the first kxld context in that function. Afterwards, it will be
6821 * destroyed in flushNonloadedKexts.
6822 */
6823 if (!sConsiderUnloadsCalled) {
6824 sConsiderUnloadsCalled = true;
6825 OSKext::considerDestroyingLinkContext();
6826 }
6827
6828 IORecursiveLockUnlock(sKextInnerLock);
6829 return;
6830 }
6831
6832 /*********************************************************************
6833 * Do not call any function that takes sKextLock here!
6834 *********************************************************************/
6835 extern "C" {
6836
6837 IOReturn OSKextSystemSleepOrWake(UInt32 messageType);
6838 IOReturn OSKextSystemSleepOrWake(UInt32 messageType)
6839 {
6840 IORecursiveLockLock(sKextInnerLock);
6841
6842 /* If the system is going to sleep, cancel the reaper thread timer,
6843 * and note that we're in a sleep state in case it just fired but hasn't
6844 * taken the lock yet. If we are coming back from sleep, just
6845 * clear the sleep flag; IOService's normal operation will cause
6846 * unloads to be considered soon enough.
6847 */
6848 if (messageType == kIOMessageSystemWillSleep) {
6849 if (sUnloadCallout) {
6850 thread_call_cancel(sUnloadCallout);
6851 }
6852 sSystemSleep = true;
6853 AbsoluteTime_to_scalar(&sLastWakeTime) = 0;
6854 } else if (messageType == kIOMessageSystemHasPoweredOn) {
6855 sSystemSleep = false;
6856 clock_get_uptime(&sLastWakeTime);
6857 }
6858 IORecursiveLockUnlock(sKextInnerLock);
6859
6860 return kIOReturnSuccess;
6861 }
6862
6863 };
6864
6865
6866 #if PRAGMA_MARK
6867 #pragma mark Prelinked Kernel
6868 #endif
6869 /*********************************************************************
6870 * Do not access sConsiderUnloads... variables other than
6871 * sConsiderUnloadsExecuted in this function. They are guarded by a
6872 * different lock.
6873 *********************************************************************/
6874 /* static */
6875 void
6876 OSKext::considerRebuildOfPrelinkedKernel(void)
6877 {
6878 static bool requestedPrelink = false;
6879 OSReturn checkResult = kOSReturnError;
6880 OSDictionary * prelinkRequest = NULL; // must release
6881 OSCollectionIterator * kextIterator = NULL; // must release
6882 const OSSymbol * thisID = NULL; // do not release
6883 bool doRebuild = false;
6884 AbsoluteTime my_abstime;
6885 UInt64 my_ns;
6886 SInt32 delta_secs;
6887
6888 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
6889 if (requestedPrelink || !sPrelinkBoot) {
6890 return;
6891 }
6892
6893 /* no direct return from this point */
6894 IORecursiveLockLock(sKextLock);
6895
6896 /* We need to wait for kextd to get up and running with unloads already done
6897 * and any new startup kexts loaded.
6898 */
6899 if (!sConsiderUnloadsExecuted ||
6900 !sDeferredLoadSucceeded) {
6901 goto finish;
6902 }
6903
6904 /* we really only care about boot / system start up related kexts so bail
6905 * if we're here after REBUILD_MAX_TIME.
6906 */
6907 if (!_OSKextInPrelinkRebuildWindow()) {
6908 OSKextLog(/* kext */ NULL,
6909 kOSKextLogArchiveFlag,
6910 "%s prebuild rebuild has expired",
6911 __FUNCTION__);
6912 requestedPrelink = true;
6913 goto finish;
6914 }
6915
6916 /* we do not want to trigger a rebuild if we get here too close to waking
6917 * up. (see radar 10233768)
6918 */
6919 IORecursiveLockLock(sKextInnerLock);
6920
6921 clock_get_uptime(&my_abstime);
6922 delta_secs = MINIMUM_WAKEUP_SECONDS + 1;
6923 if (AbsoluteTime_to_scalar(&sLastWakeTime) != 0) {
6924 SUB_ABSOLUTETIME(&my_abstime, &sLastWakeTime);
6925 absolutetime_to_nanoseconds(my_abstime, &my_ns);
6926 delta_secs = (SInt32)(my_ns / NSEC_PER_SEC);
6927 }
6928 IORecursiveLockUnlock(sKextInnerLock);
6929
6930 if (delta_secs < MINIMUM_WAKEUP_SECONDS) {
6931 /* too close to time of last wake from sleep */
6932 goto finish;
6933 }
6934 requestedPrelink = true;
6935
6936 /* Now it's time to see if we have a reason to rebuild. We may have done
6937 * some loads and unloads but the kernel cache didn't actually change.
6938 * We will rebuild if any kext is not marked prelinked AND is not in our
6939 * list of prelinked kexts that got unloaded. (see radar 9055303)
6940 */
6941 kextIterator = OSCollectionIterator::withCollection(sKextsByID);
6942 if (!kextIterator) {
6943 goto finish;
6944 }
6945
6946 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
6947 OSKext * thisKext; // do not release
6948
6949 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
6950 if (!thisKext || thisKext->isPrelinked() || thisKext->isKernel()) {
6951 continue;
6952 }
6953
6954 if (_OSKextInUnloadedPrelinkedKexts(thisKext->bundleID)) {
6955 continue;
6956 }
6957 /* kext is loaded and was not in current kernel cache so let's rebuild
6958 */
6959 doRebuild = true;
6960 OSKextLog(/* kext */ NULL,
6961 kOSKextLogArchiveFlag,
6962 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
6963 thisKext->bundleID->getCStringNoCopy());
6964 break;
6965 }
6966 sUnloadedPrelinkedKexts->flushCollection();
6967
6968 if (!doRebuild) {
6969 goto finish;
6970 }
6971
6972 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
6973 &prelinkRequest);
6974 if (checkResult != kOSReturnSuccess) {
6975 goto finish;
6976 }
6977
6978 if (!sKernelRequests->setObject(prelinkRequest)) {
6979 goto finish;
6980 }
6981
6982 OSKext::pingKextd();
6983
6984 finish:
6985 IORecursiveLockUnlock(sKextLock);
6986 OSSafeReleaseNULL(prelinkRequest);
6987 OSSafeReleaseNULL(kextIterator);
6988
6989 return;
6990 }
6991
6992 #if PRAGMA_MARK
6993 #pragma mark Dependencies
6994 #endif
6995 /*********************************************************************
6996 *********************************************************************/
6997 bool
6998 OSKext::resolveDependencies(
6999 OSArray * loopStack)
7000 {
7001 bool result = false;
7002 OSArray * localLoopStack = NULL; // must release
7003 bool addedToLoopStack = false;
7004 OSDictionary * libraries = NULL; // do not release
7005 OSCollectionIterator * libraryIterator = NULL; // must release
7006 OSString * libraryID = NULL; // do not release
7007 OSString * infoString = NULL; // do not release
7008 OSString * readableString = NULL; // do not release
7009 OSKext * libraryKext = NULL; // do not release
7010 bool hasRawKernelDependency = false;
7011 bool hasKernelDependency = false;
7012 bool hasKPIDependency = false;
7013 bool hasPrivateKPIDependency = false;
7014 unsigned int count;
7015
7016 /* A kernel component will automatically have this flag set,
7017 * and a loaded kext should also have it set (as should all its
7018 * loaded dependencies).
7019 */
7020 if (flags.hasAllDependencies) {
7021 result = true;
7022 goto finish;
7023 }
7024
7025 /* Check for loops in the dependency graph.
7026 */
7027 if (loopStack) {
7028 if (loopStack->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
7029 OSKextLog(this,
7030 kOSKextLogErrorLevel |
7031 kOSKextLogDependenciesFlag,
7032 "Kext %s has a dependency loop; can't resolve dependencies.",
7033 getIdentifierCString());
7034 goto finish;
7035 }
7036 } else {
7037 OSKextLog(this,
7038 kOSKextLogStepLevel |
7039 kOSKextLogDependenciesFlag,
7040 "Kext %s resolving dependencies.",
7041 getIdentifierCString());
7042
7043 loopStack = OSArray::withCapacity(6); // any small capacity will do
7044 if (!loopStack) {
7045 OSKextLog(this,
7046 kOSKextLogErrorLevel |
7047 kOSKextLogDependenciesFlag,
7048 "Kext %s can't create bookkeeping stack to resolve dependencies.",
7049 getIdentifierCString());
7050 goto finish;
7051 }
7052 localLoopStack = loopStack;
7053 }
7054 if (!loopStack->setObject(this)) {
7055 OSKextLog(this,
7056 kOSKextLogErrorLevel |
7057 kOSKextLogDependenciesFlag,
7058 "Kext %s - internal error resolving dependencies.",
7059 getIdentifierCString());
7060 goto finish;
7061 }
7062 addedToLoopStack = true;
7063
7064 /* Purge any existing kexts in the dependency list and start over.
7065 */
7066 flushDependencies();
7067 if (dependencies) {
7068 OSKextLog(this,
7069 kOSKextLogErrorLevel |
7070 kOSKextLogDependenciesFlag,
7071 "Kext %s - internal error resolving dependencies.",
7072 getIdentifierCString());
7073 }
7074
7075 libraries = OSDynamicCast(OSDictionary,
7076 getPropertyForHostArch(kOSBundleLibrariesKey));
7077 if (libraries == NULL || libraries->getCount() == 0) {
7078 OSKextLog(this,
7079 kOSKextLogErrorLevel |
7080 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
7081 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
7082 getIdentifierCString(), kOSBundleLibrariesKey);
7083 goto finish;
7084 }
7085
7086 /* Make a new array to hold the dependencies (flush freed the old one).
7087 */
7088 dependencies = OSArray::withCapacity(libraries->getCount());
7089 if (!dependencies) {
7090 OSKextLog(this,
7091 kOSKextLogErrorLevel |
7092 kOSKextLogDependenciesFlag,
7093 "Kext %s - can't allocate dependencies array.",
7094 getIdentifierCString());
7095 goto finish;
7096 }
7097
7098 // xxx - compat: We used to add an implicit dependency on kernel 6.0
7099 // xxx - compat: if none were declared.
7100
7101 libraryIterator = OSCollectionIterator::withCollection(libraries);
7102 if (!libraryIterator) {
7103 OSKextLog(this,
7104 kOSKextLogErrorLevel |
7105 kOSKextLogDependenciesFlag,
7106 "Kext %s - can't allocate dependencies iterator.",
7107 getIdentifierCString());
7108 goto finish;
7109 }
7110
7111 while ((libraryID = OSDynamicCast(OSString,
7112 libraryIterator->getNextObject()))) {
7113
7114 const char * library_id = libraryID->getCStringNoCopy();
7115
7116 OSString * libraryVersion = OSDynamicCast(OSString,
7117 libraries->getObject(libraryID));
7118 if (libraryVersion == NULL) {
7119 OSKextLog(this,
7120 kOSKextLogErrorLevel |
7121 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
7122 "Kext %s - illegal type in OSBundleLibraries.",
7123 getIdentifierCString());
7124 goto finish;
7125 }
7126
7127 OSKextVersion libraryVers =
7128 OSKextParseVersionString(libraryVersion->getCStringNoCopy());
7129 if (libraryVers == -1) {
7130 OSKextLog(this,
7131 kOSKextLogErrorLevel |
7132 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
7133 "Kext %s - invalid library version %s.",
7134 getIdentifierCString(),
7135 libraryVersion->getCStringNoCopy());
7136 goto finish;
7137 }
7138
7139 libraryKext = OSDynamicCast(OSKext, sKextsByID->getObject(libraryID));
7140 if (libraryKext == NULL) {
7141 OSKextLog(this,
7142 kOSKextLogErrorLevel |
7143 kOSKextLogDependenciesFlag,
7144 "Kext %s - library kext %s not found.",
7145 getIdentifierCString(), library_id);
7146 goto finish;
7147 }
7148
7149 if (!libraryKext->isCompatibleWithVersion(libraryVers)) {
7150 OSKextLog(this,
7151 kOSKextLogErrorLevel |
7152 kOSKextLogDependenciesFlag,
7153 "Kext %s - library kext %s not compatible "
7154 "with requested version %s.",
7155 getIdentifierCString(), library_id,
7156 libraryVersion->getCStringNoCopy());
7157 goto finish;
7158 }
7159
7160 /* If a nonprelinked library somehow got into the mix for a
7161 * prelinked kext, at any point in the chain, we must fail
7162 * because the prelinked relocs for the library will be all wrong.
7163 */
7164 if (this->isPrelinked() &&
7165 libraryKext->declaresExecutable() &&
7166 !libraryKext->isPrelinked()) {
7167
7168 OSKextLog(this,
7169 kOSKextLogErrorLevel |
7170 kOSKextLogDependenciesFlag,
7171 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
7172 getIdentifierCString(), library_id,
7173 libraryVersion->getCStringNoCopy());
7174 goto finish;
7175 }
7176
7177 if (!libraryKext->resolveDependencies(loopStack)) {
7178 goto finish;
7179 }
7180
7181 /* Add the library directly only if it has an executable to link.
7182 * Otherwise it's just used to collect other dependencies, so put
7183 * *its* dependencies on the list for this kext.
7184 */
7185 // xxx - We are losing info here; would like to make fake entries or
7186 // xxx - keep these in the dependency graph for loaded kexts.
7187 // xxx - I really want to make kernel components not a special case!
7188 if (libraryKext->declaresExecutable() ||
7189 libraryKext->isInterface()) {
7190
7191 if (dependencies->getNextIndexOfObject(libraryKext, 0) == (unsigned)-1) {
7192 dependencies->setObject(libraryKext);
7193
7194 OSKextLog(this,
7195 kOSKextLogDetailLevel |
7196 kOSKextLogDependenciesFlag,
7197 "Kext %s added dependency %s.",
7198 getIdentifierCString(),
7199 libraryKext->getIdentifierCString());
7200 }
7201 } else {
7202 int numLibDependencies = libraryKext->getNumDependencies();
7203 OSArray * libraryDependencies = libraryKext->getDependencies();
7204 int index;
7205
7206 if (numLibDependencies) {
7207 // xxx - this msg level should be 1 lower than the per-kext one
7208 OSKextLog(this,
7209 kOSKextLogDetailLevel |
7210 kOSKextLogDependenciesFlag,
7211 "Kext %s pulling %d dependencies from codeless library %s.",
7212 getIdentifierCString(),
7213 numLibDependencies,
7214 libraryKext->getIdentifierCString());
7215 }
7216 for (index = 0; index < numLibDependencies; index++) {
7217 OSKext * thisLibDependency = OSDynamicCast(OSKext,
7218 libraryDependencies->getObject(index));
7219 if (dependencies->getNextIndexOfObject(thisLibDependency, 0) == (unsigned)-1) {
7220 dependencies->setObject(thisLibDependency);
7221 OSKextLog(this,
7222 kOSKextLogDetailLevel |
7223 kOSKextLogDependenciesFlag,
7224 "Kext %s added dependency %s from codeless library %s.",
7225 getIdentifierCString(),
7226 thisLibDependency->getIdentifierCString(),
7227 libraryKext->getIdentifierCString());
7228 }
7229 }
7230 }
7231
7232 if ((strlen(library_id) == strlen(KERNEL_LIB)) &&
7233 0 == strncmp(library_id, KERNEL_LIB, sizeof(KERNEL_LIB)-1)) {
7234
7235 hasRawKernelDependency = true;
7236 } else if (STRING_HAS_PREFIX(library_id, KERNEL_LIB_PREFIX)) {
7237 hasKernelDependency = true;
7238 } else if (STRING_HAS_PREFIX(library_id, KPI_LIB_PREFIX)) {
7239 hasKPIDependency = true;
7240 if (!strncmp(library_id, PRIVATE_KPI, sizeof(PRIVATE_KPI)-1)) {
7241 hasPrivateKPIDependency = true;
7242 }
7243 }
7244 }
7245
7246 if (hasRawKernelDependency) {
7247 OSKextLog(this,
7248 kOSKextLogErrorLevel |
7249 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
7250 "Error - kext %s declares a dependency on %s, which is not permitted.",
7251 getIdentifierCString(), KERNEL_LIB);
7252 goto finish;
7253 }
7254 #if __LP64__
7255 if (hasKernelDependency) {
7256 OSKextLog(this,
7257 kOSKextLogErrorLevel |
7258 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
7259 "Error - kext %s declares %s dependencies. "
7260 "Only %s* dependencies are supported for 64-bit kexts.",
7261 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
7262 goto finish;
7263 }
7264 if (!hasKPIDependency) {
7265 OSKextLog(this,
7266 kOSKextLogWarningLevel |
7267 kOSKextLogDependenciesFlag,
7268 "Warning - kext %s declares no %s* dependencies. "
7269 "If it uses any KPIs, the link may fail with undefined symbols.",
7270 getIdentifierCString(), KPI_LIB_PREFIX);
7271 }
7272 #else /* __LP64__ */
7273 // xxx - will change to flatly disallow "kernel" dependencies at some point
7274 // xxx - is it invalid to do both "com.apple.kernel" and any
7275 // xxx - "com.apple.kernel.*"?
7276
7277 if (hasKernelDependency && hasKPIDependency) {
7278 OSKextLog(this,
7279 kOSKextLogWarningLevel |
7280 kOSKextLogDependenciesFlag,
7281 "Warning - kext %s has immediate dependencies on both "
7282 "%s* and %s* components; use only one style.",
7283 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
7284 }
7285
7286 if (!hasKernelDependency && !hasKPIDependency) {
7287 // xxx - do we want to use validation flag for these too?
7288 OSKextLog(this,
7289 kOSKextLogWarningLevel |
7290 kOSKextLogDependenciesFlag,
7291 "Warning - %s declares no kernel dependencies; using %s.",
7292 getIdentifierCString(), KERNEL6_LIB);
7293 OSKext * kernelKext = OSDynamicCast(OSKext,
7294 sKextsByID->getObject(KERNEL6_LIB));
7295 if (kernelKext) {
7296 dependencies->setObject(kernelKext);
7297 } else {
7298 OSKextLog(this,
7299 kOSKextLogErrorLevel |
7300 kOSKextLogDependenciesFlag,
7301 "Error - Library %s not found for %s.",
7302 KERNEL6_LIB, getIdentifierCString());
7303 }
7304 }
7305
7306 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
7307 * its indirect dependencies to simulate old-style linking. XXX - Should
7308 * check for duplicates.
7309 */
7310 if (!hasKPIDependency) {
7311 unsigned int i;
7312
7313 flags.hasBleedthrough = true;
7314
7315 count = getNumDependencies();
7316
7317 /* We add to the dependencies array in this loop, but do not iterate
7318 * past its original count.
7319 */
7320 for (i = 0; i < count; i++) {
7321 OSKext * dependencyKext = OSDynamicCast(OSKext,
7322 dependencies->getObject(i));
7323 dependencyKext->addBleedthroughDependencies(dependencies);
7324 }
7325 }
7326 #endif /* __LP64__ */
7327
7328 if (hasPrivateKPIDependency) {
7329 bool hasApplePrefix = false;
7330 bool infoCopyrightIsValid = false;
7331 bool readableCopyrightIsValid = false;
7332
7333 hasApplePrefix = STRING_HAS_PREFIX(getIdentifierCString(),
7334 APPLE_KEXT_PREFIX);
7335
7336 infoString = OSDynamicCast(OSString,
7337 getPropertyForHostArch("CFBundleGetInfoString"));
7338 if (infoString) {
7339 infoCopyrightIsValid =
7340 kxld_validate_copyright_string(infoString->getCStringNoCopy());
7341 }
7342
7343 readableString = OSDynamicCast(OSString,
7344 getPropertyForHostArch("NSHumanReadableCopyright"));
7345 if (readableString) {
7346 readableCopyrightIsValid =
7347 kxld_validate_copyright_string(readableString->getCStringNoCopy());
7348 }
7349
7350 if (!hasApplePrefix || (!infoCopyrightIsValid && !readableCopyrightIsValid)) {
7351 OSKextLog(this,
7352 kOSKextLogErrorLevel |
7353 kOSKextLogDependenciesFlag,
7354 "Error - kext %s declares a dependency on %s. "
7355 "Only Apple kexts may declare a dependency on %s.",
7356 getIdentifierCString(), PRIVATE_KPI, PRIVATE_KPI);
7357 goto finish;
7358 }
7359 }
7360
7361 result = true;
7362 flags.hasAllDependencies = 1;
7363
7364 finish:
7365
7366 if (addedToLoopStack) {
7367 count = loopStack->getCount();
7368 if (count > 0 && (this == loopStack->getObject(count - 1))) {
7369 loopStack->removeObject(count - 1);
7370 } else {
7371 OSKextLog(this,
7372 kOSKextLogErrorLevel |
7373 kOSKextLogDependenciesFlag,
7374 "Kext %s - internal error resolving dependencies.",
7375 getIdentifierCString());
7376 }
7377 }
7378
7379 if (result && localLoopStack) {
7380 OSKextLog(this,
7381 kOSKextLogStepLevel |
7382 kOSKextLogDependenciesFlag,
7383 "Kext %s successfully resolved dependencies.",
7384 getIdentifierCString());
7385 }
7386
7387 OSSafeReleaseNULL(localLoopStack);
7388 OSSafeReleaseNULL(libraryIterator);
7389
7390 return result;
7391 }
7392
7393 /*********************************************************************
7394 *********************************************************************/
7395 bool
7396 OSKext::addBleedthroughDependencies(OSArray * anArray)
7397 {
7398 bool result = false;
7399 unsigned int dependencyIndex, dependencyCount;
7400
7401 dependencyCount = getNumDependencies();
7402
7403 for (dependencyIndex = 0;
7404 dependencyIndex < dependencyCount;
7405 dependencyIndex++) {
7406
7407 OSKext * dependency = OSDynamicCast(OSKext,
7408 dependencies->getObject(dependencyIndex));
7409 if (!dependency) {
7410 OSKextLog(this,
7411 kOSKextLogErrorLevel |
7412 kOSKextLogDependenciesFlag,
7413 "Kext %s - internal error propagating compatibility dependencies.",
7414 getIdentifierCString());
7415 goto finish;
7416 }
7417 if (anArray->getNextIndexOfObject(dependency, 0) == (unsigned int)-1) {
7418 anArray->setObject(dependency);
7419 }
7420 dependency->addBleedthroughDependencies(anArray);
7421 }
7422
7423 result = true;
7424
7425 finish:
7426 return result;
7427 }
7428
7429 /*********************************************************************
7430 *********************************************************************/
7431 bool
7432 OSKext::flushDependencies(bool forceFlag)
7433 {
7434 bool result = false;
7435
7436 /* Only clear the dependencies if the kext isn't loaded;
7437 * we need the info for loaded kexts to track references.
7438 */
7439 if (!isLoaded() || forceFlag) {
7440 if (dependencies) {
7441 // xxx - check level
7442 OSKextLog(this,
7443 kOSKextLogProgressLevel |
7444 kOSKextLogDependenciesFlag,
7445 "Kext %s flushing dependencies.",
7446 getIdentifierCString());
7447 OSSafeReleaseNULL(dependencies);
7448
7449 }
7450 if (!isKernelComponent()) {
7451 flags.hasAllDependencies = 0;
7452 }
7453 result = true;
7454 }
7455
7456 return result;
7457 }
7458
7459 /*********************************************************************
7460 *********************************************************************/
7461 uint32_t
7462 OSKext::getNumDependencies(void)
7463 {
7464 if (!dependencies) {
7465 return 0;
7466 }
7467 return dependencies->getCount();
7468 }
7469
7470 /*********************************************************************
7471 *********************************************************************/
7472 OSArray *
7473 OSKext::getDependencies(void)
7474 {
7475 return dependencies;
7476 }
7477
7478 #if PRAGMA_MARK
7479 #pragma mark OSMetaClass Support
7480 #endif
7481 /*********************************************************************
7482 *********************************************************************/
7483 OSReturn
7484 OSKext::addClass(
7485 OSMetaClass * aClass,
7486 uint32_t numClasses)
7487 {
7488 OSReturn result = kOSMetaClassNoInsKModSet;
7489
7490 if (!metaClasses) {
7491 metaClasses = OSSet::withCapacity(numClasses);
7492 if (!metaClasses) {
7493 goto finish;
7494 }
7495 }
7496
7497 if (metaClasses->containsObject(aClass)) {
7498 OSKextLog(this,
7499 kOSKextLogWarningLevel |
7500 kOSKextLogLoadFlag,
7501 "Notice - kext %s has already registered class %s.",
7502 getIdentifierCString(),
7503 aClass->getClassName());
7504 result = kOSReturnSuccess;
7505 goto finish;
7506 }
7507
7508 if (!metaClasses->setObject(aClass)) {
7509 goto finish;
7510 } else {
7511 OSKextLog(this,
7512 kOSKextLogDetailLevel |
7513 kOSKextLogLoadFlag,
7514 "Kext %s registered class %s.",
7515 getIdentifierCString(),
7516 aClass->getClassName());
7517 }
7518
7519 if (!flags.autounloadEnabled) {
7520 const OSMetaClass * metaScan = NULL; // do not release
7521
7522 for (metaScan = aClass; metaScan; metaScan = metaScan->getSuperClass()) {
7523 if (metaScan == OSTypeID(IOService)) {
7524
7525 OSKextLog(this,
7526 kOSKextLogProgressLevel |
7527 kOSKextLogLoadFlag,
7528 "Kext %s has IOService subclass %s; enabling autounload.",
7529 getIdentifierCString(),
7530 aClass->getClassName());
7531
7532 flags.autounloadEnabled = 1;
7533 break;
7534 }
7535 }
7536 }
7537
7538 notifyAddClassObservers(this, aClass, flags);
7539
7540 result = kOSReturnSuccess;
7541
7542 finish:
7543 if (result != kOSReturnSuccess) {
7544 OSKextLog(this,
7545 kOSKextLogErrorLevel |
7546 kOSKextLogLoadFlag,
7547 "Kext %s failed to register class %s.",
7548 getIdentifierCString(),
7549 aClass->getClassName());
7550 }
7551
7552 return result;
7553 }
7554
7555 /*********************************************************************
7556 *********************************************************************/
7557 OSReturn
7558 OSKext::removeClass(
7559 OSMetaClass * aClass)
7560 {
7561 OSReturn result = kOSMetaClassNoKModSet;
7562
7563 if (!metaClasses) {
7564 goto finish;
7565 }
7566
7567 if (!metaClasses->containsObject(aClass)) {
7568 OSKextLog(this,
7569 kOSKextLogWarningLevel |
7570 kOSKextLogLoadFlag,
7571 "Notice - kext %s asked to unregister unknown class %s.",
7572 getIdentifierCString(),
7573 aClass->getClassName());
7574 result = kOSReturnSuccess;
7575 goto finish;
7576 }
7577
7578 OSKextLog(this,
7579 kOSKextLogDetailLevel |
7580 kOSKextLogLoadFlag,
7581 "Kext %s unregistering class %s.",
7582 getIdentifierCString(),
7583 aClass->getClassName());
7584
7585 metaClasses->removeObject(aClass);
7586
7587 notifyRemoveClassObservers(this, aClass, flags);
7588
7589 result = kOSReturnSuccess;
7590
7591 finish:
7592 if (result != kOSReturnSuccess) {
7593 OSKextLog(this,
7594 kOSKextLogErrorLevel |
7595 kOSKextLogLoadFlag,
7596 "Failed to unregister kext %s class %s.",
7597 getIdentifierCString(),
7598 aClass->getClassName());
7599 }
7600 return result;
7601 }
7602
7603 /*********************************************************************
7604 *********************************************************************/
7605 OSSet *
7606 OSKext::getMetaClasses(void)
7607 {
7608 return metaClasses;
7609 }
7610
7611 /*********************************************************************
7612 *********************************************************************/
7613 bool
7614 OSKext::hasOSMetaClassInstances(void)
7615 {
7616 bool result = false;
7617 OSCollectionIterator * classIterator = NULL; // must release
7618 OSMetaClass * checkClass = NULL; // do not release
7619
7620 if (!metaClasses) {
7621 goto finish;
7622 }
7623
7624 classIterator = OSCollectionIterator::withCollection(metaClasses);
7625 if (!classIterator) {
7626 // xxx - log alloc failure?
7627 goto finish;
7628 }
7629 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
7630 if (checkClass->getInstanceCount()) {
7631 result = true;
7632 goto finish;
7633 }
7634 }
7635
7636 finish:
7637
7638 OSSafeReleaseNULL(classIterator);
7639 return result;
7640 }
7641
7642 /*********************************************************************
7643 *********************************************************************/
7644 /* static */
7645 void
7646 OSKext::reportOSMetaClassInstances(
7647 const char * kextIdentifier,
7648 OSKextLogSpec msgLogSpec)
7649 {
7650 OSKext * theKext = NULL; // must release
7651
7652 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
7653 if (!theKext) {
7654 goto finish;
7655 }
7656
7657 theKext->reportOSMetaClassInstances(msgLogSpec);
7658 finish:
7659 OSSafeReleaseNULL(theKext);
7660 return;
7661 }
7662
7663 /*********************************************************************
7664 *********************************************************************/
7665 void
7666 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
7667 {
7668 OSCollectionIterator * classIterator = NULL; // must release
7669 OSMetaClass * checkClass = NULL; // do not release
7670
7671 if (!metaClasses) {
7672 goto finish;
7673 }
7674
7675 classIterator = OSCollectionIterator::withCollection(metaClasses);
7676 if (!classIterator) {
7677 goto finish;
7678 }
7679 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
7680 if (checkClass->getInstanceCount()) {
7681 OSKextLog(this,
7682 msgLogSpec,
7683 " Kext %s class %s has %d instance%s.",
7684 getIdentifierCString(),
7685 checkClass->getClassName(),
7686 checkClass->getInstanceCount(),
7687 checkClass->getInstanceCount() == 1 ? "" : "s");
7688 }
7689 }
7690
7691 finish:
7692 OSSafeReleaseNULL(classIterator);
7693 return;
7694 }
7695
7696 #if PRAGMA_MARK
7697 #pragma mark User-Space Requests
7698 #endif
7699 /*********************************************************************
7700 * XXX - this function is a big ugly mess
7701 *********************************************************************/
7702 /* static */
7703 OSReturn
7704 OSKext::handleRequest(
7705 host_priv_t hostPriv,
7706 OSKextLogSpec clientLogFilter,
7707 char * requestBuffer,
7708 uint32_t requestLength,
7709 char ** responseOut,
7710 uint32_t * responseLengthOut,
7711 char ** logInfoOut,
7712 uint32_t * logInfoLengthOut)
7713 {
7714 OSReturn result = kOSReturnError;
7715 kern_return_t kmem_result = KERN_FAILURE;
7716
7717 char * response = NULL; // returned by reference
7718 uint32_t responseLength = 0;
7719
7720 OSObject * parsedXML = NULL; // must release
7721 OSDictionary * requestDict = NULL; // do not release
7722 OSString * errorString = NULL; // must release
7723
7724 OSObject * responseObject = NULL; // must release
7725
7726 OSSerialize * serializer = NULL; // must release
7727
7728 OSArray * logInfoArray = NULL; // must release
7729
7730 OSString * predicate = NULL; // do not release
7731 OSString * kextIdentifier = NULL; // do not release
7732 OSArray * kextIdentifiers = NULL; // do not release
7733 OSKext * theKext = NULL; // do not release
7734 OSBoolean * boolArg = NULL; // do not release
7735
7736 IORecursiveLockLock(sKextLock);
7737
7738 if (responseOut) {
7739 *responseOut = NULL;
7740 *responseLengthOut = 0;
7741 }
7742 if (logInfoOut) {
7743 *logInfoOut = NULL;
7744 *logInfoLengthOut = 0;
7745 }
7746
7747 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
7748
7749 /* XML must be nul-terminated.
7750 */
7751 if (requestBuffer[requestLength - 1] != '\0') {
7752 OSKextLog(/* kext */ NULL,
7753 kOSKextLogErrorLevel |
7754 kOSKextLogIPCFlag,
7755 "Invalid request from user space (not nul-terminated).");
7756 result = kOSKextReturnBadData;
7757 goto finish;
7758 }
7759 parsedXML = OSUnserializeXML((const char *)requestBuffer, &errorString);
7760 if (parsedXML) {
7761 requestDict = OSDynamicCast(OSDictionary, parsedXML);
7762 }
7763 if (!requestDict) {
7764 const char * errorCString = "(unknown error)";
7765
7766 if (errorString && errorString->getCStringNoCopy()) {
7767 errorCString = errorString->getCStringNoCopy();
7768 } else if (parsedXML) {
7769 errorCString = "not a dictionary";
7770 }
7771 OSKextLog(/* kext */ NULL,
7772 kOSKextLogErrorLevel |
7773 kOSKextLogIPCFlag,
7774 "Error unserializing request from user space: %s.",
7775 errorCString);
7776 result = kOSKextReturnSerialization;
7777 goto finish;
7778 }
7779
7780 predicate = _OSKextGetRequestPredicate(requestDict);
7781 if (!predicate) {
7782 OSKextLog(/* kext */ NULL,
7783 kOSKextLogErrorLevel |
7784 kOSKextLogIPCFlag,
7785 "Recieved kext request from user space with no predicate.");
7786 result = kOSKextReturnInvalidArgument;
7787 goto finish;
7788 }
7789
7790 OSKextLog(/* kext */ NULL,
7791 kOSKextLogDebugLevel |
7792 kOSKextLogIPCFlag,
7793 "Received '%s' request from user space.",
7794 predicate->getCStringNoCopy());
7795
7796 result = kOSKextReturnNotPrivileged;
7797 if (hostPriv == HOST_PRIV_NULL) {
7798 /* must be root to use these kext requests */
7799 if (predicate->isEqualTo(kKextRequestPredicateUnload) ||
7800 predicate->isEqualTo(kKextRequestPredicateStart) ||
7801 predicate->isEqualTo(kKextRequestPredicateStop) ||
7802 predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
7803 predicate->isEqualTo(kKextRequestPredicateSendResource) ) {
7804 OSKextLog(/* kext */ NULL,
7805 kOSKextLogErrorLevel |
7806 kOSKextLogIPCFlag,
7807 "Access Failure - must be root user.");
7808 goto finish;
7809 }
7810 }
7811
7812 /* Get common args in anticipation of use.
7813 */
7814 kextIdentifier = OSDynamicCast(OSString, _OSKextGetRequestArgument(
7815 requestDict, kKextRequestArgumentBundleIdentifierKey));
7816 kextIdentifiers = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
7817 requestDict, kKextRequestArgumentBundleIdentifierKey));
7818 if (kextIdentifier) {
7819 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
7820 }
7821 boolArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
7822 requestDict, kKextRequestArgumentValueKey));
7823
7824 result = kOSKextReturnInvalidArgument;
7825
7826 if (predicate->isEqualTo(kKextRequestPredicateStart)) {
7827 if (!kextIdentifier) {
7828 OSKextLog(/* kext */ NULL,
7829 kOSKextLogErrorLevel |
7830 kOSKextLogIPCFlag,
7831 "Invalid arguments to kext start request.");
7832 } else if (!theKext) {
7833 OSKextLog(/* kext */ NULL,
7834 kOSKextLogErrorLevel |
7835 kOSKextLogIPCFlag,
7836 "Kext %s not found for start request.",
7837 kextIdentifier->getCStringNoCopy());
7838 result = kOSKextReturnNotFound;
7839 } else {
7840 result = theKext->start();
7841 }
7842
7843 } else if (predicate->isEqualTo(kKextRequestPredicateStop)) {
7844 if (!kextIdentifier) {
7845 OSKextLog(/* kext */ NULL,
7846 kOSKextLogErrorLevel |
7847 kOSKextLogIPCFlag,
7848 "Invalid arguments to kext stop request.");
7849 } else if (!theKext) {
7850 OSKextLog(/* kext */ NULL,
7851 kOSKextLogErrorLevel |
7852 kOSKextLogIPCFlag,
7853 "Kext %s not found for stop request.",
7854 kextIdentifier->getCStringNoCopy());
7855 result = kOSKextReturnNotFound;
7856 } else {
7857 result = theKext->stop();
7858 }
7859
7860 } else if (predicate->isEqualTo(kKextRequestPredicateUnload)) {
7861 if (!kextIdentifier) {
7862 OSKextLog(/* kext */ NULL,
7863 kOSKextLogErrorLevel |
7864 kOSKextLogIPCFlag,
7865 "Invalid arguments to kext unload request.");
7866 } else if (!theKext) {
7867 OSKextLog(/* kext */ NULL,
7868 kOSKextLogErrorLevel |
7869 kOSKextLogIPCFlag,
7870 "Kext %s not found for unload request.",
7871 kextIdentifier->getCStringNoCopy());
7872 result = kOSKextReturnNotFound;
7873 } else {
7874 OSBoolean * terminateFlag = OSDynamicCast(OSBoolean,
7875 _OSKextGetRequestArgument(requestDict,
7876 kKextRequestArgumentTerminateIOServicesKey));
7877 result = OSKext::removeKext(theKext, terminateFlag == kOSBooleanTrue);
7878 }
7879
7880 } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
7881 result = OSKext::dispatchResource(requestDict);
7882
7883 } else if (predicate->isEqualTo(kKextRequestPredicateGetUUIDByAddress)) {
7884
7885 OSNumber *lookupNum = NULL;
7886 lookupNum = OSDynamicCast(OSNumber,
7887 _OSKextGetRequestArgument(requestDict,
7888 kKextRequestArgumentLookupAddressKey));
7889
7890 responseObject = OSKext::copyKextUUIDForAddress(lookupNum);
7891 if (responseObject) {
7892 result = kOSReturnSuccess;
7893 } else {
7894 OSKextLog(/* kext */ NULL,
7895 kOSKextLogErrorLevel |
7896 kOSKextLogIPCFlag,
7897 "Get UUID by Address failed.");
7898 goto finish;
7899 }
7900
7901 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded) ||
7902 predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
7903 OSBoolean * delayAutounloadBool = NULL;
7904 OSObject * infoKeysRaw = NULL;
7905 OSArray * infoKeys = NULL;
7906 uint32_t infoKeysCount = 0;
7907
7908 delayAutounloadBool = OSDynamicCast(OSBoolean,
7909 _OSKextGetRequestArgument(requestDict,
7910 kKextRequestArgumentDelayAutounloadKey));
7911
7912 /* If asked to delay autounload, reset the timer if it's currently set.
7913 * (That is, don't schedule an unload if one isn't already pending.
7914 */
7915 if (delayAutounloadBool == kOSBooleanTrue) {
7916 OSKext::considerUnloads(/* rescheduleOnly? */ true);
7917 }
7918
7919 infoKeysRaw = _OSKextGetRequestArgument(requestDict,
7920 kKextRequestArgumentInfoKeysKey);
7921 infoKeys = OSDynamicCast(OSArray, infoKeysRaw);
7922 if (infoKeysRaw && !infoKeys) {
7923 OSKextLog(/* kext */ NULL,
7924 kOSKextLogErrorLevel |
7925 kOSKextLogIPCFlag,
7926 "Invalid arguments to kext info request.");
7927 goto finish;
7928 }
7929
7930 if (infoKeys) {
7931 infoKeysCount = infoKeys->getCount();
7932 for (uint32_t i = 0; i < infoKeysCount; i++) {
7933 if (!OSDynamicCast(OSString, infoKeys->getObject(i))) {
7934 OSKextLog(/* kext */ NULL,
7935 kOSKextLogErrorLevel |
7936 kOSKextLogIPCFlag,
7937 "Invalid arguments to kext info request.");
7938 goto finish;
7939 }
7940 }
7941 }
7942
7943 if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
7944 responseObject = OSKext::copyLoadedKextInfo(kextIdentifiers, infoKeys);
7945 }
7946 else if (predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
7947 responseObject = OSKext::copyLoadedKextInfoByUUID(kextIdentifiers, infoKeys);
7948 }
7949 if (!responseObject) {
7950 result = kOSKextReturnInternalError;
7951 } else {
7952 OSKextLog(/* kext */ NULL,
7953 kOSKextLogDebugLevel |
7954 kOSKextLogIPCFlag,
7955 "Returning loaded kext info.");
7956 result = kOSReturnSuccess;
7957 }
7958 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
7959
7960 /* Hand the current sKernelRequests array to the caller
7961 * (who must release it), and make a new one.
7962 */
7963 responseObject = sKernelRequests;
7964 sKernelRequests = OSArray::withCapacity(0);
7965 sPostedKextLoadIdentifiers->flushCollection();
7966 OSKextLog(/* kext */ NULL,
7967 kOSKextLogDebugLevel |
7968 kOSKextLogIPCFlag,
7969 "Returning kernel requests.");
7970 result = kOSReturnSuccess;
7971
7972 } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
7973
7974 /* Return the set of all requested bundle identifiers */
7975 responseObject = sAllKextLoadIdentifiers;
7976 responseObject->retain();
7977 OSKextLog(/* kext */ NULL,
7978 kOSKextLogDebugLevel |
7979 kOSKextLogIPCFlag,
7980 "Returning load requests.");
7981 result = kOSReturnSuccess;
7982 }
7983 else {
7984 OSKextLog(/* kext */ NULL,
7985 kOSKextLogDebugLevel |
7986 kOSKextLogIPCFlag,
7987 "Received '%s' invalid request from user space.",
7988 predicate->getCStringNoCopy());
7989 goto finish;
7990 }
7991
7992 /**********
7993 * Now we have handle the request, or not. Gather up the response & logging
7994 * info to ship to user space.
7995 *********/
7996
7997 /* Note: Nothing in OSKext is supposed to retain requestDict,
7998 * but you never know....
7999 */
8000 if (requestDict->getRetainCount() > 1) {
8001 OSKextLog(/* kext */ NULL,
8002 kOSKextLogWarningLevel |
8003 kOSKextLogIPCFlag,
8004 "Request from user space still retained by a kext; "
8005 "probable memory leak.");
8006 }
8007
8008 if (responseOut && responseObject) {
8009 serializer = OSSerialize::withCapacity(0);
8010 if (!serializer) {
8011 result = kOSKextReturnNoMemory;
8012 goto finish;
8013 }
8014
8015 if (!responseObject->serialize(serializer)) {
8016 OSKextLog(/* kext */ NULL,
8017 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
8018 "Failed to serialize response to request from user space.");
8019 result = kOSKextReturnSerialization;
8020 goto finish;
8021 }
8022
8023 response = (char *)serializer->text();
8024 responseLength = serializer->getLength();
8025 }
8026
8027 if (responseOut && response) {
8028 char * buffer;
8029
8030 /* This kmem_alloc sets the return value of the function.
8031 */
8032 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer,
8033 round_page(responseLength), VM_KERN_MEMORY_OSKEXT);
8034 if (kmem_result != KERN_SUCCESS) {
8035 OSKextLog(/* kext */ NULL,
8036 kOSKextLogErrorLevel |
8037 kOSKextLogIPCFlag,
8038 "Failed to copy response to request from user space.");
8039 result = kmem_result;
8040 goto finish;
8041 } else {
8042 /* 11981737 - clear uninitialized data in last page */
8043 bzero((void *)(buffer + responseLength),
8044 (round_page(responseLength) - responseLength));
8045 memcpy(buffer, response, responseLength);
8046 *responseOut = buffer;
8047 *responseLengthOut = responseLength;
8048 }
8049 }
8050
8051 finish:
8052
8053 /* Gather up the collected log messages for user space. Any messages
8054 * messages past this call will not make it up as log messages but
8055 * will be in the system log. Note that we ignore the return of the
8056 * serialize; it has no bearing on the operation at hand even if we
8057 * fail to get the log messages.
8058 */
8059 logInfoArray = OSKext::clearUserSpaceLogFilter();
8060
8061 if (logInfoArray && logInfoOut && logInfoLengthOut) {
8062 (void)OSKext::serializeLogInfo(logInfoArray,
8063 logInfoOut, logInfoLengthOut);
8064 }
8065
8066 IORecursiveLockUnlock(sKextLock);
8067
8068 OSSafeReleaseNULL(parsedXML);
8069 OSSafeReleaseNULL(errorString);
8070 OSSafeReleaseNULL(responseObject);
8071 OSSafeReleaseNULL(serializer);
8072 OSSafeReleaseNULL(logInfoArray);
8073
8074 return result;
8075 }
8076
8077
8078 // #include <InstrProfiling.h>
8079 extern "C" {
8080
8081 uint64_t __llvm_profile_get_size_for_buffer_internal(const char *DataBegin,
8082 const char *DataEnd,
8083 const char *CountersBegin,
8084 const char *CountersEnd ,
8085 const char *NamesBegin,
8086 const char *NamesEnd);
8087 int __llvm_profile_write_buffer_internal(char *Buffer,
8088 const char *DataBegin,
8089 const char *DataEnd,
8090 const char *CountersBegin,
8091 const char *CountersEnd ,
8092 const char *NamesBegin,
8093 const char *NamesEnd);
8094 }
8095
8096
8097 static
8098 void OSKextPgoMetadataPut(char *pBuffer,
8099 size_t *position,
8100 size_t bufferSize,
8101 uint32_t *num_pairs,
8102 const char *key,
8103 const char *value)
8104 {
8105 size_t strlen_key = strlen(key);
8106 size_t strlen_value = strlen(value);
8107 size_t len = strlen(key) + 1 + strlen(value) + 1;
8108 char *pos = pBuffer + *position;
8109 *position += len;
8110 if (pBuffer && bufferSize && *position <= bufferSize) {
8111 memcpy(pos, key, strlen_key); pos += strlen_key;
8112 *(pos++) = '=';
8113 memcpy(pos, value, strlen_value); pos += strlen_value;
8114 *(pos++) = 0;
8115 if (num_pairs) {
8116 (*num_pairs)++;
8117 }
8118 }
8119 }
8120
8121
8122 static
8123 void OSKextPgoMetadataPutMax(size_t *position, const char *key, size_t value_max)
8124 {
8125 *position += strlen(key) + 1 + value_max + 1;
8126 }
8127
8128
8129 static
8130 void OSKextPgoMetadataPutAll(OSKext *kext,
8131 uuid_t instance_uuid,
8132 char *pBuffer,
8133 size_t *position,
8134 size_t bufferSize,
8135 uint32_t *num_pairs)
8136 {
8137 _static_assert_1_arg(sizeof(clock_sec_t) % 2 == 0);
8138 //log_10 2^16 ≈ 4.82
8139 const size_t max_secs_string_size = 5 * sizeof(clock_sec_t)/2;
8140 const size_t max_timestamp_string_size = max_secs_string_size + 1 + 6;
8141
8142 if (!pBuffer) {
8143 OSKextPgoMetadataPutMax(position, "INSTANCE", 36);
8144 OSKextPgoMetadataPutMax(position, "UUID", 36);
8145 OSKextPgoMetadataPutMax(position, "TIMESTAMP", max_timestamp_string_size);
8146 } else {
8147 uuid_string_t instance_uuid_string;
8148 uuid_unparse(instance_uuid, instance_uuid_string);
8149 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
8150 "INSTANCE", instance_uuid_string);
8151
8152 OSData *uuid_data;
8153 uuid_t uuid;
8154 uuid_string_t uuid_string;
8155 uuid_data = kext->copyUUID();
8156 if (uuid_data) {
8157 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
8158 OSSafeReleaseNULL(uuid_data);
8159 uuid_unparse(uuid, uuid_string);
8160 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
8161 "UUID", uuid_string);
8162 }
8163
8164 clock_sec_t secs;
8165 clock_usec_t usecs;
8166 clock_get_calendar_microtime(&secs, &usecs);
8167 assert(usecs < 1000000);
8168 char timestamp[max_timestamp_string_size + 1];
8169 _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t));
8170 snprintf(timestamp, sizeof(timestamp), "%lu.%06d", (unsigned long)secs, (int)usecs);
8171 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
8172 "TIMESTAMP", timestamp);
8173 }
8174
8175 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
8176 "NAME", kext->getIdentifierCString());
8177
8178 char versionCString[kOSKextVersionMaxLength];
8179 OSKextVersionGetString(kext->getVersion(), versionCString, kOSKextVersionMaxLength);
8180 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
8181 "VERSION", versionCString);
8182
8183 }
8184
8185 static
8186 size_t OSKextPgoMetadataSize(OSKext *kext)
8187 {
8188 size_t position = 0;
8189 uuid_t fakeuuid = {};
8190 OSKextPgoMetadataPutAll(kext, fakeuuid, NULL, &position, 0, NULL);
8191 return position;
8192 }
8193
8194
8195 int OSKextGrabPgoDataLocked(OSKext *kext,
8196 bool metadata,
8197 uuid_t instance_uuid,
8198 uint64_t *pSize,
8199 char *pBuffer,
8200 uint64_t bufferSize)
8201 {
8202
8203 int err = 0;
8204
8205 kernel_section_t *sect_prf_data = NULL;
8206 kernel_section_t *sect_prf_name = NULL;
8207 kernel_section_t *sect_prf_cnts = NULL;
8208 uint64_t size;
8209 size_t metadata_size = 0;
8210
8211 sect_prf_data = kext->lookupSection("__DATA", "__llvm_prf_data");
8212 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_name");
8213 sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
8214
8215 if (!sect_prf_data || !sect_prf_name || !sect_prf_cnts) {
8216 err = ENOTSUP;
8217 goto out;
8218 }
8219
8220 size = __llvm_profile_get_size_for_buffer_internal(
8221 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
8222 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
8223 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
8224
8225 if (metadata) {
8226 metadata_size = OSKextPgoMetadataSize(kext);
8227 size += metadata_size;
8228 size += sizeof(pgo_metadata_footer);
8229 }
8230
8231
8232 if (pSize) {
8233 *pSize = size;
8234 }
8235
8236 if (pBuffer && bufferSize) {
8237 if (bufferSize < size) {
8238 err = ERANGE;
8239 goto out;
8240 }
8241
8242 err = __llvm_profile_write_buffer_internal(
8243 pBuffer,
8244 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
8245 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
8246 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
8247
8248 if (err) {
8249 err = EIO;
8250 goto out;
8251 }
8252
8253 if (metadata) {
8254 char *end_of_buffer = pBuffer + size;
8255 struct pgo_metadata_footer *footerp = (struct pgo_metadata_footer *) (end_of_buffer - sizeof(struct pgo_metadata_footer));
8256 char *metadata_buffer = end_of_buffer - (sizeof(struct pgo_metadata_footer) + metadata_size);
8257
8258 size_t metadata_position = 0;
8259 uint32_t num_pairs = 0;
8260 OSKextPgoMetadataPutAll(kext, instance_uuid, metadata_buffer, &metadata_position, metadata_size, &num_pairs);
8261 while (metadata_position < metadata_size) {
8262 metadata_buffer[metadata_position++] = 0;
8263 }
8264
8265 struct pgo_metadata_footer footer;
8266 footer.magic = htonl(0x6d657461);
8267 footer.number_of_pairs = htonl( num_pairs );
8268 footer.offset_to_pairs = htonl( sizeof(struct pgo_metadata_footer) + metadata_size );
8269 memcpy(footerp, &footer, sizeof(footer));
8270 }
8271
8272 }
8273
8274 out:
8275 return err;
8276 }
8277
8278
8279 int
8280 OSKextGrabPgoData(uuid_t uuid,
8281 uint64_t *pSize,
8282 char *pBuffer,
8283 uint64_t bufferSize,
8284 int wait_for_unload,
8285 int metadata)
8286 {
8287 int err = 0;
8288 OSKext *kext = NULL;
8289
8290
8291 IORecursiveLockLock(sKextLock);
8292
8293 kext = OSKext::lookupKextWithUUID(uuid);
8294 if (!kext) {
8295 err = ENOENT;
8296 goto out;
8297 }
8298
8299 if (wait_for_unload) {
8300 OSKextGrabPgoStruct s;
8301
8302 s.metadata = metadata;
8303 s.pSize = pSize;
8304 s.pBuffer = pBuffer;
8305 s.bufferSize = bufferSize;
8306 s.err = EINTR;
8307
8308 struct list_head *prev = &kext->pendingPgoHead;
8309 struct list_head *next = kext->pendingPgoHead.next;
8310
8311 s.list_head.prev = prev;
8312 s.list_head.next = next;
8313
8314 prev->next = &s.list_head;
8315 next->prev = &s.list_head;
8316
8317 kext->release();
8318 kext = NULL;
8319
8320 IORecursiveLockSleep(sKextLock, &s, THREAD_ABORTSAFE);
8321
8322 prev = s.list_head.prev;
8323 next = s.list_head.next;
8324
8325 prev->next = next;
8326 next->prev = prev;
8327
8328 err = s.err;
8329
8330 } else {
8331 err = OSKextGrabPgoDataLocked(kext, metadata, kext->instance_uuid, pSize, pBuffer, bufferSize);
8332 }
8333
8334 out:
8335 if (kext) {
8336 kext->release();
8337 }
8338
8339 IORecursiveLockUnlock(sKextLock);
8340
8341 return err;
8342 }
8343
8344 void
8345 OSKextResetPgoCountersLock()
8346 {
8347 IORecursiveLockLock(sKextLock);
8348 }
8349
8350 void
8351 OSKextResetPgoCountersUnlock()
8352 {
8353 IORecursiveLockUnlock(sKextLock);
8354 }
8355
8356
8357 extern unsigned int not_in_kdp;
8358
8359 void
8360 OSKextResetPgoCounters()
8361 {
8362 assert(!not_in_kdp);
8363 uint32_t count = sLoadedKexts->getCount();
8364 for (uint32_t i = 0; i < count; i++) {
8365 OSKext *kext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
8366 kernel_section_t *sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
8367 if (!sect_prf_cnts) {
8368 continue;
8369 }
8370 memset((void*)sect_prf_cnts->addr, 0, sect_prf_cnts->size);
8371 }
8372 }
8373
8374 OSDictionary *
8375 OSKext::copyLoadedKextInfoByUUID(
8376 OSArray * kextIdentifiers,
8377 OSArray * infoKeys)
8378 {
8379 OSDictionary * result = NULL;
8380 OSDictionary * kextInfo = NULL; // must release
8381 uint32_t count, i;
8382 uint32_t idCount = 0;
8383 uint32_t idIndex = 0;
8384
8385 IORecursiveLockLock(sKextLock);
8386
8387 #if CONFIG_MACF
8388 /* Is the calling process allowed to query kext info? */
8389 if (current_task() != kernel_task) {
8390 int macCheckResult = 0;
8391 kauth_cred_t cred = NULL;
8392
8393 cred = kauth_cred_get_with_ref();
8394 macCheckResult = mac_kext_check_query(cred);
8395 kauth_cred_unref(&cred);
8396
8397 if (macCheckResult != 0) {
8398 OSKextLog(/* kext */ NULL,
8399 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
8400 "Failed to query kext info (MAC policy error 0x%x).",
8401 macCheckResult);
8402 goto finish;
8403 }
8404 }
8405 #endif
8406
8407 /* Empty list of UUIDs is equivalent to no list (get all).
8408 */
8409 if (kextIdentifiers && !kextIdentifiers->getCount()) {
8410 kextIdentifiers = NULL;
8411 } else if (kextIdentifiers) {
8412 idCount = kextIdentifiers->getCount();
8413 }
8414
8415 /* Same for keys.
8416 */
8417 if (infoKeys && !infoKeys->getCount()) {
8418 infoKeys = NULL;
8419 }
8420
8421 count = sLoadedKexts->getCount();
8422 result = OSDictionary::withCapacity(count);
8423 if (!result) {
8424 goto finish;
8425 }
8426
8427 for (i = 0; i < count; i++) {
8428 OSKext *thisKext = NULL; // do not release
8429 Boolean includeThis = true;
8430 uuid_t thisKextUUID;
8431 OSData *uuid_data;
8432 uuid_string_t uuid_key;
8433
8434 if (kextInfo) {
8435 kextInfo->release();
8436 kextInfo = NULL;
8437 }
8438
8439 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
8440 if (!thisKext) {
8441 continue;
8442 }
8443
8444 uuid_data = thisKext->copyUUID();
8445 if (!uuid_data) {
8446 continue;
8447 }
8448
8449 memcpy(&thisKextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextUUID));
8450 OSSafeReleaseNULL(uuid_data);
8451
8452 uuid_unparse(thisKextUUID, uuid_key);
8453
8454 /* Skip current kext if we have a list of UUIDs and
8455 * it isn't in the list.
8456 */
8457 if (kextIdentifiers) {
8458 includeThis = false;
8459
8460 for (idIndex = 0; idIndex < idCount; idIndex++) {
8461 const OSString* wantedUUID = OSDynamicCast(OSString,
8462 kextIdentifiers->getObject(idIndex));
8463
8464 uuid_t uuid;
8465 uuid_parse(wantedUUID->getCStringNoCopy(), uuid);
8466
8467 if (0 == uuid_compare(uuid, thisKextUUID)) {
8468 includeThis = true;
8469 break;
8470 }
8471
8472 }
8473 }
8474
8475 if (!includeThis) {
8476 continue;
8477 }
8478
8479 kextInfo = thisKext->copyInfo(infoKeys);
8480 if (kextInfo) {
8481 result->setObject(uuid_key, kextInfo);
8482 }
8483 }
8484
8485 finish:
8486 IORecursiveLockUnlock(sKextLock);
8487
8488 if (kextInfo) kextInfo->release();
8489
8490 return result;
8491 }
8492
8493 /*********************************************************************
8494 *********************************************************************/
8495 /* static */
8496 OSData *
8497 OSKext::copyKextUUIDForAddress(OSNumber *address)
8498 {
8499 OSKext *kext = NULL;
8500 OSData *uuid = NULL;
8501 vm_address_t vm_addr = 0;
8502
8503 if (!address)
8504 goto finish;
8505
8506 #if CONFIG_MACF
8507 /* Is the calling process allowed to query kext info? */
8508 if (current_task() != kernel_task) {
8509 int macCheckResult = 0;
8510 kauth_cred_t cred = NULL;
8511
8512 cred = kauth_cred_get_with_ref();
8513 macCheckResult = mac_kext_check_query(cred);
8514 kauth_cred_unref(&cred);
8515
8516 if (macCheckResult != 0) {
8517 OSKextLog(/* kext */ NULL,
8518 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
8519 "Failed to query kext UUID (MAC policy error 0x%x).",
8520 macCheckResult);
8521 goto finish;
8522 }
8523 }
8524 #endif
8525
8526 vm_addr = (vm_address_t)(address->unsigned64BitValue() + vm_kernel_slide);
8527
8528 kext = OSKext::lookupKextWithAddress(vm_addr);
8529 if (kext) {
8530 uuid = kext->copyUUID();
8531 }
8532
8533 finish:
8534 if (kext) {
8535 kext->release();
8536 }
8537 return uuid;
8538 }
8539
8540
8541 /*********************************************************************
8542 *********************************************************************/
8543 /* static */
8544 OSDictionary *
8545 OSKext::copyLoadedKextInfo(
8546 OSArray * kextIdentifiers,
8547 OSArray * infoKeys)
8548 {
8549 OSDictionary * result = NULL;
8550 OSDictionary * kextInfo = NULL; // must release
8551 uint32_t count, i;
8552 uint32_t idCount = 0;
8553 uint32_t idIndex = 0;
8554
8555 IORecursiveLockLock(sKextLock);
8556
8557 #if CONFIG_MACF
8558 /* Is the calling process allowed to query kext info? */
8559 if (current_task() != kernel_task) {
8560 int macCheckResult = 0;
8561 kauth_cred_t cred = NULL;
8562
8563 cred = kauth_cred_get_with_ref();
8564 macCheckResult = mac_kext_check_query(cred);
8565 kauth_cred_unref(&cred);
8566
8567 if (macCheckResult != 0) {
8568 OSKextLog(/* kext */ NULL,
8569 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
8570 "Failed to query kext info (MAC policy error 0x%x).",
8571 macCheckResult);
8572 goto finish;
8573 }
8574 }
8575 #endif
8576
8577 /* Empty list of bundle ids is equivalent to no list (get all).
8578 */
8579 if (kextIdentifiers && !kextIdentifiers->getCount()) {
8580 kextIdentifiers = NULL;
8581 } else if (kextIdentifiers) {
8582 idCount = kextIdentifiers->getCount();
8583 }
8584
8585 /* Same for keys.
8586 */
8587 if (infoKeys && !infoKeys->getCount()) {
8588 infoKeys = NULL;
8589 }
8590
8591 count = sLoadedKexts->getCount();
8592 result = OSDictionary::withCapacity(count);
8593 if (!result) {
8594 goto finish;
8595 }
8596
8597 #if 0
8598 OSKextLog(/* kext */ NULL,
8599 kOSKextLogErrorLevel |
8600 kOSKextLogGeneralFlag,
8601 "kaslr: vm_kernel_slide 0x%lx \n",
8602 vm_kernel_slide);
8603 OSKextLog(/* kext */ NULL,
8604 kOSKextLogErrorLevel |
8605 kOSKextLogGeneralFlag,
8606 "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
8607 vm_kernel_stext, vm_kernel_etext);
8608 OSKextLog(/* kext */ NULL,
8609 kOSKextLogErrorLevel |
8610 kOSKextLogGeneralFlag,
8611 "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
8612 vm_kernel_base, vm_kernel_top);
8613 OSKextLog(/* kext */ NULL,
8614 kOSKextLogErrorLevel |
8615 kOSKextLogGeneralFlag,
8616 "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
8617 vm_kext_base, vm_kext_top);
8618 OSKextLog(/* kext */ NULL,
8619 kOSKextLogErrorLevel |
8620 kOSKextLogGeneralFlag,
8621 "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
8622 vm_prelink_stext, vm_prelink_etext);
8623 OSKextLog(/* kext */ NULL,
8624 kOSKextLogErrorLevel |
8625 kOSKextLogGeneralFlag,
8626 "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
8627 vm_prelink_sinfo, vm_prelink_einfo);
8628 OSKextLog(/* kext */ NULL,
8629 kOSKextLogErrorLevel |
8630 kOSKextLogGeneralFlag,
8631 "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
8632 vm_slinkedit, vm_elinkedit);
8633 #endif
8634
8635 for (i = 0; i < count; i++) {
8636 OSKext * thisKext = NULL; // do not release
8637 Boolean includeThis = true;
8638
8639 if (kextInfo) {
8640 kextInfo->release();
8641 kextInfo = NULL;
8642 }
8643 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
8644 if (!thisKext) {
8645 continue;
8646 }
8647
8648 /* Skip current kext if we have a list of bundle IDs and
8649 * it isn't in the list.
8650 */
8651 if (kextIdentifiers) {
8652 const OSString * thisKextID = thisKext->getIdentifier();
8653
8654 includeThis = false;
8655
8656 for (idIndex = 0; idIndex < idCount; idIndex++) {
8657 const OSString * thisRequestID = OSDynamicCast(OSString,
8658 kextIdentifiers->getObject(idIndex));
8659 if (thisKextID->isEqualTo(thisRequestID)) {
8660 includeThis = true;
8661 break;
8662 }
8663 }
8664 }
8665
8666 if (!includeThis) {
8667 continue;
8668 }
8669
8670 kextInfo = thisKext->copyInfo(infoKeys);
8671 if (kextInfo) {
8672 result->setObject(thisKext->getIdentifier(), kextInfo);
8673 }
8674 }
8675
8676 finish:
8677 IORecursiveLockUnlock(sKextLock);
8678
8679 if (kextInfo) kextInfo->release();
8680
8681 return result;
8682 }
8683
8684 /*********************************************************************
8685 * Any info that needs to do allocations must goto finish on alloc
8686 * failure. Info that is just a lookup should just not set the object
8687 * if the info does not exist.
8688 *********************************************************************/
8689 #define _OSKextLoadInfoDictCapacity (12)
8690
8691 OSDictionary *
8692 OSKext::copyInfo(OSArray * infoKeys)
8693 {
8694 OSDictionary * result = NULL;
8695 bool success = false;
8696 OSData * headerData = NULL; // must release
8697 OSData * logData = NULL; // must release
8698 OSNumber * cpuTypeNumber = NULL; // must release
8699 OSNumber * cpuSubtypeNumber = NULL; // must release
8700 OSString * versionString = NULL; // do not release
8701 uint32_t executablePathCStringSize = 0;
8702 char * executablePathCString = NULL; // must release
8703 OSString * executablePathString = NULL; // must release
8704 OSData * uuid = NULL; // must release
8705 OSNumber * scratchNumber = NULL; // must release
8706 OSArray * dependencyLoadTags = NULL; // must release
8707 OSCollectionIterator * metaClassIterator = NULL; // must release
8708 OSArray * metaClassInfo = NULL; // must release
8709 OSDictionary * metaClassDict = NULL; // must release
8710 OSMetaClass * thisMetaClass = NULL; // do not release
8711 OSString * metaClassName = NULL; // must release
8712 OSString * superclassName = NULL; // must release
8713 uint32_t count, i;
8714
8715 result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
8716 if (!result) {
8717 goto finish;
8718 }
8719
8720
8721 /* Empty keys means no keys, but NULL is quicker to check.
8722 */
8723 if (infoKeys && !infoKeys->getCount()) {
8724 infoKeys = NULL;
8725 }
8726
8727 /* Headers, CPU type, and CPU subtype.
8728 */
8729 if (!infoKeys ||
8730 _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey) ||
8731 _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey) ||
8732 _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey) ||
8733 _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey))
8734 {
8735
8736 if (linkedExecutable && !isInterface()) {
8737
8738 kernel_mach_header_t *kext_mach_hdr = (kernel_mach_header_t *)
8739 linkedExecutable->getBytesNoCopy();
8740
8741 #if !SECURE_KERNEL
8742 // do not return macho header info on shipping iOS - 19095897
8743 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey)) {
8744 kernel_mach_header_t * temp_kext_mach_hdr;
8745 struct load_command * lcp;
8746
8747 headerData = OSData::withBytes(kext_mach_hdr,
8748 (u_int) (sizeof(*kext_mach_hdr) + kext_mach_hdr->sizeofcmds));
8749 if (!headerData) {
8750 goto finish;
8751 }
8752
8753 // unslide any vmaddrs we return to userspace - 10726716
8754 temp_kext_mach_hdr = (kernel_mach_header_t *)
8755 headerData->getBytesNoCopy();
8756 if (temp_kext_mach_hdr == NULL) {
8757 goto finish;
8758 }
8759
8760 lcp = (struct load_command *) (temp_kext_mach_hdr + 1);
8761 for (i = 0; i < temp_kext_mach_hdr->ncmds; i++) {
8762 if (lcp->cmd == LC_SEGMENT_KERNEL) {
8763 kernel_segment_command_t * segp;
8764 kernel_section_t * secp;
8765
8766 segp = (kernel_segment_command_t *) lcp;
8767 // 10543468 - if we jettisoned __LINKEDIT clear size info
8768 if (flags.jettisonLinkeditSeg) {
8769 if (strncmp(segp->segname, SEG_LINKEDIT, sizeof(segp->segname)) == 0) {
8770 segp->vmsize = 0;
8771 segp->fileoff = 0;
8772 segp->filesize = 0;
8773 }
8774 }
8775 #if 0
8776 OSKextLog(/* kext */ NULL,
8777 kOSKextLogErrorLevel |
8778 kOSKextLogGeneralFlag,
8779 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
8780 __FUNCTION__, segp->segname, segp->vmaddr,
8781 VM_KERNEL_UNSLIDE(segp->vmaddr),
8782 segp->vmsize, segp->nsects);
8783 if ( (VM_KERNEL_IS_SLID(segp->vmaddr) == false) &&
8784 (VM_KERNEL_IS_KEXT(segp->vmaddr) == false) &&
8785 (VM_KERNEL_IS_PRELINKTEXT(segp->vmaddr) == false) &&
8786 (VM_KERNEL_IS_PRELINKINFO(segp->vmaddr) == false) &&
8787 (VM_KERNEL_IS_KEXT_LINKEDIT(segp->vmaddr) == false) ) {
8788 OSKextLog(/* kext */ NULL,
8789 kOSKextLogErrorLevel |
8790 kOSKextLogGeneralFlag,
8791 "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
8792 __FUNCTION__, segp->vmaddr, vm_kext_base, vm_kext_top);
8793 }
8794 #endif
8795 segp->vmaddr = VM_KERNEL_UNSLIDE(segp->vmaddr);
8796
8797 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
8798 secp->addr = VM_KERNEL_UNSLIDE(secp->addr);
8799 }
8800 }
8801 lcp = (struct load_command *)((caddr_t)lcp + lcp->cmdsize);
8802 }
8803 result->setObject(kOSBundleMachOHeadersKey, headerData);
8804 }
8805 #endif // SECURE_KERNEL
8806
8807 if (_OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
8808 osLogDataHeaderRef *header;
8809 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
8810
8811 void *os_log_data = NULL;
8812 void *cstring_data = NULL;
8813 unsigned long os_log_size = 0;
8814 unsigned long cstring_size = 0;
8815 uint32_t os_log_offset = 0;
8816 uint32_t cstring_offset = 0;
8817 bool res;
8818
8819 os_log_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__os_log", &os_log_size);
8820 os_log_offset = getsectoffsetfromheader(kext_mach_hdr, "__TEXT", "__os_log");
8821 cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__cstring", &cstring_size);
8822 cstring_offset = getsectoffsetfromheader(kext_mach_hdr, "__TEXT", "__cstring");
8823
8824 header = (osLogDataHeaderRef *) headerBytes;
8825 header->version = OS_LOG_HDR_VERSION;
8826 header->sect_count = NUM_OS_LOG_SECTIONS;
8827 header->sections[OS_LOG_SECT_IDX].sect_offset = os_log_offset;
8828 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) os_log_size;
8829 header->sections[CSTRING_SECT_IDX].sect_offset = cstring_offset;
8830 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) cstring_size;
8831
8832
8833 logData = OSData::withBytes(header, (u_int) (sizeof(osLogDataHeaderRef)));
8834 if (!logData) {
8835 goto finish;
8836 }
8837 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
8838 if (!res) {
8839 goto finish;
8840 }
8841 if (os_log_data) {
8842 res = logData->appendBytes(os_log_data, (u_int)header->sections[OS_LOG_SECT_IDX].sect_size);
8843 if (!res) {
8844 goto finish;
8845 }
8846 }
8847 if (cstring_data) {
8848 res = logData->appendBytes(cstring_data, (u_int)header->sections[CSTRING_SECT_IDX].sect_size);
8849 if (!res) {
8850 goto finish;
8851 }
8852 }
8853 result->setObject(kOSBundleLogStringsKey, logData);
8854 }
8855
8856 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey)) {
8857 cpuTypeNumber = OSNumber::withNumber(
8858 (uint64_t) kext_mach_hdr->cputype,
8859 8 * sizeof(kext_mach_hdr->cputype));
8860 if (!cpuTypeNumber) {
8861 goto finish;
8862 }
8863 result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber);
8864 }
8865
8866 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
8867 cpuSubtypeNumber = OSNumber::withNumber(
8868 (uint64_t) kext_mach_hdr->cpusubtype,
8869 8 * sizeof(kext_mach_hdr->cpusubtype));
8870 if (!cpuSubtypeNumber) {
8871 goto finish;
8872 }
8873 result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber);
8874 }
8875 }
8876 }
8877
8878 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
8879 */
8880 result->setObject(kCFBundleIdentifierKey, bundleID);
8881
8882 /* CFBundleVersion.
8883 */
8884 if (!infoKeys || _OSArrayContainsCString(infoKeys, kCFBundleVersionKey)) {
8885 versionString = OSDynamicCast(OSString,
8886 getPropertyForHostArch(kCFBundleVersionKey));
8887 if (versionString) {
8888 result->setObject(kCFBundleVersionKey, versionString);
8889 }
8890 }
8891
8892 /* OSBundleCompatibleVersion.
8893 */
8894 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCompatibleVersionKey)) {
8895 versionString = OSDynamicCast(OSString,
8896 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
8897 if (versionString) {
8898 result->setObject(kOSBundleCompatibleVersionKey, versionString);
8899 }
8900 }
8901
8902 /* Path.
8903 */
8904 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePathKey)) {
8905 if (path) {
8906 result->setObject(kOSBundlePathKey, path);
8907 }
8908 }
8909
8910
8911 /* OSBundleExecutablePath.
8912 */
8913 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecutablePathKey)) {
8914 if (path && executableRelPath) {
8915
8916 uint32_t pathLength = path->getLength(); // gets incremented below
8917
8918 // +1 for slash, +1 for \0
8919 executablePathCStringSize = pathLength + executableRelPath->getLength() + 2;
8920
8921 executablePathCString = (char *)kalloc_tag((executablePathCStringSize) *
8922 sizeof(char), VM_KERN_MEMORY_OSKEXT); // +1 for \0
8923 if (!executablePathCString) {
8924 goto finish;
8925 }
8926 strlcpy(executablePathCString, path->getCStringNoCopy(),
8927 executablePathCStringSize);
8928 executablePathCString[pathLength++] = '/';
8929 executablePathCString[pathLength++] = '\0';
8930 strlcat(executablePathCString, executableRelPath->getCStringNoCopy(),
8931 executablePathCStringSize);
8932
8933 executablePathString = OSString::withCString(executablePathCString);
8934
8935 if (!executablePathString) {
8936 goto finish;
8937 }
8938
8939 result->setObject(kOSBundleExecutablePathKey, executablePathString);
8940 }
8941 }
8942
8943 /* UUID, if the kext has one.
8944 */
8945 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleUUIDKey)) {
8946 uuid = copyUUID();
8947 if (uuid) {
8948 result->setObject(kOSBundleUUIDKey, uuid);
8949 }
8950 }
8951
8952 /*****
8953 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
8954 */
8955 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKernelResourceKey)) {
8956 result->setObject(kOSKernelResourceKey,
8957 isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
8958 }
8959
8960 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleIsInterfaceKey)) {
8961 result->setObject(kOSBundleIsInterfaceKey,
8962 isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
8963 }
8964
8965 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePrelinkedKey)) {
8966 result->setObject(kOSBundlePrelinkedKey,
8967 isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
8968 }
8969
8970 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleStartedKey)) {
8971 result->setObject(kOSBundleStartedKey,
8972 isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
8973 }
8974
8975 /* LoadTag (Index).
8976 */
8977 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadTagKey)) {
8978 scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
8979 /* numBits */ 8 * sizeof(loadTag));
8980 if (!scratchNumber) {
8981 goto finish;
8982 }
8983 result->setObject(kOSBundleLoadTagKey, scratchNumber);
8984 OSSafeReleaseNULL(scratchNumber);
8985 }
8986
8987 /* LoadAddress, LoadSize.
8988 */
8989 if (!infoKeys ||
8990 _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey) ||
8991 _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey) ||
8992 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey) ||
8993 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey) ||
8994 _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey))
8995 {
8996 if (isInterface() || linkedExecutable) {
8997 /* These go to userspace via serialization, so we don't want any doubts
8998 * about their size.
8999 */
9000 uint64_t loadAddress = 0;
9001 uint32_t loadSize = 0;
9002 uint32_t wiredSize = 0;
9003 uint64_t execLoadAddress = 0;
9004 uint32_t execLoadSize = 0;
9005
9006 /* Interfaces always report 0 load address & size.
9007 * Just the way they roll.
9008 *
9009 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
9010 * xxx - shouldn't have one!
9011 */
9012 if (linkedExecutable /* && !isInterface() */) {
9013 kernel_mach_header_t *mh = NULL;
9014 kernel_segment_command_t *seg = NULL;
9015
9016 loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
9017 mh = (kernel_mach_header_t *)loadAddress;
9018 loadAddress = VM_KERNEL_UNSLIDE(loadAddress);
9019 loadSize = linkedExecutable->getLength();
9020
9021 /* Walk through the kext, looking for the first executable
9022 * segment in case we were asked for its size/address.
9023 */
9024 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
9025 if (seg->initprot & VM_PROT_EXECUTE) {
9026 execLoadAddress = VM_KERNEL_UNSLIDE(seg->vmaddr);
9027 execLoadSize = seg->vmsize;
9028 break;
9029 }
9030 }
9031
9032 /* If we have a kmod_info struct, calculated the wired size
9033 * from that. Otherwise it's the full load size.
9034 */
9035 if (kmod_info) {
9036 wiredSize = loadSize - kmod_info->hdr_size;
9037 } else {
9038 wiredSize = loadSize;
9039 }
9040 }
9041
9042 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey)) {
9043 scratchNumber = OSNumber::withNumber(
9044 (unsigned long long)(loadAddress),
9045 /* numBits */ 8 * sizeof(loadAddress));
9046 if (!scratchNumber) {
9047 goto finish;
9048 }
9049 result->setObject(kOSBundleLoadAddressKey, scratchNumber);
9050 OSSafeReleaseNULL(scratchNumber);
9051 }
9052 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey)) {
9053 scratchNumber = OSNumber::withNumber(
9054 (unsigned long long)(execLoadAddress),
9055 /* numBits */ 8 * sizeof(execLoadAddress));
9056 if (!scratchNumber) {
9057 goto finish;
9058 }
9059 result->setObject(kOSBundleExecLoadAddressKey, scratchNumber);
9060 OSSafeReleaseNULL(scratchNumber);
9061 }
9062 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey)) {
9063 scratchNumber = OSNumber::withNumber(
9064 (unsigned long long)(loadSize),
9065 /* numBits */ 8 * sizeof(loadSize));
9066 if (!scratchNumber) {
9067 goto finish;
9068 }
9069 result->setObject(kOSBundleLoadSizeKey, scratchNumber);
9070 OSSafeReleaseNULL(scratchNumber);
9071 }
9072 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey)) {
9073 scratchNumber = OSNumber::withNumber(
9074 (unsigned long long)(execLoadSize),
9075 /* numBits */ 8 * sizeof(execLoadSize));
9076 if (!scratchNumber) {
9077 goto finish;
9078 }
9079 result->setObject(kOSBundleExecLoadSizeKey, scratchNumber);
9080 OSSafeReleaseNULL(scratchNumber);
9081 }
9082 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
9083 scratchNumber = OSNumber::withNumber(
9084 (unsigned long long)(wiredSize),
9085 /* numBits */ 8 * sizeof(wiredSize));
9086 if (!scratchNumber) {
9087 goto finish;
9088 }
9089 result->setObject(kOSBundleWiredSizeKey, scratchNumber);
9090 OSSafeReleaseNULL(scratchNumber);
9091 }
9092 }
9093 }
9094
9095 /* OSBundleDependencies. In descending order for
9096 * easy compatibility with kextstat(8).
9097 */
9098 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleDependenciesKey)) {
9099 if ((count = getNumDependencies())) {
9100 dependencyLoadTags = OSArray::withCapacity(count);
9101 result->setObject(kOSBundleDependenciesKey, dependencyLoadTags);
9102
9103 i = count - 1;
9104 do {
9105 OSKext * dependency = OSDynamicCast(OSKext,
9106 dependencies->getObject(i));
9107
9108 OSSafeReleaseNULL(scratchNumber);
9109
9110 if (!dependency) {
9111 continue;
9112 }
9113 scratchNumber = OSNumber::withNumber(
9114 (unsigned long long)dependency->getLoadTag(),
9115 /* numBits*/ 8 * sizeof(loadTag));
9116 if (!scratchNumber) {
9117 goto finish;
9118 }
9119 dependencyLoadTags->setObject(scratchNumber);
9120 } while (i--);
9121 }
9122 }
9123
9124 OSSafeReleaseNULL(scratchNumber);
9125
9126 /* OSBundleMetaClasses.
9127 */
9128 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleClassesKey)) {
9129 if (metaClasses && metaClasses->getCount()) {
9130 metaClassIterator = OSCollectionIterator::withCollection(metaClasses);
9131 metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
9132 if (!metaClassIterator || !metaClassInfo) {
9133 goto finish;
9134 }
9135 result->setObject(kOSBundleClassesKey, metaClassInfo);
9136
9137 while ( (thisMetaClass = OSDynamicCast(OSMetaClass,
9138 metaClassIterator->getNextObject())) ) {
9139
9140 OSSafeReleaseNULL(metaClassDict);
9141 OSSafeReleaseNULL(scratchNumber);
9142 OSSafeReleaseNULL(metaClassName);
9143 OSSafeReleaseNULL(superclassName);
9144
9145 metaClassDict = OSDictionary::withCapacity(3);
9146 if (!metaClassDict) {
9147 goto finish;
9148 }
9149
9150 metaClassName = OSString::withCString(thisMetaClass->getClassName());
9151 if (thisMetaClass->getSuperClass()) {
9152 superclassName = OSString::withCString(
9153 thisMetaClass->getSuperClass()->getClassName());
9154 }
9155 scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
9156 8 * sizeof(unsigned int));
9157
9158 /* Bail if any of the essentials is missing. The root class lacks a superclass,
9159 * of course.
9160 */
9161 if (!metaClassDict || !metaClassName || !scratchNumber) {
9162 goto finish;
9163 }
9164
9165 metaClassInfo->setObject(metaClassDict);
9166 metaClassDict->setObject(kOSMetaClassNameKey, metaClassName);
9167 if (superclassName) {
9168 metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName);
9169 }
9170 metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber);
9171 }
9172 }
9173 }
9174
9175 /* OSBundleRetainCount.
9176 */
9177 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleRetainCountKey)) {
9178 OSSafeReleaseNULL(scratchNumber);
9179 {
9180 int kextRetainCount = getRetainCount() - 1;
9181 if (isLoaded()) {
9182 kextRetainCount--;
9183 }
9184 scratchNumber = OSNumber::withNumber(
9185 (int)kextRetainCount,
9186 /* numBits*/ 8 * sizeof(int));
9187 if (scratchNumber) {
9188 result->setObject(kOSBundleRetainCountKey, scratchNumber);
9189 }
9190 }
9191 }
9192
9193 success = true;
9194
9195 finish:
9196 OSSafeReleaseNULL(headerData);
9197 OSSafeReleaseNULL(logData);
9198 OSSafeReleaseNULL(cpuTypeNumber);
9199 OSSafeReleaseNULL(cpuSubtypeNumber);
9200 OSSafeReleaseNULL(executablePathString);
9201 if (executablePathCString) kfree(executablePathCString, executablePathCStringSize);
9202 OSSafeReleaseNULL(uuid);
9203 OSSafeReleaseNULL(scratchNumber);
9204 OSSafeReleaseNULL(dependencyLoadTags);
9205 OSSafeReleaseNULL(metaClassIterator);
9206 OSSafeReleaseNULL(metaClassInfo);
9207 OSSafeReleaseNULL(metaClassDict);
9208 OSSafeReleaseNULL(metaClassName);
9209 OSSafeReleaseNULL(superclassName);
9210 if (!success) {
9211 OSSafeReleaseNULL(result);
9212 }
9213 return result;
9214 }
9215
9216 /*********************************************************************
9217 *********************************************************************/
9218 /* static */
9219 OSReturn
9220 OSKext::requestResource(
9221 const char * kextIdentifierCString,
9222 const char * resourceNameCString,
9223 OSKextRequestResourceCallback callback,
9224 void * context,
9225 OSKextRequestTag * requestTagOut)
9226 {
9227 OSReturn result = kOSReturnError;
9228 OSKext * callbackKext = NULL; // must release (looked up)
9229
9230 OSKextRequestTag requestTag = -1;
9231 OSNumber * requestTagNum = NULL; // must release
9232
9233 OSDictionary * requestDict = NULL; // must release
9234 OSString * kextIdentifier = NULL; // must release
9235 OSString * resourceName = NULL; // must release
9236
9237 OSDictionary * callbackRecord = NULL; // must release
9238 OSData * callbackWrapper = NULL; // must release
9239
9240 OSData * contextWrapper = NULL; // must release
9241
9242 IORecursiveLockLock(sKextLock);
9243
9244 if (requestTagOut) {
9245 *requestTagOut = kOSKextRequestTagInvalid;
9246 }
9247
9248 /* If requests to user space are disabled, don't go any further */
9249 if (!sKernelRequestsEnabled) {
9250 OSKextLog(/* kext */ NULL,
9251 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
9252 "Can't request resource %s for %s - requests to user space are disabled.",
9253 resourceNameCString,
9254 kextIdentifierCString);
9255 result = kOSKextReturnDisabled;
9256 goto finish;
9257 }
9258
9259 if (!kextIdentifierCString || !resourceNameCString || !callback) {
9260 result = kOSKextReturnInvalidArgument;
9261 goto finish;
9262 }
9263
9264 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
9265 if (!callbackKext) {
9266 OSKextLog(/* kext */ NULL,
9267 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
9268 "Resource request has bad callback address.");
9269 result = kOSKextReturnInvalidArgument;
9270 goto finish;
9271 }
9272 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
9273 OSKextLog(/* kext */ NULL,
9274 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
9275 "Resource request callback is in a kext that is not started.");
9276 result = kOSKextReturnInvalidArgument;
9277 goto finish;
9278 }
9279
9280 /* Do not allow any new requests to be made on a kext that is unloading.
9281 */
9282 if (callbackKext->flags.stopping) {
9283 result = kOSKextReturnStopping;
9284 goto finish;
9285 }
9286
9287 /* If we're wrapped the next available request tag around to the negative
9288 * numbers, we can't service any more requests.
9289 */
9290 if (sNextRequestTag == kOSKextRequestTagInvalid) {
9291 OSKextLog(/* kext */ NULL,
9292 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
9293 "No more request tags available; restart required.");
9294 result = kOSKextReturnNoResources;
9295 goto finish;
9296 }
9297 requestTag = sNextRequestTag++;
9298
9299 result = _OSKextCreateRequest(kKextRequestPredicateRequestResource,
9300 &requestDict);
9301 if (result != kOSReturnSuccess) {
9302 goto finish;
9303 }
9304
9305 kextIdentifier = OSString::withCString(kextIdentifierCString);
9306 resourceName = OSString::withCString(resourceNameCString);
9307 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
9308 8 * sizeof(requestTag));
9309 if (!kextIdentifier ||
9310 !resourceName ||
9311 !requestTagNum ||
9312 !_OSKextSetRequestArgument(requestDict,
9313 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
9314 !_OSKextSetRequestArgument(requestDict,
9315 kKextRequestArgumentNameKey, resourceName) ||
9316 !_OSKextSetRequestArgument(requestDict,
9317 kKextRequestArgumentRequestTagKey, requestTagNum)) {
9318
9319 result = kOSKextReturnNoMemory;
9320 goto finish;
9321 }
9322
9323 callbackRecord = OSDynamicCast(OSDictionary, requestDict->copyCollection());
9324 if (!callbackRecord) {
9325 result = kOSKextReturnNoMemory;
9326 goto finish;
9327 }
9328 // we validate callback address at call time
9329 callbackWrapper = OSData::withBytes((void *)&callback, sizeof(void *));
9330 if (context) {
9331 contextWrapper = OSData::withBytes((void *)&context, sizeof(void *));
9332 }
9333 if (!callbackWrapper || !_OSKextSetRequestArgument(callbackRecord,
9334 kKextRequestArgumentCallbackKey, callbackWrapper)) {
9335
9336 result = kOSKextReturnNoMemory;
9337 goto finish;
9338 }
9339
9340 if (context) {
9341 if (!contextWrapper || !_OSKextSetRequestArgument(callbackRecord,
9342 kKextRequestArgumentContextKey, contextWrapper)) {
9343
9344 result = kOSKextReturnNoMemory;
9345 goto finish;
9346 }
9347 }
9348
9349 /* Only post the requests after all the other potential failure points
9350 * have been passed.
9351 */
9352 if (!sKernelRequests->setObject(requestDict) ||
9353 !sRequestCallbackRecords->setObject(callbackRecord)) {
9354
9355 result = kOSKextReturnNoMemory;
9356 goto finish;
9357 }
9358
9359 OSKext::pingKextd();
9360
9361 result = kOSReturnSuccess;
9362 if (requestTagOut) {
9363 *requestTagOut = requestTag;
9364 }
9365
9366 finish:
9367
9368 /* If we didn't succeed, yank the request & callback
9369 * from their holding arrays.
9370 */
9371 if (result != kOSReturnSuccess) {
9372 unsigned int index;
9373
9374 index = sKernelRequests->getNextIndexOfObject(requestDict, 0);
9375 if (index != (unsigned int)-1) {
9376 sKernelRequests->removeObject(index);
9377 }
9378 index = sRequestCallbackRecords->getNextIndexOfObject(callbackRecord, 0);
9379 if (index != (unsigned int)-1) {
9380 sRequestCallbackRecords->removeObject(index);
9381 }
9382 }
9383
9384 OSKext::considerUnloads(/* rescheduleOnly? */ true);
9385
9386 IORecursiveLockUnlock(sKextLock);
9387
9388 if (callbackKext) callbackKext->release();
9389 if (requestTagNum) requestTagNum->release();
9390
9391 if (requestDict) requestDict->release();
9392 if (kextIdentifier) kextIdentifier->release();
9393 if (resourceName) resourceName->release();
9394
9395 if (callbackRecord) callbackRecord->release();
9396 if (callbackWrapper) callbackWrapper->release();
9397 if (contextWrapper) contextWrapper->release();
9398
9399 return result;
9400 }
9401
9402 /*********************************************************************
9403 * Assumes sKextLock is held.
9404 *********************************************************************/
9405 /* static */
9406 OSReturn
9407 OSKext::dequeueCallbackForRequestTag(
9408 OSKextRequestTag requestTag,
9409 OSDictionary ** callbackRecordOut)
9410 {
9411 OSReturn result = kOSReturnError;
9412 OSNumber * requestTagNum = NULL; // must release
9413
9414 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
9415 8 * sizeof(requestTag));
9416 if (!requestTagNum) {
9417 goto finish;
9418 }
9419
9420 result = OSKext::dequeueCallbackForRequestTag(requestTagNum,
9421 callbackRecordOut);
9422
9423 finish:
9424 OSSafeReleaseNULL(requestTagNum);
9425
9426 return result;
9427 }
9428
9429 /*********************************************************************
9430 * Assumes sKextLock is held.
9431 *********************************************************************/
9432 /* static */
9433 OSReturn
9434 OSKext::dequeueCallbackForRequestTag(
9435 OSNumber * requestTagNum,
9436 OSDictionary ** callbackRecordOut)
9437 {
9438 OSReturn result = kOSKextReturnInvalidArgument;
9439 OSDictionary * callbackRecord = NULL; // retain if matched!
9440 OSNumber * callbackTagNum = NULL; // do not release
9441 unsigned int count, i;
9442
9443 result = kOSReturnError;
9444 count = sRequestCallbackRecords->getCount();
9445 for (i = 0; i < count; i++) {
9446 callbackRecord = OSDynamicCast(OSDictionary,
9447 sRequestCallbackRecords->getObject(i));
9448 if (!callbackRecord) {
9449 goto finish;
9450 }
9451
9452 /* If we don't find a tag, we basically have a leak here. Maybe
9453 * we should just remove it.
9454 */
9455 callbackTagNum = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(
9456 callbackRecord, kKextRequestArgumentRequestTagKey));
9457 if (!callbackTagNum) {
9458 goto finish;
9459 }
9460
9461 /* We could be even more paranoid and check that all the incoming
9462 * args match what's in the callback record.
9463 */
9464 if (callbackTagNum->isEqualTo(requestTagNum)) {
9465 if (callbackRecordOut) {
9466 *callbackRecordOut = callbackRecord;
9467 callbackRecord->retain();
9468 }
9469 sRequestCallbackRecords->removeObject(i);
9470 result = kOSReturnSuccess;
9471 goto finish;
9472 }
9473 }
9474 result = kOSKextReturnNotFound;
9475
9476 finish:
9477 return result;
9478 }
9479
9480 /*********************************************************************
9481 * Assumes sKextLock is held.
9482 *********************************************************************/
9483 /* static */
9484 OSReturn
9485 OSKext::dispatchResource(OSDictionary * requestDict)
9486 {
9487 OSReturn result = kOSReturnError;
9488 OSDictionary * callbackRecord = NULL; // must release
9489 OSNumber * requestTag = NULL; // do not release
9490 OSNumber * requestResult = NULL; // do not release
9491 OSData * dataObj = NULL; // do not release
9492 uint32_t dataLength = 0;
9493 const void * dataPtr = NULL; // do not free
9494 OSData * callbackWrapper = NULL; // do not release
9495 OSKextRequestResourceCallback callback = NULL;
9496 OSData * contextWrapper = NULL; // do not release
9497 void * context = NULL; // do not free
9498 OSKext * callbackKext = NULL; // must release (looked up)
9499
9500 /* Get the args from the request. Right now we need the tag
9501 * to look up the callback record, and the result for invoking the callback.
9502 */
9503 requestTag = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
9504 kKextRequestArgumentRequestTagKey));
9505 requestResult = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
9506 kKextRequestArgumentResultKey));
9507 if (!requestTag || !requestResult) {
9508 result = kOSKextReturnInvalidArgument;
9509 goto finish;
9510 }
9511
9512 /* Look for a callback record matching this request's tag.
9513 */
9514 result = dequeueCallbackForRequestTag(requestTag, &callbackRecord);
9515 if (result != kOSReturnSuccess) {
9516 goto finish;
9517 }
9518
9519 /*****
9520 * Get the context pointer of the callback record (if there is one).
9521 */
9522 contextWrapper = OSDynamicCast(OSData, _OSKextGetRequestArgument(callbackRecord,
9523 kKextRequestArgumentContextKey));
9524 context = _OSKextExtractPointer(contextWrapper);
9525 if (contextWrapper && !context) {
9526 goto finish;
9527 }
9528
9529 callbackWrapper = OSDynamicCast(OSData,
9530 _OSKextGetRequestArgument(callbackRecord,
9531 kKextRequestArgumentCallbackKey));
9532 callback = (OSKextRequestResourceCallback)
9533 _OSKextExtractPointer(callbackWrapper);
9534 if (!callback) {
9535 goto finish;
9536 }
9537
9538 /* Check for a data obj. We might not have one and that's ok, that means
9539 * we didn't find the requested resource, and we still have to tell the
9540 * caller that via the callback.
9541 */
9542 dataObj = OSDynamicCast(OSData, _OSKextGetRequestArgument(requestDict,
9543 kKextRequestArgumentValueKey));
9544 if (dataObj) {
9545 dataPtr = dataObj->getBytesNoCopy();
9546 dataLength = dataObj->getLength();
9547 }
9548
9549 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
9550 if (!callbackKext) {
9551 OSKextLog(/* kext */ NULL,
9552 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
9553 "Can't invoke callback for resource request; ");
9554 goto finish;
9555 }
9556 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
9557 OSKextLog(/* kext */ NULL,
9558 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
9559 "Can't invoke kext resource callback; ");
9560 goto finish;
9561 }
9562
9563 (void)callback(requestTag->unsigned32BitValue(),
9564 (OSReturn)requestResult->unsigned32BitValue(),
9565 dataPtr, dataLength, context);
9566
9567 result = kOSReturnSuccess;
9568
9569 finish:
9570 if (callbackKext) callbackKext->release();
9571 if (callbackRecord) callbackRecord->release();
9572
9573 return result;
9574 }
9575
9576 /*********************************************************************
9577 *********************************************************************/
9578 /* static */
9579 void
9580 OSKext::invokeRequestCallback(
9581 OSDictionary * callbackRecord,
9582 OSReturn callbackResult)
9583 {
9584 OSString * predicate = _OSKextGetRequestPredicate(callbackRecord);
9585 OSNumber * resultNum = NULL; // must release
9586
9587 if (!predicate) {
9588 goto finish;
9589 }
9590
9591 resultNum = OSNumber::withNumber((long long unsigned int)callbackResult,
9592 8 * sizeof(callbackResult));
9593 if (!resultNum) {
9594 goto finish;
9595 }
9596
9597 /* Insert the result into the callback record and dispatch it as if it
9598 * were the reply coming down from user space.
9599 */
9600 _OSKextSetRequestArgument(callbackRecord, kKextRequestArgumentResultKey,
9601 resultNum);
9602
9603 if (predicate->isEqualTo(kKextRequestPredicateRequestResource)) {
9604 /* This removes the pending callback record.
9605 */
9606 OSKext::dispatchResource(callbackRecord);
9607 }
9608
9609 finish:
9610 if (resultNum) resultNum->release();
9611 return;
9612 }
9613
9614 /*********************************************************************
9615 * Assumes sKextLock is held.
9616 *********************************************************************/
9617 /* static */
9618 OSReturn
9619 OSKext::cancelRequest(
9620 OSKextRequestTag requestTag,
9621 void ** contextOut)
9622 {
9623 OSReturn result = kOSKextReturnNoMemory;
9624 OSDictionary * callbackRecord = NULL; // must release
9625 OSData * contextWrapper = NULL; // do not release
9626
9627 IORecursiveLockLock(sKextLock);
9628 result = OSKext::dequeueCallbackForRequestTag(requestTag,
9629 &callbackRecord);
9630 IORecursiveLockUnlock(sKextLock);
9631
9632 if (result == kOSReturnSuccess && contextOut) {
9633 contextWrapper = OSDynamicCast(OSData,
9634 _OSKextGetRequestArgument(callbackRecord,
9635 kKextRequestArgumentContextKey));
9636 *contextOut = _OSKextExtractPointer(contextWrapper);
9637 }
9638
9639 if (callbackRecord) callbackRecord->release();
9640
9641 return result;
9642 }
9643
9644 /*********************************************************************
9645 * Assumes sKextLock is held.
9646 *********************************************************************/
9647 void
9648 OSKext::invokeOrCancelRequestCallbacks(
9649 OSReturn callbackResult,
9650 bool invokeFlag)
9651 {
9652 unsigned int count, i;
9653
9654 count = sRequestCallbackRecords->getCount();
9655 if (!count) {
9656 goto finish;
9657 }
9658
9659 i = count - 1;
9660 do {
9661 OSDictionary * request = OSDynamicCast(OSDictionary,
9662 sRequestCallbackRecords->getObject(i));
9663
9664 if (!request) {
9665 continue;
9666 }
9667 OSData * callbackWrapper = OSDynamicCast(OSData,
9668 _OSKextGetRequestArgument(request,
9669 kKextRequestArgumentCallbackKey));
9670
9671 if (!callbackWrapper) {
9672 sRequestCallbackRecords->removeObject(i);
9673 continue;
9674 }
9675
9676 vm_address_t callbackAddress = (vm_address_t)
9677 _OSKextExtractPointer(callbackWrapper);
9678
9679 if ((kmod_info->address <= callbackAddress) &&
9680 (callbackAddress < (kmod_info->address + kmod_info->size))) {
9681
9682 if (invokeFlag) {
9683 /* This removes the callback record.
9684 */
9685 invokeRequestCallback(request, callbackResult);
9686 } else {
9687 sRequestCallbackRecords->removeObject(i);
9688 }
9689 }
9690 } while (i--);
9691
9692 finish:
9693 return;
9694 }
9695
9696 /*********************************************************************
9697 * Assumes sKextLock is held.
9698 *********************************************************************/
9699 uint32_t
9700 OSKext::countRequestCallbacks(void)
9701 {
9702 uint32_t result = 0;
9703 unsigned int count, i;
9704
9705 count = sRequestCallbackRecords->getCount();
9706 if (!count) {
9707 goto finish;
9708 }
9709
9710 i = count - 1;
9711 do {
9712 OSDictionary * request = OSDynamicCast(OSDictionary,
9713 sRequestCallbackRecords->getObject(i));
9714
9715 if (!request) {
9716 continue;
9717 }
9718 OSData * callbackWrapper = OSDynamicCast(OSData,
9719 _OSKextGetRequestArgument(request,
9720 kKextRequestArgumentCallbackKey));
9721
9722 if (!callbackWrapper) {
9723 continue;
9724 }
9725
9726 vm_address_t callbackAddress = (vm_address_t)
9727 _OSKextExtractPointer(callbackWrapper);
9728
9729 if ((kmod_info->address <= callbackAddress) &&
9730 (callbackAddress < (kmod_info->address + kmod_info->size))) {
9731
9732 result++;
9733 }
9734 } while (i--);
9735
9736 finish:
9737 return result;
9738 }
9739
9740 /*********************************************************************
9741 *********************************************************************/
9742 static OSReturn _OSKextCreateRequest(
9743 const char * predicate,
9744 OSDictionary ** requestP)
9745 {
9746 OSReturn result = kOSKextReturnNoMemory;
9747 OSDictionary * request = NULL; // must release on error
9748
9749 request = OSDictionary::withCapacity(2);
9750 if (!request) {
9751 goto finish;
9752 }
9753 result = _OSDictionarySetCStringValue(request,
9754 kKextRequestPredicateKey, predicate);
9755 if (result != kOSReturnSuccess) {
9756 goto finish;
9757 }
9758 result = kOSReturnSuccess;
9759
9760 finish:
9761 if (result != kOSReturnSuccess) {
9762 if (request) request->release();
9763 } else {
9764 *requestP = request;
9765 }
9766
9767 return result;
9768 }
9769
9770 /*********************************************************************
9771 *********************************************************************/
9772 static OSString * _OSKextGetRequestPredicate(OSDictionary * requestDict)
9773 {
9774 return OSDynamicCast(OSString,
9775 requestDict->getObject(kKextRequestPredicateKey));
9776 }
9777
9778 /*********************************************************************
9779 *********************************************************************/
9780 static OSObject * _OSKextGetRequestArgument(
9781 OSDictionary * requestDict,
9782 const char * argName)
9783 {
9784 OSDictionary * args = OSDynamicCast(OSDictionary,
9785 requestDict->getObject(kKextRequestArgumentsKey));
9786 if (args) {
9787 return args->getObject(argName);
9788 }
9789 return NULL;
9790 }
9791
9792 /*********************************************************************
9793 *********************************************************************/
9794 static bool _OSKextSetRequestArgument(
9795 OSDictionary * requestDict,
9796 const char * argName,
9797 OSObject * value)
9798 {
9799 OSDictionary * args = OSDynamicCast(OSDictionary,
9800 requestDict->getObject(kKextRequestArgumentsKey));
9801 if (!args) {
9802 args = OSDictionary::withCapacity(2);
9803 if (!args) {
9804 goto finish;
9805 }
9806 requestDict->setObject(kKextRequestArgumentsKey, args);
9807 args->release();
9808 }
9809 if (args) {
9810 return args->setObject(argName, value);
9811 }
9812 finish:
9813 return false;
9814 }
9815
9816 /*********************************************************************
9817 *********************************************************************/
9818 static void * _OSKextExtractPointer(OSData * wrapper)
9819 {
9820 void * result = NULL;
9821 const void * resultPtr = NULL;
9822
9823 if (!wrapper) {
9824 goto finish;
9825 }
9826 resultPtr = wrapper->getBytesNoCopy();
9827 result = *(void **)resultPtr;
9828 finish:
9829 return result;
9830 }
9831
9832 /*********************************************************************
9833 *********************************************************************/
9834 static OSReturn _OSDictionarySetCStringValue(
9835 OSDictionary * dict,
9836 const char * cKey,
9837 const char * cValue)
9838 {
9839 OSReturn result = kOSKextReturnNoMemory;
9840 const OSSymbol * key = NULL; // must release
9841 OSString * value = NULL; // must release
9842
9843 key = OSSymbol::withCString(cKey);
9844 value = OSString::withCString(cValue);
9845 if (!key || !value) {
9846 goto finish;
9847 }
9848 if (dict->setObject(key, value)) {
9849 result = kOSReturnSuccess;
9850 }
9851
9852 finish:
9853 if (key) key->release();
9854 if (value) value->release();
9855
9856 return result;
9857 }
9858
9859 /*********************************************************************
9860 *********************************************************************/
9861 static bool _OSArrayContainsCString(
9862 OSArray * array,
9863 const char * cString)
9864 {
9865 bool result = false;
9866 const OSSymbol * symbol = NULL;
9867 uint32_t count, i;
9868
9869 if (!array || !cString) {
9870 goto finish;
9871 }
9872
9873 symbol = OSSymbol::withCStringNoCopy(cString);
9874 if (!symbol) {
9875 goto finish;
9876 }
9877
9878 count = array->getCount();
9879 for (i = 0; i < count; i++) {
9880 OSObject * thisObject = array->getObject(i);
9881 if (symbol->isEqualTo(thisObject)) {
9882 result = true;
9883 goto finish;
9884 }
9885 }
9886
9887 finish:
9888 if (symbol) symbol->release();
9889 return result;
9890 }
9891
9892 /*********************************************************************
9893 * We really only care about boot / system start up related kexts.
9894 * We return true if we're less than REBUILD_MAX_TIME since start up,
9895 * otherwise return false.
9896 *********************************************************************/
9897 bool _OSKextInPrelinkRebuildWindow(void)
9898 {
9899 static bool outside_the_window = false;
9900 AbsoluteTime my_abstime;
9901 UInt64 my_ns;
9902 SInt32 my_secs;
9903
9904 if (outside_the_window) {
9905 return(false);
9906 }
9907 clock_get_uptime(&my_abstime);
9908 absolutetime_to_nanoseconds(my_abstime, &my_ns);
9909 my_secs = (SInt32)(my_ns / NSEC_PER_SEC);
9910 if (my_secs > REBUILD_MAX_TIME) {
9911 outside_the_window = true;
9912 return(false);
9913 }
9914 return(true);
9915 }
9916
9917 /*********************************************************************
9918 *********************************************************************/
9919 bool _OSKextInUnloadedPrelinkedKexts( const OSSymbol * theBundleID )
9920 {
9921 int unLoadedCount, i;
9922 bool result = false;
9923
9924 IORecursiveLockLock(sKextLock);
9925
9926 if (sUnloadedPrelinkedKexts == NULL) {
9927 goto finish;
9928 }
9929 unLoadedCount = sUnloadedPrelinkedKexts->getCount();
9930 if (unLoadedCount == 0) {
9931 goto finish;
9932 }
9933
9934 for (i = 0; i < unLoadedCount; i++) {
9935 const OSSymbol * myBundleID; // do not release
9936
9937 myBundleID = OSDynamicCast(OSSymbol, sUnloadedPrelinkedKexts->getObject(i));
9938 if (!myBundleID) continue;
9939 if (theBundleID->isEqualTo(myBundleID->getCStringNoCopy())) {
9940 result = true;
9941 break;
9942 }
9943 }
9944 finish:
9945 IORecursiveLockUnlock(sKextLock);
9946 return(result);
9947 }
9948
9949 #if PRAGMA_MARK
9950 #pragma mark Personalities (IOKit Drivers)
9951 #endif
9952 /*********************************************************************
9953 *********************************************************************/
9954 /* static */
9955 OSArray *
9956 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag)
9957 {
9958 OSArray * result = NULL; // returned
9959 OSCollectionIterator * kextIterator = NULL; // must release
9960 OSArray * personalities = NULL; // must release
9961 OSCollectionIterator * personalitiesIterator = NULL; // must release
9962
9963 OSString * kextID = NULL; // do not release
9964 OSKext * theKext = NULL; // do not release
9965
9966 IORecursiveLockLock(sKextLock);
9967
9968 /* Let's conservatively guess that any given kext has around 3
9969 * personalities for now.
9970 */
9971 result = OSArray::withCapacity(sKextsByID->getCount() * 3);
9972 if (!result) {
9973 goto finish;
9974 }
9975
9976 kextIterator = OSCollectionIterator::withCollection(sKextsByID);
9977 if (!kextIterator) {
9978 goto finish;
9979 }
9980
9981 while ((kextID = OSDynamicCast(OSString, kextIterator->getNextObject()))) {
9982 if (personalitiesIterator) {
9983 personalitiesIterator->release();
9984 personalitiesIterator = NULL;
9985 }
9986 if (personalities) {
9987 personalities->release();
9988 personalities = NULL;
9989 }
9990
9991 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextID));
9992 if (!sSafeBoot || !filterSafeBootFlag || theKext->isLoadableInSafeBoot()) {
9993 personalities = theKext->copyPersonalitiesArray();
9994 if (!personalities) {
9995 continue;
9996 }
9997 result->merge(personalities);
9998 } else {
9999 // xxx - check for better place to put this log msg
10000 OSKextLog(theKext,
10001 kOSKextLogWarningLevel |
10002 kOSKextLogLoadFlag,
10003 "Kext %s is not loadable during safe boot; "
10004 "omitting its personalities.",
10005 theKext->getIdentifierCString());
10006 }
10007
10008 }
10009
10010 finish:
10011 IORecursiveLockUnlock(sKextLock);
10012
10013 if (kextIterator) kextIterator->release();
10014 if (personalitiesIterator) personalitiesIterator->release();
10015 if (personalities) personalities->release();
10016
10017 return result;
10018 }
10019
10020 /*********************************************************************
10021 *********************************************************************/
10022 /* static */
10023 void
10024 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching)
10025 {
10026 int numPersonalities = 0;
10027
10028 OSKextLog(/* kext */ NULL,
10029 kOSKextLogStepLevel |
10030 kOSKextLogLoadFlag,
10031 "Sending all eligible registered kexts' personalities "
10032 "to the IOCatalogue %s.",
10033 startMatching ? "and starting matching" : "but not starting matching");
10034
10035 OSArray * personalities = OSKext::copyAllKextPersonalities(
10036 /* filterSafeBootFlag */ true);
10037
10038 if (personalities) {
10039 gIOCatalogue->addDrivers(personalities, startMatching);
10040 numPersonalities = personalities->getCount();
10041 personalities->release();
10042 }
10043
10044 OSKextLog(/* kext */ NULL,
10045 kOSKextLogStepLevel |
10046 kOSKextLogLoadFlag,
10047 "%d kext personalit%s sent to the IOCatalogue; %s.",
10048 numPersonalities, numPersonalities > 0 ? "ies" : "y",
10049 startMatching ? "matching started" : "matching not started");
10050 return;
10051 }
10052
10053 /*********************************************************************
10054 * Do not make a deep copy, just convert the IOKitPersonalities dict
10055 * to an array for sending to the IOCatalogue.
10056 *********************************************************************/
10057 OSArray *
10058 OSKext::copyPersonalitiesArray(void)
10059 {
10060 OSArray * result = NULL;
10061 OSDictionary * personalities = NULL; // do not release
10062 OSCollectionIterator * personalitiesIterator = NULL; // must release
10063
10064 OSString * personalityName = NULL; // do not release
10065 OSString * personalityBundleIdentifier = NULL; // do not release
10066
10067 personalities = OSDynamicCast(OSDictionary,
10068 getPropertyForHostArch(kIOKitPersonalitiesKey));
10069 if (!personalities) {
10070 goto finish;
10071 }
10072
10073 result = OSArray::withCapacity(personalities->getCount());
10074 if (!result) {
10075 goto finish;
10076 }
10077
10078 personalitiesIterator =
10079 OSCollectionIterator::withCollection(personalities);
10080 if (!personalitiesIterator) {
10081 goto finish;
10082 }
10083 while ((personalityName = OSDynamicCast(OSString,
10084 personalitiesIterator->getNextObject()))) {
10085
10086 OSDictionary * personality = OSDynamicCast(OSDictionary,
10087 personalities->getObject(personalityName));
10088
10089 /******
10090 * If the personality doesn't have a CFBundleIdentifier, or if it
10091 * differs from the kext's, insert the kext's ID so we can find it.
10092 * The publisher ID is used to remove personalities from bundles
10093 * correctly.
10094 */
10095 personalityBundleIdentifier = OSDynamicCast(OSString,
10096 personality->getObject(kCFBundleIdentifierKey));
10097
10098 if (!personalityBundleIdentifier) {
10099 personality->setObject(kCFBundleIdentifierKey, bundleID);
10100 } else if (!personalityBundleIdentifier->isEqualTo(bundleID)) {
10101 personality->setObject(kIOPersonalityPublisherKey, bundleID);
10102 }
10103
10104 result->setObject(personality);
10105 }
10106
10107 finish:
10108 if (personalitiesIterator) personalitiesIterator->release();
10109
10110 return result;
10111 }
10112
10113 /*********************************************************************
10114 Might want to change this to a bool return?
10115 *********************************************************************/
10116 OSReturn
10117 OSKext::sendPersonalitiesToCatalog(
10118 bool startMatching,
10119 OSArray * personalityNames)
10120 {
10121 OSReturn result = kOSReturnSuccess;
10122 OSArray * personalitiesToSend = NULL; // must release
10123 OSDictionary * kextPersonalities = NULL; // do not release
10124 int count, i;
10125
10126 if (!sLoadEnabled) {
10127 OSKextLog(this,
10128 kOSKextLogErrorLevel |
10129 kOSKextLogLoadFlag,
10130 "Kext loading is disabled (attempt to start matching for kext %s).",
10131 getIdentifierCString());
10132 result = kOSKextReturnDisabled;
10133 goto finish;
10134 }
10135
10136 if (sSafeBoot && !isLoadableInSafeBoot()) {
10137 OSKextLog(this,
10138 kOSKextLogErrorLevel |
10139 kOSKextLogLoadFlag,
10140 "Kext %s is not loadable during safe boot; "
10141 "not sending personalities to the IOCatalogue.",
10142 getIdentifierCString());
10143 result = kOSKextReturnNotLoadable;
10144 goto finish;
10145 }
10146
10147 if (!personalityNames || !personalityNames->getCount()) {
10148 personalitiesToSend = copyPersonalitiesArray();
10149 } else {
10150 kextPersonalities = OSDynamicCast(OSDictionary,
10151 getPropertyForHostArch(kIOKitPersonalitiesKey));
10152 if (!kextPersonalities || !kextPersonalities->getCount()) {
10153 // not an error
10154 goto finish;
10155 }
10156 personalitiesToSend = OSArray::withCapacity(0);
10157 if (!personalitiesToSend) {
10158 result = kOSKextReturnNoMemory;
10159 goto finish;
10160 }
10161 count = personalityNames->getCount();
10162 for (i = 0; i < count; i++) {
10163 OSString * name = OSDynamicCast(OSString,
10164 personalityNames->getObject(i));
10165 if (!name) {
10166 continue;
10167 }
10168 OSDictionary * personality = OSDynamicCast(OSDictionary,
10169 kextPersonalities->getObject(name));
10170 if (personality) {
10171 personalitiesToSend->setObject(personality);
10172 }
10173 }
10174 }
10175 if (personalitiesToSend) {
10176 unsigned numPersonalities = personalitiesToSend->getCount();
10177 OSKextLog(this,
10178 kOSKextLogStepLevel |
10179 kOSKextLogLoadFlag,
10180 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
10181 getIdentifierCString(),
10182 numPersonalities,
10183 numPersonalities > 1 ? "ies" : "y",
10184 startMatching ? " and starting matching" : " but not starting matching");
10185 gIOCatalogue->addDrivers(personalitiesToSend, startMatching);
10186 }
10187 finish:
10188 if (personalitiesToSend) {
10189 personalitiesToSend->release();
10190 }
10191 return result;
10192 }
10193
10194 /*********************************************************************
10195 * xxx - We should allow removing the kext's declared personalities,
10196 * xxx - even with other bundle identifiers.
10197 *********************************************************************/
10198 void
10199 OSKext::removePersonalitiesFromCatalog(void)
10200 {
10201 OSDictionary * personality = NULL; // do not release
10202
10203 personality = OSDictionary::withCapacity(1);
10204 if (!personality) {
10205 goto finish;
10206 }
10207 personality->setObject(kCFBundleIdentifierKey, getIdentifier());
10208
10209 OSKextLog(this,
10210 kOSKextLogStepLevel |
10211 kOSKextLogLoadFlag,
10212 "Kext %s removing all personalities naming it from the IOCatalogue.",
10213 getIdentifierCString());
10214
10215 /* Have the IOCatalog remove all personalities matching this kext's
10216 * bundle ID and trigger matching anew.
10217 */
10218 gIOCatalogue->removeDrivers(personality, /* startMatching */ true);
10219
10220 finish:
10221 if (personality) personality->release();
10222
10223 return;
10224 }
10225
10226
10227 #if PRAGMA_MARK
10228 #pragma mark Logging
10229 #endif
10230 /*********************************************************************
10231 * Do not call any function that takes sKextLock here!
10232 *********************************************************************/
10233 /* static */
10234 OSKextLogSpec
10235 OSKext::setUserSpaceLogFilter(
10236 OSKextLogSpec newUserLogFilter,
10237 bool captureFlag)
10238 {
10239 OSKextLogSpec result;
10240 bool allocError = false;
10241
10242 /* Do not call any function that takes sKextLoggingLock during
10243 * this critical block. That means do logging after.
10244 */
10245 IOLockLock(sKextLoggingLock);
10246
10247 result = sUserSpaceKextLogFilter;
10248 sUserSpaceKextLogFilter = newUserLogFilter;
10249
10250 if (newUserLogFilter && captureFlag &&
10251 !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
10252
10253 // xxx - do some measurements for a good initial capacity?
10254 sUserSpaceLogSpecArray = OSArray::withCapacity(0);
10255 sUserSpaceLogMessageArray = OSArray::withCapacity(0);
10256
10257 if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
10258 OSSafeReleaseNULL(sUserSpaceLogSpecArray);
10259 OSSafeReleaseNULL(sUserSpaceLogMessageArray);
10260 allocError = true;
10261 }
10262 }
10263
10264 IOLockUnlock(sKextLoggingLock);
10265
10266 /* If the config flag itself is changing, log the state change
10267 * going both ways, before setting up the user-space log arrays,
10268 * so that this is only logged in the kernel.
10269 */
10270 if (result != newUserLogFilter) {
10271 OSKextLog(/* kext */ NULL,
10272 kOSKextLogDebugLevel |
10273 kOSKextLogGeneralFlag,
10274 "User-space log flags changed from 0x%x to 0x%x.",
10275 result, newUserLogFilter);
10276 }
10277 if (allocError) {
10278 OSKextLog(/* kext */ NULL,
10279 kOSKextLogErrorLevel |
10280 kOSKextLogGeneralFlag,
10281 "Failed to allocate user-space log message arrays.");
10282 }
10283
10284 return result;
10285 }
10286
10287 /*********************************************************************
10288 * Do not call any function that takes sKextLock here!
10289 *********************************************************************/
10290 /* static */
10291 OSArray *
10292 OSKext::clearUserSpaceLogFilter(void)
10293 {
10294 OSArray * result = NULL;
10295 OSKextLogSpec oldLogFilter;
10296 OSKextLogSpec newLogFilter = kOSKextLogSilentFilter;
10297
10298 /* Do not call any function that takes sKextLoggingLock during
10299 * this critical block. That means do logging after.
10300 */
10301 IOLockLock(sKextLoggingLock);
10302
10303 result = OSArray::withCapacity(2);
10304 if (result) {
10305 result->setObject(sUserSpaceLogSpecArray);
10306 result->setObject(sUserSpaceLogMessageArray);
10307 }
10308 OSSafeReleaseNULL(sUserSpaceLogSpecArray);
10309 OSSafeReleaseNULL(sUserSpaceLogMessageArray);
10310
10311 oldLogFilter = sUserSpaceKextLogFilter;
10312 sUserSpaceKextLogFilter = newLogFilter;
10313
10314 IOLockUnlock(sKextLoggingLock);
10315
10316 /* If the config flag itself is changing, log the state change
10317 * going both ways, after tearing down the user-space log
10318 * arrays, so this is only logged within the kernel.
10319 */
10320 if (oldLogFilter != newLogFilter) {
10321 OSKextLog(/* kext */ NULL,
10322 kOSKextLogDebugLevel |
10323 kOSKextLogGeneralFlag,
10324 "User-space log flags changed from 0x%x to 0x%x.",
10325 oldLogFilter, newLogFilter);
10326 }
10327
10328 return result;
10329 }
10330
10331
10332 /*********************************************************************
10333 * Do not call any function that takes sKextLock here!
10334 *********************************************************************/
10335 /* static */
10336 OSKextLogSpec
10337 OSKext::getUserSpaceLogFilter(void)
10338 {
10339 OSKextLogSpec result;
10340
10341 IOLockLock(sKextLoggingLock);
10342 result = sUserSpaceKextLogFilter;
10343 IOLockUnlock(sKextLoggingLock);
10344
10345 return result;
10346 }
10347
10348 /*********************************************************************
10349 * This function is called by OSMetaClass during kernel C++ setup.
10350 * Be careful what you access here; assume only OSKext::initialize()
10351 * has been called.
10352 *
10353 * Do not call any function that takes sKextLock here!
10354 *********************************************************************/
10355 #define VTRESET "\033[0m"
10356
10357 #define VTBOLD "\033[1m"
10358 #define VTUNDER "\033[4m"
10359
10360 #define VTRED "\033[31m"
10361 #define VTGREEN "\033[32m"
10362 #define VTYELLOW "\033[33m"
10363 #define VTBLUE "\033[34m"
10364 #define VTMAGENTA "\033[35m"
10365 #define VTCYAN "\033[36m"
10366
10367 inline const char * colorForFlags(OSKextLogSpec flags)
10368 {
10369 OSKextLogSpec logLevel = flags & kOSKextLogLevelMask;
10370
10371 switch (logLevel) {
10372 case kOSKextLogErrorLevel:
10373 return VTRED VTBOLD;
10374 case kOSKextLogWarningLevel:
10375 return VTRED;
10376 case kOSKextLogBasicLevel:
10377 return VTYELLOW VTUNDER;
10378 case kOSKextLogProgressLevel:
10379 return VTYELLOW;
10380 case kOSKextLogStepLevel:
10381 return VTGREEN;
10382 case kOSKextLogDetailLevel:
10383 return VTCYAN;
10384 case kOSKextLogDebugLevel:
10385 return VTMAGENTA;
10386 default:
10387 return ""; // white
10388 }
10389 }
10390
10391 inline bool logSpecMatch(
10392 OSKextLogSpec msgLogSpec,
10393 OSKextLogSpec logFilter)
10394 {
10395 OSKextLogSpec filterKextGlobal = logFilter & kOSKextLogKextOrGlobalMask;
10396 OSKextLogSpec filterLevel = logFilter & kOSKextLogLevelMask;
10397 OSKextLogSpec filterFlags = logFilter & kOSKextLogFlagsMask;
10398
10399 OSKextLogSpec msgKextGlobal = msgLogSpec & kOSKextLogKextOrGlobalMask;
10400 OSKextLogSpec msgLevel = msgLogSpec & kOSKextLogLevelMask;
10401 OSKextLogSpec msgFlags = msgLogSpec & kOSKextLogFlagsMask;
10402
10403 /* Explicit messages always get logged.
10404 */
10405 if (msgLevel == kOSKextLogExplicitLevel) {
10406 return true;
10407 }
10408
10409 /* Warnings and errors are logged regardless of the flags.
10410 */
10411 if (msgLevel <= kOSKextLogBasicLevel && (msgLevel <= filterLevel)) {
10412 return true;
10413 }
10414
10415 /* A verbose message that isn't for a logging-enabled kext and isn't global
10416 * does *not* get logged.
10417 */
10418 if (!msgKextGlobal && !filterKextGlobal) {
10419 return false;
10420 }
10421
10422 /* Warnings and errors are logged regardless of the flags.
10423 * All other messages must fit the flags and
10424 * have a level at or below the filter.
10425 *
10426 */
10427 if ((msgFlags & filterFlags) && (msgLevel <= filterLevel)) {
10428 return true;
10429 }
10430 return false;
10431 }
10432
10433 extern "C" {
10434
10435 void
10436 OSKextLog(
10437 OSKext * aKext,
10438 OSKextLogSpec msgLogSpec,
10439 const char * format, ...)
10440 {
10441 va_list argList;
10442
10443 va_start(argList, format);
10444 OSKextVLog(aKext, msgLogSpec, format, argList);
10445 va_end(argList);
10446 }
10447
10448 void
10449 OSKextVLog(
10450 OSKext * aKext,
10451 OSKextLogSpec msgLogSpec,
10452 const char * format,
10453 va_list srcArgList)
10454 {
10455 extern int disableConsoleOutput;
10456
10457 bool logForKernel = false;
10458 bool logForUser = false;
10459 va_list argList;
10460 char stackBuffer[120];
10461 uint32_t length = 0;
10462 char * allocBuffer = NULL; // must kfree
10463 OSNumber * logSpecNum = NULL; // must release
10464 OSString * logString = NULL; // must release
10465 char * buffer = stackBuffer; // do not free
10466
10467 IOLockLock(sKextLoggingLock);
10468
10469 /* Set the kext/global bit in the message spec if we have no
10470 * kext or if the kext requests logging.
10471 */
10472 if (!aKext || aKext->flags.loggingEnabled) {
10473 msgLogSpec = msgLogSpec | kOSKextLogKextOrGlobalMask;
10474 }
10475
10476 logForKernel = logSpecMatch(msgLogSpec, sKernelLogFilter);
10477 if (sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
10478 logForUser = logSpecMatch(msgLogSpec, sUserSpaceKextLogFilter);
10479 }
10480
10481 if (! (logForKernel || logForUser) ) {
10482 goto finish;
10483 }
10484
10485 /* No goto from here until past va_end()!
10486 */
10487 va_copy(argList, srcArgList);
10488 length = vsnprintf(stackBuffer, sizeof(stackBuffer), format, argList);
10489 va_end(argList);
10490
10491 if (length + 1 >= sizeof(stackBuffer)) {
10492 allocBuffer = (char *)kalloc_tag((length + 1) * sizeof(char), VM_KERN_MEMORY_OSKEXT);
10493 if (!allocBuffer) {
10494 goto finish;
10495 }
10496
10497 /* No goto from here until past va_end()!
10498 */
10499 va_copy(argList, srcArgList);
10500 vsnprintf(allocBuffer, length + 1, format, argList);
10501 va_end(argList);
10502
10503 buffer = allocBuffer;
10504 }
10505
10506 /* If user space wants the log message, queue it up.
10507 */
10508 if (logForUser && sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
10509 logSpecNum = OSNumber::withNumber(msgLogSpec, 8 * sizeof(msgLogSpec));
10510 logString = OSString::withCString(buffer);
10511 if (logSpecNum && logString) {
10512 sUserSpaceLogSpecArray->setObject(logSpecNum);
10513 sUserSpaceLogMessageArray->setObject(logString);
10514 }
10515 }
10516
10517 /* Always log messages from the kernel according to the kernel's
10518 * log flags.
10519 */
10520 if (logForKernel) {
10521
10522 /* If we are in console mode and have a custom log filter,
10523 * colorize the log message.
10524 */
10525 if (!disableConsoleOutput && sBootArgLogFilterFound) {
10526 const char * color = ""; // do not free
10527 color = colorForFlags(msgLogSpec);
10528 printf("%s%s%s\n", colorForFlags(msgLogSpec),
10529 buffer, color[0] ? VTRESET : "");
10530 } else {
10531 printf("%s\n", buffer);
10532 }
10533 }
10534
10535 finish:
10536 IOLockUnlock(sKextLoggingLock);
10537
10538 if (allocBuffer) {
10539 kfree(allocBuffer, (length + 1) * sizeof(char));
10540 }
10541 OSSafeReleaseNULL(logString);
10542 OSSafeReleaseNULL(logSpecNum);
10543 return;
10544 }
10545
10546 #if KASLR_IOREG_DEBUG
10547
10548 #define IOLOG_INDENT( the_indention ) \
10549 { \
10550 int i; \
10551 for ( i = 0; i < (the_indention); i++ ) { \
10552 IOLog(" "); \
10553 } \
10554 }
10555
10556 extern vm_offset_t vm_kernel_stext;
10557 extern vm_offset_t vm_kernel_etext;
10558 extern mach_vm_offset_t kext_alloc_base;
10559 extern mach_vm_offset_t kext_alloc_max;
10560
10561 bool ScanForAddrInObject(OSObject * theObject,
10562 int indent );
10563
10564 bool ScanForAddrInObject(OSObject * theObject,
10565 int indent)
10566 {
10567 const OSMetaClass * myTypeID;
10568 OSCollectionIterator * myIter;
10569 OSSymbol * myKey;
10570 OSObject * myValue;
10571 bool myResult = false;
10572
10573 if ( theObject == NULL ) {
10574 IOLog("%s: theObject is NULL \n",
10575 __FUNCTION__);
10576 return myResult;
10577 }
10578
10579 myTypeID = OSTypeIDInst(theObject);
10580
10581 if ( myTypeID == OSTypeID(OSDictionary) ) {
10582 OSDictionary * myDictionary;
10583
10584 myDictionary = OSDynamicCast(OSDictionary, theObject);
10585 myIter = OSCollectionIterator::withCollection( myDictionary );
10586 if ( myIter == NULL )
10587 return myResult;
10588 myIter->reset();
10589
10590 while ( (myKey = OSDynamicCast(OSSymbol, myIter->getNextObject())) ) {
10591 bool myTempResult;
10592
10593 myValue = myDictionary->getObject(myKey);
10594 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
10595 if (myTempResult) {
10596 // if we ever get a true result return true
10597 myResult = true;
10598 IOLOG_INDENT(indent);
10599 IOLog("OSDictionary key \"%s\" \n", myKey->getCStringNoCopy());
10600 }
10601 }
10602 myIter->release();
10603 }
10604 else if ( myTypeID == OSTypeID(OSArray) ) {
10605 OSArray * myArray;
10606
10607 myArray = OSDynamicCast(OSArray, theObject);
10608 myIter = OSCollectionIterator::withCollection(myArray);
10609 if ( myIter == NULL )
10610 return myResult;
10611 myIter->reset();
10612
10613 while ( (myValue = myIter->getNextObject()) ) {
10614 bool myTempResult;
10615 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
10616 if (myTempResult) {
10617 // if we ever get a true result return true
10618 myResult = true;
10619 IOLOG_INDENT(indent);
10620 IOLog("OSArray: \n");
10621 }
10622 }
10623 myIter->release();
10624 }
10625 else if ( myTypeID == OSTypeID(OSString) || myTypeID == OSTypeID(OSSymbol) ) {
10626
10627 // should we look for addresses in strings?
10628 }
10629 else if ( myTypeID == OSTypeID(OSData) ) {
10630
10631 void * * myPtrPtr;
10632 unsigned int myLen;
10633 OSData * myDataObj;
10634
10635 myDataObj = OSDynamicCast(OSData, theObject);
10636 myPtrPtr = (void * *) myDataObj->getBytesNoCopy();
10637 myLen = myDataObj->getLength();
10638
10639 if (myPtrPtr && myLen && myLen > 7) {
10640 int i;
10641 int myPtrCount = (myLen / sizeof(void *));
10642
10643 for (i = 0; i < myPtrCount; i++) {
10644 UInt64 numberValue = (UInt64) *(myPtrPtr);
10645
10646 if ( kext_alloc_max != 0 &&
10647 numberValue >= kext_alloc_base &&
10648 numberValue < kext_alloc_max ) {
10649
10650 OSKext * myKext = NULL; // must release (looked up)
10651 // IOLog("found OSData %p in kext map %p to %p \n",
10652 // *(myPtrPtr),
10653 // (void *) kext_alloc_base,
10654 // (void *) kext_alloc_max);
10655
10656 myKext = OSKext::lookupKextWithAddress( (vm_address_t) *(myPtrPtr) );
10657 if (myKext) {
10658 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
10659 *(myPtrPtr),
10660 myKext->getIdentifierCString());
10661 myKext->release();
10662 }
10663 myResult = true;
10664 }
10665 if ( vm_kernel_etext != 0 &&
10666 numberValue >= vm_kernel_stext &&
10667 numberValue < vm_kernel_etext ) {
10668 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
10669 *(myPtrPtr),
10670 (void *) vm_kernel_stext,
10671 (void *) vm_kernel_etext);
10672 myResult = true;
10673 }
10674 myPtrPtr++;
10675 }
10676 }
10677 }
10678 else if ( myTypeID == OSTypeID(OSBoolean) ) {
10679
10680 // do nothing here...
10681 }
10682 else if ( myTypeID == OSTypeID(OSNumber) ) {
10683
10684 OSNumber * number = OSDynamicCast(OSNumber, theObject);
10685
10686 UInt64 numberValue = number->unsigned64BitValue();
10687
10688 if ( kext_alloc_max != 0 &&
10689 numberValue >= kext_alloc_base &&
10690 numberValue < kext_alloc_max ) {
10691
10692 OSKext * myKext = NULL; // must release (looked up)
10693 IOLog("found OSNumber in kext map %p to %p \n",
10694 (void *) kext_alloc_base,
10695 (void *) kext_alloc_max);
10696 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
10697
10698 myKext = OSKext::lookupKextWithAddress( (vm_address_t) numberValue );
10699 if (myKext) {
10700 IOLog("found in kext \"%s\" \n",
10701 myKext->getIdentifierCString());
10702 myKext->release();
10703 }
10704
10705 myResult = true;
10706 }
10707 if ( vm_kernel_etext != 0 &&
10708 numberValue >= vm_kernel_stext &&
10709 numberValue < vm_kernel_etext ) {
10710 IOLog("found OSNumber in kernel text segment %p to %p \n",
10711 (void *) vm_kernel_stext,
10712 (void *) vm_kernel_etext);
10713 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
10714 myResult = true;
10715 }
10716 }
10717 #if 0
10718 else {
10719 const OSMetaClass* myMetaClass = NULL;
10720
10721 myMetaClass = theObject->getMetaClass();
10722 if ( myMetaClass ) {
10723 IOLog("class %s \n", myMetaClass->getClassName() );
10724 }
10725 else {
10726 IOLog("Unknown object \n" );
10727 }
10728 }
10729 #endif
10730
10731 return myResult;
10732 }
10733 #endif // KASLR_KEXT_DEBUG
10734
10735 }; /* extern "C" */
10736
10737 #if PRAGMA_MARK
10738 #pragma mark Backtrace Dump & kmod_get_info() support
10739 #endif
10740 /*********************************************************************
10741 * This function must be safe to call in panic context.
10742 *********************************************************************/
10743 /* static */
10744 void
10745 OSKext::printKextsInBacktrace(
10746 vm_offset_t * addr,
10747 unsigned int cnt,
10748 int (* printf_func)(const char *fmt, ...),
10749 bool lockFlag,
10750 bool doUnslide)
10751 {
10752 addr64_t summary_page = 0;
10753 addr64_t last_summary_page = 0;
10754 bool found_kmod = false;
10755 u_int i = 0;
10756
10757 if (lockFlag) {
10758 if (!sKextSummariesLock) return;
10759 IOLockLock(sKextSummariesLock);
10760 }
10761
10762 if (!gLoadedKextSummaries) {
10763 (*printf_func)(" can't perform kext scan: no kext summary");
10764 goto finish;
10765 }
10766
10767 summary_page = trunc_page((addr64_t)(uintptr_t)gLoadedKextSummaries);
10768 last_summary_page = round_page(summary_page + sLoadedKextSummariesAllocSize);
10769 for (; summary_page < last_summary_page; summary_page += PAGE_SIZE) {
10770 if (pmap_find_phys(kernel_pmap, summary_page) == 0) {
10771 (*printf_func)(" can't perform kext scan: "
10772 "missing kext summary page %p", summary_page);
10773 goto finish;
10774 }
10775 }
10776
10777 for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
10778 OSKextLoadedKextSummary * summary;
10779
10780 summary = gLoadedKextSummaries->summaries + i;
10781 if (!summary->address) {
10782 continue;
10783 }
10784
10785 if (!summaryIsInBacktrace(summary, addr, cnt)) {
10786 continue;
10787 }
10788
10789 if (!found_kmod) {
10790 (*printf_func)(" Kernel Extensions in backtrace:\n");
10791 found_kmod = true;
10792 }
10793
10794 printSummary(summary, printf_func, doUnslide);
10795 }
10796
10797 finish:
10798 if (lockFlag) {
10799 IOLockUnlock(sKextSummariesLock);
10800 }
10801
10802 return;
10803 }
10804
10805 /*********************************************************************
10806 * This function must be safe to call in panic context.
10807 *********************************************************************/
10808 /* static */
10809 boolean_t
10810 OSKext::summaryIsInBacktrace(
10811 OSKextLoadedKextSummary * summary,
10812 vm_offset_t * addr,
10813 unsigned int cnt)
10814 {
10815 u_int i = 0;
10816
10817 for (i = 0; i < cnt; i++) {
10818 vm_offset_t kscan_addr = addr[i];
10819 if ((kscan_addr >= summary->address) &&
10820 (kscan_addr < (summary->address + summary->size)))
10821 {
10822 return TRUE;
10823 }
10824 }
10825
10826 return FALSE;
10827 }
10828
10829 /* static */
10830 void *
10831 OSKext::kextForAddress(
10832 const void * addr)
10833 {
10834 void *image = NULL;
10835 u_int i;
10836
10837 #if !VM_MAPPED_KEXTS
10838 kernel_mach_header_t *mh = NULL;
10839 kernel_segment_command_t *seg = NULL;
10840 #endif
10841
10842 if (((vm_offset_t)(uintptr_t)addr >= vm_kernel_stext) &&
10843 ((vm_offset_t)(uintptr_t)addr < vm_kernel_etext)) {
10844 return (void *)&_mh_execute_header;
10845 }
10846
10847 if (!sKextSummariesLock) return image;
10848 IOLockLock(sKextSummariesLock);
10849
10850 if (!gLoadedKextSummaries) {
10851 goto finish;
10852 }
10853
10854 for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
10855 OSKextLoadedKextSummary * summary;
10856
10857 summary = gLoadedKextSummaries->summaries + i;
10858 if (!summary->address) {
10859 continue;
10860 }
10861
10862 #if !VM_MAPPED_KEXTS
10863 mh = (kernel_mach_header_t *)summary->address;
10864
10865 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
10866 if (((uint64_t)addr >= seg->vmaddr) &&
10867 ((uint64_t)addr < (seg->vmaddr + seg->vmsize))) {
10868 image = (void *)summary->address;
10869 break;
10870 }
10871 }
10872
10873 if (image) {
10874 break;
10875 }
10876 #else
10877 /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
10878 * support split kexts, but we also may unmap the kexts, which can
10879 * race with the above codepath (see OSKext::unload). As such,
10880 * use a simple range lookup if we are using VM_MAPPED_KEXTS.
10881 */
10882 if (((uint64_t)(uintptr_t)addr >= summary->address) &&
10883 ((uint64_t)(uintptr_t)addr < (summary->address + summary->size)))
10884 {
10885 image = (void *)(uintptr_t)summary->address;
10886 break;
10887 }
10888 #endif
10889 }
10890
10891 finish:
10892 IOLockUnlock(sKextSummariesLock);
10893
10894 return image;
10895 }
10896
10897 /*********************************************************************
10898 * scan list of loaded kext summaries looking for a load address match and if
10899 * found return the UUID C string. If not found then set empty string.
10900 *********************************************************************/
10901 static void findSummaryUUID(
10902 uint32_t tag_ID,
10903 uuid_string_t uuid);
10904
10905 static void findSummaryUUID(
10906 uint32_t tag_ID,
10907 uuid_string_t uuid)
10908 {
10909 u_int i;
10910
10911 uuid[0] = 0x00; // default to no UUID
10912
10913 for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
10914 OSKextLoadedKextSummary * summary;
10915
10916 summary = gLoadedKextSummaries->summaries + i;
10917
10918 if (summary->loadTag == tag_ID) {
10919 (void) uuid_unparse(summary->uuid, uuid);
10920 break;
10921 }
10922 }
10923 return;
10924 }
10925
10926 /*********************************************************************
10927 * This function must be safe to call in panic context.
10928 *********************************************************************/
10929 void OSKext::printSummary(
10930 OSKextLoadedKextSummary * summary,
10931 int (* printf_func)(const char *fmt, ...),
10932 bool doUnslide)
10933 {
10934 kmod_reference_t * kmod_ref = NULL;
10935 uuid_string_t uuid;
10936 char version[kOSKextVersionMaxLength];
10937 uint64_t tmpAddr;
10938
10939 if (!OSKextVersionGetString(summary->version, version, sizeof(version))) {
10940 strlcpy(version, "unknown version", sizeof(version));
10941 }
10942 (void) uuid_unparse(summary->uuid, uuid);
10943
10944 if (doUnslide) {
10945 tmpAddr = VM_KERNEL_UNSLIDE(summary->address);
10946 }
10947 else {
10948 tmpAddr = summary->address;
10949 }
10950 (*printf_func)(" %s(%s)[%s]@0x%llx->0x%llx\n",
10951 summary->name, version, uuid,
10952 tmpAddr, tmpAddr + summary->size - 1);
10953
10954 /* print dependency info */
10955 for (kmod_ref = (kmod_reference_t *) summary->reference_list;
10956 kmod_ref;
10957 kmod_ref = kmod_ref->next) {
10958 kmod_info_t * rinfo;
10959
10960 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_ref)) == 0) {
10961 (*printf_func)(" kmod dependency scan stopped "
10962 "due to missing dependency page: %p\n",
10963 doUnslide ? (void *)VM_KERNEL_UNSLIDE(kmod_ref) : kmod_ref);
10964 break;
10965 }
10966 rinfo = kmod_ref->info;
10967
10968 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
10969 (*printf_func)(" kmod dependency scan stopped "
10970 "due to missing kmod page: %p\n",
10971 doUnslide ? (void *)VM_KERNEL_UNSLIDE(rinfo) : rinfo);
10972 break;
10973 }
10974
10975 if (!rinfo->address) {
10976 continue; // skip fake entries for built-ins
10977 }
10978
10979 /* locate UUID in gLoadedKextSummaries */
10980 findSummaryUUID(rinfo->id, uuid);
10981
10982 if (doUnslide) {
10983 tmpAddr = VM_KERNEL_UNSLIDE(rinfo->address);
10984 }
10985 else {
10986 tmpAddr = rinfo->address;
10987 }
10988 (*printf_func)(" dependency: %s(%s)[%s]@%p\n",
10989 rinfo->name, rinfo->version, uuid, tmpAddr);
10990 }
10991 return;
10992 }
10993
10994
10995 /*******************************************************************************
10996 * substitute() looks at an input string (a pointer within a larger buffer)
10997 * for a match to a substring, and on match it writes the marker & substitution
10998 * character to an output string, updating the scan (from) and
10999 * output (to) indexes as appropriate.
11000 *******************************************************************************/
11001 static int substitute(
11002 const char * scan_string,
11003 char * string_out,
11004 uint32_t * to_index,
11005 uint32_t * from_index,
11006 const char * substring,
11007 char marker,
11008 char substitution);
11009
11010 /* string_out must be at least KMOD_MAX_NAME bytes.
11011 */
11012 static int
11013 substitute(
11014 const char * scan_string,
11015 char * string_out,
11016 uint32_t * to_index,
11017 uint32_t * from_index,
11018 const char * substring,
11019 char marker,
11020 char substitution)
11021 {
11022 uint32_t substring_length = strnlen(substring, KMOD_MAX_NAME - 1);
11023
11024 /* On a substring match, append the marker (if there is one) and then
11025 * the substitution character, updating the output (to) index accordingly.
11026 * Then update the input (from) length by the length of the substring
11027 * that got replaced.
11028 */
11029 if (!strncmp(scan_string, substring, substring_length)) {
11030 if (marker) {
11031 string_out[(*to_index)++] = marker;
11032 }
11033 string_out[(*to_index)++] = substitution;
11034 (*from_index) += substring_length;
11035 return 1;
11036 }
11037 return 0;
11038 }
11039
11040 /*******************************************************************************
11041 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
11042 * KMOD_MAX_NAME characters and performs various substitutions of common
11043 * prefixes & substrings as defined by tables in kext_panic_report.h.
11044 *******************************************************************************/
11045 static void compactIdentifier(
11046 const char * identifier,
11047 char * identifier_out,
11048 char ** identifier_out_end);
11049
11050 static void
11051 compactIdentifier(
11052 const char * identifier,
11053 char * identifier_out,
11054 char ** identifier_out_end)
11055 {
11056 uint32_t from_index, to_index;
11057 uint32_t scan_from_index = 0;
11058 uint32_t scan_to_index = 0;
11059 subs_entry_t * subs_entry = NULL;
11060 int did_sub = 0;
11061
11062 from_index = to_index = 0;
11063 identifier_out[0] = '\0';
11064
11065 /* Replace certain identifier prefixes with shorter @+character sequences.
11066 * Check the return value of substitute() so we only replace the prefix.
11067 */
11068 for (subs_entry = &kext_identifier_prefix_subs[0];
11069 subs_entry->substring && !did_sub;
11070 subs_entry++) {
11071
11072 did_sub = substitute(identifier, identifier_out,
11073 &scan_to_index, &scan_from_index,
11074 subs_entry->substring, /* marker */ '\0', subs_entry->substitute);
11075 }
11076 did_sub = 0;
11077
11078 /* Now scan through the identifier looking for the common substrings
11079 * and replacing them with shorter !+character sequences via substitute().
11080 */
11081 for (/* see above */;
11082 scan_from_index < KMOD_MAX_NAME - 1 && identifier[scan_from_index];
11083 /* see loop */) {
11084
11085 const char * scan_string = &identifier[scan_from_index];
11086
11087 did_sub = 0;
11088
11089 if (scan_from_index) {
11090 for (subs_entry = &kext_identifier_substring_subs[0];
11091 subs_entry->substring && !did_sub;
11092 subs_entry++) {
11093
11094 did_sub = substitute(scan_string, identifier_out,
11095 &scan_to_index, &scan_from_index,
11096 subs_entry->substring, '!', subs_entry->substitute);
11097 }
11098 }
11099
11100 /* If we didn't substitute, copy the input character to the output.
11101 */
11102 if (!did_sub) {
11103 identifier_out[scan_to_index++] = identifier[scan_from_index++];
11104 }
11105 }
11106
11107 identifier_out[scan_to_index] = '\0';
11108 if (identifier_out_end) {
11109 *identifier_out_end = &identifier_out[scan_to_index];
11110 }
11111
11112 return;
11113 }
11114
11115 /*******************************************************************************
11116 * assemble_identifier_and_version() adds to a string buffer a compacted
11117 * bundle identifier followed by a version string.
11118 *******************************************************************************/
11119
11120 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
11121 */
11122 static int assemble_identifier_and_version(
11123 kmod_info_t * kmod_info,
11124 char * identPlusVers,
11125 int bufSize);
11126
11127 static int
11128 assemble_identifier_and_version(
11129 kmod_info_t * kmod_info,
11130 char * identPlusVers,
11131 int bufSize)
11132 {
11133 int result = 0;
11134
11135 compactIdentifier(kmod_info->name, identPlusVers, NULL);
11136 result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
11137 identPlusVers[result++] = '\t'; // increment for real char
11138 identPlusVers[result] = '\0'; // don't increment for nul char
11139 result = strlcat(identPlusVers, kmod_info->version, bufSize);
11140 if (result >= bufSize) {
11141 identPlusVers[bufSize - 1] = '\0';
11142 result = bufSize - 1;
11143 }
11144
11145 return result;
11146 }
11147
11148 /*******************************************************************************
11149 * Assumes sKextLock is held.
11150 *******************************************************************************/
11151 /* static */
11152 int
11153 OSKext::saveLoadedKextPanicListTyped(
11154 const char * prefix,
11155 int invertFlag,
11156 int libsFlag,
11157 char * paniclist,
11158 uint32_t list_size)
11159 {
11160 int result = -1;
11161 unsigned int count, i;
11162
11163 count = sLoadedKexts->getCount();
11164 if (!count) {
11165 goto finish;
11166 }
11167
11168 i = count - 1;
11169 do {
11170 OSObject * rawKext = sLoadedKexts->getObject(i);
11171 OSKext * theKext = OSDynamicCast(OSKext, rawKext);
11172 int match;
11173 uint32_t identPlusVersLength;
11174 uint32_t tempLen;
11175 char identPlusVers[2*KMOD_MAX_NAME];
11176
11177 if (!rawKext) {
11178 printf("OSKext::saveLoadedKextPanicListTyped - "
11179 "NULL kext in loaded kext list; continuing\n");
11180 continue;
11181 }
11182
11183 if (!theKext) {
11184 printf("OSKext::saveLoadedKextPanicListTyped - "
11185 "Kext type cast failed in loaded kext list; continuing\n");
11186 continue;
11187 }
11188
11189 /* Skip all built-in kexts.
11190 */
11191 if (theKext->isKernelComponent()) {
11192 continue;
11193 }
11194
11195 kmod_info_t * kmod_info = theKext->kmod_info;
11196
11197 /* Filter for kmod name (bundle identifier).
11198 */
11199 match = !strncmp(kmod_info->name, prefix, strnlen(prefix, KMOD_MAX_NAME));
11200 if ((match && invertFlag) || (!match && !invertFlag)) {
11201 continue;
11202 }
11203
11204 /* Filter for libraries (kexts that have a compatible version).
11205 */
11206 if ((libsFlag == 0 && theKext->getCompatibleVersion() > 1) ||
11207 (libsFlag == 1 && theKext->getCompatibleVersion() < 1)) {
11208
11209 continue;
11210 }
11211
11212 if (!kmod_info ||
11213 !pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_info))) {
11214
11215 printf("kext scan stopped due to missing kmod_info page: %p\n",
11216 kmod_info);
11217 goto finish;
11218 }
11219
11220 identPlusVersLength = assemble_identifier_and_version(kmod_info,
11221 identPlusVers,
11222 sizeof(identPlusVers));
11223 if (!identPlusVersLength) {
11224 printf("error saving loaded kext info\n");
11225 goto finish;
11226 }
11227
11228 /* make sure everything fits and we null terminate.
11229 */
11230 tempLen = strlcat(paniclist, identPlusVers, list_size);
11231 if (tempLen >= list_size) {
11232 // panic list is full, keep it and null terminate
11233 paniclist[list_size - 1] = 0x00;
11234 result = 0;
11235 goto finish;
11236 }
11237 tempLen = strlcat(paniclist, "\n", list_size);
11238 if (tempLen >= list_size) {
11239 // panic list is full, keep it and null terminate
11240 paniclist[list_size - 1] = 0x00;
11241 result = 0;
11242 goto finish;
11243 }
11244 } while (i--);
11245
11246 result = 0;
11247 finish:
11248
11249 return result;
11250 }
11251
11252 /*********************************************************************
11253 *********************************************************************/
11254 /* static */
11255 void
11256 OSKext::saveLoadedKextPanicList(void)
11257 {
11258 char * newlist = NULL;
11259 uint32_t newlist_size = 0;
11260
11261 newlist_size = KEXT_PANICLIST_SIZE;
11262 newlist = (char *)kalloc_tag(newlist_size, VM_KERN_MEMORY_OSKEXT);
11263
11264 if (!newlist) {
11265 OSKextLog(/* kext */ NULL,
11266 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
11267 "Couldn't allocate kext panic log buffer.");
11268 goto finish;
11269 }
11270
11271 newlist[0] = '\0';
11272
11273 // non-"com.apple." kexts
11274 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
11275 /* libs? */ -1, newlist, newlist_size) != 0) {
11276
11277 goto finish;
11278 }
11279 // "com.apple." nonlibrary kexts
11280 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
11281 /* libs? */ 0, newlist, newlist_size) != 0) {
11282
11283 goto finish;
11284 }
11285 // "com.apple." library kexts
11286 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
11287 /* libs? */ 1, newlist, newlist_size) != 0) {
11288
11289 goto finish;
11290 }
11291
11292 if (loaded_kext_paniclist) {
11293 kfree(loaded_kext_paniclist, loaded_kext_paniclist_size);
11294 }
11295 loaded_kext_paniclist = newlist;
11296 newlist = NULL;
11297 loaded_kext_paniclist_size = newlist_size;
11298
11299 finish:
11300 if (newlist) {
11301 kfree(newlist, newlist_size);
11302 }
11303 return;
11304 }
11305
11306 /*********************************************************************
11307 * Assumes sKextLock is held.
11308 *********************************************************************/
11309 void
11310 OSKext::savePanicString(bool isLoading)
11311 {
11312 u_long len;
11313
11314 if (!kmod_info) {
11315 return; // do not goto finish here b/c of lock
11316 }
11317
11318 len = assemble_identifier_and_version( kmod_info,
11319 (isLoading) ? last_loaded_str_buf : last_unloaded_str_buf,
11320 (isLoading) ? sizeof(last_loaded_str_buf) : sizeof(last_unloaded_str_buf) );
11321 if (!len) {
11322 printf("error saving unloaded kext info\n");
11323 goto finish;
11324 }
11325
11326 if (isLoading) {
11327 last_loaded_strlen = len;
11328 last_loaded_address = (void *)kmod_info->address;
11329 last_loaded_size = kmod_info->size;
11330 clock_get_uptime(&last_loaded_timestamp);
11331 } else {
11332 last_unloaded_strlen = len;
11333 last_unloaded_address = (void *)kmod_info->address;
11334 last_unloaded_size = kmod_info->size;
11335 clock_get_uptime(&last_unloaded_timestamp);
11336 }
11337
11338 finish:
11339 return;
11340 }
11341
11342 /*********************************************************************
11343 *********************************************************************/
11344 /* static */
11345 void
11346 OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
11347 {
11348 if (last_loaded_strlen) {
11349 printf_func("last loaded kext at %llu: %.*s (addr %p, size %lu)\n",
11350 AbsoluteTime_to_scalar(&last_loaded_timestamp),
11351 last_loaded_strlen, last_loaded_str_buf,
11352 last_loaded_address, last_loaded_size);
11353 }
11354
11355 if (last_unloaded_strlen) {
11356 printf_func("last unloaded kext at %llu: %.*s (addr %p, size %lu)\n",
11357 AbsoluteTime_to_scalar(&last_unloaded_timestamp),
11358 last_unloaded_strlen, last_unloaded_str_buf,
11359 last_unloaded_address, last_unloaded_size);
11360 }
11361
11362 printf_func("loaded kexts:\n");
11363 if (loaded_kext_paniclist &&
11364 pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
11365 loaded_kext_paniclist[0]) {
11366
11367 printf_func("%.*s",
11368 strnlen(loaded_kext_paniclist, loaded_kext_paniclist_size),
11369 loaded_kext_paniclist);
11370 } else {
11371 printf_func("(none)\n");
11372 }
11373 return;
11374 }
11375
11376 /*********************************************************************
11377 * Assumes sKextLock is held.
11378 *********************************************************************/
11379 /* static */
11380 void
11381 OSKext::updateLoadedKextSummaries(void)
11382 {
11383 kern_return_t result = KERN_FAILURE;
11384 OSKextLoadedKextSummaryHeader *summaryHeader = NULL;
11385 OSKextLoadedKextSummaryHeader *summaryHeaderAlloc = NULL;
11386 OSKext *aKext;
11387 vm_map_offset_t start, end;
11388 size_t summarySize = 0;
11389 size_t size;
11390 u_int count;
11391 u_int maxKexts;
11392 u_int i, j;
11393 OSKextActiveAccount * accountingList;
11394 OSKextActiveAccount * prevAccountingList;
11395 uint32_t idx, accountingListAlloc, accountingListCount, prevAccountingListCount;
11396
11397 prevAccountingList = NULL;
11398 prevAccountingListCount = 0;
11399
11400 #if DEVELOPMENT || DEBUG
11401 if (IORecursiveLockHaveLock(sKextLock) == false) {
11402 panic("sKextLock must be held");
11403 }
11404 #endif
11405
11406 IOLockLock(sKextSummariesLock);
11407
11408 count = sLoadedKexts->getCount();
11409 for (i = 0, maxKexts = 0; i < count; ++i) {
11410 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
11411 maxKexts += (aKext && aKext->isExecutable());
11412 }
11413
11414 if (!maxKexts) goto finish;
11415 if (maxKexts < kOSKextTypicalLoadCount) maxKexts = kOSKextTypicalLoadCount;
11416
11417 /* Calculate the size needed for the new summary headers.
11418 */
11419
11420 size = sizeof(*gLoadedKextSummaries);
11421 size += maxKexts * sizeof(*gLoadedKextSummaries->summaries);
11422 size = round_page(size);
11423
11424 if (gLoadedKextSummaries == NULL || sLoadedKextSummariesAllocSize < size) {
11425 if (gLoadedKextSummaries) {
11426 kmem_free(kernel_map, (vm_offset_t)gLoadedKextSummaries, sLoadedKextSummariesAllocSize);
11427 gLoadedKextSummaries = NULL;
11428 gLoadedKextSummariesTimestamp = mach_absolute_time();
11429 sLoadedKextSummariesAllocSize = 0;
11430 }
11431 result = kmem_alloc(kernel_map, (vm_offset_t *)&summaryHeaderAlloc, size, VM_KERN_MEMORY_OSKEXT);
11432 if (result != KERN_SUCCESS) goto finish;
11433 summaryHeader = summaryHeaderAlloc;
11434 summarySize = size;
11435 }
11436 else {
11437 summaryHeader = gLoadedKextSummaries;
11438 summarySize = sLoadedKextSummariesAllocSize;
11439
11440 start = (vm_map_offset_t) summaryHeader;
11441 end = start + summarySize;
11442 result = vm_map_protect(kernel_map,
11443 start,
11444 end,
11445 VM_PROT_DEFAULT,
11446 FALSE);
11447 if (result != KERN_SUCCESS) goto finish;
11448 }
11449
11450 /* Populate the summary header.
11451 */
11452
11453 bzero(summaryHeader, summarySize);
11454 summaryHeader->version = kOSKextLoadedKextSummaryVersion;
11455 summaryHeader->entry_size = sizeof(OSKextLoadedKextSummary);
11456
11457 /* Populate each kext summary.
11458 */
11459
11460 count = sLoadedKexts->getCount();
11461 accountingListAlloc = 0;
11462 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
11463 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
11464 if (!aKext || !aKext->isExecutable()) {
11465 continue;
11466 }
11467
11468 aKext->updateLoadedKextSummary(&summaryHeader->summaries[j++]);
11469 summaryHeader->numSummaries++;
11470 accountingListAlloc++;
11471 }
11472
11473 accountingList = IONew(typeof(accountingList[0]), accountingListAlloc);
11474 accountingListCount = 0;
11475 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
11476 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
11477 if (!aKext || !aKext->isExecutable()) {
11478 continue;
11479 }
11480
11481 OSKextActiveAccount activeAccount;
11482 aKext->updateActiveAccount(&activeAccount);
11483 // order by address
11484 for (idx = 0; idx < accountingListCount; idx++)
11485 {
11486 if (activeAccount.address < accountingList[idx].address) break;
11487 }
11488 bcopy(&accountingList[idx], &accountingList[idx + 1], (accountingListCount - idx) * sizeof(accountingList[0]));
11489 accountingList[idx] = activeAccount;
11490 accountingListCount++;
11491 }
11492 assert(accountingListCount == accountingListAlloc);
11493 /* Write protect the buffer and move it into place.
11494 */
11495
11496 start = (vm_map_offset_t) summaryHeader;
11497 end = start + summarySize;
11498
11499 result = vm_map_protect(kernel_map, start, end, VM_PROT_READ, FALSE);
11500 if (result != KERN_SUCCESS)
11501 goto finish;
11502
11503 gLoadedKextSummaries = summaryHeader;
11504 gLoadedKextSummariesTimestamp = mach_absolute_time();
11505 sLoadedKextSummariesAllocSize = summarySize;
11506 summaryHeaderAlloc = NULL;
11507
11508 /* Call the magic breakpoint function through a static function pointer so
11509 * the compiler can't optimize the function away.
11510 */
11511 if (sLoadedKextSummariesUpdated) (*sLoadedKextSummariesUpdated)();
11512
11513 IOSimpleLockLock(sKextAccountsLock);
11514 prevAccountingList = sKextAccounts;
11515 prevAccountingListCount = sKextAccountsCount;
11516 sKextAccounts = accountingList;
11517 sKextAccountsCount = accountingListCount;
11518 IOSimpleLockUnlock(sKextAccountsLock);
11519
11520 finish:
11521 IOLockUnlock(sKextSummariesLock);
11522
11523 /* If we had to allocate a new buffer but failed to generate the summaries,
11524 * free that now.
11525 */
11526 if (summaryHeaderAlloc) {
11527 kmem_free(kernel_map, (vm_offset_t)summaryHeaderAlloc, summarySize);
11528 }
11529 if (prevAccountingList) {
11530 IODelete(prevAccountingList, typeof(accountingList[0]), prevAccountingListCount);
11531 }
11532
11533 return;
11534 }
11535
11536 /*********************************************************************
11537 *********************************************************************/
11538 void
11539 OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary *summary)
11540 {
11541 OSData *uuid;
11542
11543 strlcpy(summary->name, getIdentifierCString(),
11544 sizeof(summary->name));
11545
11546 uuid = copyUUID();
11547 if (uuid) {
11548 memcpy(summary->uuid, uuid->getBytesNoCopy(), sizeof(summary->uuid));
11549 OSSafeReleaseNULL(uuid);
11550 }
11551
11552 summary->address = kmod_info->address;
11553 summary->size = kmod_info->size;
11554 summary->version = getVersion();
11555 summary->loadTag = kmod_info->id;
11556 summary->flags = 0;
11557 summary->reference_list = (uint64_t) kmod_info->reference_list;
11558
11559 return;
11560 }
11561
11562 /*********************************************************************
11563 *********************************************************************/
11564
11565 void
11566 OSKext::updateActiveAccount(OSKextActiveAccount *accountp)
11567 {
11568 kernel_mach_header_t *hdr = NULL;
11569 kernel_segment_command_t *seg = NULL;
11570
11571 hdr = (kernel_mach_header_t *)kmod_info->address;
11572
11573 if (getcommandfromheader(hdr, LC_SEGMENT_SPLIT_INFO)) {
11574 /* If this kext supports split segments, use the first
11575 * executable segment as the range for instructions
11576 * (and thus for backtracing.
11577 */
11578 for (seg = firstsegfromheader(hdr); seg != NULL; seg = nextsegfromheader(hdr, seg)) {
11579 if (seg->initprot & VM_PROT_EXECUTE) {
11580 break;
11581 }
11582 }
11583 }
11584
11585 bzero(accountp, sizeof(*accountp));
11586 if (seg) {
11587 accountp->address = seg->vmaddr;
11588 if (accountp->address) {
11589 accountp->address_end = seg->vmaddr + seg->vmsize;
11590 }
11591 } else {
11592 /* For non-split kexts and for kexts without executable
11593 * segments, just use the kmod_info range (as the kext
11594 * is either all in one range or should not show up in
11595 * instruction backtraces).
11596 */
11597 accountp->address = kmod_info->address;
11598 if (accountp->address) {
11599 accountp->address_end = kmod_info->address + kmod_info->size;
11600 }
11601 }
11602 accountp->account = this->account;
11603 }
11604
11605 extern "C" const vm_allocation_site_t *
11606 OSKextGetAllocationSiteForCaller(uintptr_t address)
11607 {
11608 OSKextActiveAccount * active;
11609 vm_allocation_site_t * site;
11610 uint32_t baseIdx;
11611 uint32_t lim;
11612
11613 IOSimpleLockLock(sKextAccountsLock);
11614 site = NULL;
11615 // bsearch sKextAccounts list
11616 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1)
11617 {
11618 active = &sKextAccounts[baseIdx + (lim >> 1)];
11619 if ((address >= active->address) && (address < active->address_end))
11620 {
11621 site = &active->account->site;
11622 if (!site->tag) vm_tag_alloc_locked(site);
11623 break;
11624 }
11625 else if (address > active->address)
11626 {
11627 // move right
11628 baseIdx += (lim >> 1) + 1;
11629 lim--;
11630 }
11631 // else move left
11632 }
11633 IOSimpleLockUnlock(sKextAccountsLock);
11634
11635 return (site);
11636 }
11637
11638 extern "C" uint32_t
11639 OSKextGetKmodIDForSite(vm_allocation_site_t * site, char * name, vm_size_t namelen)
11640 {
11641 OSKextAccount * account = (typeof(account)) site;
11642 const char * kname;
11643
11644 if (name)
11645 {
11646 if (account->kext) kname = account->kext->getIdentifierCString();
11647 else kname = "<>";
11648 strlcpy(name, kname, namelen);
11649 }
11650
11651 return (account->loadTag);
11652 }
11653
11654 extern "C" void
11655 OSKextFreeSite(vm_allocation_site_t * site)
11656 {
11657 OSKextAccount * freeAccount = (typeof(freeAccount)) site;
11658 IODelete(freeAccount, OSKextAccount, 1);
11659 }
11660
11661 /*********************************************************************
11662 *********************************************************************/
11663
11664 #if CONFIG_KEC_FIPS
11665
11666 #if PRAGMA_MARK
11667 #pragma mark Kernel External Components for FIPS compliance
11668 #endif
11669
11670 /*********************************************************************
11671 * Kernel External Components for FIPS compliance (KEC_FIPS)
11672 *********************************************************************/
11673 static void *
11674 GetAppleTEXTHashForKext(OSKext * theKext, OSDictionary *theInfoDict)
11675 {
11676 AppleTEXTHash_t my_ath = {2, 0, NULL};
11677 AppleTEXTHash_t * my_athp = NULL; // do not release
11678 OSData * segmentHash = NULL; // do not release
11679
11680 if (theKext == NULL || theInfoDict == NULL) {
11681 return(NULL);
11682 }
11683
11684 // Get the part of the plist associate with kAppleTextHashesKey and let
11685 // the crypto library do further parsing (slice/architecture)
11686 segmentHash = OSDynamicCast(OSData, theInfoDict->getObject(kAppleTextHashesKey));
11687 // Support for ATH v1 while rolling out ATH v2 without revision locking submissions
11688 // Remove this when v2 PLIST are supported
11689 if (segmentHash == NULL) {
11690 // If this fails, we may be dealing with a v1 PLIST
11691 OSDictionary * textHashDict = NULL; // do not release
11692 textHashDict = OSDynamicCast(OSDictionary, theInfoDict->getObject(kAppleTextHashesKey));
11693 if (textHashDict == NULL) {
11694 return(NULL);
11695 }
11696 my_ath.ath_version=1;
11697 segmentHash = OSDynamicCast(OSData,textHashDict->getObject(ARCHNAME));
11698 } // end of v2 rollout
11699
11700 if (segmentHash == NULL) {
11701 return(NULL);
11702 }
11703
11704 // KEC_FIPS type kexts never unload so we don't have to clean up our
11705 // AppleTEXTHash_t
11706 if (kmem_alloc(kernel_map, (vm_offset_t *) &my_athp,
11707 sizeof(AppleTEXTHash_t), VM_KERN_MEMORY_OSKEXT) != KERN_SUCCESS) {
11708 return(NULL);
11709 }
11710
11711 memcpy(my_athp, &my_ath, sizeof(my_ath));
11712 my_athp->ath_length = segmentHash->getLength();
11713 if (my_athp->ath_length > 0) {
11714 my_athp->ath_hash = (void *)segmentHash->getBytesNoCopy();
11715 }
11716
11717 #if 0
11718 OSKextLog(theKext,
11719 kOSKextLogErrorLevel |
11720 kOSKextLogGeneralFlag,
11721 "Kext %s ath_version %d ath_length %d ath_hash %p",
11722 theKext->getIdentifierCString(),
11723 my_athp->ath_version,
11724 my_athp->ath_length,
11725 my_athp->ath_hash);
11726 #endif
11727
11728 return( (void *) my_athp );
11729 }
11730
11731 #endif // CONFIG_KEC_FIPS
11732