]> git.saurik.com Git - apple/xnu.git/blob - libkern/c++/OSKext.cpp
feb99abadd39246d64868fb7ad45f74fb2fba07e
[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 <firehose/chunk_private.h>
36 #include <os/firehose_buffer_private.h>
37 #include <vm/vm_kern.h>
38 #include <kextd/kextd_mach.h>
39 #include <libkern/kernel_mach_header.h>
40 #include <libkern/kext_panic_report.h>
41 #include <libkern/kext_request_keys.h>
42 #include <libkern/mkext.h>
43 #include <libkern/prelink.h>
44 #include <libkern/version.h>
45 #include <libkern/zlib.h>
46 #include <mach/host_special_ports.h>
47 #include <mach/mach_vm.h>
48 #include <mach/mach_time.h>
49 #include <sys/sysctl.h>
50 #include <uuid/uuid.h>
51 // 04/18/11 - gab: <rdar://problem/9236163>
52 #include <sys/random.h>
53
54 #include <sys/pgo.h>
55
56 #if CONFIG_MACF
57 #include <sys/kauth.h>
58 #include <security/mac_framework.h>
59 #endif
60 };
61
62 #include <libkern/OSKextLibPrivate.h>
63 #include <libkern/c++/OSKext.h>
64 #include <libkern/c++/OSLib.h>
65
66 #include <IOKit/IOLib.h>
67 #include <IOKit/IOCatalogue.h>
68 #include <IOKit/IORegistryEntry.h>
69 #include <IOKit/IOService.h>
70
71 #include <IOKit/IOStatisticsPrivate.h>
72 #include <IOKit/IOBSD.h>
73
74 #include <san/kasan.h>
75
76 #if PRAGMA_MARK
77 #pragma mark External & Internal Function Protos
78 #endif
79 /*********************************************************************
80 *********************************************************************/
81 extern "C" {
82 extern int IODTGetLoaderInfo(const char * key, void ** infoAddr, int * infoSize);
83 extern void IODTFreeLoaderInfo(const char * key, void * infoAddr, int infoSize);
84 extern void OSRuntimeUnloadCPPForSegment(kernel_segment_command_t * segment);
85 extern void OSRuntimeUnloadCPP(kmod_info_t * ki, void * data);
86
87 extern ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va); /* osfmk/machine/pmap.h */
88 }
89
90 static OSReturn _OSKextCreateRequest(
91 const char * predicate,
92 OSDictionary ** requestP);
93 static OSString * _OSKextGetRequestPredicate(OSDictionary * requestDict);
94 static OSObject * _OSKextGetRequestArgument(
95 OSDictionary * requestDict,
96 const char * argName);
97 static bool _OSKextSetRequestArgument(
98 OSDictionary * requestDict,
99 const char * argName,
100 OSObject * value);
101 static void * _OSKextExtractPointer(OSData * wrapper);
102 static OSReturn _OSDictionarySetCStringValue(
103 OSDictionary * dict,
104 const char * key,
105 const char * value);
106 static bool _OSKextInPrelinkRebuildWindow(void);
107 static bool _OSKextInUnloadedPrelinkedKexts(const OSSymbol * theBundleID);
108
109 // We really should add containsObject() & containsCString to OSCollection & subclasses.
110 // So few pad slots, though....
111 static bool _OSArrayContainsCString(OSArray * array, const char * cString);
112
113 #if CONFIG_KEC_FIPS
114 static void * GetAppleTEXTHashForKext(OSKext * theKext, OSDictionary *theInfoDict);
115 #endif // CONFIG_KEC_FIPS
116
117 /* Prelinked arm kexts do not have VM entries because the method we use to
118 * fake an entry (see libsa/bootstrap.cpp:readPrelinkedExtensions()) does
119 * not work on ARM. To get around that, we must free prelinked kext
120 * executables with ml_static_mfree() instead of kext_free().
121 */
122 #if __i386__ || __x86_64__
123 #define VM_MAPPED_KEXTS 1
124 #define KASLR_KEXT_DEBUG 0
125 #define KASLR_IOREG_DEBUG 0
126 #elif __arm__ || __arm64__
127 #define VM_MAPPED_KEXTS 0
128 #define KASLR_KEXT_DEBUG 0
129 #else
130 #error Unsupported architecture
131 #endif
132
133 #if PRAGMA_MARK
134 #pragma mark Constants & Macros
135 #endif
136 /*********************************************************************
137 * Constants & Macros
138 *********************************************************************/
139
140 /* Use this number to create containers.
141 */
142 #define kOSKextTypicalLoadCount (150)
143
144 /* Any kext will have at least 1 retain for the internal lookup-by-ID dict.
145 * A loaded kext will no dependents or external retains will have 2 retains.
146 */
147 #define kOSKextMinRetainCount (1)
148 #define kOSKextMinLoadedRetainCount (2)
149
150 /**********
151 * Strings and substrings used in dependency resolution.
152 */
153 #define APPLE_KEXT_PREFIX "com.apple."
154 #define KERNEL_LIB "com.apple.kernel"
155
156 #define PRIVATE_KPI "com.apple.kpi.private"
157
158 /* Version for compatbility pseudokexts (com.apple.kernel.*),
159 * compatible back to v6.0.
160 */
161 #define KERNEL6_LIB "com.apple.kernel.6.0"
162 #define KERNEL6_VERSION "7.9.9"
163
164 #define KERNEL_LIB_PREFIX "com.apple.kernel."
165 #define KPI_LIB_PREFIX "com.apple.kpi."
166
167 #define STRING_HAS_PREFIX(s, p) (strncmp((s), (p), strlen(p)) == 0)
168
169 #define REBUILD_MAX_TIME (60 * 5) // 5 minutes
170 #define MINIMUM_WAKEUP_SECONDS (30)
171
172 /*********************************************************************
173 * infoDict keys for internally-stored data. Saves on ivar slots for
174 * objects we don't keep around past boot time or during active load.
175 *********************************************************************/
176
177 /* A usable, uncompressed file is stored under this key.
178 */
179 #define _kOSKextExecutableKey "_OSKextExecutable"
180
181 /* An indirect reference to the executable file from an mkext
182 * is stored under this key.
183 */
184 #define _kOSKextMkextExecutableReferenceKey "_OSKextMkextExecutableReference"
185
186 /* If the file is contained in a larger buffer laid down by the booter or
187 * sent from user space, the OSKext stores that OSData under this key so that
188 * references are properly tracked. This is always an mkext, right now.
189 */
190 #define _kOSKextExecutableExternalDataKey "_OSKextExecutableExternalData"
191
192 #define OS_LOG_HDR_VERSION 1
193 #define NUM_OS_LOG_SECTIONS 2
194
195 #define OS_LOG_SECT_IDX 0
196 #define CSTRING_SECT_IDX 1
197
198 #if PRAGMA_MARK
199 #pragma mark Typedefs
200 #endif
201 /*********************************************************************
202 * Typedefs
203 *********************************************************************/
204
205 /*********************************************************************
206 * osLogDataHeaderRef describes the header information of an OSData
207 * object that is returned when querying for kOSBundleLogStringsKey.
208 * We currently return information regarding 2 sections - os_log and
209 * cstring. In the case that the os_log section doesn't exist, we just
210 * return an offset and length of 0 for that section.
211 *********************************************************************/
212 typedef struct osLogDataHeader {
213 uint32_t version;
214 uint32_t sect_count;
215 struct {
216 uint32_t sect_offset;
217 uint32_t sect_size;
218 } sections[0];
219 } osLogDataHeaderRef;
220
221 /*********************************************************************
222 * MkextEntryRef describes the contents of an OSData object
223 * referencing a file entry from an mkext so that we can uncompress
224 * (if necessary) and extract it on demand.
225 *
226 * It contains the mkextVersion in case we ever wind up supporting
227 * multiple mkext formats. Mkext format 1 is officially retired as of
228 * Snow Leopard.
229 *********************************************************************/
230 typedef struct MkextEntryRef {
231 mkext_basic_header * mkext; // beginning of whole mkext file
232 void * fileinfo; // mkext2_file_entry or equiv; see mkext.h
233 } MkextEntryRef;
234
235 #if PRAGMA_MARK
236 #pragma mark Global and static Module Variables
237 #endif
238 /*********************************************************************
239 * Global & static variables, used to keep track of kexts.
240 *********************************************************************/
241
242 static bool sPrelinkBoot = false;
243 static bool sSafeBoot = false;
244 static bool sKeepSymbols = false;
245
246 /*********************************************************************
247 * sKextLock is the principal lock for OSKext, and guards all static
248 * and global variables not owned by other locks (declared further
249 * below). It must be taken by any entry-point method or function,
250 * including internal functions called on scheduled threads.
251 *
252 * sKextLock and sKextInnerLock are recursive due to multiple functions
253 * that are called both externally and internally. The other locks are
254 * nonrecursive.
255 *
256 * Which locks are taken depends on what they protect, but if more than
257 * one must be taken, they must always be locked in this order
258 * (and unlocked in reverse order) to prevent deadlocks:
259 *
260 * 1. sKextLock
261 * 2. sKextInnerLock
262 * 3. sKextSummariesLock
263 * 4. sKextLoggingLock
264 */
265 static IORecursiveLock * sKextLock = NULL;
266
267 static OSDictionary * sKextsByID = NULL;
268 static OSDictionary * sExcludeListByID = NULL;
269 static OSKextVersion sExcludeListVersion = 0;
270 static OSArray * sLoadedKexts = NULL;
271 static OSArray * sUnloadedPrelinkedKexts = NULL;
272
273 // Requests to kextd waiting to be picked up.
274 static OSArray * sKernelRequests = NULL;
275 // Identifier of kext load requests in sKernelRequests
276 static OSSet * sPostedKextLoadIdentifiers = NULL;
277 static OSArray * sRequestCallbackRecords = NULL;
278
279 // Identifiers of all kexts ever requested in kernel; used for prelinked kernel
280 static OSSet * sAllKextLoadIdentifiers = NULL;
281 static KXLDContext * sKxldContext = NULL;
282 static uint32_t sNextLoadTag = 0;
283 static uint32_t sNextRequestTag = 0;
284
285 static bool sUserLoadsActive = false;
286 static bool sKextdActive = false;
287 static bool sDeferredLoadSucceeded = false;
288 static bool sConsiderUnloadsExecuted = false;
289
290 #if NO_KEXTD
291 static bool sKernelRequestsEnabled = false;
292 #else
293 static bool sKernelRequestsEnabled = true;
294 #endif
295 static bool sLoadEnabled = true;
296 static bool sUnloadEnabled = true;
297
298 /*********************************************************************
299 * Stuff for the OSKext representing the kernel itself.
300 **********/
301 static OSKext * sKernelKext = NULL;
302
303 /* Set up a fake kmod_info struct for the kernel.
304 * It's used in OSRuntime.cpp to call OSRuntimeInitializeCPP()
305 * before OSKext is initialized; that call only needs the name
306 * and address to be set correctly.
307 *
308 * We don't do much else with the kerne's kmod_info; we never
309 * put it into the kmod list, never adjust the reference count,
310 * and never have kernel components reference it.
311 * For that matter, we don't do much with kmod_info structs
312 * at all anymore! We just keep them filled in for gdb and
313 * binary compability.
314 */
315 kmod_info_t g_kernel_kmod_info = {
316 /* next */ 0,
317 /* info_version */ KMOD_INFO_VERSION,
318 /* id */ 0, // loadTag: kernel is always 0
319 /* name */ kOSKextKernelIdentifier, // bundle identifier
320 /* version */ "0", // filled in in OSKext::initialize()
321 /* reference_count */ -1, // never adjusted; kernel never unloads
322 /* reference_list */ NULL,
323 /* address */ 0,
324 /* size */ 0, // filled in in OSKext::initialize()
325 /* hdr_size */ 0,
326 /* start */ 0,
327 /* stop */ 0
328 };
329
330 extern "C" {
331 // symbol 'kmod' referenced in: model_dep.c, db_trace.c, symbols.c, db_low_trace.c,
332 // dtrace.c, dtrace_glue.h, OSKext.cpp, locore.s, lowmem_vectors.s,
333 // misc_protos.h, db_low_trace.c, kgmacros
334 // 'kmod' is a holdover from the old kmod system, we can't rename it.
335 kmod_info_t * kmod = NULL;
336
337 #define KEXT_PANICLIST_SIZE (2 * PAGE_SIZE)
338
339
340 static char * loaded_kext_paniclist = NULL;
341 static uint32_t loaded_kext_paniclist_size = 0;
342
343 AbsoluteTime last_loaded_timestamp;
344 static char last_loaded_str_buf[2*KMOD_MAX_NAME];
345 static u_long last_loaded_strlen = 0;
346 static void * last_loaded_address = NULL;
347 static u_long last_loaded_size = 0;
348
349 AbsoluteTime last_unloaded_timestamp;
350 static char last_unloaded_str_buf[2*KMOD_MAX_NAME];
351 static u_long last_unloaded_strlen = 0;
352 static void * last_unloaded_address = NULL;
353 static u_long last_unloaded_size = 0;
354
355 /*********************************************************************
356 * sKextInnerLock protects against cross-calls with IOService and
357 * IOCatalogue, and owns the variables declared immediately below.
358 *
359 * Note that sConsiderUnloadsExecuted above belongs to sKextLock!
360 *
361 * When both sKextLock and sKextInnerLock need to be taken,
362 * always lock sKextLock first and unlock it second. Never take both
363 * locks in an entry point to OSKext; if you need to do so, you must
364 * spawn an independent thread to avoid potential deadlocks for threads
365 * calling into OSKext.
366 **********/
367 static IORecursiveLock * sKextInnerLock = NULL;
368
369 static bool sAutounloadEnabled = true;
370 static bool sConsiderUnloadsCalled = false;
371 static bool sConsiderUnloadsPending = false;
372
373 static unsigned int sConsiderUnloadDelay = 60; // seconds
374 static thread_call_t sUnloadCallout = 0;
375 static thread_call_t sDestroyLinkContextThread = 0; // one-shot, one-at-a-time thread
376 static bool sSystemSleep = false; // true when system going to sleep
377 static AbsoluteTime sLastWakeTime; // last time we woke up
378
379 /*********************************************************************
380 * Backtraces can be printed at various times so we need a tight lock
381 * on data used for that. sKextSummariesLock protects the variables
382 * declared immediately below.
383 *
384 * gLoadedKextSummaries is accessed by other modules, but only during
385 * a panic so the lock isn't needed then.
386 *
387 * gLoadedKextSummaries has the "used" attribute in order to ensure
388 * that it remains visible even when we are performing extremely
389 * aggressive optimizations, as it is needed to allow the debugger
390 * to automatically parse the list of loaded kexts.
391 **********/
392 static IOLock * sKextSummariesLock = NULL;
393 extern "C" lck_spin_t vm_allocation_sites_lock;
394 static IOSimpleLock * sKextAccountsLock = &vm_allocation_sites_lock;
395
396 void (*sLoadedKextSummariesUpdated)(void) = OSKextLoadedKextSummariesUpdated;
397 OSKextLoadedKextSummaryHeader * gLoadedKextSummaries __attribute__((used)) = NULL;
398 uint64_t gLoadedKextSummariesTimestamp __attribute__((used)) = 0;
399 static size_t sLoadedKextSummariesAllocSize = 0;
400
401 static OSKextActiveAccount * sKextAccounts;
402 static uint32_t sKextAccountsCount;
403 };
404
405 /*********************************************************************
406 * sKextLoggingLock protects the logging variables declared immediately below.
407 **********/
408 static IOLock * sKextLoggingLock = NULL;
409
410 static const OSKextLogSpec kDefaultKernelLogFilter = kOSKextLogBasicLevel |
411 kOSKextLogVerboseFlagsMask;
412 static OSKextLogSpec sKernelLogFilter = kDefaultKernelLogFilter;
413 static bool sBootArgLogFilterFound = false;
414 SYSCTL_UINT(_debug, OID_AUTO, kextlog, CTLFLAG_RW | CTLFLAG_LOCKED, &sKernelLogFilter,
415 0, "kernel kext logging");
416
417 static OSKextLogSpec sUserSpaceKextLogFilter = kOSKextLogSilentFilter;
418 static OSArray * sUserSpaceLogSpecArray = NULL;
419 static OSArray * sUserSpaceLogMessageArray = NULL;
420
421 /*********
422 * End scope for sKextInnerLock-protected variables.
423 *********************************************************************/
424
425
426 /*********************************************************************
427 helper function used for collecting PGO data upon unload of a kext
428 */
429
430 static int OSKextGrabPgoDataLocked(OSKext *kext,
431 bool metadata,
432 uuid_t instance_uuid,
433 uint64_t *pSize,
434 char *pBuffer,
435 uint64_t bufferSize);
436
437 /**********************************************************************/
438
439
440
441 #if PRAGMA_MARK
442 #pragma mark OSData callbacks (need to move to OSData)
443 #endif
444 /*********************************************************************
445 * C functions used for callbacks.
446 *********************************************************************/
447 extern "C" {
448 void osdata_kmem_free(void * ptr, unsigned int length) {
449 kmem_free(kernel_map, (vm_address_t)ptr, length);
450 return;
451 }
452
453 void osdata_phys_free(void * ptr, unsigned int length) {
454 ml_static_mfree((vm_offset_t)ptr, length);
455 return;
456 }
457
458 void osdata_vm_deallocate(void * ptr, unsigned int length)
459 {
460 (void)vm_deallocate(kernel_map, (vm_offset_t)ptr, length);
461 return;
462 }
463
464 void osdata_kext_free(void * ptr, unsigned int length)
465 {
466 (void)kext_free((vm_offset_t)ptr, length);
467 }
468
469 };
470
471 #if PRAGMA_MARK
472 #pragma mark KXLD Allocation Callback
473 #endif
474 /*********************************************************************
475 * KXLD Allocation Callback
476 *********************************************************************/
477 kxld_addr_t
478 kern_allocate(
479 u_long size,
480 KXLDAllocateFlags * flags,
481 void * user_data)
482 {
483 vm_address_t result = 0; // returned
484 kern_return_t mach_result = KERN_FAILURE;
485 bool success = false;
486 OSKext * theKext = (OSKext *)user_data;
487 u_long roundSize = round_page(size);
488 OSData * linkBuffer = NULL; // must release
489
490 mach_result = kext_alloc(&result, roundSize, /* fixed */ FALSE);
491 if (mach_result != KERN_SUCCESS) {
492 OSKextLog(theKext,
493 kOSKextLogErrorLevel |
494 kOSKextLogGeneralFlag,
495 "Can't allocate kernel memory to link %s.",
496 theKext->getIdentifierCString());
497 goto finish;
498 }
499
500 /* Create an OSData wrapper for the allocated buffer.
501 */
502 linkBuffer = OSData::withBytesNoCopy((void *)result, roundSize);
503 if (!linkBuffer) {
504 OSKextLog(theKext,
505 kOSKextLogErrorLevel |
506 kOSKextLogGeneralFlag,
507 "Can't allocate linked executable wrapper for %s.",
508 theKext->getIdentifierCString());
509 goto finish;
510 }
511 linkBuffer->setDeallocFunction(osdata_kext_free);
512 OSKextLog(theKext,
513 kOSKextLogProgressLevel |
514 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
515 "Allocated link buffer for kext %s at %p (%lu bytes).",
516 theKext->getIdentifierCString(),
517 (void *)result, (unsigned long)roundSize);
518
519 theKext->setLinkedExecutable(linkBuffer);
520
521 *flags = kKxldAllocateWritable;
522 success = true;
523
524 finish:
525 if (!success && result) {
526 kext_free(result, roundSize);
527 result = 0;
528 }
529
530 OSSafeReleaseNULL(linkBuffer);
531
532 return (kxld_addr_t)result;
533 }
534
535 /*********************************************************************
536 *********************************************************************/
537 void
538 kxld_log_callback(
539 KXLDLogSubsystem subsystem,
540 KXLDLogLevel level,
541 const char * format,
542 va_list argList,
543 void * user_data)
544 {
545 OSKext *theKext = (OSKext *) user_data;
546 OSKextLogSpec logSpec = 0;
547
548 switch (subsystem) {
549 case kKxldLogLinking:
550 logSpec |= kOSKextLogLinkFlag;
551 break;
552 case kKxldLogPatching:
553 logSpec |= kOSKextLogPatchFlag;
554 break;
555 }
556
557 switch (level) {
558 case kKxldLogExplicit:
559 logSpec |= kOSKextLogExplicitLevel;
560 break;
561 case kKxldLogErr:
562 logSpec |= kOSKextLogErrorLevel;
563 break;
564 case kKxldLogWarn:
565 logSpec |= kOSKextLogWarningLevel;
566 break;
567 case kKxldLogBasic:
568 logSpec |= kOSKextLogProgressLevel;
569 break;
570 case kKxldLogDetail:
571 logSpec |= kOSKextLogDetailLevel;
572 break;
573 case kKxldLogDebug:
574 logSpec |= kOSKextLogDebugLevel;
575 break;
576 }
577
578 OSKextVLog(theKext, logSpec, format, argList);
579 }
580
581 #if PRAGMA_MARK
582 #pragma mark IOStatistics defines
583 #endif
584
585 #if IOKITSTATS
586
587 #define notifyKextLoadObservers(kext, kmod_info) \
588 do { \
589 IOStatistics::onKextLoad(kext, kmod_info); \
590 } while (0)
591
592 #define notifyKextUnloadObservers(kext) \
593 do { \
594 IOStatistics::onKextUnload(kext); \
595 } while (0)
596
597 #define notifyAddClassObservers(kext, addedClass, flags) \
598 do { \
599 IOStatistics::onClassAdded(kext, addedClass); \
600 } while (0)
601
602 #define notifyRemoveClassObservers(kext, removedClass, flags) \
603 do { \
604 IOStatistics::onClassRemoved(kext, removedClass); \
605 } while (0)
606
607 #else
608
609 #define notifyKextLoadObservers(kext, kmod_info)
610 #define notifyKextUnloadObservers(kext)
611 #define notifyAddClassObservers(kext, addedClass, flags)
612 #define notifyRemoveClassObservers(kext, removedClass, flags)
613
614 #endif /* IOKITSTATS */
615
616 #if PRAGMA_MARK
617 #pragma mark Module Config (Startup & Shutdown)
618 #endif
619 /*********************************************************************
620 * Module Config (Class Definition & Class Methods)
621 *********************************************************************/
622 #define super OSObject
623 OSDefineMetaClassAndStructors(OSKext, OSObject)
624
625 /*********************************************************************
626 *********************************************************************/
627 /* static */
628 void
629 OSKext::initialize(void)
630 {
631 OSData * kernelExecutable = NULL; // do not release
632 u_char * kernelStart = NULL; // do not free
633 size_t kernelLength = 0;
634 OSString * scratchString = NULL; // must release
635 IORegistryEntry * registryRoot = NULL; // do not release
636 OSNumber * kernelCPUType = NULL; // must release
637 OSNumber * kernelCPUSubtype = NULL; // must release
638 OSKextLogSpec bootLogFilter = kOSKextLogSilentFilter;
639 bool setResult = false;
640 uint64_t * timestamp = 0;
641 char bootArgBuffer[16]; // for PE_parse_boot_argn w/strings
642
643 /* This must be the first thing allocated. Everything else grabs this lock.
644 */
645 sKextLock = IORecursiveLockAlloc();
646 sKextInnerLock = IORecursiveLockAlloc();
647 sKextSummariesLock = IOLockAlloc();
648 sKextLoggingLock = IOLockAlloc();
649 assert(sKextLock);
650 assert(sKextInnerLock);
651 assert(sKextSummariesLock);
652 assert(sKextLoggingLock);
653
654 sKextsByID = OSDictionary::withCapacity(kOSKextTypicalLoadCount);
655 sLoadedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
656 sUnloadedPrelinkedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount / 10);
657 sKernelRequests = OSArray::withCapacity(0);
658 sPostedKextLoadIdentifiers = OSSet::withCapacity(0);
659 sAllKextLoadIdentifiers = OSSet::withCapacity(kOSKextTypicalLoadCount);
660 sRequestCallbackRecords = OSArray::withCapacity(0);
661 assert(sKextsByID && sLoadedKexts && sKernelRequests &&
662 sPostedKextLoadIdentifiers && sAllKextLoadIdentifiers &&
663 sRequestCallbackRecords && sUnloadedPrelinkedKexts);
664
665 /* Read the log flag boot-args and set the log flags.
666 */
667 if (PE_parse_boot_argn("kextlog", &bootLogFilter, sizeof(bootLogFilter))) {
668 sBootArgLogFilterFound = true;
669 sKernelLogFilter = bootLogFilter;
670 // log this if any flags are set
671 OSKextLog(/* kext */ NULL,
672 kOSKextLogBasicLevel |
673 kOSKextLogFlagsMask,
674 "Kernel kext log filter 0x%x per kextlog boot arg.",
675 (unsigned)sKernelLogFilter);
676 }
677
678 sSafeBoot = PE_parse_boot_argn("-x", bootArgBuffer,
679 sizeof(bootArgBuffer)) ? true : false;
680
681 if (sSafeBoot) {
682 OSKextLog(/* kext */ NULL,
683 kOSKextLogWarningLevel |
684 kOSKextLogGeneralFlag,
685 "SAFE BOOT DETECTED - "
686 "only valid OSBundleRequired kexts will be loaded.");
687 }
688
689 PE_parse_boot_argn("keepsyms", &sKeepSymbols, sizeof(sKeepSymbols));
690 #if KASAN_DYNAMIC_BLACKLIST
691 /* needed for function lookup */
692 sKeepSymbols = true;
693 #endif
694
695 /* Set up an OSKext instance to represent the kernel itself.
696 */
697 sKernelKext = new OSKext;
698 assert(sKernelKext);
699
700 kernelStart = (u_char *)&_mh_execute_header;
701 kernelLength = getlastaddr() - (vm_offset_t)kernelStart;
702 kernelExecutable = OSData::withBytesNoCopy(
703 kernelStart, kernelLength);
704 assert(kernelExecutable);
705
706 #if KASLR_KEXT_DEBUG
707 IOLog("kaslr: kernel start 0x%lx end 0x%lx length %lu vm_kernel_slide %llu (0x%016lx) \n",
708 (unsigned long)kernelStart,
709 (unsigned long)getlastaddr(),
710 kernelLength,
711 vm_kernel_slide, vm_kernel_slide);
712 #endif
713
714 sKernelKext->loadTag = sNextLoadTag++; // the kernel is load tag 0
715 sKernelKext->bundleID = OSSymbol::withCString(kOSKextKernelIdentifier);
716
717 sKernelKext->version = OSKextParseVersionString(osrelease);
718 sKernelKext->compatibleVersion = sKernelKext->version;
719 sKernelKext->linkedExecutable = kernelExecutable;
720
721 sKernelKext->flags.hasAllDependencies = 1;
722 sKernelKext->flags.kernelComponent = 1;
723 sKernelKext->flags.prelinked = 0;
724 sKernelKext->flags.loaded = 1;
725 sKernelKext->flags.started = 1;
726 sKernelKext->flags.CPPInitialized = 0;
727 sKernelKext->flags.jettisonLinkeditSeg = 0;
728
729 sKernelKext->kmod_info = &g_kernel_kmod_info;
730 strlcpy(g_kernel_kmod_info.version, osrelease,
731 sizeof(g_kernel_kmod_info.version));
732 g_kernel_kmod_info.size = kernelLength;
733 g_kernel_kmod_info.id = sKernelKext->loadTag;
734
735 /* Cons up an info dict, so we don't have to have special-case
736 * checking all over.
737 */
738 sKernelKext->infoDict = OSDictionary::withCapacity(5);
739 assert(sKernelKext->infoDict);
740 setResult = sKernelKext->infoDict->setObject(kCFBundleIdentifierKey,
741 sKernelKext->bundleID);
742 assert(setResult);
743 setResult = sKernelKext->infoDict->setObject(kOSKernelResourceKey,
744 kOSBooleanTrue);
745 assert(setResult);
746
747 scratchString = OSString::withCStringNoCopy(osrelease);
748 assert(scratchString);
749 setResult = sKernelKext->infoDict->setObject(kCFBundleVersionKey,
750 scratchString);
751 assert(setResult);
752 OSSafeReleaseNULL(scratchString);
753
754 scratchString = OSString::withCStringNoCopy("mach_kernel");
755 assert(scratchString);
756 setResult = sKernelKext->infoDict->setObject(kCFBundleNameKey,
757 scratchString);
758 assert(setResult);
759 OSSafeReleaseNULL(scratchString);
760
761 /* Add the kernel kext to the bookkeeping dictionaries. Note that
762 * the kernel kext doesn't have a kmod_info struct. copyInfo()
763 * gathers info from other places anyhow.
764 */
765 setResult = sKextsByID->setObject(sKernelKext->bundleID, sKernelKext);
766 assert(setResult);
767 setResult = sLoadedKexts->setObject(sKernelKext);
768 assert(setResult);
769 sKernelKext->release();
770
771 registryRoot = IORegistryEntry::getRegistryRoot();
772 kernelCPUType = OSNumber::withNumber(
773 (long long unsigned int)_mh_execute_header.cputype,
774 8 * sizeof(_mh_execute_header.cputype));
775 kernelCPUSubtype = OSNumber::withNumber(
776 (long long unsigned int)_mh_execute_header.cpusubtype,
777 8 * sizeof(_mh_execute_header.cpusubtype));
778 assert(registryRoot && kernelCPUSubtype && kernelCPUType);
779
780 registryRoot->setProperty(kOSKernelCPUTypeKey, kernelCPUType);
781 registryRoot->setProperty(kOSKernelCPUSubtypeKey, kernelCPUSubtype);
782
783 OSSafeReleaseNULL(kernelCPUType);
784 OSSafeReleaseNULL(kernelCPUSubtype);
785
786 timestamp = __OSAbsoluteTimePtr(&last_loaded_timestamp);
787 *timestamp = 0;
788 timestamp = __OSAbsoluteTimePtr(&last_unloaded_timestamp);
789 *timestamp = 0;
790 timestamp = __OSAbsoluteTimePtr(&sLastWakeTime);
791 *timestamp = 0;
792
793 OSKextLog(/* kext */ NULL,
794 kOSKextLogProgressLevel |
795 kOSKextLogGeneralFlag,
796 "Kext system initialized.");
797
798 notifyKextLoadObservers(sKernelKext, sKernelKext->kmod_info);
799
800 return;
801 }
802
803 /*********************************************************************
804 * This could be in OSKextLib.cpp but we need to hold a lock
805 * while removing all the segments and sKextLock will do.
806 *********************************************************************/
807 /* static */
808 OSReturn
809 OSKext::removeKextBootstrap(void)
810 {
811 OSReturn result = kOSReturnError;
812
813 static bool alreadyDone = false;
814
815 const char * dt_kernel_header_name = "Kernel-__HEADER";
816 const char * dt_kernel_symtab_name = "Kernel-__SYMTAB";
817 kernel_mach_header_t * dt_mach_header = NULL;
818 int dt_mach_header_size = 0;
819 struct symtab_command * dt_symtab = NULL;
820 int dt_symtab_size = 0;
821 int dt_result = 0;
822
823 kernel_segment_command_t * seg_to_remove = NULL;
824
825 #if __arm__ || __arm64__
826 const char * dt_segment_name = NULL;
827 void * segment_paddress = NULL;
828 int segment_size = 0;
829 #endif
830
831 /* This must be the very first thing done by this function.
832 */
833 IORecursiveLockLock(sKextLock);
834
835 /* If we already did this, it's a success.
836 */
837 if (alreadyDone) {
838 result = kOSReturnSuccess;
839 goto finish;
840 }
841
842 OSKextLog(/* kext */ NULL,
843 kOSKextLogProgressLevel |
844 kOSKextLogGeneralFlag,
845 "Jettisoning kext bootstrap segments.");
846
847 /*****
848 * Dispose of unnecessary stuff that the booter didn't need to load.
849 */
850 dt_result = IODTGetLoaderInfo(dt_kernel_header_name,
851 (void **)&dt_mach_header, &dt_mach_header_size);
852 if (dt_result == 0 && dt_mach_header) {
853 IODTFreeLoaderInfo(dt_kernel_header_name, (void *)dt_mach_header,
854 round_page_32(dt_mach_header_size));
855 }
856 dt_result = IODTGetLoaderInfo(dt_kernel_symtab_name,
857 (void **)&dt_symtab, &dt_symtab_size);
858 if (dt_result == 0 && dt_symtab) {
859 IODTFreeLoaderInfo(dt_kernel_symtab_name, (void *)dt_symtab,
860 round_page_32(dt_symtab_size));
861 }
862
863 /*****
864 * KLD bootstrap segment.
865 */
866 // xxx - should rename KLD segment
867 seg_to_remove = getsegbyname("__KLD");
868 if (seg_to_remove) {
869 OSRuntimeUnloadCPPForSegment(seg_to_remove);
870 }
871
872 #if __arm__ || __arm64__
873 #if !(defined(KERNEL_INTEGRITY_KTRR))
874 /* Free the memory that was set up by bootx.
875 */
876 dt_segment_name = "Kernel-__KLD";
877 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
878 /* We cannot free this with KTRR enabled, as we cannot
879 * update the permissions on the KLD range this late
880 * in the boot process.
881 */
882 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
883 (int)segment_size);
884 }
885 #endif /* !(defined(KERNEL_INTEGRITY_KTRR)) */
886 #elif __i386__ || __x86_64__
887 /* On x86, use the mapping data from the segment load command to
888 * unload KLD directly.
889 * This may invalidate any assumptions about "avail_start"
890 * defining the lower bound for valid physical addresses.
891 */
892 if (seg_to_remove && seg_to_remove->vmaddr && seg_to_remove->vmsize) {
893 // 04/18/11 - gab: <rdar://problem/9236163>
894 // overwrite memory occupied by KLD segment with random data before
895 // releasing it.
896 read_frandom((void *) seg_to_remove->vmaddr, seg_to_remove->vmsize);
897 ml_static_mfree(seg_to_remove->vmaddr, seg_to_remove->vmsize);
898 }
899 #else
900 #error arch
901 #endif
902
903 seg_to_remove = NULL;
904
905 /*****
906 * Prelinked kernel's symtab (if there is one).
907 */
908 kernel_section_t * sect;
909 sect = getsectbyname("__PRELINK", "__symtab");
910 if (sect && sect->addr && sect->size) {
911 ml_static_mfree(sect->addr, sect->size);
912 }
913
914 seg_to_remove = (kernel_segment_command_t *)getsegbyname("__LINKEDIT");
915
916 /* kxld always needs the kernel's __LINKEDIT segment, but we can make it
917 * pageable, unless keepsyms is set. To do that, we have to copy it from
918 * its booter-allocated memory, free the booter memory, reallocate proper
919 * managed memory, then copy the segment back in.
920 */
921 #if CONFIG_KXLD
922 #if (__arm__ || __arm64__)
923 #error CONFIG_KXLD not expected for this arch
924 #endif
925 if (!sKeepSymbols) {
926 kern_return_t mem_result;
927 void *seg_copy = NULL;
928 void *seg_data = NULL;
929 vm_map_offset_t seg_offset = 0;
930 vm_map_offset_t seg_copy_offset = 0;
931 vm_map_size_t seg_length = 0;
932
933 seg_data = (void *) seg_to_remove->vmaddr;
934 seg_offset = (vm_map_offset_t) seg_to_remove->vmaddr;
935 seg_length = (vm_map_size_t) seg_to_remove->vmsize;
936
937 /* Allocate space for the LINKEDIT copy.
938 */
939 mem_result = kmem_alloc(kernel_map, (vm_offset_t *) &seg_copy,
940 seg_length, VM_KERN_MEMORY_KEXT);
941 if (mem_result != KERN_SUCCESS) {
942 OSKextLog(/* kext */ NULL,
943 kOSKextLogErrorLevel |
944 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
945 "Can't copy __LINKEDIT segment for VM reassign.");
946 goto finish;
947 }
948 seg_copy_offset = (vm_map_offset_t) seg_copy;
949
950 /* Copy it out.
951 */
952 memcpy(seg_copy, seg_data, seg_length);
953
954 /* Dump the booter memory.
955 */
956 ml_static_mfree(seg_offset, seg_length);
957
958 /* Set up the VM region.
959 */
960 mem_result = vm_map_enter_mem_object(
961 kernel_map,
962 &seg_offset,
963 seg_length, /* mask */ 0,
964 VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
965 VM_MAP_KERNEL_FLAGS_NONE,
966 VM_KERN_MEMORY_NONE,
967 (ipc_port_t)NULL,
968 (vm_object_offset_t) 0,
969 /* copy */ FALSE,
970 /* cur_protection */ VM_PROT_READ | VM_PROT_WRITE,
971 /* max_protection */ VM_PROT_ALL,
972 /* inheritance */ VM_INHERIT_DEFAULT);
973 if ((mem_result != KERN_SUCCESS) ||
974 (seg_offset != (vm_map_offset_t) seg_data))
975 {
976 OSKextLog(/* kext */ NULL,
977 kOSKextLogErrorLevel |
978 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
979 "Can't create __LINKEDIT VM entry at %p, length 0x%llx (error 0x%x).",
980 seg_data, seg_length, mem_result);
981 goto finish;
982 }
983
984 /* And copy it back.
985 */
986 memcpy(seg_data, seg_copy, seg_length);
987
988 /* Free the copy.
989 */
990 kmem_free(kernel_map, seg_copy_offset, seg_length);
991 }
992 #else /* we are not CONFIG_KXLD */
993 #if !(__arm__ || __arm64__)
994 #error CONFIG_KXLD is expected for this arch
995 #endif
996
997 /*****
998 * Dump the LINKEDIT segment, unless keepsyms is set.
999 */
1000 if (!sKeepSymbols) {
1001 dt_segment_name = "Kernel-__LINKEDIT";
1002 if (0 == IODTGetLoaderInfo(dt_segment_name,
1003 &segment_paddress, &segment_size)) {
1004 #ifdef SECURE_KERNEL
1005 vm_offset_t vmaddr = ml_static_ptovirt((vm_offset_t)segment_paddress);
1006 bzero((void*)vmaddr, segment_size);
1007 #endif
1008 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1009 (int)segment_size);
1010 }
1011 } else {
1012 OSKextLog(/* kext */ NULL,
1013 kOSKextLogBasicLevel |
1014 kOSKextLogGeneralFlag,
1015 "keepsyms boot arg specified; keeping linkedit segment for symbols.");
1016 }
1017 #endif /* CONFIG_KXLD */
1018
1019 seg_to_remove = NULL;
1020
1021 alreadyDone = true;
1022 result = kOSReturnSuccess;
1023
1024 finish:
1025
1026 /* This must be the very last thing done before returning.
1027 */
1028 IORecursiveLockUnlock(sKextLock);
1029
1030 return result;
1031 }
1032
1033 /*********************************************************************
1034 *********************************************************************/
1035 void
1036 OSKext::flushNonloadedKexts(
1037 Boolean flushPrelinkedKexts)
1038 {
1039 OSSet * prelinkedKexts = NULL; // must release
1040 OSCollectionIterator * kextIterator = NULL; // must release
1041 OSCollectionIterator * prelinkIterator = NULL; // must release
1042 const OSSymbol * thisID = NULL; // do not release
1043 OSKext * thisKext = NULL; // do not release
1044 uint32_t count, i;
1045
1046 IORecursiveLockLock(sKextLock);
1047
1048 OSKextLog(/* kext */ NULL,
1049 kOSKextLogProgressLevel |
1050 kOSKextLogKextBookkeepingFlag,
1051 "Flushing nonloaded kexts and other unused data.");
1052
1053 OSKext::considerDestroyingLinkContext();
1054
1055 /* If we aren't flushing unused prelinked kexts, we have to put them
1056 * aside while we flush everything else so make a container for them.
1057 */
1058 if (!flushPrelinkedKexts) {
1059 prelinkedKexts = OSSet::withCapacity(0);
1060 if (!prelinkedKexts) {
1061 goto finish;
1062 }
1063 }
1064
1065 /* Set aside prelinked kexts (in-use or not) and break
1066 * any lingering inter-kext references for nonloaded kexts
1067 * so they have min. retain counts.
1068 */
1069 kextIterator = OSCollectionIterator::withCollection(sKextsByID);
1070 if (!kextIterator) {
1071 goto finish;
1072 }
1073
1074 while ((thisID = OSDynamicCast(OSSymbol,
1075 kextIterator->getNextObject()))) {
1076
1077 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
1078
1079 if (thisKext) {
1080 if (prelinkedKexts && thisKext->isPrelinked()) {
1081 prelinkedKexts->setObject(thisKext);
1082 }
1083 thisKext->flushDependencies(/* forceIfLoaded */ false);
1084 }
1085 }
1086
1087 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
1088 */
1089 sKextsByID->flushCollection();
1090
1091 /* Now put the loaded kexts back into the ID dictionary.
1092 */
1093 count = sLoadedKexts->getCount();
1094 for (i = 0; i < count; i++) {
1095 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
1096 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1097 }
1098
1099 /* Finally, put back the prelinked kexts if we saved any.
1100 */
1101 if (prelinkedKexts) {
1102 prelinkIterator = OSCollectionIterator::withCollection(prelinkedKexts);
1103 if (!prelinkIterator) {
1104 goto finish;
1105 }
1106
1107 while ((thisKext = OSDynamicCast(OSKext,
1108 prelinkIterator->getNextObject()))) {
1109
1110 sKextsByID->setObject(thisKext->getIdentifierCString(),
1111 thisKext);
1112 }
1113 }
1114
1115 finish:
1116 IORecursiveLockUnlock(sKextLock);
1117
1118 OSSafeReleaseNULL(prelinkedKexts);
1119 OSSafeReleaseNULL(kextIterator);
1120 OSSafeReleaseNULL(prelinkIterator);
1121
1122 return;
1123 }
1124
1125 /*********************************************************************
1126 *********************************************************************/
1127 /* static */
1128 void
1129 OSKext::setKextdActive(Boolean active)
1130 {
1131 IORecursiveLockLock(sKextLock);
1132 sKextdActive = active;
1133 if (sKernelRequests->getCount()) {
1134 OSKext::pingKextd();
1135 }
1136 IORecursiveLockUnlock(sKextLock);
1137
1138 return;
1139 }
1140
1141 /*********************************************************************
1142 * OSKextLib.cpp might need access to this someday but for now it's
1143 * private.
1144 *********************************************************************/
1145 extern "C" {
1146 extern void ipc_port_release_send(ipc_port_t);
1147 };
1148
1149 /* static */
1150 OSReturn
1151 OSKext::pingKextd(void)
1152 {
1153 OSReturn result = kOSReturnError;
1154 #if !NO_KEXTD
1155 mach_port_t kextd_port = IPC_PORT_NULL;
1156
1157 if (!sKextdActive) {
1158 result = kOSKextReturnDisabled; // basically unavailable
1159 goto finish;
1160 }
1161
1162 result = host_get_kextd_port(host_priv_self(), &kextd_port);
1163 if (result != KERN_SUCCESS || !IPC_PORT_VALID(kextd_port)) {
1164 OSKextLog(/* kext */ NULL,
1165 kOSKextLogErrorLevel |
1166 kOSKextLogIPCFlag,
1167 "Can't get kextd port.");
1168 goto finish;
1169 }
1170
1171 result = kextd_ping(kextd_port);
1172 if (result != KERN_SUCCESS) {
1173 OSKextLog(/* kext */ NULL,
1174 kOSKextLogErrorLevel |
1175 kOSKextLogIPCFlag,
1176 "kextd ping failed (0x%x).", (int)result);
1177 goto finish;
1178 }
1179
1180 finish:
1181 if (IPC_PORT_VALID(kextd_port)) {
1182 ipc_port_release_send(kextd_port);
1183 }
1184 #endif
1185
1186 return result;
1187 }
1188
1189 /*********************************************************************
1190 *********************************************************************/
1191 /* static */
1192 void
1193 OSKext::setDeferredLoadSucceeded(Boolean succeeded)
1194 {
1195 IORecursiveLockLock(sKextLock);
1196 sDeferredLoadSucceeded = succeeded;
1197 IORecursiveLockUnlock(sKextLock);
1198
1199 return;
1200 }
1201
1202 /*********************************************************************
1203 * Called from IOSystemShutdownNotification.
1204 *********************************************************************/
1205 /* static */
1206 void
1207 OSKext::willShutdown(void)
1208 {
1209 #if !NO_KEXTD
1210 OSReturn checkResult = kOSReturnError;
1211 #endif
1212 OSDictionary * exitRequest = NULL; // must release
1213
1214 IORecursiveLockLock(sKextLock);
1215
1216 OSKext::setLoadEnabled(false);
1217 OSKext::setUnloadEnabled(false);
1218 OSKext::setAutounloadsEnabled(false);
1219 OSKext::setKernelRequestsEnabled(false);
1220
1221 #if !NO_KEXTD
1222 OSKextLog(/* kext */ NULL,
1223 kOSKextLogProgressLevel |
1224 kOSKextLogGeneralFlag,
1225 "System shutdown; requesting immediate kextd exit.");
1226
1227 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestKextdExit,
1228 &exitRequest);
1229 if (checkResult != kOSReturnSuccess) {
1230 goto finish;
1231 }
1232 if (!sKernelRequests->setObject(exitRequest)) {
1233 goto finish;
1234 }
1235
1236 OSKext::pingKextd();
1237
1238 finish:
1239 #endif
1240
1241 IORecursiveLockUnlock(sKextLock);
1242
1243 OSSafeReleaseNULL(exitRequest);
1244 return;
1245 }
1246
1247 /*********************************************************************
1248 *********************************************************************/
1249 /* static */
1250 bool
1251 OSKext::getLoadEnabled(void)
1252 {
1253 bool result;
1254
1255 IORecursiveLockLock(sKextLock);
1256 result = sLoadEnabled;
1257 IORecursiveLockUnlock(sKextLock);
1258 return result;
1259 }
1260
1261 /*********************************************************************
1262 *********************************************************************/
1263 /* static */
1264 bool
1265 OSKext::setLoadEnabled(bool flag)
1266 {
1267 bool result;
1268
1269 IORecursiveLockLock(sKextLock);
1270 result = sLoadEnabled;
1271 sLoadEnabled = (flag ? true : false);
1272
1273 if (sLoadEnabled != result) {
1274 OSKextLog(/* kext */ NULL,
1275 kOSKextLogBasicLevel |
1276 kOSKextLogLoadFlag,
1277 "Kext loading now %sabled.", sLoadEnabled ? "en" : "dis");
1278 }
1279
1280 IORecursiveLockUnlock(sKextLock);
1281
1282 return result;
1283 }
1284
1285 /*********************************************************************
1286 *********************************************************************/
1287 /* static */
1288 bool
1289 OSKext::getUnloadEnabled(void)
1290 {
1291 bool result;
1292
1293 IORecursiveLockLock(sKextLock);
1294 result = sUnloadEnabled;
1295 IORecursiveLockUnlock(sKextLock);
1296 return result;
1297 }
1298
1299 /*********************************************************************
1300 *********************************************************************/
1301 /* static */
1302 bool
1303 OSKext::setUnloadEnabled(bool flag)
1304 {
1305 bool result;
1306
1307 IORecursiveLockLock(sKextLock);
1308 result = sUnloadEnabled;
1309 sUnloadEnabled = (flag ? true : false);
1310 IORecursiveLockUnlock(sKextLock);
1311
1312 if (sUnloadEnabled != result) {
1313 OSKextLog(/* kext */ NULL,
1314 kOSKextLogBasicLevel |
1315 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1316 "Kext unloading now %sabled.", sUnloadEnabled ? "en" : "dis");
1317 }
1318
1319 return result;
1320 }
1321
1322 /*********************************************************************
1323 * Do not call any function that takes sKextLock here!
1324 *********************************************************************/
1325 /* static */
1326 bool
1327 OSKext::getAutounloadEnabled(void)
1328 {
1329 bool result;
1330
1331 IORecursiveLockLock(sKextInnerLock);
1332 result = sAutounloadEnabled ? true : false;
1333 IORecursiveLockUnlock(sKextInnerLock);
1334 return result;
1335 }
1336
1337 /*********************************************************************
1338 * Do not call any function that takes sKextLock here!
1339 *********************************************************************/
1340 /* static */
1341 bool
1342 OSKext::setAutounloadsEnabled(bool flag)
1343 {
1344 bool result;
1345
1346 IORecursiveLockLock(sKextInnerLock);
1347
1348 result = sAutounloadEnabled;
1349 sAutounloadEnabled = (flag ? true : false);
1350 if (!sAutounloadEnabled && sUnloadCallout) {
1351 thread_call_cancel(sUnloadCallout);
1352 }
1353
1354 if (sAutounloadEnabled != result) {
1355 OSKextLog(/* kext */ NULL,
1356 kOSKextLogBasicLevel |
1357 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1358 "Kext autounloading now %sabled.",
1359 sAutounloadEnabled ? "en" : "dis");
1360 }
1361
1362 IORecursiveLockUnlock(sKextInnerLock);
1363
1364 return result;
1365 }
1366
1367 /*********************************************************************
1368 *********************************************************************/
1369 /* instance method operating on OSKext field */
1370 bool
1371 OSKext::setAutounloadEnabled(bool flag)
1372 {
1373 bool result = flags.autounloadEnabled ? true : false;
1374 flags.autounloadEnabled = flag ? 1 : 0;
1375
1376 if (result != (flag ? true : false)) {
1377 OSKextLog(this,
1378 kOSKextLogProgressLevel |
1379 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
1380 "Autounloading for kext %s now %sabled.",
1381 getIdentifierCString(),
1382 flags.autounloadEnabled ? "en" : "dis");
1383 }
1384 return result;
1385 }
1386
1387 /*********************************************************************
1388 *********************************************************************/
1389 /* static */
1390 bool
1391 OSKext::setKernelRequestsEnabled(bool flag)
1392 {
1393 bool result;
1394
1395 IORecursiveLockLock(sKextLock);
1396 result = sKernelRequestsEnabled;
1397 sKernelRequestsEnabled = flag ? true : false;
1398
1399 if (sKernelRequestsEnabled != result) {
1400 OSKextLog(/* kext */ NULL,
1401 kOSKextLogBasicLevel |
1402 kOSKextLogGeneralFlag,
1403 "Kernel requests now %sabled.",
1404 sKernelRequestsEnabled ? "en" : "dis");
1405 }
1406 IORecursiveLockUnlock(sKextLock);
1407 return result;
1408 }
1409
1410 /*********************************************************************
1411 *********************************************************************/
1412 /* static */
1413 bool
1414 OSKext::getKernelRequestsEnabled(void)
1415 {
1416 bool result;
1417
1418 IORecursiveLockLock(sKextLock);
1419 result = sKernelRequestsEnabled;
1420 IORecursiveLockUnlock(sKextLock);
1421 return result;
1422 }
1423
1424 #if PRAGMA_MARK
1425 #pragma mark Kext Life Cycle
1426 #endif
1427 /*********************************************************************
1428 *********************************************************************/
1429 OSKext *
1430 OSKext::withPrelinkedInfoDict(
1431 OSDictionary * anInfoDict,
1432 bool doCoalesedSlides)
1433 {
1434 OSKext * newKext = new OSKext;
1435
1436 if (newKext && !newKext->initWithPrelinkedInfoDict(anInfoDict, doCoalesedSlides)) {
1437 newKext->release();
1438 return NULL;
1439 }
1440
1441 return newKext;
1442 }
1443
1444 /*********************************************************************
1445 *********************************************************************/
1446 bool
1447 OSKext::initWithPrelinkedInfoDict(
1448 OSDictionary * anInfoDict,
1449 bool doCoalesedSlides)
1450 {
1451 bool result = false;
1452 OSString * kextPath = NULL; // do not release
1453 OSNumber * addressNum = NULL; // reused; do not release
1454 OSNumber * lengthNum = NULL; // reused; do not release
1455 void * data = NULL; // do not free
1456 void * srcData = NULL; // do not free
1457 OSData * prelinkedExecutable = NULL; // must release
1458 uint32_t length = 0; // reused
1459
1460 if (!super::init()) {
1461 goto finish;
1462 }
1463
1464 /* Get the path. Don't look for an arch-specific path property.
1465 */
1466 kextPath = OSDynamicCast(OSString,
1467 anInfoDict->getObject(kPrelinkBundlePathKey));
1468
1469 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
1470 goto finish;
1471 }
1472 #if KASLR_KEXT_DEBUG
1473 IOLog("kaslr: doCoalesedSlides %d kext %s \n", doCoalesedSlides, getIdentifierCString());
1474 #endif
1475
1476 /* Also get the executable's bundle-relative path if present.
1477 * Don't look for an arch-specific path property.
1478 */
1479 executableRelPath = OSDynamicCast(OSString,
1480 anInfoDict->getObject(kPrelinkExecutableRelativePathKey));
1481 if (executableRelPath) {
1482 executableRelPath->retain();
1483 }
1484
1485 /* Don't need the paths to be in the info dictionary any more.
1486 */
1487 anInfoDict->removeObject(kPrelinkBundlePathKey);
1488 anInfoDict->removeObject(kPrelinkExecutableRelativePathKey);
1489
1490 /* Create an OSData wrapper around the linked executable.
1491 */
1492 addressNum = OSDynamicCast(OSNumber,
1493 anInfoDict->getObject(kPrelinkExecutableLoadKey));
1494 if (addressNum) {
1495 lengthNum = OSDynamicCast(OSNumber,
1496 anInfoDict->getObject(kPrelinkExecutableSizeKey));
1497 if (!lengthNum) {
1498 OSKextLog(this,
1499 kOSKextLogErrorLevel |
1500 kOSKextLogArchiveFlag,
1501 "Kext %s can't find prelinked kext executable size.",
1502 getIdentifierCString());
1503 goto finish;
1504 }
1505
1506 data = (void *) ((intptr_t) (addressNum->unsigned64BitValue()) + vm_kernel_slide);
1507 length = (uint32_t) (lengthNum->unsigned32BitValue());
1508
1509 #if KASLR_KEXT_DEBUG
1510 IOLog("kaslr: unslid 0x%lx slid 0x%lx length %u - prelink executable \n",
1511 (unsigned long)VM_KERNEL_UNSLIDE(data),
1512 (unsigned long)data,
1513 length);
1514 #endif
1515
1516 anInfoDict->removeObject(kPrelinkExecutableLoadKey);
1517 anInfoDict->removeObject(kPrelinkExecutableSizeKey);
1518
1519 /* If the kext's load address differs from its source address, allocate
1520 * space in the kext map at the load address and copy the kext over.
1521 */
1522 addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject(kPrelinkExecutableSourceKey));
1523 if (addressNum) {
1524 srcData = (void *) ((intptr_t) (addressNum->unsigned64BitValue()) + vm_kernel_slide);
1525
1526 #if KASLR_KEXT_DEBUG
1527 IOLog("kaslr: unslid 0x%lx slid 0x%lx - prelink executable source \n",
1528 (unsigned long)VM_KERNEL_UNSLIDE(srcData),
1529 (unsigned long)srcData);
1530 #endif
1531
1532 if (data != srcData) {
1533 #if __LP64__
1534 kern_return_t alloc_result;
1535
1536 alloc_result = kext_alloc((vm_offset_t *)&data, length, /* fixed */ TRUE);
1537 if (alloc_result != KERN_SUCCESS) {
1538 OSKextLog(this,
1539 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1540 "Failed to allocate space for prelinked kext %s.",
1541 getIdentifierCString());
1542 goto finish;
1543 }
1544 memcpy(data, srcData, length);
1545 #else
1546 OSKextLog(this,
1547 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1548 "Error: prelinked kext %s - source and load addresses "
1549 "differ on ILP32 architecture.",
1550 getIdentifierCString());
1551 goto finish;
1552 #endif /* __LP64__ */
1553 }
1554
1555 anInfoDict->removeObject(kPrelinkExecutableSourceKey);
1556 }
1557
1558 prelinkedExecutable = OSData::withBytesNoCopy(data, length);
1559 if (!prelinkedExecutable) {
1560 OSKextLog(this,
1561 kOSKextLogErrorLevel |
1562 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1563 "Kext %s failed to create executable wrapper.",
1564 getIdentifierCString());
1565 goto finish;
1566 }
1567
1568 #if VM_MAPPED_KEXTS
1569 prelinkedExecutable->setDeallocFunction(osdata_kext_free);
1570 #else
1571 prelinkedExecutable->setDeallocFunction(osdata_phys_free);
1572 #endif
1573 setLinkedExecutable(prelinkedExecutable);
1574 addressNum = OSDynamicCast(OSNumber,
1575 anInfoDict->getObject(kPrelinkKmodInfoKey));
1576 if (!addressNum) {
1577 OSKextLog(this,
1578 kOSKextLogErrorLevel |
1579 kOSKextLogArchiveFlag,
1580 "Kext %s can't find prelinked kext kmod_info address.",
1581 getIdentifierCString());
1582 goto finish;
1583 }
1584
1585 if (addressNum->unsigned64BitValue() != 0) {
1586 kmod_info = (kmod_info_t *) (intptr_t) (addressNum->unsigned64BitValue() + vm_kernel_slide);
1587 kmod_info->address += vm_kernel_slide;
1588 #if KASLR_KEXT_DEBUG
1589 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info \n",
1590 (unsigned long)VM_KERNEL_UNSLIDE(kmod_info),
1591 (unsigned long)kmod_info);
1592 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info->address \n",
1593 (unsigned long)VM_KERNEL_UNSLIDE(kmod_info->address),
1594 (unsigned long)kmod_info->address);
1595 #endif
1596 }
1597
1598 anInfoDict->removeObject(kPrelinkKmodInfoKey);
1599 }
1600
1601 /* If the plist has a UUID for an interface, save that off.
1602 */
1603 if (isInterface()) {
1604 interfaceUUID = OSDynamicCast(OSData,
1605 anInfoDict->getObject(kPrelinkInterfaceUUIDKey));
1606 if (interfaceUUID) {
1607 interfaceUUID->retain();
1608 anInfoDict->removeObject(kPrelinkInterfaceUUIDKey);
1609 }
1610 }
1611
1612 result = slidePrelinkedExecutable(doCoalesedSlides);
1613 if (result != kOSReturnSuccess) {
1614 goto finish;
1615 }
1616
1617 if (doCoalesedSlides == false) {
1618 /* set VM protections now, wire later at kext load */
1619 result = setVMAttributes(true, false);
1620 if (result != KERN_SUCCESS) {
1621 goto finish;
1622 }
1623 }
1624
1625 flags.prelinked = true;
1626
1627 /* If we created a kext from prelink info,
1628 * we must be booting from a prelinked kernel.
1629 */
1630 sPrelinkBoot = true;
1631
1632 result = registerIdentifier();
1633
1634 finish:
1635 OSSafeReleaseNULL(prelinkedExecutable);
1636
1637 return result;
1638 }
1639
1640 /*********************************************************************
1641 *********************************************************************/
1642 /* static */
1643 void OSKext::setAllVMAttributes(void)
1644 {
1645 OSCollectionIterator * kextIterator = NULL; // must release
1646 const OSSymbol * thisID = NULL; // do not release
1647
1648 IORecursiveLockLock(sKextLock);
1649
1650 kextIterator = OSCollectionIterator::withCollection(sKextsByID);
1651 if (!kextIterator) {
1652 goto finish;
1653 }
1654
1655 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
1656 OSKext * thisKext; // do not release
1657
1658 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
1659 if (!thisKext || thisKext->isInterface() || !thisKext->declaresExecutable()) {
1660 continue;
1661 }
1662
1663 /* set VM protections now, wire later at kext load */
1664 thisKext->setVMAttributes(true, false);
1665 }
1666
1667 finish:
1668 IORecursiveLockUnlock(sKextLock);
1669 OSSafeReleaseNULL(kextIterator);
1670
1671 return;
1672 }
1673
1674 /*********************************************************************
1675 *********************************************************************/
1676 OSKext *
1677 OSKext::withBooterData(
1678 OSString * deviceTreeName,
1679 OSData * booterData)
1680 {
1681 OSKext * newKext = new OSKext;
1682
1683 if (newKext && !newKext->initWithBooterData(deviceTreeName, booterData)) {
1684 newKext->release();
1685 return NULL;
1686 }
1687
1688 return newKext;
1689 }
1690
1691 /*********************************************************************
1692 *********************************************************************/
1693 typedef struct _BooterKextFileInfo {
1694 uint32_t infoDictPhysAddr;
1695 uint32_t infoDictLength;
1696 uint32_t executablePhysAddr;
1697 uint32_t executableLength;
1698 uint32_t bundlePathPhysAddr;
1699 uint32_t bundlePathLength;
1700 } _BooterKextFileInfo;
1701
1702 bool
1703 OSKext::initWithBooterData(
1704 OSString * deviceTreeName,
1705 OSData * booterData)
1706 {
1707 bool result = false;
1708 _BooterKextFileInfo * kextFileInfo = NULL; // do not free
1709 char * infoDictAddr = NULL; // do not free
1710 void * executableAddr = NULL; // do not free
1711 char * bundlePathAddr = NULL; // do not free
1712
1713 OSObject * parsedXML = NULL; // must release
1714 OSDictionary * theInfoDict = NULL; // do not release
1715 OSString * kextPath = NULL; // must release
1716 OSString * errorString = NULL; // must release
1717 OSData * executable = NULL; // must release
1718
1719 if (!super::init()) {
1720 goto finish;
1721 }
1722
1723 kextFileInfo = (_BooterKextFileInfo *)booterData->getBytesNoCopy();
1724 if (!kextFileInfo) {
1725 OSKextLog(this,
1726 kOSKextLogErrorLevel |
1727 kOSKextLogGeneralFlag,
1728 "No booter-provided data for kext device tree entry %s.",
1729 deviceTreeName->getCStringNoCopy());
1730 goto finish;
1731 }
1732
1733 /* The info plist must exist or we can't read the kext.
1734 */
1735 if (!kextFileInfo->infoDictPhysAddr || !kextFileInfo->infoDictLength) {
1736 OSKextLog(this,
1737 kOSKextLogErrorLevel |
1738 kOSKextLogGeneralFlag,
1739 "No kext info dictionary for booter device tree entry %s.",
1740 deviceTreeName->getCStringNoCopy());
1741 goto finish;
1742 }
1743
1744 infoDictAddr = (char *)ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
1745 if (!infoDictAddr) {
1746 OSKextLog(this,
1747 kOSKextLogErrorLevel |
1748 kOSKextLogGeneralFlag,
1749 "Can't translate physical address 0x%x of kext info dictionary "
1750 "for device tree entry %s.",
1751 (int)kextFileInfo->infoDictPhysAddr,
1752 deviceTreeName->getCStringNoCopy());
1753 goto finish;
1754 }
1755
1756 parsedXML = OSUnserializeXML(infoDictAddr, &errorString);
1757 if (parsedXML) {
1758 theInfoDict = OSDynamicCast(OSDictionary, parsedXML);
1759 }
1760 if (!theInfoDict) {
1761 const char * errorCString = "(unknown error)";
1762
1763 if (errorString && errorString->getCStringNoCopy()) {
1764 errorCString = errorString->getCStringNoCopy();
1765 } else if (parsedXML) {
1766 errorCString = "not a dictionary";
1767 }
1768 OSKextLog(this,
1769 kOSKextLogErrorLevel |
1770 kOSKextLogGeneralFlag,
1771 "Error unserializing info dictionary for device tree entry %s: %s.",
1772 deviceTreeName->getCStringNoCopy(), errorCString);
1773 goto finish;
1774 }
1775
1776 /* A bundle path is not mandatory.
1777 */
1778 if (kextFileInfo->bundlePathPhysAddr && kextFileInfo->bundlePathLength) {
1779 bundlePathAddr = (char *)ml_static_ptovirt(kextFileInfo->bundlePathPhysAddr);
1780 if (!bundlePathAddr) {
1781 OSKextLog(this,
1782 kOSKextLogErrorLevel |
1783 kOSKextLogGeneralFlag,
1784 "Can't translate physical address 0x%x of kext bundle path "
1785 "for device tree entry %s.",
1786 (int)kextFileInfo->bundlePathPhysAddr,
1787 deviceTreeName->getCStringNoCopy());
1788 goto finish;
1789 }
1790 bundlePathAddr[kextFileInfo->bundlePathLength-1] = '\0'; // just in case!
1791
1792 kextPath = OSString::withCString(bundlePathAddr);
1793 if (!kextPath) {
1794 OSKextLog(this,
1795 kOSKextLogErrorLevel |
1796 kOSKextLogGeneralFlag,
1797 "Failed to create wrapper for device tree entry %s kext path %s.",
1798 deviceTreeName->getCStringNoCopy(), bundlePathAddr);
1799 goto finish;
1800 }
1801 }
1802
1803 if (!setInfoDictionaryAndPath(theInfoDict, kextPath)) {
1804 goto finish;
1805 }
1806
1807 /* An executable is not mandatory.
1808 */
1809 if (kextFileInfo->executablePhysAddr && kextFileInfo->executableLength) {
1810 executableAddr = (void *)ml_static_ptovirt(kextFileInfo->executablePhysAddr);
1811 if (!executableAddr) {
1812 OSKextLog(this,
1813 kOSKextLogErrorLevel |
1814 kOSKextLogGeneralFlag,
1815 "Can't translate physical address 0x%x of kext executable "
1816 "for device tree entry %s.",
1817 (int)kextFileInfo->executablePhysAddr,
1818 deviceTreeName->getCStringNoCopy());
1819 goto finish;
1820 }
1821
1822 executable = OSData::withBytesNoCopy(executableAddr,
1823 kextFileInfo->executableLength);
1824 if (!executable) {
1825 OSKextLog(this,
1826 kOSKextLogErrorLevel |
1827 kOSKextLogGeneralFlag,
1828 "Failed to create executable wrapper for device tree entry %s.",
1829 deviceTreeName->getCStringNoCopy());
1830 goto finish;
1831 }
1832
1833 /* A kext with an executable needs to retain the whole booterData
1834 * object to keep the executable in memory.
1835 */
1836 if (!setExecutable(executable, booterData)) {
1837 OSKextLog(this,
1838 kOSKextLogErrorLevel |
1839 kOSKextLogGeneralFlag,
1840 "Failed to set kext executable for device tree entry %s.",
1841 deviceTreeName->getCStringNoCopy());
1842 goto finish;
1843 }
1844 }
1845
1846 result = registerIdentifier();
1847
1848 finish:
1849 OSSafeReleaseNULL(parsedXML);
1850 OSSafeReleaseNULL(kextPath);
1851 OSSafeReleaseNULL(errorString);
1852 OSSafeReleaseNULL(executable);
1853
1854 return result;
1855 }
1856
1857 /*********************************************************************
1858 *********************************************************************/
1859 bool
1860 OSKext::registerIdentifier(void)
1861 {
1862 bool result = false;
1863 OSKext * existingKext = NULL; // do not release
1864 bool existingIsLoaded = false;
1865 bool existingIsPrelinked = false;
1866 OSKextVersion newVersion = -1;
1867 OSKextVersion existingVersion = -1;
1868 char newVersionCString[kOSKextVersionMaxLength];
1869 char existingVersionCString[kOSKextVersionMaxLength];
1870 OSData * newUUID = NULL; // must release
1871 OSData * existingUUID = NULL; // must release
1872
1873 IORecursiveLockLock(sKextLock);
1874
1875 /* Get the new kext's version for checks & log messages.
1876 */
1877 newVersion = getVersion();
1878 OSKextVersionGetString(newVersion, newVersionCString,
1879 kOSKextVersionMaxLength);
1880
1881 /* If we don't have an existing kext with this identifier,
1882 * just record the new kext and we're done!
1883 */
1884 existingKext = OSDynamicCast(OSKext, sKextsByID->getObject(bundleID));
1885 if (!existingKext) {
1886 sKextsByID->setObject(bundleID, this);
1887 result = true;
1888 goto finish;
1889 }
1890
1891 /* Get the existing kext's version for checks & log messages.
1892 */
1893 existingVersion = existingKext->getVersion();
1894 OSKextVersionGetString(existingVersion,
1895 existingVersionCString, kOSKextVersionMaxLength);
1896
1897 existingIsLoaded = existingKext->isLoaded();
1898 existingIsPrelinked = existingKext->isPrelinked();
1899
1900 /* If we have a kext with this identifier that's already loaded/prelinked,
1901 * we can't use the new one, but let's be really thorough and check how
1902 * the two are related for a precise diagnostic log message.
1903 *
1904 * Note that user space can't find out about nonloaded prelinked kexts,
1905 * so in this case we log a message when new & existing are equivalent
1906 * at the step rather than warning level, because we are always going
1907 * be getting a copy of the kext in the user load request mkext.
1908 */
1909 if (existingIsLoaded || existingIsPrelinked) {
1910 bool sameVersion = (newVersion == existingVersion);
1911 bool sameExecutable = true; // assume true unless we have UUIDs
1912
1913 /* Only get the UUID if the existing kext is loaded. Doing so
1914 * might have to uncompress an mkext executable and we shouldn't
1915 * take that hit when neither kext is loaded.
1916 */
1917 newUUID = copyUUID();
1918 existingUUID = existingKext->copyUUID();
1919
1920 /* I'm entirely too paranoid about checking equivalence of executables,
1921 * but I remember nasty problems with it in the past.
1922 *
1923 * - If we have UUIDs for both kexts, compare them.
1924 * - If only one kext has a UUID, they're definitely different.
1925 */
1926 if (newUUID && existingUUID) {
1927 sameExecutable = newUUID->isEqualTo(existingUUID);
1928 } else if (newUUID || existingUUID) {
1929 sameExecutable = false;
1930 }
1931
1932 if (!newUUID && !existingUUID) {
1933
1934 /* If there are no UUIDs, we can't really tell that the executables
1935 * are *different* without a lot of work; the loaded kext's
1936 * unrelocated executable is no longer around (and we never had it
1937 * in-kernel for a prelinked kext). We certainly don't want to do
1938 * a whole fake link for the new kext just to compare, either.
1939 */
1940
1941 OSKextVersionGetString(version, newVersionCString,
1942 sizeof(newVersionCString));
1943 OSKextLog(this,
1944 kOSKextLogWarningLevel |
1945 kOSKextLogKextBookkeepingFlag,
1946 "Notice - new kext %s, v%s matches %s kext "
1947 "but can't determine if executables are the same (no UUIDs).",
1948 getIdentifierCString(),
1949 newVersionCString,
1950 (existingIsLoaded ? "loaded" : "prelinked"));
1951 }
1952
1953 if (sameVersion && sameExecutable) {
1954 OSKextLog(this,
1955 (existingIsLoaded ? kOSKextLogWarningLevel : kOSKextLogStepLevel) |
1956 kOSKextLogKextBookkeepingFlag,
1957 "Refusing new kext %s, v%s: a %s copy is already present "
1958 "(same version and executable).",
1959 getIdentifierCString(), newVersionCString,
1960 (existingIsLoaded ? "loaded" : "prelinked"));
1961 } else {
1962 if (!sameVersion) {
1963 /* This condition is significant so log it under warnings.
1964 */
1965 OSKextLog(this,
1966 kOSKextLogWarningLevel |
1967 kOSKextLogKextBookkeepingFlag,
1968 "Refusing new kext %s, v%s: already have %s v%s.",
1969 getIdentifierCString(),
1970 newVersionCString,
1971 (existingIsLoaded ? "loaded" : "prelinked"),
1972 existingVersionCString);
1973 } else {
1974 /* This condition is significant so log it under warnings.
1975 */
1976 OSKextLog(this,
1977 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
1978 "Refusing new kext %s, v%s: a %s copy with a different "
1979 "executable UUID is already present.",
1980 getIdentifierCString(), newVersionCString,
1981 (existingIsLoaded ? "loaded" : "prelinked"));
1982 }
1983 }
1984 goto finish;
1985 } /* if (existingIsLoaded || existingIsPrelinked) */
1986
1987 /* We have two nonloaded/nonprelinked kexts, so our decision depends on whether
1988 * user loads are happening or if we're still in early boot. User agents are
1989 * supposed to resolve dependencies topside and include only the exact
1990 * kexts needed; so we always accept the new kext (in fact we should never
1991 * see an older unloaded copy hanging around).
1992 */
1993 if (sUserLoadsActive) {
1994 sKextsByID->setObject(bundleID, this);
1995 result = true;
1996
1997 OSKextLog(this,
1998 kOSKextLogStepLevel |
1999 kOSKextLogKextBookkeepingFlag,
2000 "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
2001 getIdentifierCString(),
2002 existingVersionCString,
2003 newVersionCString);
2004
2005 goto finish;
2006 }
2007
2008 /* During early boot, the kext with the highest version always wins out.
2009 * Prelinked kernels will never hit this, but mkexts and booter-read
2010 * kexts might have duplicates.
2011 */
2012 if (newVersion > existingVersion) {
2013 sKextsByID->setObject(bundleID, this);
2014 result = true;
2015
2016 OSKextLog(this,
2017 kOSKextLogStepLevel |
2018 kOSKextLogKextBookkeepingFlag,
2019 "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
2020 existingVersionCString,
2021 getIdentifierCString(),
2022 newVersionCString);
2023
2024 } else {
2025 OSKextLog(this,
2026 kOSKextLogStepLevel |
2027 kOSKextLogKextBookkeepingFlag,
2028 "Kext %s is already registered with a higher/same version (v%s); "
2029 "dropping newly-added (v%s).",
2030 getIdentifierCString(),
2031 existingVersionCString,
2032 newVersionCString);
2033 }
2034
2035 /* result has been set appropriately by now. */
2036
2037 finish:
2038
2039 IORecursiveLockUnlock(sKextLock);
2040
2041 if (result) {
2042 OSKextLog(this,
2043 kOSKextLogStepLevel |
2044 kOSKextLogKextBookkeepingFlag,
2045 "Kext %s, v%s registered and available for loading.",
2046 getIdentifierCString(), newVersionCString);
2047 }
2048
2049 OSSafeReleaseNULL(newUUID);
2050 OSSafeReleaseNULL(existingUUID);
2051
2052 return result;
2053 }
2054
2055 /*********************************************************************
2056 * Does the bare minimum validation to look up a kext.
2057 * All other validation is done on the spot as needed.
2058 **********************************************************************/
2059 bool
2060 OSKext::setInfoDictionaryAndPath(
2061 OSDictionary * aDictionary,
2062 OSString * aPath)
2063 {
2064 bool result = false;
2065 OSString * bundleIDString = NULL; // do not release
2066 OSString * versionString = NULL; // do not release
2067 OSString * compatibleVersionString = NULL; // do not release
2068 const char * versionCString = NULL; // do not free
2069 const char * compatibleVersionCString = NULL; // do not free
2070 OSBoolean * scratchBool = NULL; // do not release
2071 OSDictionary * scratchDict = NULL; // do not release
2072
2073 if (infoDict) {
2074 panic("Attempt to set info dictionary on a kext "
2075 "that already has one (%s).",
2076 getIdentifierCString());
2077 }
2078
2079 if (!aDictionary || !OSDynamicCast(OSDictionary, aDictionary)) {
2080 goto finish;
2081 }
2082
2083 infoDict = aDictionary;
2084 infoDict->retain();
2085
2086 /* Check right away if the info dictionary has any log flags.
2087 */
2088 scratchBool = OSDynamicCast(OSBoolean,
2089 getPropertyForHostArch(kOSBundleEnableKextLoggingKey));
2090 if (scratchBool == kOSBooleanTrue) {
2091 flags.loggingEnabled = 1;
2092 }
2093
2094 /* The very next thing to get is the bundle identifier. Unlike
2095 * in user space, a kext with no bundle identifier gets axed
2096 * immediately.
2097 */
2098 bundleIDString = OSDynamicCast(OSString,
2099 getPropertyForHostArch(kCFBundleIdentifierKey));
2100 if (!bundleIDString) {
2101 OSKextLog(this,
2102 kOSKextLogErrorLevel |
2103 kOSKextLogValidationFlag,
2104 "CFBundleIdentifier missing/invalid type in kext %s.",
2105 aPath ? aPath->getCStringNoCopy() : "(unknown)");
2106 goto finish;
2107 }
2108 bundleID = OSSymbol::withString(bundleIDString);
2109 if (!bundleID) {
2110 OSKextLog(this,
2111 kOSKextLogErrorLevel |
2112 kOSKextLogValidationFlag,
2113 "Can't copy bundle identifier as symbol for kext %s.",
2114 bundleIDString->getCStringNoCopy());
2115 goto finish;
2116 }
2117
2118 /* Save the path if we got one (it should always be available but it's
2119 * just something nice to have for bookkeeping).
2120 */
2121 if (aPath) {
2122 path = aPath;
2123 path->retain();
2124 }
2125
2126 /*****
2127 * Minimal validation to initialize. We'll do other validation on the spot.
2128 */
2129 if (bundleID->getLength() >= KMOD_MAX_NAME) {
2130 OSKextLog(this,
2131 kOSKextLogErrorLevel |
2132 kOSKextLogValidationFlag,
2133 "Kext %s error - CFBundleIdentifier over max length %d.",
2134 getIdentifierCString(), KMOD_MAX_NAME - 1);
2135 goto finish;
2136 }
2137
2138 version = compatibleVersion = -1;
2139
2140 versionString = OSDynamicCast(OSString,
2141 getPropertyForHostArch(kCFBundleVersionKey));
2142 if (!versionString) {
2143 OSKextLog(this,
2144 kOSKextLogErrorLevel |
2145 kOSKextLogValidationFlag,
2146 "Kext %s error - CFBundleVersion missing/invalid type.",
2147 getIdentifierCString());
2148 goto finish;
2149 }
2150 versionCString = versionString->getCStringNoCopy();
2151 version = OSKextParseVersionString(versionCString);
2152 if (version < 0) {
2153 OSKextLog(this,
2154 kOSKextLogErrorLevel |
2155 kOSKextLogValidationFlag,
2156 "Kext %s error - CFBundleVersion bad value '%s'.",
2157 getIdentifierCString(), versionCString);
2158 goto finish;
2159 }
2160
2161 compatibleVersion = -1; // set to illegal value for kexts that don't have
2162
2163 compatibleVersionString = OSDynamicCast(OSString,
2164 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
2165 if (compatibleVersionString) {
2166 compatibleVersionCString = compatibleVersionString->getCStringNoCopy();
2167 compatibleVersion = OSKextParseVersionString(compatibleVersionCString);
2168 if (compatibleVersion < 0) {
2169 OSKextLog(this,
2170 kOSKextLogErrorLevel |
2171 kOSKextLogValidationFlag,
2172 "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
2173 getIdentifierCString(), compatibleVersionCString);
2174 goto finish;
2175 }
2176
2177 if (compatibleVersion > version) {
2178 OSKextLog(this,
2179 kOSKextLogErrorLevel |
2180 kOSKextLogValidationFlag,
2181 "Kext %s error - %s %s > %s %s (must be <=).",
2182 getIdentifierCString(),
2183 kOSBundleCompatibleVersionKey, compatibleVersionCString,
2184 kCFBundleVersionKey, versionCString);
2185 goto finish;
2186 }
2187 }
2188
2189 /* Check to see if this kext is in exclude list */
2190 if ( isInExcludeList() ) {
2191 OSKextLog(this,
2192 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2193 "Kext %s is in exclude list, not loadable",
2194 getIdentifierCString());
2195 goto finish;
2196 }
2197
2198 /* Set flags for later use if the infoDict gets flushed. We only
2199 * check for true values, not false ones(!)
2200 */
2201 scratchBool = OSDynamicCast(OSBoolean,
2202 getPropertyForHostArch(kOSBundleIsInterfaceKey));
2203 if (scratchBool == kOSBooleanTrue) {
2204 flags.interface = 1;
2205 }
2206
2207 scratchBool = OSDynamicCast(OSBoolean,
2208 getPropertyForHostArch(kOSKernelResourceKey));
2209 if (scratchBool == kOSBooleanTrue) {
2210 flags.kernelComponent = 1;
2211 flags.interface = 1; // xxx - hm. the kernel itself isn't an interface...
2212 flags.started = 1;
2213
2214 /* A kernel component has one implicit dependency on the kernel.
2215 */
2216 flags.hasAllDependencies = 1;
2217 }
2218
2219 /* Make sure common string values in personalities are uniqued to OSSymbols.
2220 */
2221 scratchDict = OSDynamicCast(OSDictionary,
2222 getPropertyForHostArch(kIOKitPersonalitiesKey));
2223 if (scratchDict) {
2224 uniquePersonalityProperties(scratchDict);
2225 }
2226
2227 result = true;
2228
2229 finish:
2230
2231 return result;
2232 }
2233
2234 /*********************************************************************
2235 * Not used for prelinked kernel boot as there is no unrelocated
2236 * executable.
2237 *********************************************************************/
2238 bool
2239 OSKext::setExecutable(
2240 OSData * anExecutable,
2241 OSData * externalData,
2242 bool externalDataIsMkext)
2243 {
2244 bool result = false;
2245 const char * executableKey = NULL; // do not free
2246
2247 if (!anExecutable) {
2248 infoDict->removeObject(_kOSKextExecutableKey);
2249 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
2250 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
2251 result = true;
2252 goto finish;
2253 }
2254
2255 if (infoDict->getObject(_kOSKextExecutableKey) ||
2256 infoDict->getObject(_kOSKextMkextExecutableReferenceKey)) {
2257
2258 panic("Attempt to set an executable on a kext "
2259 "that already has one (%s).",
2260 getIdentifierCString());
2261 goto finish;
2262 }
2263
2264 if (externalDataIsMkext) {
2265 executableKey = _kOSKextMkextExecutableReferenceKey;
2266 } else {
2267 executableKey = _kOSKextExecutableKey;
2268 }
2269
2270 if (anExecutable) {
2271 infoDict->setObject(executableKey, anExecutable);
2272 if (externalData) {
2273 infoDict->setObject(_kOSKextExecutableExternalDataKey, externalData);
2274 }
2275 }
2276
2277 result = true;
2278
2279 finish:
2280 return result;
2281 }
2282
2283 /*********************************************************************
2284 *********************************************************************/
2285 static void
2286 uniqueStringPlistProperty(OSDictionary * dict, const char * key)
2287 {
2288 OSString * stringValue = NULL; // do not release
2289 const OSSymbol * symbolValue = NULL; // must release
2290
2291 stringValue = OSDynamicCast(OSString, dict->getObject(key));
2292 if (!stringValue) {
2293 goto finish;
2294 }
2295
2296 symbolValue = OSSymbol::withString(stringValue);
2297 if (!symbolValue) {
2298 goto finish;
2299 }
2300
2301 dict->setObject(key, symbolValue);
2302
2303 finish:
2304 if (symbolValue) symbolValue->release();
2305
2306 return;
2307 }
2308
2309 /*********************************************************************
2310 *********************************************************************/
2311 static void
2312 uniqueStringPlistProperty(OSDictionary * dict, const OSString * key)
2313 {
2314 OSString * stringValue = NULL; // do not release
2315 const OSSymbol * symbolValue = NULL; // must release
2316
2317 stringValue = OSDynamicCast(OSString, dict->getObject(key));
2318 if (!stringValue) {
2319 goto finish;
2320 }
2321
2322 symbolValue = OSSymbol::withString(stringValue);
2323 if (!symbolValue) {
2324 goto finish;
2325 }
2326
2327 dict->setObject(key, symbolValue);
2328
2329 finish:
2330 if (symbolValue) symbolValue->release();
2331
2332 return;
2333 }
2334
2335 /*********************************************************************
2336 * Replace common personality property values with uniqued instances
2337 * to save on wired memory.
2338 *********************************************************************/
2339 /* static */
2340 void
2341 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict)
2342 {
2343 /* Properties every personality has.
2344 */
2345 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKey);
2346 uniqueStringPlistProperty(personalityDict, kIOProviderClassKey);
2347 uniqueStringPlistProperty(personalityDict, gIOClassKey);
2348
2349 /* Other commonly used properties.
2350 */
2351 uniqueStringPlistProperty(personalityDict, gIOMatchCategoryKey);
2352 uniqueStringPlistProperty(personalityDict, gIOResourceMatchKey);
2353 uniqueStringPlistProperty(personalityDict, gIOUserClientClassKey);
2354
2355 uniqueStringPlistProperty(personalityDict, "HIDDefaultBehavior");
2356 uniqueStringPlistProperty(personalityDict, "HIDPointerAccelerationType");
2357 uniqueStringPlistProperty(personalityDict, "HIDRemoteControlType");
2358 uniqueStringPlistProperty(personalityDict, "HIDScrollAccelerationType");
2359 uniqueStringPlistProperty(personalityDict, "IOPersonalityPublisher");
2360 uniqueStringPlistProperty(personalityDict, "Physical Interconnect");
2361 uniqueStringPlistProperty(personalityDict, "Physical Interconnect Location");
2362 uniqueStringPlistProperty(personalityDict, "Vendor");
2363 uniqueStringPlistProperty(personalityDict, "Vendor Identification");
2364 uniqueStringPlistProperty(personalityDict, "Vendor Name");
2365 uniqueStringPlistProperty(personalityDict, "bConfigurationValue");
2366 uniqueStringPlistProperty(personalityDict, "bInterfaceNumber");
2367 uniqueStringPlistProperty(personalityDict, "idProduct");
2368
2369 return;
2370 }
2371
2372 /*********************************************************************
2373 *********************************************************************/
2374 void
2375 OSKext::free(void)
2376 {
2377 if (isLoaded()) {
2378 panic("Attempt to free loaded kext %s.", getIdentifierCString());
2379 }
2380
2381 OSSafeReleaseNULL(infoDict);
2382 OSSafeReleaseNULL(bundleID);
2383 OSSafeReleaseNULL(path);
2384 OSSafeReleaseNULL(executableRelPath);
2385 OSSafeReleaseNULL(dependencies);
2386 OSSafeReleaseNULL(linkedExecutable);
2387 OSSafeReleaseNULL(metaClasses);
2388 OSSafeReleaseNULL(interfaceUUID);
2389
2390 if (isInterface() && kmod_info) {
2391 kfree(kmod_info, sizeof(kmod_info_t));
2392 }
2393
2394 super::free();
2395 return;
2396 }
2397
2398 #if PRAGMA_MARK
2399 #pragma mark Mkext files
2400 #endif
2401 /*********************************************************************
2402 *********************************************************************/
2403 OSReturn
2404 OSKext::readMkextArchive(OSData * mkextData,
2405 uint32_t * checksumPtr)
2406 {
2407 OSReturn result = kOSKextReturnBadData;
2408 uint32_t mkextLength = 0;
2409 mkext_header * mkextHeader = 0; // do not free
2410 uint32_t mkextVersion = 0;
2411
2412 /* Note default return of kOSKextReturnBadData above.
2413 */
2414 mkextLength = mkextData->getLength();
2415 if (mkextLength < sizeof(mkext_basic_header)) {
2416 OSKextLog(/* kext */ NULL,
2417 kOSKextLogErrorLevel |
2418 kOSKextLogArchiveFlag,
2419 "Mkext archive too small to be valid.");
2420 goto finish;
2421 }
2422
2423 mkextHeader = (mkext_header *)mkextData->getBytesNoCopy();
2424
2425 if (MKEXT_GET_MAGIC(mkextHeader) != MKEXT_MAGIC ||
2426 MKEXT_GET_SIGNATURE(mkextHeader) != MKEXT_SIGN) {
2427 OSKextLog(/* kext */ NULL,
2428 kOSKextLogErrorLevel |
2429 kOSKextLogArchiveFlag,
2430 "Mkext archive has invalid magic or signature.");
2431 goto finish;
2432 }
2433
2434 if (MKEXT_GET_LENGTH(mkextHeader) != mkextLength) {
2435 OSKextLog(/* kext */ NULL,
2436 kOSKextLogErrorLevel |
2437 kOSKextLogArchiveFlag,
2438 "Mkext archive recorded length doesn't match actual file length.");
2439 goto finish;
2440 }
2441
2442 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
2443
2444 if (mkextVersion == MKEXT_VERS_2) {
2445 result = OSKext::readMkext2Archive(mkextData, NULL, checksumPtr);
2446 } else {
2447 OSKextLog(/* kext */ NULL,
2448 kOSKextLogErrorLevel |
2449 kOSKextLogArchiveFlag,
2450 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion);
2451 result = kOSKextReturnUnsupported;
2452 }
2453
2454 finish:
2455 return result;
2456 }
2457
2458 /*********************************************************************
2459 * Assumes magic, signature, version, length have been checked.
2460 * xxx - need to add further bounds checking for each file entry
2461 *
2462 * Should keep track of all kexts created so far, and if we hit a
2463 * fatal error halfway through, remove those kexts. If we've dropped
2464 * an older version that had already been read, whoops! Might want to
2465 * add a level of buffering?
2466 *********************************************************************/
2467 /* static */
2468 OSReturn
2469 OSKext::readMkext2Archive(
2470 OSData * mkextData,
2471 OSDictionary ** mkextPlistOut,
2472 uint32_t * checksumPtr)
2473 {
2474 OSReturn result = kOSReturnError;
2475 uint32_t mkextLength;
2476 mkext2_header * mkextHeader = NULL; // do not free
2477 void * mkextEnd = NULL; // do not free
2478 uint32_t mkextVersion;
2479 uint8_t * crc_address = NULL;
2480 uint32_t checksum;
2481 uint32_t mkextPlistOffset;
2482 uint32_t mkextPlistCompressedSize;
2483 char * mkextPlistEnd = NULL; // do not free
2484 uint32_t mkextPlistFullSize;
2485 OSString * errorString = NULL; // must release
2486 OSData * mkextPlistUncompressedData = NULL; // must release
2487 const char * mkextPlistDataBuffer = NULL; // do not free
2488 OSObject * parsedXML = NULL; // must release
2489 OSDictionary * mkextPlist = NULL; // do not release
2490 OSArray * mkextInfoDictArray = NULL; // do not release
2491 uint32_t count, i;
2492
2493 mkextLength = mkextData->getLength();
2494 mkextHeader = (mkext2_header *)mkextData->getBytesNoCopy();
2495 mkextEnd = (char *)mkextHeader + mkextLength;
2496 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
2497
2498 crc_address = (u_int8_t *)&mkextHeader->version;
2499 checksum = mkext_adler32(crc_address,
2500 (uintptr_t)mkextHeader +
2501 MKEXT_GET_LENGTH(mkextHeader) - (uintptr_t)crc_address);
2502
2503 if (MKEXT_GET_CHECKSUM(mkextHeader) != checksum) {
2504 OSKextLog(/* kext */ NULL,
2505 kOSKextLogErrorLevel |
2506 kOSKextLogArchiveFlag,
2507 "Mkext archive has bad checksum.");
2508 result = kOSKextReturnBadData;
2509 goto finish;
2510 }
2511
2512 if (checksumPtr) {
2513 *checksumPtr = checksum;
2514 }
2515
2516 /* Check that the CPU type & subtype match that of the running kernel. */
2517 if (MKEXT_GET_CPUTYPE(mkextHeader) == (UInt32)CPU_TYPE_ANY) {
2518 OSKextLog(/* kext */ NULL,
2519 kOSKextLogErrorLevel |
2520 kOSKextLogArchiveFlag,
2521 "Mkext archive must have a specific CPU type.");
2522 result = kOSKextReturnBadData;
2523 goto finish;
2524 } else {
2525 if ((UInt32)_mh_execute_header.cputype !=
2526 MKEXT_GET_CPUTYPE(mkextHeader)) {
2527
2528 OSKextLog(/* kext */ NULL,
2529 kOSKextLogErrorLevel |
2530 kOSKextLogArchiveFlag,
2531 "Mkext archive does not match the running kernel's CPU type.");
2532 result = kOSKextReturnArchNotFound;
2533 goto finish;
2534 }
2535 }
2536
2537 mkextPlistOffset = MKEXT2_GET_PLIST(mkextHeader);
2538 mkextPlistCompressedSize = MKEXT2_GET_PLIST_COMPSIZE(mkextHeader);
2539 mkextPlistEnd = (char *)mkextHeader + mkextPlistOffset +
2540 mkextPlistCompressedSize;
2541 if (mkextPlistEnd > mkextEnd) {
2542 OSKextLog(/* kext */ NULL,
2543 kOSKextLogErrorLevel |
2544 kOSKextLogArchiveFlag,
2545 "Mkext archive file overrun.");
2546 result = kOSKextReturnBadData;
2547 }
2548
2549 mkextPlistFullSize = MKEXT2_GET_PLIST_FULLSIZE(mkextHeader);
2550 if (mkextPlistCompressedSize) {
2551 mkextPlistUncompressedData = sKernelKext->extractMkext2FileData(
2552 (UInt8 *)mkextHeader + mkextPlistOffset,
2553 "plist",
2554 mkextPlistCompressedSize, mkextPlistFullSize);
2555 if (!mkextPlistUncompressedData) {
2556 goto finish;
2557 }
2558 mkextPlistDataBuffer = (const char *)
2559 mkextPlistUncompressedData->getBytesNoCopy();
2560 } else {
2561 mkextPlistDataBuffer = (const char *)mkextHeader + mkextPlistOffset;
2562 }
2563
2564 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
2565 */
2566 parsedXML = OSUnserializeXML(mkextPlistDataBuffer, &errorString);
2567 if (parsedXML) {
2568 mkextPlist = OSDynamicCast(OSDictionary, parsedXML);
2569 }
2570 if (!mkextPlist) {
2571 const char * errorCString = "(unknown error)";
2572
2573 if (errorString && errorString->getCStringNoCopy()) {
2574 errorCString = errorString->getCStringNoCopy();
2575 } else if (parsedXML) {
2576 errorCString = "not a dictionary";
2577 }
2578 OSKextLog(/* kext */ NULL,
2579 kOSKextLogErrorLevel |
2580 kOSKextLogArchiveFlag,
2581 "Error unserializing mkext plist: %s.", errorCString);
2582 goto finish;
2583 }
2584
2585 /* If the caller needs the plist, hand it back and retain it.
2586 * (This function releases it at the end.)
2587 */
2588 if (mkextPlistOut) {
2589 *mkextPlistOut = mkextPlist;
2590 (*mkextPlistOut)->retain();
2591 }
2592
2593 mkextInfoDictArray = OSDynamicCast(OSArray,
2594 mkextPlist->getObject(kMKEXTInfoDictionariesKey));
2595 if (!mkextInfoDictArray) {
2596 OSKextLog(/* kext */ NULL,
2597 kOSKextLogErrorLevel |
2598 kOSKextLogArchiveFlag,
2599 "Mkext archive contains no kext info dictionaries.");
2600 goto finish;
2601 }
2602
2603 count = mkextInfoDictArray->getCount();
2604 for (i = 0; i < count; i++) {
2605 OSDictionary * infoDict;
2606
2607
2608 infoDict = OSDynamicCast(OSDictionary,
2609 mkextInfoDictArray->getObject(i));
2610
2611 /* Create the kext for the entry, then release it, because the
2612 * kext system keeps them around until explicitly removed.
2613 * Any creation/registration failures are already logged for us.
2614 */
2615 if (infoDict) {
2616 OSKext * newKext = OSKext::withMkext2Info(infoDict, mkextData);
2617 OSSafeReleaseNULL(newKext);
2618 }
2619 }
2620
2621 /* Even if we didn't keep any kexts from the mkext, we may have a load
2622 * request to process, so we are successful (no errors occurred).
2623 */
2624 result = kOSReturnSuccess;
2625
2626 finish:
2627
2628 OSSafeReleaseNULL(parsedXML);
2629 OSSafeReleaseNULL(mkextPlistUncompressedData);
2630 OSSafeReleaseNULL(errorString);
2631
2632 return result;
2633 }
2634
2635 /*********************************************************************
2636 *********************************************************************/
2637 /* static */
2638 OSKext *
2639 OSKext::withMkext2Info(
2640 OSDictionary * anInfoDict,
2641 OSData * mkextData)
2642 {
2643 OSKext * newKext = new OSKext;
2644
2645 if (newKext && !newKext->initWithMkext2Info(anInfoDict, mkextData)) {
2646 newKext->release();
2647 return NULL;
2648 }
2649
2650 return newKext;
2651 }
2652
2653 /*********************************************************************
2654 *********************************************************************/
2655 bool
2656 OSKext::initWithMkext2Info(
2657 OSDictionary * anInfoDict,
2658 OSData * mkextData)
2659 {
2660 bool result = false;
2661 OSString * kextPath = NULL; // do not release
2662 OSNumber * executableOffsetNum = NULL; // do not release
2663 OSCollectionIterator * iterator = NULL; // must release
2664 OSData * executable = NULL; // must release
2665
2666 if (anInfoDict == NULL || !super::init()) {
2667 goto finish;
2668 }
2669
2670 /* Get the path. Don't look for an arch-specific path property.
2671 */
2672 kextPath = OSDynamicCast(OSString,
2673 anInfoDict->getObject(kMKEXTBundlePathKey));
2674
2675 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
2676 goto finish;
2677 }
2678
2679 /* If we have a path to the executable, save it.
2680 */
2681 executableRelPath = OSDynamicCast(OSString,
2682 anInfoDict->getObject(kMKEXTExecutableRelativePathKey));
2683 if (executableRelPath) {
2684 executableRelPath->retain();
2685 }
2686
2687 /* Don't need the paths to be in the info dictionary any more.
2688 */
2689 anInfoDict->removeObject(kMKEXTBundlePathKey);
2690 anInfoDict->removeObject(kMKEXTExecutableRelativePathKey);
2691
2692 executableOffsetNum = OSDynamicCast(OSNumber,
2693 infoDict->getObject(kMKEXTExecutableKey));
2694 if (executableOffsetNum) {
2695 executable = createMkext2FileEntry(mkextData,
2696 executableOffsetNum, "executable");
2697 infoDict->removeObject(kMKEXTExecutableKey);
2698 if (!executable) {
2699 goto finish;
2700 }
2701 if (!setExecutable(executable, mkextData, true)) {
2702 goto finish;
2703 }
2704 }
2705
2706 result = registerIdentifier();
2707
2708 finish:
2709
2710 OSSafeReleaseNULL(executable);
2711 OSSafeReleaseNULL(iterator);
2712 return result;
2713 }
2714
2715 /*********************************************************************
2716 *********************************************************************/
2717 OSData *
2718 OSKext::createMkext2FileEntry(
2719 OSData * mkextData,
2720 OSNumber * offsetNum,
2721 const char * name)
2722 {
2723 OSData * result = NULL;
2724 MkextEntryRef entryRef;
2725 uint8_t * mkextBuffer = (uint8_t *)mkextData->getBytesNoCopy();
2726 uint32_t entryOffset = offsetNum->unsigned32BitValue();
2727
2728 result = OSData::withCapacity(sizeof(entryRef));
2729 if (!result) {
2730 goto finish;
2731 }
2732
2733 entryRef.mkext = (mkext_basic_header *)mkextBuffer;
2734 entryRef.fileinfo = mkextBuffer + entryOffset;
2735 if (!result->appendBytes(&entryRef, sizeof(entryRef))) {
2736 OSSafeReleaseNULL(result);
2737 goto finish;
2738 }
2739
2740 finish:
2741 if (!result) {
2742 OSKextLog(this,
2743 kOSKextLogErrorLevel |
2744 kOSKextLogArchiveFlag,
2745 "Can't create wrapper for mkext file entry '%s' of kext %s.",
2746 name, getIdentifierCString());
2747 }
2748 return result;
2749 }
2750
2751 /*********************************************************************
2752 *********************************************************************/
2753 extern "C" {
2754 static void * z_alloc(void *, u_int items, u_int size);
2755 static void z_free(void *, void *ptr);
2756
2757 typedef struct z_mem {
2758 uint32_t alloc_size;
2759 uint8_t data[0];
2760 } z_mem;
2761
2762 /*
2763 * Space allocation and freeing routines for use by zlib routines.
2764 */
2765 void *
2766 z_alloc(void * notused __unused, u_int num_items, u_int size)
2767 {
2768 void * result = NULL;
2769 z_mem * zmem = NULL;
2770
2771 uint64_t total = ((uint64_t)num_items) * ((uint64_t)size);
2772 //Check for overflow due to multiplication
2773 if (total > UINT32_MAX){
2774 panic("z_alloc(%p, %x, %x): overflow caused by %x * %x\n",
2775 notused, num_items, size, num_items, size);
2776 }
2777
2778 uint64_t allocSize64 = total + ((uint64_t)sizeof(zmem));
2779 //Check for overflow due to addition
2780 if (allocSize64 > UINT32_MAX){
2781 panic("z_alloc(%p, %x, %x): overflow caused by %x + %lx\n",
2782 notused, num_items, size, (uint32_t)total, sizeof(zmem));
2783 }
2784 uint32_t allocSize = (uint32_t)allocSize64;
2785
2786 zmem = (z_mem *)kalloc_tag(allocSize, VM_KERN_MEMORY_OSKEXT);
2787 if (!zmem) {
2788 goto finish;
2789 }
2790 zmem->alloc_size = allocSize;
2791 result = (void *)&(zmem->data);
2792 finish:
2793 return result;
2794 }
2795
2796 void
2797 z_free(void * notused __unused, void * ptr)
2798 {
2799 uint32_t * skipper = (uint32_t *)ptr - 1;
2800 z_mem * zmem = (z_mem *)skipper;
2801 kfree((void *)zmem, zmem->alloc_size);
2802 return;
2803 }
2804 };
2805
2806 OSData *
2807 OSKext::extractMkext2FileData(
2808 UInt8 * data,
2809 const char * name,
2810 uint32_t compressedSize,
2811 uint32_t fullSize)
2812 {
2813 OSData * result = NULL;
2814
2815 OSData * uncompressedData = NULL; // release on error
2816
2817 uint8_t * uncompressedDataBuffer = 0; // do not free
2818 unsigned long uncompressedSize;
2819 z_stream zstream;
2820 bool zstream_inited = false;
2821 int zlib_result;
2822
2823 /* If the file isn't compressed, we want to make a copy
2824 * so that we don't have the tie to the larger mkext file buffer any more.
2825 */
2826 if (!compressedSize) {
2827 uncompressedData = OSData::withBytes(data, fullSize);
2828 // xxx - no check for failure?
2829 result = uncompressedData;
2830 goto finish;
2831 }
2832
2833 if (KERN_SUCCESS != kmem_alloc(kernel_map,
2834 (vm_offset_t*)&uncompressedDataBuffer, fullSize, VM_KERN_MEMORY_OSKEXT)) {
2835
2836 /* How's this for cheesy? The kernel is only asked to extract
2837 * kext plists so we tailor the log messages.
2838 */
2839 if (isKernel()) {
2840 OSKextLog(this,
2841 kOSKextLogErrorLevel |
2842 kOSKextLogArchiveFlag,
2843 "Allocation failure extracting %s from mkext.", name);
2844 } else {
2845 OSKextLog(this,
2846 kOSKextLogErrorLevel |
2847 kOSKextLogArchiveFlag,
2848 "Allocation failure extracting %s from mkext for kext %s.",
2849 name, getIdentifierCString());
2850 }
2851
2852 goto finish;
2853 }
2854 uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer, fullSize);
2855 if (!uncompressedData) {
2856 if (isKernel()) {
2857 OSKextLog(this,
2858 kOSKextLogErrorLevel |
2859 kOSKextLogArchiveFlag,
2860 "Allocation failure extracting %s from mkext.", name);
2861 } else {
2862 OSKextLog(this,
2863 kOSKextLogErrorLevel |
2864 kOSKextLogArchiveFlag,
2865 "Allocation failure extracting %s from mkext for kext %s.",
2866 name, getIdentifierCString());
2867 }
2868 goto finish;
2869 }
2870 uncompressedData->setDeallocFunction(&osdata_kmem_free);
2871
2872 if (isKernel()) {
2873 OSKextLog(this,
2874 kOSKextLogDetailLevel |
2875 kOSKextLogArchiveFlag,
2876 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
2877 name, compressedSize, fullSize);
2878 } else {
2879 OSKextLog(this,
2880 kOSKextLogDetailLevel |
2881 kOSKextLogArchiveFlag,
2882 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
2883 getIdentifierCString(), name, compressedSize, fullSize);
2884 }
2885
2886 bzero(&zstream, sizeof(zstream));
2887 zstream.next_in = (UInt8 *)data;
2888 zstream.avail_in = compressedSize;
2889
2890 zstream.next_out = uncompressedDataBuffer;
2891 zstream.avail_out = fullSize;
2892
2893 zstream.zalloc = z_alloc;
2894 zstream.zfree = z_free;
2895
2896 zlib_result = inflateInit(&zstream);
2897 if (Z_OK != zlib_result) {
2898 if (isKernel()) {
2899 OSKextLog(this,
2900 kOSKextLogErrorLevel |
2901 kOSKextLogArchiveFlag,
2902 "Mkext error; zlib inflateInit failed (%d) for %s.",
2903 zlib_result, name);
2904 } else {
2905 OSKextLog(this,
2906 kOSKextLogErrorLevel |
2907 kOSKextLogArchiveFlag,
2908 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
2909 getIdentifierCString(), zlib_result, name);
2910 }
2911 goto finish;
2912 } else {
2913 zstream_inited = true;
2914 }
2915
2916 zlib_result = inflate(&zstream, Z_FINISH);
2917
2918 if (zlib_result == Z_STREAM_END || zlib_result == Z_OK) {
2919 uncompressedSize = zstream.total_out;
2920 } else {
2921 if (isKernel()) {
2922 OSKextLog(this,
2923 kOSKextLogErrorLevel |
2924 kOSKextLogArchiveFlag,
2925 "Mkext error; zlib inflate failed (%d) for %s.",
2926 zlib_result, name);
2927 } else {
2928 OSKextLog(this,
2929 kOSKextLogErrorLevel |
2930 kOSKextLogArchiveFlag,
2931 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
2932 getIdentifierCString(), zlib_result, name);
2933 }
2934 if (zstream.msg) {
2935 OSKextLog(this,
2936 kOSKextLogErrorLevel |
2937 kOSKextLogArchiveFlag,
2938 "zlib error: %s.", zstream.msg);
2939 }
2940 goto finish;
2941 }
2942
2943 if (uncompressedSize != fullSize) {
2944 if (isKernel()) {
2945 OSKextLog(this,
2946 kOSKextLogErrorLevel |
2947 kOSKextLogArchiveFlag,
2948 "Mkext error; zlib inflate discrepancy for %s, "
2949 "uncompressed size != original size.", name);
2950 } else {
2951 OSKextLog(this,
2952 kOSKextLogErrorLevel |
2953 kOSKextLogArchiveFlag,
2954 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
2955 "uncompressed size != original size.",
2956 getIdentifierCString(), name);
2957 }
2958 goto finish;
2959 }
2960
2961 result = uncompressedData;
2962
2963 finish:
2964 /* Don't bother checking return, nothing we can do on fail.
2965 */
2966 if (zstream_inited) inflateEnd(&zstream);
2967
2968 if (!result) {
2969 OSSafeReleaseNULL(uncompressedData);
2970 }
2971
2972 return result;
2973 }
2974
2975 /*********************************************************************
2976 *********************************************************************/
2977 /* static */
2978 OSReturn
2979 OSKext::loadFromMkext(
2980 OSKextLogSpec clientLogFilter,
2981 char * mkextBuffer,
2982 uint32_t mkextBufferLength,
2983 char ** logInfoOut,
2984 uint32_t * logInfoLengthOut)
2985 {
2986 OSReturn result = kOSReturnError;
2987 OSReturn tempResult = kOSReturnError;
2988
2989 OSData * mkextData = NULL; // must release
2990 OSDictionary * mkextPlist = NULL; // must release
2991
2992 OSArray * logInfoArray = NULL; // must release
2993 OSSerialize * serializer = NULL; // must release
2994
2995 OSString * predicate = NULL; // do not release
2996 OSDictionary * requestArgs = NULL; // do not release
2997
2998 OSString * kextIdentifier = NULL; // do not release
2999 OSNumber * startKextExcludeNum = NULL; // do not release
3000 OSNumber * startMatchingExcludeNum = NULL; // do not release
3001 OSBoolean * delayAutounloadBool = NULL; // do not release
3002 OSArray * personalityNames = NULL; // do not release
3003
3004 /* Default values for these two options: regular autounload behavior,
3005 * load all kexts, send no personalities.
3006 */
3007 Boolean delayAutounload = false;
3008 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
3009 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeAll;
3010
3011 IORecursiveLockLock(sKextLock);
3012
3013 if (logInfoOut) {
3014 *logInfoOut = NULL;
3015 *logInfoLengthOut = 0;
3016 }
3017
3018 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
3019
3020 OSKextLog(/* kext */ NULL,
3021 kOSKextLogDebugLevel |
3022 kOSKextLogIPCFlag,
3023 "Received kext load request from user space.");
3024
3025 /* Regardless of processing, the fact that we have gotten here means some
3026 * user-space program is up and talking to us, so we'll switch our kext
3027 * registration to reflect that.
3028 */
3029 if (!sUserLoadsActive) {
3030 OSKextLog(/* kext */ NULL,
3031 kOSKextLogProgressLevel |
3032 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
3033 "Switching to late startup (user-space) kext loading policy.");
3034
3035 sUserLoadsActive = true;
3036 }
3037
3038 if (!sLoadEnabled) {
3039 OSKextLog(/* kext */ NULL,
3040 kOSKextLogErrorLevel |
3041 kOSKextLogLoadFlag,
3042 "Kext loading is disabled.");
3043 result = kOSKextReturnDisabled;
3044 goto finish;
3045 }
3046
3047 /* Note that we do not set a dealloc function on this OSData
3048 * object! No references to it can remain after the loadFromMkext()
3049 * call since we are in a MIG function, and will vm_deallocate()
3050 * the buffer.
3051 */
3052 mkextData = OSData::withBytesNoCopy(mkextBuffer,
3053 mkextBufferLength);
3054 if (!mkextData) {
3055 OSKextLog(/* kext */ NULL,
3056 kOSKextLogErrorLevel |
3057 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3058 "Failed to create wrapper for kext load request.");
3059 result = kOSKextReturnNoMemory;
3060 goto finish;
3061 }
3062
3063 result = readMkext2Archive(mkextData, &mkextPlist, NULL);
3064 if (result != kOSReturnSuccess) {
3065 OSKextLog(/* kext */ NULL,
3066 kOSKextLogErrorLevel |
3067 kOSKextLogLoadFlag,
3068 "Failed to read kext load request.");
3069 goto finish;
3070 }
3071
3072 predicate = _OSKextGetRequestPredicate(mkextPlist);
3073 if (!predicate || !predicate->isEqualTo(kKextRequestPredicateLoad)) {
3074 OSKextLog(/* kext */ NULL,
3075 kOSKextLogErrorLevel |
3076 kOSKextLogLoadFlag,
3077 "Received kext load request with no predicate; skipping.");
3078 result = kOSKextReturnInvalidArgument;
3079 goto finish;
3080 }
3081
3082 requestArgs = OSDynamicCast(OSDictionary,
3083 mkextPlist->getObject(kKextRequestArgumentsKey));
3084 if (!requestArgs || !requestArgs->getCount()) {
3085 OSKextLog(/* kext */ NULL,
3086 kOSKextLogErrorLevel |
3087 kOSKextLogLoadFlag,
3088 "Received kext load request with no arguments.");
3089 result = kOSKextReturnInvalidArgument;
3090 goto finish;
3091 }
3092
3093 kextIdentifier = OSDynamicCast(OSString,
3094 requestArgs->getObject(kKextRequestArgumentBundleIdentifierKey));
3095 if (!kextIdentifier) {
3096 OSKextLog(/* kext */ NULL,
3097 kOSKextLogErrorLevel |
3098 kOSKextLogLoadFlag,
3099 "Received kext load request with no kext identifier.");
3100 result = kOSKextReturnInvalidArgument;
3101 goto finish;
3102 }
3103
3104 startKextExcludeNum = OSDynamicCast(OSNumber,
3105 requestArgs->getObject(kKextRequestArgumentStartExcludeKey));
3106 startMatchingExcludeNum = OSDynamicCast(OSNumber,
3107 requestArgs->getObject(kKextRequestArgumentStartMatchingExcludeKey));
3108 delayAutounloadBool = OSDynamicCast(OSBoolean,
3109 requestArgs->getObject(kKextRequestArgumentDelayAutounloadKey));
3110 personalityNames = OSDynamicCast(OSArray,
3111 requestArgs->getObject(kKextRequestArgumentPersonalityNamesKey));
3112
3113 if (delayAutounloadBool) {
3114 delayAutounload = delayAutounloadBool->getValue();
3115 }
3116 if (startKextExcludeNum) {
3117 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
3118 }
3119 if (startMatchingExcludeNum) {
3120 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
3121 }
3122
3123 OSKextLog(/* kext */ NULL,
3124 kOSKextLogProgressLevel |
3125 kOSKextLogIPCFlag,
3126 "Received request from user space to load kext %s.",
3127 kextIdentifier->getCStringNoCopy());
3128
3129 /* Load the kext, with no deferral, since this is a load from outside
3130 * the kernel.
3131 * xxx - Would like a better way to handle the default values for the
3132 * xxx - start/match opt args.
3133 */
3134 result = OSKext::loadKextWithIdentifier(
3135 kextIdentifier,
3136 /* allowDefer */ false,
3137 delayAutounload,
3138 startKextExcludeLevel,
3139 startMatchingExcludeLevel,
3140 personalityNames);
3141 if (result != kOSReturnSuccess) {
3142 goto finish;
3143 }
3144 /* If the load came down from kextd, it will shortly inform IOCatalogue
3145 * for matching via a separate IOKit calldown.
3146 */
3147
3148 finish:
3149
3150 /* Gather up the collected log messages for user space. Any
3151 * error messages past this call will not make it up as log messages
3152 * but will be in the system log.
3153 */
3154 logInfoArray = OSKext::clearUserSpaceLogFilter();
3155
3156 if (logInfoArray && logInfoOut && logInfoLengthOut) {
3157 tempResult = OSKext::serializeLogInfo(logInfoArray,
3158 logInfoOut, logInfoLengthOut);
3159 if (tempResult != kOSReturnSuccess) {
3160 result = tempResult;
3161 }
3162 }
3163
3164 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
3165
3166 /* Note: mkextDataObject will have been retained by every kext w/an
3167 * executable in it. That should all have been flushed out at the
3168 * and of the load operation, but you never know....
3169 */
3170 if (mkextData && mkextData->getRetainCount() > 1) {
3171 OSKextLog(/* kext */ NULL,
3172 kOSKextLogErrorLevel |
3173 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3174 "Kext load request buffer from user space still retained by a kext; "
3175 "probable memory leak.");
3176 }
3177
3178 IORecursiveLockUnlock(sKextLock);
3179
3180 OSSafeReleaseNULL(mkextData);
3181 OSSafeReleaseNULL(mkextPlist);
3182 OSSafeReleaseNULL(serializer);
3183 OSSafeReleaseNULL(logInfoArray);
3184
3185 return result;
3186 }
3187
3188 /*********************************************************************
3189 *********************************************************************/
3190 /* static */
3191 OSReturn
3192 OSKext::serializeLogInfo(
3193 OSArray * logInfoArray,
3194 char ** logInfoOut,
3195 uint32_t * logInfoLengthOut)
3196 {
3197 OSReturn result = kOSReturnError;
3198 char * buffer = NULL;
3199 kern_return_t kmem_result = KERN_FAILURE;
3200 OSSerialize * serializer = NULL; // must release; reused
3201 char * logInfo = NULL; // returned by reference
3202 uint32_t logInfoLength = 0;
3203
3204 if (!logInfoArray || !logInfoOut || !logInfoLengthOut) {
3205 OSKextLog(/* kext */ NULL,
3206 kOSKextLogErrorLevel |
3207 kOSKextLogIPCFlag,
3208 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
3209 /* Bad programmer. */
3210 result = kOSKextReturnInvalidArgument;
3211 goto finish;
3212 }
3213
3214 serializer = OSSerialize::withCapacity(0);
3215 if (!serializer) {
3216 OSKextLog(/* kext */ NULL,
3217 kOSKextLogErrorLevel |
3218 kOSKextLogIPCFlag,
3219 "Failed to create serializer on log info for request from user space.");
3220 /* Incidental error; we're going to (try to) allow the request
3221 * itself to succeed. */
3222 }
3223
3224 if (!logInfoArray->serialize(serializer)) {
3225 OSKextLog(/* kext */ NULL,
3226 kOSKextLogErrorLevel |
3227 kOSKextLogIPCFlag,
3228 "Failed to serialize log info for request from user space.");
3229 /* Incidental error; we're going to (try to) allow the request
3230 * itself to succeed. */
3231 } else {
3232 logInfo = serializer->text();
3233 logInfoLength = serializer->getLength();
3234
3235 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer, round_page(logInfoLength), VM_KERN_MEMORY_OSKEXT);
3236 if (kmem_result != KERN_SUCCESS) {
3237 OSKextLog(/* kext */ NULL,
3238 kOSKextLogErrorLevel |
3239 kOSKextLogIPCFlag,
3240 "Failed to copy log info for request from user space.");
3241 /* Incidental error; we're going to (try to) allow the request
3242 * to succeed. */
3243 } else {
3244 /* 11981737 - clear uninitialized data in last page */
3245 bzero((void *)(buffer + logInfoLength),
3246 (round_page(logInfoLength) - logInfoLength));
3247 memcpy(buffer, logInfo, logInfoLength);
3248 *logInfoOut = buffer;
3249 *logInfoLengthOut = logInfoLength;
3250 }
3251 }
3252
3253 result = kOSReturnSuccess;
3254 finish:
3255 OSSafeReleaseNULL(serializer);
3256 return result;
3257 }
3258
3259 #if PRAGMA_MARK
3260 #pragma mark Instance Management Methods
3261 #endif
3262 /*********************************************************************
3263 *********************************************************************/
3264 OSKext *
3265 OSKext::lookupKextWithIdentifier(const char * kextIdentifier)
3266 {
3267 OSKext * foundKext = NULL;
3268
3269 IORecursiveLockLock(sKextLock);
3270 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
3271 if (foundKext) {
3272 foundKext->retain();
3273 }
3274 IORecursiveLockUnlock(sKextLock);
3275
3276 return foundKext;
3277 }
3278
3279 /*********************************************************************
3280 *********************************************************************/
3281 OSKext *
3282 OSKext::lookupKextWithIdentifier(OSString * kextIdentifier)
3283 {
3284 return OSKext::lookupKextWithIdentifier(kextIdentifier->getCStringNoCopy());
3285 }
3286
3287 /*********************************************************************
3288 *********************************************************************/
3289 OSKext *
3290 OSKext::lookupKextWithLoadTag(uint32_t aTag)
3291 {
3292 OSKext * foundKext = NULL; // returned
3293 uint32_t count, i;
3294
3295 IORecursiveLockLock(sKextLock);
3296
3297 count = sLoadedKexts->getCount();
3298 for (i = 0; i < count; i++) {
3299 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
3300 if (thisKext->getLoadTag() == aTag) {
3301 foundKext = thisKext;
3302 foundKext->retain();
3303 goto finish;
3304 }
3305 }
3306
3307 finish:
3308 IORecursiveLockUnlock(sKextLock);
3309
3310 return foundKext;
3311 }
3312
3313 /*********************************************************************
3314 *********************************************************************/
3315 OSKext *
3316 OSKext::lookupKextWithAddress(vm_address_t address)
3317 {
3318 OSKext * foundKext = NULL; // returned
3319 uint32_t count, i;
3320
3321 IORecursiveLockLock(sKextLock);
3322
3323 count = sLoadedKexts->getCount();
3324 for (i = 0; i < count; i++) {
3325 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
3326 if (thisKext->linkedExecutable) {
3327 vm_address_t kext_start =
3328 (vm_address_t)thisKext->linkedExecutable->getBytesNoCopy();
3329 vm_address_t kext_end = kext_start +
3330 thisKext->linkedExecutable->getLength();
3331 if ((kext_start <= address) && (address < kext_end)) {
3332 foundKext = thisKext;
3333 foundKext->retain();
3334 goto finish;
3335 }
3336 }
3337 }
3338
3339 finish:
3340 IORecursiveLockUnlock(sKextLock);
3341
3342 return foundKext;
3343 }
3344
3345 OSData *
3346 OSKext::copyKextUUIDForAddress(OSNumber *address)
3347 {
3348 OSData *uuid = NULL;
3349
3350 if (!address) {
3351 return NULL;
3352 }
3353
3354 uintptr_t addr = (uintptr_t)address->unsigned64BitValue() + vm_kernel_slide;
3355
3356 #if CONFIG_MACF
3357 /* Is the calling process allowed to query kext info? */
3358 if (current_task() != kernel_task) {
3359 int macCheckResult = 0;
3360 kauth_cred_t cred = NULL;
3361
3362 cred = kauth_cred_get_with_ref();
3363 macCheckResult = mac_kext_check_query(cred);
3364 kauth_cred_unref(&cred);
3365
3366 if (macCheckResult != 0) {
3367 OSKextLog(/* kext */ NULL,
3368 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
3369 "Failed to query kext UUID (MAC policy error 0x%x).",
3370 macCheckResult);
3371 return NULL;
3372 }
3373 }
3374 #endif
3375
3376 if (((vm_offset_t)addr >= vm_kernel_stext) && ((vm_offset_t)addr < vm_kernel_etext)) {
3377 /* address in xnu proper */
3378 unsigned long uuid_len = 0;
3379 uuid = OSData::withBytes(getuuidfromheader(&_mh_execute_header, &uuid_len), uuid_len);
3380 } else {
3381 IOLockLock(sKextSummariesLock);
3382 OSKextLoadedKextSummary *summary = OSKext::summaryForAddress(addr);
3383 if (summary) {
3384 uuid = OSData::withBytes(summary->uuid, sizeof(uuid_t));
3385 }
3386 IOLockUnlock(sKextSummariesLock);
3387 }
3388
3389 return uuid;
3390 }
3391
3392 /*********************************************************************
3393 *********************************************************************/
3394 OSKext *
3395 OSKext::lookupKextWithUUID(uuid_t wanted)
3396 {
3397 OSKext * foundKext = NULL; // returned
3398 uint32_t count, i;
3399
3400 IORecursiveLockLock(sKextLock);
3401
3402 count = sLoadedKexts->getCount();
3403
3404 for (i = 0; i < count; i++) {
3405 OSKext * thisKext = NULL;
3406
3407 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
3408 if (!thisKext) {
3409 continue;
3410 }
3411
3412 OSData *uuid_data = thisKext->copyUUID();
3413 if (!uuid_data) {
3414 continue;
3415 }
3416
3417 uuid_t uuid;
3418 memcpy(&uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
3419 uuid_data->release();
3420
3421 if (0 == uuid_compare(wanted, uuid)) {
3422 foundKext = thisKext;
3423 foundKext->retain();
3424 goto finish;
3425 }
3426
3427 }
3428
3429 finish:
3430 IORecursiveLockUnlock(sKextLock);
3431
3432 return foundKext;
3433 }
3434
3435
3436
3437
3438 /*********************************************************************
3439 *********************************************************************/
3440 /* static */
3441 bool OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
3442 {
3443 bool result = false;
3444 OSKext * foundKext = NULL; // returned
3445
3446 IORecursiveLockLock(sKextLock);
3447
3448 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
3449 if (foundKext && foundKext->isLoaded()) {
3450 result = true;
3451 }
3452
3453 IORecursiveLockUnlock(sKextLock);
3454
3455 return result;
3456 }
3457
3458 /*********************************************************************
3459 * xxx - should spawn a separate thread so a kext can safely have
3460 * xxx - itself unloaded.
3461 *********************************************************************/
3462 /* static */
3463 OSReturn
3464 OSKext::removeKext(
3465 OSKext * aKext,
3466 #if CONFIG_EMBEDDED
3467 __unused
3468 #endif
3469 bool terminateServicesAndRemovePersonalitiesFlag)
3470 {
3471 #if CONFIG_EMBEDDED
3472 OSKextLog(aKext,
3473 kOSKextLogErrorLevel |
3474 kOSKextLogKextBookkeepingFlag,
3475 "removeKext() called for %s, not supported on embedded",
3476 aKext->getIdentifier() ? aKext->getIdentifierCString() : "unknown kext");
3477
3478 return kOSReturnSuccess;
3479 #else /* CONFIG_EMBEDDED */
3480
3481 OSReturn result = kOSKextReturnInUse;
3482 OSKext * checkKext = NULL; // do not release
3483 #if CONFIG_MACF
3484 int macCheckResult = 0;
3485 kauth_cred_t cred = NULL;
3486 #endif
3487
3488 IORecursiveLockLock(sKextLock);
3489
3490 /* If the kext has no identifier, it failed to init
3491 * so isn't in sKextsByID and it isn't loaded.
3492 */
3493 if (!aKext->getIdentifier()) {
3494 result = kOSReturnSuccess;
3495 goto finish;
3496 }
3497
3498 checkKext = OSDynamicCast(OSKext,
3499 sKextsByID->getObject(aKext->getIdentifier()));
3500 if (checkKext != aKext) {
3501 result = kOSKextReturnNotFound;
3502 goto finish;
3503 }
3504
3505 if (aKext->isLoaded()) {
3506 #if CONFIG_MACF
3507 if (current_task() != kernel_task) {
3508 cred = kauth_cred_get_with_ref();
3509 macCheckResult = mac_kext_check_unload(cred, aKext->getIdentifierCString());
3510 kauth_cred_unref(&cred);
3511 }
3512
3513 if (macCheckResult != 0) {
3514 result = kOSReturnError;
3515 OSKextLog(aKext,
3516 kOSKextLogErrorLevel |
3517 kOSKextLogKextBookkeepingFlag,
3518 "Failed to remove kext %s (MAC policy error 0x%x).",
3519 aKext->getIdentifierCString(), macCheckResult);
3520 goto finish;
3521 }
3522 #endif
3523
3524 /* make sure there are no resource requests in flight - 17187548 */
3525 if (aKext->countRequestCallbacks()) {
3526 goto finish;
3527 }
3528
3529 /* If we are terminating, send the request to the IOCatalogue
3530 * (which will actually call us right back but that's ok we have
3531 * a recursive lock don't you know) but do not ask the IOCatalogue
3532 * to call back with an unload, we'll do that right here.
3533 */
3534 if (terminateServicesAndRemovePersonalitiesFlag) {
3535 result = gIOCatalogue->terminateDriversForModule(
3536 aKext->getIdentifierCString(), /* unload */ false);
3537 if (result != kOSReturnSuccess) {
3538 OSKextLog(aKext,
3539 kOSKextLogErrorLevel |
3540 kOSKextLogKextBookkeepingFlag,
3541 "Can't remove kext %s; services failed to terminate - 0x%x.",
3542 aKext->getIdentifierCString(), result);
3543 goto finish;
3544 }
3545 }
3546
3547 result = aKext->unload();
3548 if (result != kOSReturnSuccess) {
3549 goto finish;
3550 }
3551 }
3552
3553 /* Remove personalities as requested. This is a bit redundant for a loaded
3554 * kext as IOCatalogue::terminateDriversForModule() removes driver
3555 * personalities, but it doesn't restart matching, which we always want
3556 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
3557 * that happens.
3558 */
3559 if (terminateServicesAndRemovePersonalitiesFlag) {
3560 aKext->removePersonalitiesFromCatalog();
3561 }
3562
3563 OSKextLog(aKext,
3564 kOSKextLogProgressLevel |
3565 kOSKextLogKextBookkeepingFlag,
3566 "Removing kext %s.",
3567 aKext->getIdentifierCString());
3568
3569 sKextsByID->removeObject(aKext->getIdentifier());
3570 result = kOSReturnSuccess;
3571
3572 finish:
3573 IORecursiveLockUnlock(sKextLock);
3574 return result;
3575 #endif /* CONFIG_EMBEDDED */
3576 }
3577
3578 /*********************************************************************
3579 *********************************************************************/
3580 /* static */
3581 OSReturn
3582 OSKext::removeKextWithIdentifier(
3583 const char * kextIdentifier,
3584 bool terminateServicesAndRemovePersonalitiesFlag)
3585 {
3586 OSReturn result = kOSReturnError;
3587
3588 IORecursiveLockLock(sKextLock);
3589
3590 OSKext * aKext = OSDynamicCast(OSKext,
3591 sKextsByID->getObject(kextIdentifier));
3592 if (!aKext) {
3593 result = kOSKextReturnNotFound;
3594 OSKextLog(/* kext */ NULL,
3595 kOSKextLogErrorLevel |
3596 kOSKextLogKextBookkeepingFlag,
3597 "Can't remove kext %s - not found.",
3598 kextIdentifier);
3599 goto finish;
3600 }
3601
3602 result = OSKext::removeKext(aKext,
3603 terminateServicesAndRemovePersonalitiesFlag);
3604
3605 finish:
3606 IORecursiveLockUnlock(sKextLock);
3607
3608 return result;
3609 }
3610
3611 /*********************************************************************
3612 *********************************************************************/
3613 /* static */
3614 OSReturn
3615 OSKext::removeKextWithLoadTag(
3616 OSKextLoadTag loadTag,
3617 bool terminateServicesAndRemovePersonalitiesFlag)
3618 {
3619 OSReturn result = kOSReturnError;
3620 OSKext * foundKext = NULL;
3621 uint32_t count, i;
3622
3623 IORecursiveLockLock(sKextLock);
3624
3625 count = sLoadedKexts->getCount();
3626 for (i = 0; i < count; i++) {
3627 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
3628 if (thisKext->loadTag == loadTag) {
3629 foundKext = thisKext;
3630 break;
3631 }
3632 }
3633
3634 if (!foundKext) {
3635 result = kOSKextReturnNotFound;
3636 OSKextLog(/* kext */ NULL,
3637 kOSKextLogErrorLevel |
3638 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
3639 "Can't remove kext with load tag %d - not found.",
3640 loadTag);
3641 goto finish;
3642 }
3643
3644 result = OSKext::removeKext(foundKext,
3645 terminateServicesAndRemovePersonalitiesFlag);
3646
3647 finish:
3648 IORecursiveLockUnlock(sKextLock);
3649
3650 return result;
3651 }
3652
3653 /*********************************************************************
3654 *********************************************************************/
3655 OSDictionary *
3656 OSKext::copyKexts(void)
3657 {
3658 OSDictionary * result;
3659
3660 IORecursiveLockLock(sKextLock);
3661 result = OSDynamicCast(OSDictionary, sKextsByID->copyCollection());
3662 IORecursiveLockUnlock(sKextLock);
3663
3664 return result;
3665 }
3666
3667 /*********************************************************************
3668 *********************************************************************/
3669 #define BOOTER_KEXT_PREFIX "Driver-"
3670
3671 typedef struct _DeviceTreeBuffer {
3672 uint32_t paddr;
3673 uint32_t length;
3674 } _DeviceTreeBuffer;
3675
3676 /*********************************************************************
3677 * Create a dictionary of excluded kexts from the given booter data.
3678 *********************************************************************/
3679 /* static */
3680 void
3681 OSKext::createExcludeListFromBooterData(
3682 OSDictionary * theDictionary,
3683 OSCollectionIterator * theIterator )
3684 {
3685 OSString * deviceTreeName = NULL; // do not release
3686 const _DeviceTreeBuffer * deviceTreeBuffer = NULL; // do not release
3687 char * booterDataPtr = NULL; // do not release
3688 _BooterKextFileInfo * kextFileInfo = NULL; // do not release
3689 char * infoDictAddr = NULL; // do not release
3690 OSObject * parsedXML = NULL; // must release
3691 OSDictionary * theInfoDict = NULL; // do not release
3692
3693 theIterator->reset();
3694
3695 /* look for AppleKextExcludeList.kext */
3696 while ( (deviceTreeName =
3697 OSDynamicCast(OSString, theIterator->getNextObject())) ) {
3698
3699 const char * devTreeNameCString;
3700 OSData * deviceTreeEntry;
3701 OSString * myBundleID; // do not release
3702
3703 OSSafeReleaseNULL(parsedXML);
3704
3705 deviceTreeEntry =
3706 OSDynamicCast(OSData, theDictionary->getObject(deviceTreeName));
3707 if (!deviceTreeEntry) {
3708 continue;
3709 }
3710
3711 /* Make sure it is a kext */
3712 devTreeNameCString = deviceTreeName->getCStringNoCopy();
3713 if (strncmp(devTreeNameCString, BOOTER_KEXT_PREFIX,
3714 (sizeof(BOOTER_KEXT_PREFIX) - 1)) != 0) {
3715 OSKextLog(NULL,
3716 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
3717 "\"%s\" not a kext",
3718 devTreeNameCString);
3719 continue;
3720 }
3721
3722 deviceTreeBuffer = (const _DeviceTreeBuffer *)
3723 deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
3724 if (!deviceTreeBuffer) {
3725 continue;
3726 }
3727
3728 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
3729 if (!booterDataPtr) {
3730 continue;
3731 }
3732
3733 kextFileInfo = (_BooterKextFileInfo *) booterDataPtr;
3734 if (!kextFileInfo->infoDictPhysAddr ||
3735 !kextFileInfo->infoDictLength) {
3736 continue;
3737 }
3738
3739 infoDictAddr = (char *)
3740 ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
3741 if (!infoDictAddr) {
3742 continue;
3743 }
3744
3745 parsedXML = OSUnserializeXML(infoDictAddr);
3746 if (!parsedXML) {
3747 continue;
3748 }
3749
3750 theInfoDict = OSDynamicCast(OSDictionary, parsedXML);
3751 if (!theInfoDict) {
3752 continue;
3753 }
3754
3755 myBundleID =
3756 OSDynamicCast(OSString,
3757 theInfoDict->getObject(kCFBundleIdentifierKey));
3758 if ( myBundleID &&
3759 strcmp( myBundleID->getCStringNoCopy(), "com.apple.driver.KextExcludeList" ) == 0 ) {
3760
3761 boolean_t updated = updateExcludeList(theInfoDict);
3762 if (!updated) {
3763 /* 25322874 */
3764 panic("Missing OSKextExcludeList dictionary\n");
3765 }
3766 break;
3767 }
3768
3769 } // while ( (deviceTreeName = ...) )
3770
3771 OSSafeReleaseNULL(parsedXML);
3772 return;
3773 }
3774
3775 /*********************************************************************
3776 * Create a dictionary of excluded kexts from the given prelink
3777 * info (kernelcache).
3778 *********************************************************************/
3779 /* static */
3780 void
3781 OSKext::createExcludeListFromPrelinkInfo( OSArray * theInfoArray )
3782 {
3783 OSDictionary * myInfoDict = NULL; // do not release
3784 OSString * myBundleID; // do not release
3785 u_int i;
3786
3787 /* Find com.apple.driver.KextExcludeList. */
3788 for (i = 0; i < theInfoArray->getCount(); i++) {
3789 myInfoDict = OSDynamicCast(OSDictionary, theInfoArray->getObject(i));
3790 if (!myInfoDict) {
3791 continue;
3792 }
3793 myBundleID =
3794 OSDynamicCast(OSString,
3795 myInfoDict->getObject(kCFBundleIdentifierKey));
3796 if ( myBundleID &&
3797 strcmp( myBundleID->getCStringNoCopy(), "com.apple.driver.KextExcludeList" ) == 0 ) {
3798
3799 boolean_t updated = updateExcludeList(myInfoDict);
3800 if (!updated) {
3801 /* 25322874 */
3802 panic("Missing OSKextExcludeList dictionary\n");
3803 }
3804 break;
3805 }
3806 } // for (i = 0; i < theInfoArray->getCount()...
3807
3808 return;
3809 }
3810
3811 /* static */
3812 boolean_t
3813 OSKext::updateExcludeList(OSDictionary *infoDict)
3814 {
3815 OSDictionary *myTempDict = NULL; // do not free
3816 OSString *myTempString = NULL; // do not free
3817 OSKextVersion newVersion = 0;
3818 boolean_t updated = false;
3819
3820 if (!infoDict) {
3821 return false;
3822 }
3823
3824 myTempDict = OSDynamicCast(OSDictionary, infoDict->getObject("OSKextExcludeList"));
3825 if (!myTempDict) {
3826 return false;
3827 }
3828
3829 myTempString = OSDynamicCast(OSString, infoDict->getObject(kCFBundleVersionKey));
3830 if (!myTempString) {
3831 return false;
3832 }
3833
3834 newVersion = OSKextParseVersionString(myTempString->getCStringNoCopy());
3835 if (newVersion == 0) {
3836 return false;
3837 }
3838
3839 IORecursiveLockLock(sKextLock);
3840
3841 if (newVersion > sExcludeListVersion) {
3842 OSSafeReleaseNULL(sExcludeListByID);
3843 sExcludeListByID = OSDictionary::withDictionary(myTempDict, 0);
3844 sExcludeListVersion = newVersion;
3845 updated = true;
3846 }
3847
3848 IORecursiveLockUnlock(sKextLock);
3849 return updated;
3850 }
3851
3852 #if PRAGMA_MARK
3853 #pragma mark Accessors
3854 #endif
3855 /*********************************************************************
3856 *********************************************************************/
3857 const OSSymbol *
3858 OSKext::getIdentifier(void)
3859 {
3860 return bundleID;
3861 }
3862
3863 /*********************************************************************
3864 * A kext must have a bundle identifier to even survive initialization;
3865 * this is guaranteed to exist past then.
3866 *********************************************************************/
3867 const char *
3868 OSKext::getIdentifierCString(void)
3869 {
3870 return bundleID->getCStringNoCopy();
3871 }
3872
3873 /*********************************************************************
3874 *********************************************************************/
3875 OSKextVersion
3876 OSKext::getVersion(void)
3877 {
3878 return version;
3879 }
3880
3881 /*********************************************************************
3882 *********************************************************************/
3883 OSKextVersion
3884 OSKext::getCompatibleVersion(void)
3885 {
3886 return compatibleVersion;
3887 }
3888
3889 /*********************************************************************
3890 *********************************************************************/
3891 bool
3892 OSKext::isLibrary(void)
3893 {
3894 return (getCompatibleVersion() > 0);
3895 }
3896
3897 /*********************************************************************
3898 *********************************************************************/
3899 bool
3900 OSKext::isCompatibleWithVersion(OSKextVersion aVersion)
3901 {
3902 if ((compatibleVersion > -1 && version > -1) &&
3903 (compatibleVersion <= version && aVersion <= version)) {
3904 return true;
3905 }
3906 return false;
3907 }
3908
3909 /*********************************************************************
3910 *********************************************************************/
3911 bool
3912 OSKext::declaresExecutable(void)
3913 {
3914 return (getPropertyForHostArch(kCFBundleExecutableKey) != NULL);
3915 }
3916
3917 /*********************************************************************
3918 *********************************************************************/
3919 OSData *
3920 OSKext::getExecutable(void)
3921 {
3922 OSData * result = NULL;
3923 OSData * extractedExecutable = NULL; // must release
3924 OSData * mkextExecutableRef = NULL; // do not release
3925
3926 result = OSDynamicCast(OSData, infoDict->getObject(_kOSKextExecutableKey));
3927 if (result) {
3928 goto finish;
3929 }
3930
3931 mkextExecutableRef = OSDynamicCast(OSData,
3932 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey));
3933
3934 if (mkextExecutableRef) {
3935
3936 MkextEntryRef * mkextEntryRef = (MkextEntryRef *)
3937 mkextExecutableRef->getBytesNoCopy();
3938 uint32_t mkextVersion = MKEXT_GET_VERSION(mkextEntryRef->mkext);
3939 if (mkextVersion == MKEXT_VERS_2) {
3940 mkext2_file_entry * fileinfo =
3941 (mkext2_file_entry *)mkextEntryRef->fileinfo;
3942 uint32_t compressedSize = MKEXT2_GET_ENTRY_COMPSIZE(fileinfo);
3943 uint32_t fullSize = MKEXT2_GET_ENTRY_FULLSIZE(fileinfo);
3944 extractedExecutable = extractMkext2FileData(
3945 MKEXT2_GET_ENTRY_DATA(fileinfo), "executable",
3946 compressedSize, fullSize);
3947 } else {
3948 OSKextLog(this, kOSKextLogErrorLevel |
3949 kOSKextLogArchiveFlag,
3950 "Kext %s - unknown mkext version 0x%x for executable.",
3951 getIdentifierCString(), mkextVersion);
3952 }
3953
3954 /* Regardless of success, remove the mkext executable,
3955 * and drop one reference on the mkext. (setExecutable() does not
3956 * replace, it removes, or panics if asked to replace.)
3957 */
3958 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
3959 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
3960
3961 if (extractedExecutable && extractedExecutable->getLength()) {
3962 if (!setExecutable(extractedExecutable)) {
3963 goto finish;
3964 }
3965 result = extractedExecutable;
3966 } else {
3967 goto finish;
3968 }
3969 }
3970
3971 finish:
3972
3973 OSSafeReleaseNULL(extractedExecutable);
3974
3975 return result;
3976 }
3977
3978 /*********************************************************************
3979 *********************************************************************/
3980 bool
3981 OSKext::isInterface(void)
3982 {
3983 return flags.interface;
3984 }
3985
3986 /*********************************************************************
3987 *********************************************************************/
3988 bool
3989 OSKext::isKernel(void)
3990 {
3991 return (this == sKernelKext);
3992 }
3993
3994 /*********************************************************************
3995 *********************************************************************/
3996 bool
3997 OSKext::isKernelComponent(void)
3998 {
3999 return flags.kernelComponent ? true : false;
4000 }
4001
4002 /*********************************************************************
4003 *********************************************************************/
4004 bool
4005 OSKext::isExecutable(void)
4006 {
4007 return (!isKernel() && !isInterface() && declaresExecutable());
4008 }
4009
4010 /*********************************************************************
4011 * We might want to check this recursively for all dependencies,
4012 * since a subtree of dependencies could get loaded before we hit
4013 * a dependency that isn't safe-boot-loadable.
4014 *
4015 * xxx - Might want to return false if OSBundleEnableKextLogging or
4016 * OSBundleDebugLevel
4017 * or IOKitDebug is nonzero too (we used to do that, but I don't see
4018 * the point except it's usually development drivers, which might
4019 * cause panics on startup, that have those properties). Heh; could
4020 * use a "kx" boot-arg!
4021 *********************************************************************/
4022 bool
4023 OSKext::isLoadableInSafeBoot(void)
4024 {
4025 bool result = false;
4026 OSString * required = NULL; // do not release
4027
4028 if (isKernel()) {
4029 result = true;
4030 goto finish;
4031 }
4032
4033 required = OSDynamicCast(OSString,
4034 getPropertyForHostArch(kOSBundleRequiredKey));
4035 if (!required) {
4036 goto finish;
4037 }
4038 if (required->isEqualTo(kOSBundleRequiredRoot) ||
4039 required->isEqualTo(kOSBundleRequiredLocalRoot) ||
4040 required->isEqualTo(kOSBundleRequiredNetworkRoot) ||
4041 required->isEqualTo(kOSBundleRequiredSafeBoot) ||
4042 required->isEqualTo(kOSBundleRequiredConsole)) {
4043
4044 result = true;
4045 }
4046
4047 finish:
4048 return result;
4049 }
4050
4051 /*********************************************************************
4052 *********************************************************************/
4053 bool
4054 OSKext::isPrelinked(void)
4055 {
4056 return flags.prelinked ? true : false;
4057 }
4058
4059 /*********************************************************************
4060 *********************************************************************/
4061 bool OSKext::isLoaded(void)
4062 {
4063 return flags.loaded ? true : false;
4064 }
4065
4066 /*********************************************************************
4067 *********************************************************************/
4068 bool
4069 OSKext::isStarted(void)
4070 {
4071 return flags.started ? true : false;
4072 }
4073
4074 /*********************************************************************
4075 *********************************************************************/
4076 bool
4077 OSKext::isCPPInitialized(void)
4078 {
4079 return flags.CPPInitialized;
4080 }
4081
4082 /*********************************************************************
4083 *********************************************************************/
4084 void
4085 OSKext::setCPPInitialized(bool initialized)
4086 {
4087 flags.CPPInitialized = initialized;
4088 }
4089
4090 /*********************************************************************
4091 *********************************************************************/
4092 uint32_t
4093 OSKext::getLoadTag(void)
4094 {
4095 return loadTag;
4096 }
4097
4098 /*********************************************************************
4099 *********************************************************************/
4100 void OSKext::getSizeInfo(uint32_t *loadSize, uint32_t *wiredSize)
4101 {
4102 if (linkedExecutable) {
4103 *loadSize = linkedExecutable->getLength();
4104
4105 /* If we have a kmod_info struct, calculated the wired size
4106 * from that. Otherwise it's the full load size.
4107 */
4108 if (kmod_info) {
4109 *wiredSize = *loadSize - kmod_info->hdr_size;
4110 } else {
4111 *wiredSize = *loadSize;
4112 }
4113 }
4114 else {
4115 *wiredSize = 0;
4116 *loadSize = 0;
4117 }
4118 }
4119
4120 /*********************************************************************
4121 *********************************************************************/
4122 OSData *
4123 OSKext::copyUUID(void)
4124 {
4125 OSData * result = NULL;
4126 OSData * theExecutable = NULL; // do not release
4127 const kernel_mach_header_t * header = NULL;
4128 const struct load_command * load_cmd = NULL;
4129 const struct uuid_command * uuid_cmd = NULL;
4130 uint32_t i;
4131
4132 /* An interface kext doesn't have a linked executable with an LC_UUID,
4133 * we create one when it's linked.
4134 */
4135 if (interfaceUUID) {
4136 result = interfaceUUID;
4137 result->retain();
4138 goto finish;
4139 }
4140
4141 /* For real kexts, try to get the UUID from the linked executable,
4142 * or if is hasn't been linked yet, the unrelocated executable.
4143 */
4144 theExecutable = linkedExecutable;
4145 if (!theExecutable) {
4146 theExecutable = getExecutable();
4147 }
4148 if (!theExecutable) {
4149 goto finish;
4150 }
4151
4152 header = (const kernel_mach_header_t *)theExecutable->getBytesNoCopy();
4153 load_cmd = (const struct load_command *)&header[1];
4154
4155 if (header->magic != MH_MAGIC_KERNEL) {
4156 OSKextLog(NULL,
4157 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4158 "%s: bad header %p",
4159 __func__,
4160 header);
4161 goto finish;
4162 }
4163
4164 for (i = 0; i < header->ncmds; i++) {
4165 if (load_cmd->cmd == LC_UUID) {
4166 uuid_cmd = (struct uuid_command *)load_cmd;
4167 result = OSData::withBytes(uuid_cmd->uuid, sizeof(uuid_cmd->uuid));
4168 goto finish;
4169 }
4170 load_cmd = (struct load_command *)((caddr_t)load_cmd + load_cmd->cmdsize);
4171 }
4172
4173 finish:
4174 return result;
4175 }
4176
4177 /*********************************************************************
4178 *********************************************************************/
4179 #if defined (__arm__)
4180 #include <arm/arch.h>
4181 #endif
4182
4183 #if defined (__x86_64__)
4184 #define ARCHNAME "x86_64"
4185 #elif defined (__arm64__)
4186 #define ARCHNAME "arm64"
4187 #elif defined (__arm__)
4188
4189 #if defined (__ARM_ARCH_7S__)
4190 #define ARCHNAME "armv7s"
4191 #elif defined (__ARM_ARCH_7F__)
4192 #define ARCHNAME "armv7f"
4193 #elif defined (__ARM_ARCH_7K__)
4194 #define ARCHNAME "armv7k"
4195 #elif defined (_ARM_ARCH_7) /* umbrella for all remaining */
4196 #define ARCHNAME "armv7"
4197 #elif defined (_ARM_ARCH_6) /* umbrella for all armv6 */
4198 #define ARCHNAME "armv6"
4199 #endif
4200
4201 #elif defined (__arm64__)
4202 #define ARCHNAME "arm64"
4203 #else
4204 #error architecture not supported
4205 #endif
4206
4207 #define ARCH_SEPARATOR_CHAR '_'
4208
4209 static char * makeHostArchKey(const char * key, uint32_t * keySizeOut)
4210 {
4211 char * result = NULL;
4212 uint32_t keyLength = strlen(key);
4213 uint32_t keySize;
4214
4215 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
4216 */
4217 keySize = 1 + 1 + strlen(key) + strlen(ARCHNAME);
4218 result = (char *)kalloc_tag(keySize, VM_KERN_MEMORY_OSKEXT);
4219 if (!result) {
4220 goto finish;
4221 }
4222 strlcpy(result, key, keySize);
4223 result[keyLength++] = ARCH_SEPARATOR_CHAR;
4224 result[keyLength] = '\0';
4225 strlcat(result, ARCHNAME, keySize);
4226 *keySizeOut = keySize;
4227
4228 finish:
4229 return result;
4230 }
4231
4232 /*********************************************************************
4233 *********************************************************************/
4234 OSObject *
4235 OSKext::getPropertyForHostArch(const char * key)
4236 {
4237 OSObject * result = NULL; // do not release
4238 uint32_t hostArchKeySize = 0;
4239 char * hostArchKey = NULL; // must kfree
4240
4241 if (!key || !infoDict) {
4242 goto finish;
4243 }
4244
4245 /* Some properties are not allowed to be arch-variant:
4246 * - Any CFBundle... property.
4247 * - OSBundleIsInterface.
4248 * - OSKernelResource.
4249 */
4250 if (STRING_HAS_PREFIX(key, "OS") ||
4251 STRING_HAS_PREFIX(key, "IO")) {
4252
4253 hostArchKey = makeHostArchKey(key, &hostArchKeySize);
4254 if (!hostArchKey) {
4255 OSKextLog(/* kext (this isn't about a kext) */ NULL,
4256 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4257 "Allocation failure.");
4258 goto finish;
4259 }
4260 result = infoDict->getObject(hostArchKey);
4261 }
4262
4263 if (!result) {
4264 result = infoDict->getObject(key);
4265 }
4266
4267 finish:
4268 if (hostArchKey) kfree(hostArchKey, hostArchKeySize);
4269 return result;
4270 }
4271
4272 #if PRAGMA_MARK
4273 #pragma mark Load/Start/Stop/Unload
4274 #endif
4275
4276 #define isWhiteSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == ',' || (c) == '\n')
4277
4278 /*********************************************************************
4279 * sExcludeListByID is a dictionary with keys / values of:
4280 * key = bundleID string of kext we will not allow to load
4281 * value = version string(s) of the kext that is to be denied loading.
4282 * The version strings can be comma delimited. For example if kext
4283 * com.foocompany.fookext has two versions that we want to deny
4284 * loading then the version strings might look like:
4285 * 1.0.0, 1.0.1
4286 * If the current fookext has a version of 1.0.0 OR 1.0.1 we will
4287 * not load the kext.
4288 *
4289 * Value may also be in the form of "LE 2.0.0" (version numbers
4290 * less than or equal to 2.0.0 will not load) or "LT 2.0.0" (version
4291 * number less than 2.0.0 will not load)
4292 *
4293 * NOTE - we cannot use the characters "<=" or "<" because we have code
4294 * that serializes plists and treats '<' as a special character.
4295 *********************************************************************/
4296 bool
4297 OSKext::isInExcludeList(void)
4298 {
4299 OSString * versionString = NULL; // do not release
4300 char * versionCString = NULL; // do not free
4301 size_t i;
4302 boolean_t wantLessThan = false;
4303 boolean_t wantLessThanEqualTo = false;
4304 boolean_t isInExcludeList = true;
4305 char myBuffer[32];
4306
4307 IORecursiveLockLock(sKextLock);
4308
4309 if (!sExcludeListByID) {
4310 isInExcludeList = false;
4311 } else {
4312 /* look up by bundleID in our exclude list and if found get version
4313 * string (or strings) that we will not allow to load
4314 */
4315 versionString = OSDynamicCast(OSString, sExcludeListByID->getObject(bundleID));
4316 if (versionString == NULL || versionString->getLength() > (sizeof(myBuffer) - 1)) {
4317 isInExcludeList = false;
4318 }
4319 }
4320
4321 IORecursiveLockUnlock(sKextLock);
4322
4323 if (!isInExcludeList) {
4324 return(false);
4325 }
4326
4327 /* parse version strings */
4328 versionCString = (char *) versionString->getCStringNoCopy();
4329
4330 /* look for "LT" or "LE" form of version string, must be in first two
4331 * positions.
4332 */
4333 if (*versionCString == 'L' && *(versionCString + 1) == 'T') {
4334 wantLessThan = true;
4335 versionCString +=2;
4336 }
4337 else if (*versionCString == 'L' && *(versionCString + 1) == 'E') {
4338 wantLessThanEqualTo = true;
4339 versionCString +=2;
4340 }
4341
4342 for (i = 0; *versionCString != 0x00; versionCString++) {
4343 /* skip whitespace */
4344 if (isWhiteSpace(*versionCString)) {
4345 continue;
4346 }
4347
4348 /* peek ahead for version string separator or null terminator */
4349 if (*(versionCString + 1) == ',' || *(versionCString + 1) == 0x00) {
4350
4351 /* OK, we have a version string */
4352 myBuffer[i++] = *versionCString;
4353 myBuffer[i] = 0x00;
4354
4355 OSKextVersion excludeVers;
4356 excludeVers = OSKextParseVersionString(myBuffer);
4357
4358 if (wantLessThanEqualTo) {
4359 if (version <= excludeVers) {
4360 return(true);
4361 }
4362 }
4363 else if (wantLessThan) {
4364 if (version < excludeVers) {
4365 return(true);
4366 }
4367 }
4368 else if ( version == excludeVers ) {
4369 return(true);
4370 }
4371
4372 /* reset for the next (if any) version string */
4373 i = 0;
4374 wantLessThan = false;
4375 wantLessThanEqualTo = false;
4376 }
4377 else {
4378 /* save valid version character */
4379 myBuffer[i++] = *versionCString;
4380
4381 /* make sure bogus version string doesn't overrun local buffer */
4382 if ( i >= sizeof(myBuffer) ) {
4383 break;
4384 }
4385 }
4386 }
4387
4388 return(false);
4389 }
4390
4391 /*********************************************************************
4392 *********************************************************************/
4393 /* static */
4394 OSReturn
4395 OSKext::loadKextWithIdentifier(
4396 const char * kextIdentifierCString,
4397 Boolean allowDeferFlag,
4398 Boolean delayAutounloadFlag,
4399 OSKextExcludeLevel startOpt,
4400 OSKextExcludeLevel startMatchingOpt,
4401 OSArray * personalityNames)
4402 {
4403 OSReturn result = kOSReturnError;
4404 OSString * kextIdentifier = NULL; // must release
4405
4406 kextIdentifier = OSString::withCString(kextIdentifierCString);
4407 if (!kextIdentifier) {
4408 result = kOSKextReturnNoMemory;
4409 goto finish;
4410 }
4411 result = OSKext::loadKextWithIdentifier(kextIdentifier,
4412 allowDeferFlag, delayAutounloadFlag,
4413 startOpt, startMatchingOpt, personalityNames);
4414
4415 finish:
4416 OSSafeReleaseNULL(kextIdentifier);
4417 return result;
4418 }
4419
4420 /*********************************************************************
4421 *********************************************************************/
4422 OSReturn
4423 OSKext::loadKextWithIdentifier(
4424 OSString * kextIdentifier,
4425 Boolean allowDeferFlag,
4426 Boolean delayAutounloadFlag,
4427 OSKextExcludeLevel startOpt,
4428 OSKextExcludeLevel startMatchingOpt,
4429 OSArray * personalityNames)
4430 {
4431 OSReturn result = kOSReturnError;
4432 OSReturn pingResult = kOSReturnError;
4433 OSKext * theKext = NULL; // do not release
4434 OSDictionary * loadRequest = NULL; // must release
4435 const OSSymbol * kextIdentifierSymbol = NULL; // must release
4436
4437 IORecursiveLockLock(sKextLock);
4438
4439 if (!kextIdentifier) {
4440 result = kOSKextReturnInvalidArgument;
4441 goto finish;
4442 }
4443
4444 OSKext::recordIdentifierRequest(kextIdentifier);
4445
4446 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
4447 if (!theKext) {
4448 if (!allowDeferFlag) {
4449 OSKextLog(/* kext */ NULL,
4450 kOSKextLogErrorLevel |
4451 kOSKextLogLoadFlag,
4452 "Can't load kext %s - not found.",
4453 kextIdentifier->getCStringNoCopy());
4454 goto finish;
4455 }
4456
4457 if (!sKernelRequestsEnabled) {
4458 OSKextLog(theKext,
4459 kOSKextLogErrorLevel |
4460 kOSKextLogLoadFlag,
4461 "Can't load kext %s - requests to user space are disabled.",
4462 kextIdentifier->getCStringNoCopy());
4463 result = kOSKextReturnDisabled;
4464 goto finish;
4465 }
4466
4467 /* Create a new request unless one is already sitting
4468 * in sKernelRequests for this bundle identifier
4469 */
4470 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
4471 if (!sPostedKextLoadIdentifiers->containsObject(kextIdentifierSymbol)) {
4472 result = _OSKextCreateRequest(kKextRequestPredicateRequestLoad,
4473 &loadRequest);
4474 if (result != kOSReturnSuccess) {
4475 goto finish;
4476 }
4477 if (!_OSKextSetRequestArgument(loadRequest,
4478 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
4479
4480 result = kOSKextReturnNoMemory;
4481 goto finish;
4482 }
4483 if (!sKernelRequests->setObject(loadRequest)) {
4484 result = kOSKextReturnNoMemory;
4485 goto finish;
4486 }
4487
4488 if (!sPostedKextLoadIdentifiers->setObject(kextIdentifierSymbol)) {
4489 result = kOSKextReturnNoMemory;
4490 goto finish;
4491 }
4492
4493 OSKextLog(theKext,
4494 kOSKextLogDebugLevel |
4495 kOSKextLogLoadFlag,
4496 "Kext %s not found; queued load request to user space.",
4497 kextIdentifier->getCStringNoCopy());
4498 }
4499
4500 pingResult = OSKext::pingKextd();
4501 if (pingResult == kOSKextReturnDisabled) {
4502 OSKextLog(/* kext */ NULL,
4503 ((sPrelinkBoot) ? kOSKextLogDebugLevel : kOSKextLogErrorLevel) |
4504 kOSKextLogLoadFlag,
4505 "Kext %s might not load - kextd is currently unavailable.",
4506 kextIdentifier->getCStringNoCopy());
4507 }
4508
4509 result = kOSKextReturnDeferred;
4510 goto finish;
4511 }
4512
4513 result = theKext->load(startOpt, startMatchingOpt, personalityNames);
4514
4515 if (result != kOSReturnSuccess) {
4516 OSKextLog(theKext,
4517 kOSKextLogErrorLevel |
4518 kOSKextLogLoadFlag,
4519 "Failed to load kext %s (error 0x%x).",
4520 kextIdentifier->getCStringNoCopy(), (int)result);
4521
4522 OSKext::removeKext(theKext,
4523 /* terminateService/removePersonalities */ true);
4524 goto finish;
4525 }
4526
4527 if (delayAutounloadFlag) {
4528 OSKextLog(theKext,
4529 kOSKextLogProgressLevel |
4530 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4531 "Setting delayed autounload for %s.",
4532 kextIdentifier->getCStringNoCopy());
4533 theKext->flags.delayAutounload = 1;
4534 }
4535
4536 finish:
4537 OSSafeReleaseNULL(loadRequest);
4538 OSSafeReleaseNULL(kextIdentifierSymbol);
4539
4540 IORecursiveLockUnlock(sKextLock);
4541
4542 return result;
4543 }
4544
4545 /*********************************************************************
4546 *********************************************************************/
4547 /* static */
4548 void
4549 OSKext::recordIdentifierRequest(
4550 OSString * kextIdentifier)
4551 {
4552 const OSSymbol * kextIdentifierSymbol = NULL; // must release
4553 bool fail = false;
4554
4555 if (!sAllKextLoadIdentifiers || !kextIdentifier) {
4556 goto finish;
4557 }
4558
4559 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
4560 if (!kextIdentifierSymbol) {
4561 // xxx - this is really a basic alloc failure
4562 fail = true;
4563 goto finish;
4564 }
4565
4566 IORecursiveLockLock(sKextLock);
4567 if (!sAllKextLoadIdentifiers->containsObject(kextIdentifierSymbol)) {
4568 if (!sAllKextLoadIdentifiers->setObject(kextIdentifierSymbol)) {
4569 fail = true;
4570 } else {
4571 // xxx - need to find a way to associate this whole func w/the kext
4572 OSKextLog(/* kext */ NULL,
4573 // xxx - check level
4574 kOSKextLogStepLevel |
4575 kOSKextLogArchiveFlag,
4576 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
4577 kextIdentifier->getCStringNoCopy());
4578 }
4579 }
4580 IORecursiveLockUnlock(sKextLock);
4581
4582 finish:
4583
4584 if (fail) {
4585 OSKextLog(/* kext */ NULL,
4586 kOSKextLogErrorLevel |
4587 kOSKextLogArchiveFlag,
4588 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
4589 kextIdentifier->getCStringNoCopy());
4590 }
4591 OSSafeReleaseNULL(kextIdentifierSymbol);
4592 return;
4593 }
4594
4595 /*********************************************************************
4596 *********************************************************************/
4597 OSReturn
4598 OSKext::load(
4599 OSKextExcludeLevel startOpt,
4600 OSKextExcludeLevel startMatchingOpt,
4601 OSArray * personalityNames)
4602 {
4603 OSReturn result = kOSReturnError;
4604 kern_return_t kxldResult;
4605 OSKextExcludeLevel dependenciesStartOpt = startOpt;
4606 OSKextExcludeLevel dependenciesStartMatchingOpt = startMatchingOpt;
4607 unsigned int i, count;
4608 Boolean alreadyLoaded = false;
4609 OSKext * lastLoadedKext = NULL;
4610
4611 if (isInExcludeList()) {
4612 OSKextLog(this,
4613 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
4614 kOSKextLogLoadFlag,
4615 "Kext %s is in exclude list, not loadable",
4616 getIdentifierCString());
4617
4618 result = kOSKextReturnNotLoadable;
4619 goto finish;
4620 }
4621
4622 if (isLoaded()) {
4623 alreadyLoaded = true;
4624 result = kOSReturnSuccess;
4625
4626 OSKextLog(this,
4627 kOSKextLogDebugLevel |
4628 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4629 "Kext %s is already loaded.",
4630 getIdentifierCString());
4631 goto loaded;
4632 }
4633
4634 #if CONFIG_MACF
4635 if (current_task() != kernel_task) {
4636 int macCheckResult = 0;
4637 kauth_cred_t cred = NULL;
4638
4639 cred = kauth_cred_get_with_ref();
4640 macCheckResult = mac_kext_check_load(cred, getIdentifierCString());
4641 kauth_cred_unref(&cred);
4642
4643 if (macCheckResult != 0) {
4644 result = kOSReturnError;
4645 OSKextLog(this,
4646 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
4647 "Failed to load kext %s (MAC policy error 0x%x).",
4648 getIdentifierCString(), macCheckResult);
4649 goto finish;
4650 }
4651 }
4652 #endif
4653
4654 if (!sLoadEnabled) {
4655 OSKextLog(this,
4656 kOSKextLogErrorLevel |
4657 kOSKextLogLoadFlag,
4658 "Kext loading is disabled (attempt to load kext %s).",
4659 getIdentifierCString());
4660 result = kOSKextReturnDisabled;
4661 goto finish;
4662 }
4663
4664 /* If we've pushed the next available load tag to the invalid value,
4665 * we can't load any more kexts.
4666 */
4667 if (sNextLoadTag == kOSKextInvalidLoadTag) {
4668 OSKextLog(this,
4669 kOSKextLogErrorLevel |
4670 kOSKextLogLoadFlag,
4671 "Can't load kext %s - no more load tags to assign.",
4672 getIdentifierCString());
4673 result = kOSKextReturnNoResources;
4674 goto finish;
4675 }
4676
4677 /* This is a bit of a hack, because we shouldn't be handling
4678 * personalities within the load function.
4679 */
4680 if (!declaresExecutable()) {
4681 /* There is a special case where a non-executable kext can be loaded: the
4682 * AppleKextExcludeList. Detect that special kext by bundle identifier and
4683 * load its metadata into the global data structures, if appropriate
4684 */
4685 if (strcmp(getIdentifierCString(), "com.apple.driver.KextExcludeList") == 0) {
4686 boolean_t updated = updateExcludeList(infoDict);
4687 if (updated) {
4688 OSKextLog(this,
4689 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
4690 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
4691 }
4692 }
4693 result = kOSReturnSuccess;
4694 goto loaded;
4695 }
4696
4697 /* Are we in safe boot?
4698 */
4699 if (sSafeBoot && !isLoadableInSafeBoot()) {
4700 OSKextLog(this,
4701 kOSKextLogErrorLevel |
4702 kOSKextLogLoadFlag,
4703 "Can't load kext %s - not loadable during safe boot.",
4704 getIdentifierCString());
4705 result = kOSKextReturnBootLevel;
4706 goto finish;
4707 }
4708
4709 OSKextLog(this,
4710 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
4711 "Loading kext %s.",
4712 getIdentifierCString());
4713
4714 if (!sKxldContext) {
4715 kxldResult = kxld_create_context(&sKxldContext, &kern_allocate,
4716 &kxld_log_callback, /* Flags */ (KXLDFlags) 0,
4717 /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
4718 if (kxldResult) {
4719 OSKextLog(this,
4720 kOSKextLogErrorLevel |
4721 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
4722 "Can't load kext %s - failed to create link context.",
4723 getIdentifierCString());
4724 result = kOSKextReturnNoMemory;
4725 goto finish;
4726 }
4727 }
4728
4729 /* We only need to resolve dependencies once for the whole graph, but
4730 * resolveDependencies will just return if there's no work to do, so it's
4731 * safe to call it more than once.
4732 */
4733 if (!resolveDependencies()) {
4734 // xxx - check resolveDependencies() for log msg
4735 OSKextLog(this,
4736 kOSKextLogErrorLevel |
4737 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4738 "Can't load kext %s - failed to resolve library dependencies.",
4739 getIdentifierCString());
4740 result = kOSKextReturnDependencies;
4741 goto finish;
4742 }
4743
4744 /* If we are excluding just the kext being loaded now (and not its
4745 * dependencies), drop the exclusion level to none so dependencies
4746 * start and/or add their personalities.
4747 */
4748 if (dependenciesStartOpt == kOSKextExcludeKext) {
4749 dependenciesStartOpt = kOSKextExcludeNone;
4750 }
4751
4752 if (dependenciesStartMatchingOpt == kOSKextExcludeKext) {
4753 dependenciesStartMatchingOpt = kOSKextExcludeNone;
4754 }
4755
4756 /* Load the dependencies, recursively.
4757 */
4758 count = getNumDependencies();
4759 for (i = 0; i < count; i++) {
4760 OSKext * dependency = OSDynamicCast(OSKext,
4761 dependencies->getObject(i));
4762 if (dependency == NULL) {
4763 OSKextLog(this,
4764 kOSKextLogErrorLevel |
4765 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4766 "Internal error loading kext %s; dependency disappeared.",
4767 getIdentifierCString());
4768 result = kOSKextReturnInternalError;
4769 goto finish;
4770 }
4771
4772 /* Dependencies must be started accorting to the opt,
4773 * but not given the personality names of the main kext.
4774 */
4775 result = dependency->load(dependenciesStartOpt,
4776 dependenciesStartMatchingOpt,
4777 /* personalityNames */ NULL);
4778 if (result != KERN_SUCCESS) {
4779 OSKextLog(this,
4780 kOSKextLogErrorLevel |
4781 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4782 "Dependency %s of kext %s failed to load.",
4783 dependency->getIdentifierCString(),
4784 getIdentifierCString());
4785
4786 OSKext::removeKext(dependency,
4787 /* terminateService/removePersonalities */ true);
4788 result = kOSKextReturnDependencyLoadError;
4789
4790 goto finish;
4791 }
4792 }
4793
4794 result = loadExecutable();
4795 if (result != KERN_SUCCESS) {
4796 goto finish;
4797 }
4798
4799 pendingPgoHead.next = &pendingPgoHead;
4800 pendingPgoHead.prev = &pendingPgoHead;
4801
4802 uuid_generate(instance_uuid);
4803 account = IONew(OSKextAccount, 1);
4804 if (!account) {
4805 result = KERN_MEMORY_ERROR;
4806 goto finish;
4807 }
4808 bzero(account, sizeof(*account));
4809 account->loadTag = kmod_info->id;
4810 account->site.refcount = 0;
4811 account->site.flags = VM_TAG_KMOD;
4812 account->kext = this;
4813
4814 flags.loaded = true;
4815
4816 /* Add the kext to the list of loaded kexts and update the kmod_info
4817 * struct to point to that of the last loaded kext (which is the way
4818 * it's always been done, though I'd rather do them in order now).
4819 */
4820 lastLoadedKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
4821 sLoadedKexts->setObject(this);
4822
4823 /* Keep the kernel itself out of the kmod list.
4824 */
4825 if (lastLoadedKext->isKernel()) {
4826 lastLoadedKext = NULL;
4827 }
4828
4829 if (lastLoadedKext) {
4830 kmod_info->next = lastLoadedKext->kmod_info;
4831 }
4832
4833 notifyKextLoadObservers(this, kmod_info);
4834
4835 /* Make the global kmod list point at the just-loaded kext. Note that the
4836 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
4837 * although we do report it in kextstat these days by using the newer
4838 * OSArray of loaded kexts, which does contain it.
4839 *
4840 * (The OSKext object representing the kernel doesn't even have a kmod_info
4841 * struct, though I suppose we could stick a pointer to it from the
4842 * static struct in OSRuntime.cpp.)
4843 */
4844 kmod = kmod_info;
4845
4846 /* Save the list of loaded kexts in case we panic.
4847 */
4848 OSKext::saveLoadedKextPanicList();
4849
4850 if (isExecutable()) {
4851 OSKext::updateLoadedKextSummaries();
4852 savePanicString(/* isLoading */ true);
4853
4854 #if CONFIG_DTRACE
4855 registerWithDTrace();
4856 #else
4857 jettisonLinkeditSegment();
4858 #endif /* CONFIG_DTRACE */
4859
4860 #if !VM_MAPPED_KEXTS
4861 /* If there is a page (or more) worth of padding after the end
4862 * of the last data section but before the end of the data segment
4863 * then free it in the same manner the LinkeditSegment is freed
4864 */
4865 jettisonDATASegmentPadding();
4866 #endif
4867 }
4868
4869 loaded:
4870 if (isExecutable() && !flags.started) {
4871 if (startOpt == kOSKextExcludeNone) {
4872 result = start();
4873 if (result != kOSReturnSuccess) {
4874 OSKextLog(this,
4875 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
4876 "Kext %s start failed (result 0x%x).",
4877 getIdentifierCString(), result);
4878 result = kOSKextReturnStartStopError;
4879 }
4880 }
4881 }
4882
4883 /* If not excluding matching, send the personalities to the kernel.
4884 * This never affects the result of the load operation.
4885 * This is a bit of a hack, because we shouldn't be handling
4886 * personalities within the load function.
4887 */
4888 if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
4889 result = sendPersonalitiesToCatalog(true, personalityNames);
4890 }
4891
4892 finish:
4893
4894 /* More hack! If the kext doesn't declare an executable, even if we
4895 * "loaded" it, we have to remove any personalities naming it, or we'll
4896 * never see the registry go quiet. Errors here do not count for the
4897 * load operation itself.
4898 *
4899 * Note that in every other regard it's perfectly ok for a kext to
4900 * not declare an executable and serve only as a package for personalities
4901 * naming another kext, so we do have to allow such kexts to be "loaded"
4902 * so that those other personalities get added & matched.
4903 */
4904 if (!declaresExecutable()) {
4905 OSKextLog(this,
4906 kOSKextLogStepLevel | kOSKextLogLoadFlag,
4907 "Kext %s has no executable; removing any personalities naming it.",
4908 getIdentifierCString());
4909 removePersonalitiesFromCatalog();
4910 }
4911
4912 if (result != kOSReturnSuccess) {
4913 OSKextLog(this,
4914 kOSKextLogErrorLevel |
4915 kOSKextLogLoadFlag,
4916 "Kext %s failed to load (0x%x).",
4917 getIdentifierCString(), (int)result);
4918 } else if (!alreadyLoaded) {
4919 OSKextLog(this,
4920 kOSKextLogProgressLevel |
4921 kOSKextLogLoadFlag,
4922 "Kext %s loaded.",
4923 getIdentifierCString());
4924
4925 queueKextNotification(kKextRequestPredicateLoadNotification,
4926 OSDynamicCast(OSString, bundleID));
4927 }
4928 return result;
4929 }
4930
4931 /*********************************************************************
4932 *
4933 *********************************************************************/
4934 static char * strdup(const char * string)
4935 {
4936 char * result = NULL;
4937 size_t size;
4938
4939 if (!string) {
4940 goto finish;
4941 }
4942
4943 size = 1 + strlen(string);
4944 result = (char *)kalloc_tag(size, VM_KERN_MEMORY_OSKEXT);
4945 if (!result) {
4946 goto finish;
4947 }
4948
4949 memcpy(result, string, size);
4950
4951 finish:
4952 return result;
4953 }
4954
4955 /*********************************************************************
4956 *
4957 *********************************************************************/
4958
4959 kernel_section_t *
4960 OSKext::lookupSection(const char *segname, const char *secname)
4961 {
4962 kernel_section_t * found_section = NULL;
4963 kernel_mach_header_t * mh = NULL;
4964 kernel_segment_command_t * seg = NULL;
4965 kernel_section_t * sec = NULL;
4966
4967 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
4968
4969 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
4970
4971 if (0 != strcmp(seg->segname, segname)) {
4972 continue;
4973 }
4974
4975 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
4976
4977 if (0 == strcmp(sec->sectname, secname)) {
4978 found_section = sec;
4979 goto out;
4980 }
4981 }
4982 }
4983
4984 out:
4985 return found_section;
4986 }
4987
4988 /*********************************************************************
4989 *
4990 *********************************************************************/
4991
4992 OSReturn
4993 OSKext::slidePrelinkedExecutable(bool doCoalesedSlides)
4994 {
4995 OSReturn result = kOSKextReturnBadData;
4996 kernel_mach_header_t * mh = NULL;
4997 kernel_segment_command_t * seg = NULL;
4998 kernel_segment_command_t * linkeditSeg = NULL;
4999 kernel_section_t * sec = NULL;
5000 char * linkeditBase = NULL;
5001 bool haveLinkeditBase = false;
5002 char * relocBase = NULL;
5003 bool haveRelocBase = false;
5004 struct dysymtab_command * dysymtab = NULL;
5005 struct linkedit_data_command * segmentSplitInfo = NULL;
5006 struct symtab_command * symtab = NULL;
5007 kernel_nlist_t * sym = NULL;
5008 struct relocation_info * reloc = NULL;
5009 uint32_t i = 0;
5010 int reloc_size;
5011 vm_offset_t new_kextsize;
5012
5013 if (linkedExecutable == NULL || vm_kernel_slide == 0) {
5014 result = kOSReturnSuccess;
5015 goto finish;
5016 }
5017
5018 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
5019 segmentSplitInfo = (struct linkedit_data_command *) getcommandfromheader(mh, LC_SEGMENT_SPLIT_INFO);
5020
5021 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
5022 if (!seg->vmaddr) {
5023 continue;
5024 }
5025 seg->vmaddr += vm_kernel_slide;
5026
5027 #if KASLR_KEXT_DEBUG
5028 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
5029 seg->segname,
5030 (unsigned long)VM_KERNEL_UNSLIDE(seg->vmaddr),
5031 (unsigned long)seg->vmaddr);
5032 #endif
5033
5034 if (!haveRelocBase) {
5035 relocBase = (char *) seg->vmaddr;
5036 haveRelocBase = true;
5037 }
5038 if (!strcmp(seg->segname, "__LINKEDIT")) {
5039 linkeditBase = (char *) seg->vmaddr - seg->fileoff;
5040 haveLinkeditBase = true;
5041 linkeditSeg = seg;
5042 }
5043 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
5044 sec->addr += vm_kernel_slide;
5045
5046 #if KASLR_KEXT_DEBUG
5047 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
5048 sec->sectname,
5049 (unsigned long)VM_KERNEL_UNSLIDE(sec->addr),
5050 (unsigned long)sec->addr);
5051 #endif
5052 }
5053 }
5054
5055 dysymtab = (struct dysymtab_command *) getcommandfromheader(mh, LC_DYSYMTAB);
5056
5057 symtab = (struct symtab_command *) getcommandfromheader(mh, LC_SYMTAB);
5058
5059 if (symtab != NULL && doCoalesedSlides == false) {
5060 /* Some pseudo-kexts have symbol tables without segments.
5061 * Ignore them. */
5062 if (symtab->nsyms > 0 && haveLinkeditBase) {
5063 sym = (kernel_nlist_t *) (linkeditBase + symtab->symoff);
5064 for (i = 0; i < symtab->nsyms; i++) {
5065 if (sym[i].n_type & N_STAB) {
5066 continue;
5067 }
5068 sym[i].n_value += vm_kernel_slide;
5069
5070 #if KASLR_KEXT_DEBUG
5071 #define MAX_SYMS_TO_LOG 5
5072 if ( i < MAX_SYMS_TO_LOG ) {
5073 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
5074 (unsigned long)VM_KERNEL_UNSLIDE(sym[i].n_value),
5075 (unsigned long)sym[i].n_value);
5076 }
5077 #endif
5078 }
5079 }
5080 }
5081
5082 if (dysymtab != NULL && doCoalesedSlides == false) {
5083 if (dysymtab->nextrel > 0) {
5084 OSKextLog(this,
5085 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
5086 kOSKextLogLinkFlag,
5087 "Sliding kext %s: External relocations found.",
5088 getIdentifierCString());
5089 goto finish;
5090 }
5091
5092 if (dysymtab->nlocrel > 0) {
5093 if (!haveLinkeditBase) {
5094 OSKextLog(this,
5095 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
5096 kOSKextLogLinkFlag,
5097 "Sliding kext %s: No linkedit segment.",
5098 getIdentifierCString());
5099 goto finish;
5100 }
5101
5102 if (!haveRelocBase) {
5103 OSKextLog(this,
5104 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
5105 kOSKextLogLinkFlag,
5106 #if __x86_64__
5107 "Sliding kext %s: No writable segments.",
5108 #else
5109 "Sliding kext %s: No segments.",
5110 #endif
5111 getIdentifierCString());
5112 goto finish;
5113 }
5114
5115 reloc = (struct relocation_info *) (linkeditBase + dysymtab->locreloff);
5116 reloc_size = dysymtab->nlocrel * sizeof(struct relocation_info);
5117
5118 for (i = 0; i < dysymtab->nlocrel; i++) {
5119 if ( reloc[i].r_extern != 0
5120 || reloc[i].r_type != 0
5121 || reloc[i].r_length != (sizeof(void *) == 8 ? 3 : 2)
5122 ) {
5123 OSKextLog(this,
5124 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
5125 kOSKextLogLinkFlag,
5126 "Sliding kext %s: Unexpected relocation found.",
5127 getIdentifierCString());
5128 goto finish;
5129 }
5130 if (reloc[i].r_pcrel != 0) {
5131 continue;
5132 }
5133 *((uintptr_t *)(relocBase + reloc[i].r_address)) += vm_kernel_slide;
5134
5135 #if KASLR_KEXT_DEBUG
5136 #define MAX_DYSYMS_TO_LOG 5
5137 if ( i < MAX_DYSYMS_TO_LOG ) {
5138 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
5139 (unsigned long)VM_KERNEL_UNSLIDE(*((uintptr_t *)(relocBase + reloc[i].r_address))),
5140 (unsigned long)*((uintptr_t *)(relocBase + reloc[i].r_address)));
5141 }
5142 #endif
5143 }
5144
5145 /* We should free these relocations, not just delete the reference to them.
5146 * <rdar://problem/10535549> Free relocations from PIE kexts.
5147 *
5148 * For now, we do not free LINKEDIT for kexts with split segments.
5149 */
5150 new_kextsize = round_page(kmod_info->size - reloc_size);
5151 if (((kmod_info->size - new_kextsize) > PAGE_SIZE) && (!segmentSplitInfo)) {
5152 vm_offset_t endofkext = kmod_info->address + kmod_info->size;
5153 vm_offset_t new_endofkext = kmod_info->address + new_kextsize;
5154 vm_offset_t endofrelocInfo = (vm_offset_t) (((uint8_t *)reloc) + reloc_size);
5155 int bytes_remaining = endofkext - endofrelocInfo;
5156 OSData * new_osdata = NULL;
5157
5158 /* fix up symbol offsets if they are after the dsymtab local relocs */
5159 if (symtab) {
5160 if (dysymtab->locreloff < symtab->symoff){
5161 symtab->symoff -= reloc_size;
5162 }
5163 if (dysymtab->locreloff < symtab->stroff) {
5164 symtab->stroff -= reloc_size;
5165 }
5166 }
5167 if (dysymtab->locreloff < dysymtab->extreloff) {
5168 dysymtab->extreloff -= reloc_size;
5169 }
5170
5171 /* move data behind reloc info down to new offset */
5172 if (endofrelocInfo < endofkext) {
5173 memcpy(reloc, (void *)endofrelocInfo, bytes_remaining);
5174 }
5175
5176 /* Create a new OSData for the smaller kext object and reflect
5177 * new linkedit segment size.
5178 */
5179 linkeditSeg->vmsize = round_page(linkeditSeg->vmsize - reloc_size);
5180 linkeditSeg->filesize = linkeditSeg->vmsize;
5181
5182 new_osdata = OSData::withBytesNoCopy((void *)kmod_info->address, new_kextsize);
5183 if (new_osdata) {
5184 /* Fix up kmod info and linkedExecutable.
5185 */
5186 kmod_info->size = new_kextsize;
5187 #if VM_MAPPED_KEXTS
5188 new_osdata->setDeallocFunction(osdata_kext_free);
5189 #else
5190 new_osdata->setDeallocFunction(osdata_phys_free);
5191 #endif
5192 linkedExecutable->setDeallocFunction(NULL);
5193 linkedExecutable->release();
5194 linkedExecutable = new_osdata;
5195
5196 #if VM_MAPPED_KEXTS
5197 kext_free(new_endofkext, (endofkext - new_endofkext));
5198 #else
5199 ml_static_mfree(new_endofkext, (endofkext - new_endofkext));
5200 #endif
5201 }
5202 }
5203 dysymtab->nlocrel = 0;
5204 dysymtab->locreloff = 0;
5205 }
5206 }
5207
5208 result = kOSReturnSuccess;
5209 finish:
5210 return result;
5211 }
5212
5213 /*********************************************************************
5214 * called only by load()
5215 *********************************************************************/
5216 OSReturn
5217 OSKext::loadExecutable()
5218 {
5219 OSReturn result = kOSReturnError;
5220 kern_return_t kxldResult;
5221 KXLDDependency * kxlddeps = NULL; // must kfree
5222 uint32_t num_kxlddeps = 0;
5223 OSArray * linkDependencies = NULL; // must release
5224 uint32_t numDirectDependencies = 0;
5225 uint32_t num_kmod_refs = 0;
5226 struct mach_header ** kxldHeaderPtr = NULL; // do not free
5227 struct mach_header * kxld_header = NULL; // xxx - need to free here?
5228 OSData * theExecutable = NULL; // do not release
5229 OSString * versString = NULL; // do not release
5230 const char * versCString = NULL; // do not free
5231 const char * string = NULL; // do not free
5232 unsigned int i;
5233
5234 /* We need the version string for a variety of bits below.
5235 */
5236 versString = OSDynamicCast(OSString,
5237 getPropertyForHostArch(kCFBundleVersionKey));
5238 if (!versString) {
5239 goto finish;
5240 }
5241 versCString = versString->getCStringNoCopy();
5242
5243 if (isKernelComponent()) {
5244 if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
5245
5246 if (strncmp(versCString, KERNEL6_VERSION, strlen(KERNEL6_VERSION))) {
5247 OSKextLog(this,
5248 kOSKextLogErrorLevel |
5249 kOSKextLogLoadFlag,
5250 "Kernel component %s has incorrect version %s; "
5251 "expected %s.",
5252 getIdentifierCString(),
5253 versCString, KERNEL6_VERSION);
5254 result = kOSKextReturnInternalError;
5255 goto finish;
5256 } else if (strcmp(versCString, osrelease)) {
5257 OSKextLog(this,
5258 kOSKextLogErrorLevel |
5259 kOSKextLogLoadFlag,
5260 "Kernel component %s has incorrect version %s; "
5261 "expected %s.",
5262 getIdentifierCString(),
5263 versCString, osrelease);
5264 result = kOSKextReturnInternalError;
5265 goto finish;
5266 }
5267 }
5268 }
5269
5270 if (isPrelinked()) {
5271 goto register_kmod;
5272 }
5273
5274 /* <rdar://problem/21444003> all callers must be entitled */
5275 if (FALSE == IOTaskHasEntitlement(current_task(), "com.apple.rootless.kext-management")) {
5276 OSKextLog(this,
5277 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5278 "Not entitled to link kext '%s'",
5279 getIdentifierCString());
5280 result = kOSKextReturnNotPrivileged;
5281 goto finish;
5282 }
5283
5284 theExecutable = getExecutable();
5285 if (!theExecutable) {
5286 if (declaresExecutable()) {
5287 OSKextLog(this,
5288 kOSKextLogErrorLevel |
5289 kOSKextLogLoadFlag,
5290 "Can't load kext %s - executable is missing.",
5291 getIdentifierCString());
5292 result = kOSKextReturnValidation;
5293 goto finish;
5294 }
5295 goto register_kmod;
5296 }
5297
5298 if (isInterface()) {
5299 OSData *executableCopy = OSData::withData(theExecutable);
5300 setLinkedExecutable(executableCopy);
5301 executableCopy->release();
5302 goto register_kmod;
5303 }
5304
5305 numDirectDependencies = getNumDependencies();
5306
5307 if (flags.hasBleedthrough) {
5308 linkDependencies = dependencies;
5309 linkDependencies->retain();
5310 } else {
5311 linkDependencies = OSArray::withArray(dependencies);
5312 if (!linkDependencies) {
5313 OSKextLog(this,
5314 kOSKextLogErrorLevel |
5315 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
5316 "Can't allocate link dependencies to load kext %s.",
5317 getIdentifierCString());
5318 goto finish;
5319 }
5320
5321 for (i = 0; i < numDirectDependencies; ++i) {
5322 OSKext * dependencyKext = OSDynamicCast(OSKext,
5323 dependencies->getObject(i));
5324 dependencyKext->addBleedthroughDependencies(linkDependencies);
5325 }
5326 }
5327
5328 num_kxlddeps = linkDependencies->getCount();
5329 if (!num_kxlddeps) {
5330 OSKextLog(this,
5331 kOSKextLogErrorLevel |
5332 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5333 "Can't load kext %s - it has no library dependencies.",
5334 getIdentifierCString());
5335 goto finish;
5336 }
5337
5338 kxlddeps = (KXLDDependency *)kalloc_tag(num_kxlddeps * sizeof(*kxlddeps), VM_KERN_MEMORY_OSKEXT);
5339 if (!kxlddeps) {
5340 OSKextLog(this,
5341 kOSKextLogErrorLevel |
5342 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
5343 "Can't allocate link context to load kext %s.",
5344 getIdentifierCString());
5345 goto finish;
5346 }
5347 bzero(kxlddeps, num_kxlddeps * sizeof(*kxlddeps));
5348
5349 for (i = 0; i < num_kxlddeps; ++i ) {
5350 OSKext * dependency = OSDynamicCast(OSKext, linkDependencies->getObject(i));
5351
5352 if (dependency->isInterface()) {
5353 OSKext *interfaceTargetKext = NULL;
5354 OSData * interfaceTarget = NULL;
5355
5356 if (dependency->isKernelComponent()) {
5357 interfaceTargetKext = sKernelKext;
5358 interfaceTarget = sKernelKext->linkedExecutable;
5359 } else {
5360 interfaceTargetKext = OSDynamicCast(OSKext,
5361 dependency->dependencies->getObject(0));
5362
5363 interfaceTarget = interfaceTargetKext->linkedExecutable;
5364 }
5365
5366 if (!interfaceTarget) {
5367 // panic?
5368 goto finish;
5369 }
5370
5371 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
5372 * it will be useful to have them in the debugger.
5373 * strdup() failing isn't critical right here so we don't check that.
5374 */
5375 kxlddeps[i].kext = (u_char *) interfaceTarget->getBytesNoCopy();
5376 kxlddeps[i].kext_size = interfaceTarget->getLength();
5377 kxlddeps[i].kext_name = strdup(interfaceTargetKext->getIdentifierCString());
5378
5379 kxlddeps[i].interface = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
5380 kxlddeps[i].interface_size = dependency->linkedExecutable->getLength();
5381 kxlddeps[i].interface_name = strdup(dependency->getIdentifierCString());
5382 } else {
5383 kxlddeps[i].kext = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
5384 kxlddeps[i].kext_size = dependency->linkedExecutable->getLength();
5385 kxlddeps[i].kext_name = strdup(dependency->getIdentifierCString());
5386 }
5387
5388 kxlddeps[i].is_direct_dependency = (i < numDirectDependencies);
5389 }
5390
5391 kxldHeaderPtr = &kxld_header;
5392
5393 #if DEBUG
5394 OSKextLog(this,
5395 kOSKextLogExplicitLevel |
5396 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
5397 "Kext %s - calling kxld_link_file:\n"
5398 " kxld_context: %p\n"
5399 " executable: %p executable_length: %d\n"
5400 " user_data: %p\n"
5401 " kxld_dependencies: %p num_dependencies: %d\n"
5402 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
5403 getIdentifierCString(), sKxldContext,
5404 theExecutable->getBytesNoCopy(), theExecutable->getLength(),
5405 this, kxlddeps, num_kxlddeps,
5406 kxldHeaderPtr, &kmod_info);
5407 #endif
5408
5409 /* After this call, the linkedExecutable instance variable
5410 * should exist.
5411 */
5412 kxldResult = kxld_link_file(sKxldContext,
5413 (u_char *)theExecutable->getBytesNoCopy(),
5414 theExecutable->getLength(),
5415 getIdentifierCString(), this, kxlddeps, num_kxlddeps,
5416 (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info);
5417
5418 if (kxldResult != KERN_SUCCESS) {
5419 // xxx - add kxldResult here?
5420 OSKextLog(this,
5421 kOSKextLogErrorLevel |
5422 kOSKextLogLoadFlag,
5423 "Can't load kext %s - link failed.",
5424 getIdentifierCString());
5425 result = kOSKextReturnLinkError;
5426 goto finish;
5427 }
5428
5429 /* We've written data & instructions into kernel memory, so flush the data
5430 * cache and invalidate the instruction cache.
5431 * I/D caches are coherent on x86
5432 */
5433 #if !defined(__i386__) && !defined(__x86_64__)
5434 flush_dcache(kmod_info->address, kmod_info->size, false);
5435 invalidate_icache(kmod_info->address, kmod_info->size, false);
5436 #endif
5437 register_kmod:
5438
5439 if (isInterface()) {
5440
5441 /* Whip up a fake kmod_info entry for the interface kext.
5442 */
5443 kmod_info = (kmod_info_t *)kalloc_tag(sizeof(kmod_info_t), VM_KERN_MEMORY_OSKEXT);
5444 if (!kmod_info) {
5445 result = KERN_MEMORY_ERROR;
5446 goto finish;
5447 }
5448
5449 /* A pseudokext has almost nothing in its kmod_info struct.
5450 */
5451 bzero(kmod_info, sizeof(kmod_info_t));
5452
5453 kmod_info->info_version = KMOD_INFO_VERSION;
5454
5455 /* An interface kext doesn't have a linkedExecutable, so save a
5456 * copy of the UUID out of the original executable via copyUUID()
5457 * while we still have the original executable.
5458 */
5459 interfaceUUID = copyUUID();
5460 }
5461
5462 kmod_info->id = loadTag = sNextLoadTag++;
5463 kmod_info->reference_count = 0; // KMOD_DECL... sets it to -1 (invalid).
5464
5465 /* Stamp the bundle ID and version from the OSKext over anything
5466 * resident inside the kmod_info.
5467 */
5468 string = getIdentifierCString();
5469 strlcpy(kmod_info->name, string, sizeof(kmod_info->name));
5470
5471 string = versCString;
5472 strlcpy(kmod_info->version, string, sizeof(kmod_info->version));
5473
5474 /* Add the dependencies' kmod_info structs as kmod_references.
5475 */
5476 num_kmod_refs = getNumDependencies();
5477 if (num_kmod_refs) {
5478 kmod_info->reference_list = (kmod_reference_t *)kalloc_tag(
5479 num_kmod_refs * sizeof(kmod_reference_t), VM_KERN_MEMORY_OSKEXT);
5480 if (!kmod_info->reference_list) {
5481 result = KERN_MEMORY_ERROR;
5482 goto finish;
5483 }
5484 bzero(kmod_info->reference_list,
5485 num_kmod_refs * sizeof(kmod_reference_t));
5486 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
5487 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
5488 OSKext * refKext = OSDynamicCast(OSKext, dependencies->getObject(refIndex));
5489 ref->info = refKext->kmod_info;
5490 ref->info->reference_count++;
5491
5492 if (refIndex + 1 < num_kmod_refs) {
5493 ref->next = kmod_info->reference_list + refIndex + 1;
5494 }
5495 }
5496 }
5497
5498 if (!isInterface() && linkedExecutable) {
5499 OSKextLog(this,
5500 kOSKextLogProgressLevel |
5501 kOSKextLogLoadFlag,
5502 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
5503 kmod_info->name,
5504 (unsigned)kmod_info->size / PAGE_SIZE,
5505 (unsigned long)VM_KERNEL_UNSLIDE(kmod_info->address),
5506 (unsigned)kmod_info->id);
5507 }
5508
5509 /* if prelinked, VM protections are already set */
5510 result = setVMAttributes(!isPrelinked(), true);
5511 if (result != KERN_SUCCESS) {
5512 goto finish;
5513 }
5514
5515 #if KASAN
5516 kasan_load_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(),
5517 linkedExecutable->getLength(), getIdentifierCString());
5518 #else
5519 if (lookupSection(KASAN_GLOBAL_SEGNAME, KASAN_GLOBAL_SECTNAME)) {
5520 OSKextLog(this,
5521 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5522 "KASAN: cannot load KASAN-ified kext %s on a non-KASAN kernel\n",
5523 getIdentifierCString()
5524 );
5525 result = KERN_FAILURE;
5526 goto finish;
5527 }
5528 #endif
5529
5530 result = kOSReturnSuccess;
5531
5532 finish:
5533 OSSafeReleaseNULL(linkDependencies);
5534
5535 /* Clear up locally allocated dependency info.
5536 */
5537 for (i = 0; i < num_kxlddeps; ++i ) {
5538 size_t size;
5539
5540 if (kxlddeps[i].kext_name) {
5541 size = 1 + strlen(kxlddeps[i].kext_name);
5542 kfree(kxlddeps[i].kext_name, size);
5543 }
5544 if (kxlddeps[i].interface_name) {
5545 size = 1 + strlen(kxlddeps[i].interface_name);
5546 kfree(kxlddeps[i].interface_name, size);
5547 }
5548 }
5549 if (kxlddeps) kfree(kxlddeps, (num_kxlddeps * sizeof(*kxlddeps)));
5550
5551 /* We no longer need the unrelocated executable (which the linker
5552 * has altered anyhow).
5553 */
5554 setExecutable(NULL);
5555
5556 if (result != kOSReturnSuccess) {
5557 OSKextLog(this,
5558 kOSKextLogErrorLevel |
5559 kOSKextLogLoadFlag,
5560 "Failed to load executable for kext %s.",
5561 getIdentifierCString());
5562
5563 if (kmod_info && kmod_info->reference_list) {
5564 kfree(kmod_info->reference_list,
5565 num_kmod_refs * sizeof(kmod_reference_t));
5566 }
5567 if (isInterface()) {
5568 kfree(kmod_info, sizeof(kmod_info_t));
5569 }
5570 kmod_info = NULL;
5571 if (linkedExecutable) {
5572 linkedExecutable->release();
5573 linkedExecutable = NULL;
5574 }
5575 }
5576
5577 return result;
5578 }
5579
5580 /*********************************************************************
5581 * The linkedit segment is used by the kext linker for dependency
5582 * resolution, and by dtrace for probe initialization. We can free it
5583 * for non-library kexts, since no kexts depend on non-library kexts
5584 * by definition, once dtrace has been initialized.
5585 *********************************************************************/
5586 void
5587 OSKext::jettisonLinkeditSegment(void)
5588 {
5589 kernel_mach_header_t * machhdr = (kernel_mach_header_t *)kmod_info->address;
5590 kernel_segment_command_t * linkedit = NULL;
5591 vm_offset_t start;
5592 vm_size_t linkeditsize, kextsize;
5593 OSData * data = NULL;
5594
5595 #if NO_KEXTD
5596 /* We can free symbol tables for all embedded kexts because we don't
5597 * support runtime kext linking.
5598 */
5599 if (sKeepSymbols || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
5600 #else
5601 if (sKeepSymbols || isLibrary() || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
5602 #endif
5603 goto finish;
5604 }
5605
5606 /* Find the linkedit segment. If it's not the last segment, then freeing
5607 * it will fragment the kext into multiple VM regions, which OSKext is not
5608 * designed to handle, so we'll have to skip it.
5609 */
5610 linkedit = getsegbynamefromheader(machhdr, SEG_LINKEDIT);
5611 if (!linkedit) {
5612 goto finish;
5613 }
5614
5615 if (round_page(kmod_info->address + kmod_info->size) !=
5616 round_page(linkedit->vmaddr + linkedit->vmsize))
5617 {
5618 goto finish;
5619 }
5620
5621 /* Create a new OSData for the smaller kext object.
5622 */
5623 linkeditsize = round_page(linkedit->vmsize);
5624 kextsize = kmod_info->size - linkeditsize;
5625 start = linkedit->vmaddr;
5626
5627 data = OSData::withBytesNoCopy((void *)kmod_info->address, kextsize);
5628 if (!data) {
5629 goto finish;
5630 }
5631
5632 /* Fix the kmod info and linkedExecutable.
5633 */
5634 kmod_info->size = kextsize;
5635
5636 #if VM_MAPPED_KEXTS
5637 data->setDeallocFunction(osdata_kext_free);
5638 #else
5639 data->setDeallocFunction(osdata_phys_free);
5640 #endif
5641 linkedExecutable->setDeallocFunction(NULL);
5642 linkedExecutable->release();
5643 linkedExecutable = data;
5644 flags.jettisonLinkeditSeg = 1;
5645
5646 /* Free the linkedit segment.
5647 */
5648 #if VM_MAPPED_KEXTS
5649 kext_free(start, linkeditsize);
5650 #else
5651 ml_static_mfree(start, linkeditsize);
5652 #endif
5653
5654 finish:
5655 return;
5656 }
5657
5658 /*********************************************************************
5659 * If there are whole pages that are unused betweem the last section
5660 * of the DATA segment and the end of the DATA segment then we can free
5661 * them
5662 *********************************************************************/
5663 void
5664 OSKext::jettisonDATASegmentPadding(void)
5665 {
5666 kernel_mach_header_t * mh;
5667 kernel_segment_command_t * dataSeg;
5668 kernel_section_t * sec, * lastSec;
5669 vm_offset_t dataSegEnd, lastSecEnd;
5670 vm_size_t padSize;
5671
5672 mh = (kernel_mach_header_t *)kmod_info->address;
5673
5674 dataSeg = getsegbynamefromheader(mh, SEG_DATA);
5675 if (dataSeg == NULL) {
5676 return;
5677 }
5678
5679 lastSec = NULL;
5680 sec = firstsect(dataSeg);
5681 while (sec != NULL) {
5682 lastSec = sec;
5683 sec = nextsect(dataSeg, sec);
5684 }
5685
5686 if (lastSec == NULL) {
5687 return;
5688 }
5689
5690 if ((dataSeg->vmaddr != round_page(dataSeg->vmaddr)) ||
5691 (dataSeg->vmsize != round_page(dataSeg->vmsize))) {
5692 return;
5693 }
5694
5695 dataSegEnd = dataSeg->vmaddr + dataSeg->vmsize;
5696 lastSecEnd = round_page(lastSec->addr + lastSec->size);
5697
5698 if (dataSegEnd <= lastSecEnd) {
5699 return;
5700 }
5701
5702 padSize = dataSegEnd - lastSecEnd;
5703
5704 if (padSize >= PAGE_SIZE) {
5705 #if VM_MAPPED_KEXTS
5706 kext_free(lastSecEnd, padSize);
5707 #else
5708 ml_static_mfree(lastSecEnd, padSize);
5709 #endif
5710 }
5711 }
5712
5713 /*********************************************************************
5714 *********************************************************************/
5715 void
5716 OSKext::setLinkedExecutable(OSData * anExecutable)
5717 {
5718 if (linkedExecutable) {
5719 panic("Attempt to set linked executable on kext "
5720 "that already has one (%s).\n",
5721 getIdentifierCString());
5722 }
5723 linkedExecutable = anExecutable;
5724 linkedExecutable->retain();
5725 return;
5726 }
5727
5728 #if CONFIG_DTRACE
5729 /*********************************************************************
5730 * Go through all loaded kexts and tell them to register with dtrace.
5731 * The instance method only registers if necessary.
5732 *********************************************************************/
5733 /* static */
5734 void
5735 OSKext::registerKextsWithDTrace(void)
5736 {
5737 uint32_t count = sLoadedKexts->getCount();
5738 uint32_t i;
5739
5740 IORecursiveLockLock(sKextLock);
5741
5742 for (i = 0; i < count; i++) {
5743 OSKext * thisKext = NULL; // do not release
5744
5745 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
5746 if (!thisKext || !thisKext->isExecutable()) {
5747 continue;
5748 }
5749
5750 thisKext->registerWithDTrace();
5751 }
5752
5753 IORecursiveLockUnlock(sKextLock);
5754
5755 return;
5756 }
5757
5758 extern "C" {
5759 extern int (*dtrace_modload)(struct kmod_info *, uint32_t);
5760 extern int (*dtrace_modunload)(struct kmod_info *);
5761 };
5762
5763 /*********************************************************************
5764 *********************************************************************/
5765 void
5766 OSKext::registerWithDTrace(void)
5767 {
5768 /* Register kext with dtrace. A dtrace_modload failure should not
5769 * prevent a kext from loading, so we ignore the return code.
5770 */
5771 if (!flags.dtraceInitialized && (dtrace_modload != NULL)) {
5772 uint32_t modflag = 0;
5773 OSObject * forceInit = getPropertyForHostArch("OSBundleForceDTraceInit");
5774 if (forceInit == kOSBooleanTrue) {
5775 modflag |= KMOD_DTRACE_FORCE_INIT;
5776 }
5777
5778 (void)(*dtrace_modload)(kmod_info, modflag);
5779 flags.dtraceInitialized = true;
5780 jettisonLinkeditSegment();
5781 }
5782 return;
5783 }
5784 /*********************************************************************
5785 *********************************************************************/
5786 void
5787 OSKext::unregisterWithDTrace(void)
5788 {
5789 /* Unregister kext with dtrace. A dtrace_modunload failure should not
5790 * prevent a kext from loading, so we ignore the return code.
5791 */
5792 if (flags.dtraceInitialized && (dtrace_modunload != NULL)) {
5793 (void)(*dtrace_modunload)(kmod_info);
5794 flags.dtraceInitialized = false;
5795 }
5796 return;
5797 }
5798 #endif /* CONFIG_DTRACE */
5799
5800
5801 /*********************************************************************
5802 * called only by loadExecutable()
5803 *********************************************************************/
5804 #if !VM_MAPPED_KEXTS
5805 #if defined(__arm__) || defined(__arm64__)
5806 static inline kern_return_t
5807 OSKext_protect(
5808 vm_map_t map,
5809 vm_map_offset_t start,
5810 vm_map_offset_t end,
5811 vm_prot_t new_prot,
5812 boolean_t set_max)
5813 {
5814 #pragma unused(map)
5815 assert(map == kernel_map); // we can handle KEXTs arising from the PRELINK segment and no others
5816 assert(start <= end);
5817 if (start >= end)
5818 return KERN_SUCCESS; // Punt segments of length zero (e.g., headers) or less (i.e., blunders)
5819 else if (set_max)
5820 return KERN_SUCCESS; // Punt set_max, as there's no mechanism to record that state
5821 else
5822 return ml_static_protect(start, end - start, new_prot);
5823 }
5824
5825 static inline kern_return_t
5826 OSKext_wire(
5827 vm_map_t map,
5828 vm_map_offset_t start,
5829 vm_map_offset_t end,
5830 vm_prot_t access_type,
5831 boolean_t user_wire)
5832 {
5833 #pragma unused(map,start,end,access_type,user_wire)
5834 return KERN_SUCCESS; // No-op as PRELINK kexts are cemented into physical memory at boot
5835 }
5836 #else
5837 #error Unrecognized architecture
5838 #endif
5839 #else
5840 static inline kern_return_t
5841 OSKext_protect(
5842 vm_map_t map,
5843 vm_map_offset_t start,
5844 vm_map_offset_t end,
5845 vm_prot_t new_prot,
5846 boolean_t set_max)
5847 {
5848 if (start == end) { // 10538581
5849 return(KERN_SUCCESS);
5850 }
5851 return vm_map_protect(map, start, end, new_prot, set_max);
5852 }
5853
5854 static inline kern_return_t
5855 OSKext_wire(
5856 vm_map_t map,
5857 vm_map_offset_t start,
5858 vm_map_offset_t end,
5859 vm_prot_t access_type,
5860 boolean_t user_wire)
5861 {
5862 return vm_map_wire_kernel(map, start, end, access_type, VM_KERN_MEMORY_KEXT, user_wire);
5863 }
5864 #endif
5865
5866 OSReturn
5867 OSKext::setVMAttributes(bool protect, bool wire)
5868 {
5869 vm_map_t kext_map = NULL;
5870 kernel_segment_command_t * seg = NULL;
5871 vm_map_offset_t start = 0;
5872 vm_map_offset_t end = 0;
5873 OSReturn result = kOSReturnError;
5874
5875 if (isInterface() || !declaresExecutable()) {
5876 result = kOSReturnSuccess;
5877 goto finish;
5878 }
5879
5880 /* Get the kext's vm map */
5881 kext_map = kext_get_vm_map(kmod_info);
5882 if (!kext_map) {
5883 result = KERN_MEMORY_ERROR;
5884 goto finish;
5885 }
5886
5887 #if !VM_MAPPED_KEXTS
5888 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
5889 /* This is a split kext in a prelinked kernelcache; we'll let the
5890 * platform code take care of protecting it. It is already wired.
5891 */
5892 /* TODO: Should this still allow protections for the first segment
5893 * to go through, in the event that we have a mix of split and
5894 * unsplit kexts?
5895 */
5896 result = KERN_SUCCESS;
5897 goto finish;
5898 }
5899 #endif
5900
5901 /* Protect the headers as read-only; they do not need to be wired */
5902 result = (protect) ? OSKext_protect(kext_map, kmod_info->address,
5903 kmod_info->address + kmod_info->hdr_size, VM_PROT_READ, TRUE)
5904 : KERN_SUCCESS;
5905 if (result != KERN_SUCCESS) {
5906 goto finish;
5907 }
5908
5909 /* Set the VM protections and wire down each of the segments */
5910 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
5911 while (seg) {
5912
5913 #if __arm__
5914 /* We build all ARM kexts, so we can ensure they are aligned */
5915 assert((seg->vmaddr & PAGE_MASK) == 0);
5916 assert((seg->vmsize & PAGE_MASK) == 0);
5917 #endif
5918
5919 start = round_page(seg->vmaddr);
5920 end = trunc_page(seg->vmaddr + seg->vmsize);
5921
5922 if (protect) {
5923 result = OSKext_protect(kext_map, start, end, seg->maxprot, TRUE);
5924 if (result != KERN_SUCCESS) {
5925 OSKextLog(this,
5926 kOSKextLogErrorLevel |
5927 kOSKextLogLoadFlag,
5928 "Kext %s failed to set maximum VM protections "
5929 "for segment %s - 0x%x.",
5930 getIdentifierCString(), seg->segname, (int)result);
5931 goto finish;
5932 }
5933
5934 result = OSKext_protect(kext_map, start, end, seg->initprot, FALSE);
5935 if (result != KERN_SUCCESS) {
5936 OSKextLog(this,
5937 kOSKextLogErrorLevel |
5938 kOSKextLogLoadFlag,
5939 "Kext %s failed to set initial VM protections "
5940 "for segment %s - 0x%x.",
5941 getIdentifierCString(), seg->segname, (int)result);
5942 goto finish;
5943 }
5944 }
5945
5946 if (segmentShouldBeWired(seg) && wire) {
5947 result = OSKext_wire(kext_map, start, end, seg->initprot, FALSE);
5948 if (result != KERN_SUCCESS) {
5949 goto finish;
5950 }
5951 }
5952
5953 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
5954 }
5955
5956 finish:
5957 return result;
5958 }
5959
5960 /*********************************************************************
5961 *********************************************************************/
5962 boolean_t
5963 OSKext::segmentShouldBeWired(kernel_segment_command_t *seg)
5964 {
5965 return (sKeepSymbols || strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)));
5966 }
5967
5968 /*********************************************************************
5969 *********************************************************************/
5970 OSReturn
5971 OSKext::validateKextMapping(bool startFlag)
5972 {
5973 OSReturn result = kOSReturnError;
5974 const char * whichOp = startFlag ? "start" : "stop";
5975 kern_return_t kern_result = 0;
5976 vm_map_t kext_map = NULL;
5977 kernel_segment_command_t * seg = NULL;
5978 mach_vm_address_t address = 0;
5979 mach_vm_size_t size = 0;
5980 uint32_t depth = 0;
5981 mach_msg_type_number_t count;
5982 vm_region_submap_short_info_data_64_t info;
5983
5984 count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
5985 bzero(&info, sizeof(info));
5986
5987 // xxx - do we need a distinct OSReturn value for these or is "bad data"
5988 // xxx - sufficient?
5989
5990 /* Verify that the kmod_info and start/stop pointers are non-NULL.
5991 */
5992 if (!kmod_info) {
5993 OSKextLog(this,
5994 kOSKextLogErrorLevel |
5995 kOSKextLogLoadFlag,
5996 "Kext %s - NULL kmod_info pointer.",
5997 getIdentifierCString());
5998 result = kOSKextReturnBadData;
5999 goto finish;
6000 }
6001
6002 if (startFlag) {
6003 address = (mach_vm_address_t)kmod_info->start;
6004 } else {
6005 address = (mach_vm_address_t)kmod_info->stop;
6006 }
6007
6008 if (!address) {
6009 OSKextLog(this,
6010 kOSKextLogErrorLevel |
6011 kOSKextLogLoadFlag,
6012 "Kext %s - NULL module %s pointer.",
6013 getIdentifierCString(), whichOp);
6014 result = kOSKextReturnBadData;
6015 goto finish;
6016 }
6017
6018 kext_map = kext_get_vm_map(kmod_info);
6019 depth = (kernel_map == kext_map) ? 1 : 2;
6020
6021 /* Verify that the start/stop function lies within the kext's address range.
6022 */
6023 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
6024 /* This will likely be how we deal with split kexts; walk the segments to
6025 * check that the function lies inside one of the segments of this kext.
6026 */
6027 for (seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
6028 seg != NULL;
6029 seg = nextsegfromheader((kernel_mach_header_t *)kmod_info->address, seg)) {
6030 if ((address >= seg->vmaddr) && address < (seg->vmaddr + seg->vmsize)) {
6031 break;
6032 }
6033 }
6034
6035 if (!seg) {
6036 OSKextLog(this,
6037 kOSKextLogErrorLevel |
6038 kOSKextLogLoadFlag,
6039 "Kext %s module %s pointer is outside of kext range "
6040 "(%s %p - kext starts at %p).",
6041 getIdentifierCString(),
6042 whichOp,
6043 whichOp,
6044 (void *)VM_KERNEL_UNSLIDE(address),
6045 (void *)VM_KERNEL_UNSLIDE(kmod_info->address));
6046 result = kOSKextReturnBadData;
6047 goto finish;
6048 }
6049
6050 seg = NULL;
6051 } else {
6052 if (address < kmod_info->address + kmod_info->hdr_size ||
6053 kmod_info->address + kmod_info->size <= address)
6054 {
6055 OSKextLog(this,
6056 kOSKextLogErrorLevel |
6057 kOSKextLogLoadFlag,
6058 "Kext %s module %s pointer is outside of kext range "
6059 "(%s %p - kext at %p-%p).",
6060 getIdentifierCString(),
6061 whichOp,
6062 whichOp,
6063 (void *)VM_KERNEL_UNSLIDE(address),
6064 (void *)VM_KERNEL_UNSLIDE(kmod_info->address),
6065 (void *)(VM_KERNEL_UNSLIDE(kmod_info->address) + kmod_info->size));
6066 result = kOSKextReturnBadData;
6067 goto finish;
6068 }
6069 }
6070
6071 /* Only do these checks before calling the start function;
6072 * If anything goes wrong with the mapping while the kext is running,
6073 * we'll likely have panicked well before any attempt to stop the kext.
6074 */
6075 if (startFlag) {
6076
6077 /* Verify that the start/stop function is executable.
6078 */
6079 kern_result = mach_vm_region_recurse(kernel_map, &address, &size, &depth,
6080 (vm_region_recurse_info_t)&info, &count);
6081 if (kern_result != KERN_SUCCESS) {
6082 OSKextLog(this,
6083 kOSKextLogErrorLevel |
6084 kOSKextLogLoadFlag,
6085 "Kext %s - bad %s pointer %p.",
6086 getIdentifierCString(),
6087 whichOp, (void *)VM_KERNEL_UNSLIDE(address));
6088 result = kOSKextReturnBadData;
6089 goto finish;
6090 }
6091
6092 #if VM_MAPPED_KEXTS
6093 if (!(info.protection & VM_PROT_EXECUTE)) {
6094 OSKextLog(this,
6095 kOSKextLogErrorLevel |
6096 kOSKextLogLoadFlag,
6097 "Kext %s - memory region containing module %s function "
6098 "is not executable.",
6099 getIdentifierCString(), whichOp);
6100 result = kOSKextReturnBadData;
6101 goto finish;
6102 }
6103 #endif
6104
6105 /* Verify that the kext's segments are backed by physical memory.
6106 */
6107 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
6108 while (seg) {
6109 if (!verifySegmentMapping(seg)) {
6110 result = kOSKextReturnBadData;
6111 goto finish;
6112 }
6113
6114 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
6115 }
6116
6117 }
6118
6119 result = kOSReturnSuccess;
6120 finish:
6121 return result;
6122 }
6123
6124 /*********************************************************************
6125 *********************************************************************/
6126 boolean_t
6127 OSKext::verifySegmentMapping(kernel_segment_command_t *seg)
6128 {
6129 mach_vm_address_t address = 0;
6130
6131 if (!segmentShouldBeWired(seg)) return true;
6132
6133 for (address = seg->vmaddr;
6134 address < round_page(seg->vmaddr + seg->vmsize);
6135 address += PAGE_SIZE)
6136 {
6137 if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
6138 OSKextLog(this,
6139 kOSKextLogErrorLevel |
6140 kOSKextLogLoadFlag,
6141 "Kext %s - page %p is not backed by physical memory.",
6142 getIdentifierCString(),
6143 (void *)address);
6144 return false;
6145 }
6146 }
6147
6148 return true;
6149 }
6150
6151 /*********************************************************************
6152 *********************************************************************/
6153 static void
6154 OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code)
6155 {
6156
6157 uint64_t stamp = 0;
6158 firehose_tracepoint_id_u trace_id;
6159 struct firehose_trace_uuid_info_s uuid_info_s;
6160 firehose_trace_uuid_info_t uuid_info = &uuid_info_s;
6161 size_t uuid_info_len = sizeof(struct firehose_trace_uuid_info_s);
6162 OSData *uuid_data;
6163
6164 stamp = firehose_tracepoint_time(firehose_activity_flags_default);
6165 trace_id.ftid_value = FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata, _firehose_tracepoint_type_metadata_kext, (firehose_tracepoint_flags_t)0, code);
6166
6167 uuid_data = aKext->copyUUID();
6168 if (uuid_data) {
6169 memcpy(uuid_info->ftui_uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_info->ftui_uuid));
6170 OSSafeReleaseNULL(uuid_data);
6171 }
6172
6173 uuid_info->ftui_size = size;
6174 uuid_info->ftui_address = VM_KERNEL_UNSLIDE(address);
6175
6176 firehose_trace_metadata(firehose_stream_metadata, trace_id, stamp, uuid_info, uuid_info_len);
6177 return;
6178 }
6179
6180 /*********************************************************************
6181 *********************************************************************/
6182 OSReturn
6183 OSKext::start(bool startDependenciesFlag)
6184 {
6185 OSReturn result = kOSReturnError;
6186 kern_return_t (* startfunc)(kmod_info_t *, void *);
6187 unsigned int i, count;
6188 void * kmodStartData = NULL;
6189
6190 if (isStarted() || isInterface() || isKernelComponent()) {
6191 result = kOSReturnSuccess;
6192 goto finish;
6193 }
6194
6195 if (!isLoaded()) {
6196 OSKextLog(this,
6197 kOSKextLogErrorLevel |
6198 kOSKextLogLoadFlag,
6199 "Attempt to start nonloaded kext %s.",
6200 getIdentifierCString());
6201 result = kOSKextReturnInvalidArgument;
6202 goto finish;
6203 }
6204
6205 if (!sLoadEnabled) {
6206 OSKextLog(this,
6207 kOSKextLogErrorLevel |
6208 kOSKextLogLoadFlag,
6209 "Kext loading is disabled (attempt to start kext %s).",
6210 getIdentifierCString());
6211 result = kOSKextReturnDisabled;
6212 goto finish;
6213 }
6214
6215 result = validateKextMapping(/* start? */ true);
6216 if (result != kOSReturnSuccess) {
6217 goto finish;
6218 }
6219
6220 startfunc = kmod_info->start;
6221
6222 count = getNumDependencies();
6223 for (i = 0; i < count; i++) {
6224 OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
6225 if (dependency == NULL) {
6226 OSKextLog(this,
6227 kOSKextLogErrorLevel |
6228 kOSKextLogLoadFlag,
6229 "Kext %s start - internal error, dependency disappeared.",
6230 getIdentifierCString());
6231 goto finish;
6232 }
6233 if (!dependency->isStarted()) {
6234 if (startDependenciesFlag) {
6235 OSReturn dependencyResult =
6236 dependency->start(startDependenciesFlag);
6237 if (dependencyResult != KERN_SUCCESS) {
6238 OSKextLog(this,
6239 kOSKextLogErrorLevel |
6240 kOSKextLogLoadFlag,
6241 "Kext %s start - dependency %s failed to start (error 0x%x).",
6242 getIdentifierCString(),
6243 dependency->getIdentifierCString(),
6244 dependencyResult);
6245 goto finish;
6246 }
6247 } else {
6248 OSKextLog(this,
6249 kOSKextLogErrorLevel |
6250 kOSKextLogLoadFlag,
6251 "Not starting %s - dependency %s not started yet.",
6252 getIdentifierCString(),
6253 dependency->getIdentifierCString());
6254 result = kOSKextReturnStartStopError; // xxx - make new return?
6255 goto finish;
6256 }
6257 }
6258 }
6259
6260 OSKextLog(this,
6261 kOSKextLogDetailLevel |
6262 kOSKextLogLoadFlag,
6263 "Kext %s calling module start function.",
6264 getIdentifierCString());
6265
6266 flags.starting = 1;
6267
6268 // Drop a log message so logd can grab the needed information to decode this kext
6269 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_load);
6270
6271 #if !CONFIG_STATIC_CPPINIT
6272 result = OSRuntimeInitializeCPP(kmod_info, NULL);
6273 if (result == KERN_SUCCESS) {
6274 #endif
6275
6276 #if CONFIG_KEC_FIPS
6277 kmodStartData = GetAppleTEXTHashForKext(this, this->infoDict);
6278
6279 #if 0
6280 if (kmodStartData) {
6281 OSKextLog(this,
6282 kOSKextLogErrorLevel |
6283 kOSKextLogGeneralFlag,
6284 "Kext %s calling module start function. kmodStartData %p. arch %s",
6285 getIdentifierCString(), kmodStartData, ARCHNAME);
6286 }
6287 #endif
6288 #endif // CONFIG_KEC_FIPS
6289 result = startfunc(kmod_info, kmodStartData);
6290
6291 #if !CONFIG_STATIC_CPPINIT
6292 if (result != KERN_SUCCESS) {
6293 (void) OSRuntimeFinalizeCPP(kmod_info, NULL);
6294 }
6295 }
6296 #endif
6297
6298 flags.starting = 0;
6299
6300 /* On success overlap the setting of started/starting. On failure just
6301 * clear starting.
6302 */
6303 if (result == KERN_SUCCESS) {
6304 flags.started = 1;
6305
6306 // xxx - log start error from kernel?
6307 OSKextLog(this,
6308 kOSKextLogProgressLevel |
6309 kOSKextLogLoadFlag,
6310 "Kext %s is now started.",
6311 getIdentifierCString());
6312 } else {
6313 invokeOrCancelRequestCallbacks(
6314 /* result not actually used */ kOSKextReturnStartStopError,
6315 /* invokeFlag */ false);
6316 OSKextLog(this,
6317 kOSKextLogProgressLevel |
6318 kOSKextLogLoadFlag,
6319 "Kext %s did not start (return code 0x%x).",
6320 getIdentifierCString(), result);
6321 }
6322
6323 finish:
6324 return result;
6325 }
6326
6327 /*********************************************************************
6328 *********************************************************************/
6329 /* static */
6330 bool OSKext::canUnloadKextWithIdentifier(
6331 OSString * kextIdentifier,
6332 bool checkClassesFlag)
6333 {
6334 bool result = false;
6335 OSKext * aKext = NULL; // do not release
6336
6337 IORecursiveLockLock(sKextLock);
6338
6339 aKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
6340
6341 if (!aKext) {
6342 goto finish; // can't unload what's not loaded
6343 }
6344
6345 if (aKext->isLoaded()) {
6346 if (aKext->getRetainCount() > kOSKextMinLoadedRetainCount) {
6347 goto finish;
6348 }
6349 if (checkClassesFlag && aKext->hasOSMetaClassInstances()) {
6350 goto finish;
6351 }
6352 }
6353
6354 result = true;
6355
6356 finish:
6357 IORecursiveLockUnlock(sKextLock);
6358 return result;
6359 }
6360
6361 /*********************************************************************
6362 *********************************************************************/
6363 OSReturn
6364 OSKext::stop(void)
6365 {
6366 OSReturn result = kOSReturnError;
6367 kern_return_t (*stopfunc)(kmod_info_t *, void *);
6368
6369 if (!isStarted() || isInterface()) {
6370 result = kOSReturnSuccess;
6371 goto finish;
6372 }
6373
6374 if (!isLoaded()) {
6375 OSKextLog(this,
6376 kOSKextLogErrorLevel |
6377 kOSKextLogLoadFlag,
6378 "Attempt to stop nonloaded kext %s.",
6379 getIdentifierCString());
6380 result = kOSKextReturnInvalidArgument;
6381 goto finish;
6382 }
6383
6384 /* Refuse to stop if we have clients or instances. It is up to
6385 * the caller to make sure those aren't true.
6386 */
6387 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
6388 OSKextLog(this,
6389 kOSKextLogErrorLevel |
6390 kOSKextLogLoadFlag,
6391 "Kext %s - C++ instances; can't stop.",
6392 getIdentifierCString());
6393 result = kOSKextReturnInUse;
6394 goto finish;
6395 }
6396
6397 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
6398
6399 OSKextLog(this,
6400 kOSKextLogErrorLevel |
6401 kOSKextLogLoadFlag,
6402 "Kext %s - has references (linkage or tracking object); "
6403 "can't stop.",
6404 getIdentifierCString());
6405 result = kOSKextReturnInUse;
6406 goto finish;
6407 }
6408
6409 /* Note: If validateKextMapping fails on the stop & unload path,
6410 * we are in serious trouble and a kernel panic is likely whether
6411 * we stop & unload the kext or not.
6412 */
6413 result = validateKextMapping(/* start? */ false);
6414 if (result != kOSReturnSuccess) {
6415 goto finish;
6416 }
6417
6418 stopfunc = kmod_info->stop;
6419 if (stopfunc) {
6420 OSKextLog(this,
6421 kOSKextLogDetailLevel |
6422 kOSKextLogLoadFlag,
6423 "Kext %s calling module stop function.",
6424 getIdentifierCString());
6425
6426 flags.stopping = 1;
6427
6428 result = stopfunc(kmod_info, /* userData */ NULL);
6429 #if !CONFIG_STATIC_CPPINIT
6430 if (result == KERN_SUCCESS) {
6431 result = OSRuntimeFinalizeCPP(kmod_info, NULL);
6432 }
6433 #endif
6434
6435 flags.stopping = 0;
6436
6437 if (result == KERN_SUCCESS) {
6438 flags.started = 0;
6439
6440 OSKextLog(this,
6441 kOSKextLogDetailLevel |
6442 kOSKextLogLoadFlag,
6443 "Kext %s is now stopped and ready to unload.",
6444 getIdentifierCString());
6445 } else {
6446 OSKextLog(this,
6447 kOSKextLogErrorLevel |
6448 kOSKextLogLoadFlag,
6449 "Kext %s did not stop (return code 0x%x).",
6450 getIdentifierCString(), result);
6451 result = kOSKextReturnStartStopError;
6452 }
6453 }
6454
6455 finish:
6456 // Drop a log message so logd can update this kext's metadata
6457 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_unload);
6458 return result;
6459 }
6460
6461 /*********************************************************************
6462 *********************************************************************/
6463 OSReturn
6464 OSKext::unload(void)
6465 {
6466 OSReturn result = kOSReturnError;
6467 unsigned int index;
6468 uint32_t num_kmod_refs = 0;
6469 OSKextAccount * freeAccount;
6470
6471 if (!sUnloadEnabled) {
6472 OSKextLog(this,
6473 kOSKextLogErrorLevel |
6474 kOSKextLogLoadFlag,
6475 "Kext unloading is disabled (%s).",
6476 this->getIdentifierCString());
6477
6478 result = kOSKextReturnDisabled;
6479 goto finish;
6480 }
6481
6482 /* Refuse to unload if we have clients or instances. It is up to
6483 * the caller to make sure those aren't true.
6484 */
6485 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
6486 // xxx - Don't log under errors? this is more of an info thing
6487 OSKextLog(this,
6488 kOSKextLogErrorLevel |
6489 kOSKextLogKextBookkeepingFlag,
6490 "Can't unload kext %s; outstanding references (linkage or tracking object).",
6491 getIdentifierCString());
6492 result = kOSKextReturnInUse;
6493 goto finish;
6494 }
6495
6496 if (!isLoaded()) {
6497 result = kOSReturnSuccess;
6498 goto finish;
6499 }
6500
6501 if (isKernelComponent()) {
6502 result = kOSKextReturnInvalidArgument;
6503 goto finish;
6504 }
6505
6506 if (metaClasses && !OSMetaClass::removeClasses(metaClasses)) {
6507 OSKextLog(this,
6508 kOSKextLogErrorLevel |
6509 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6510 "Can't unload kext %s; classes have instances:",
6511 getIdentifierCString());
6512 reportOSMetaClassInstances(kOSKextLogErrorLevel |
6513 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag);
6514 result = kOSKextReturnInUse;
6515 goto finish;
6516 }
6517
6518 /* Note that the kext is unloading before running any code that
6519 * might be in the kext (request callbacks, module stop function).
6520 * We will deny certain requests made against a kext in the process
6521 * of unloading.
6522 */
6523 flags.unloading = 1;
6524
6525 /* Update the string describing the last kext to unload in case we panic.
6526 */
6527 savePanicString(/* isLoading */ false);
6528
6529 if (isStarted()) {
6530 result = stop();
6531 if (result != KERN_SUCCESS) {
6532 OSKextLog(this,
6533 kOSKextLogErrorLevel |
6534 kOSKextLogLoadFlag,
6535 "Kext %s can't unload - module stop returned 0x%x.",
6536 getIdentifierCString(), (unsigned)result);
6537 result = kOSKextReturnStartStopError;
6538 goto finish;
6539 }
6540 }
6541
6542 OSKextLog(this,
6543 kOSKextLogProgressLevel |
6544 kOSKextLogLoadFlag,
6545 "Kext %s unloading.",
6546 getIdentifierCString());
6547
6548 {
6549 struct list_head *p;
6550 struct list_head *prev;
6551 struct list_head *next;
6552 for (p = pendingPgoHead.next; p != &pendingPgoHead; p = next) {
6553 OSKextGrabPgoStruct *s = container_of(p, OSKextGrabPgoStruct, list_head);
6554 s->err = OSKextGrabPgoDataLocked(this, s->metadata, instance_uuid, s->pSize, s->pBuffer, s->bufferSize);
6555 prev = p->prev;
6556 next = p->next;
6557 prev->next = next;
6558 next->prev = prev;
6559 p->prev = p;
6560 p->next = p;
6561 IORecursiveLockWakeup(sKextLock, s, false);
6562 }
6563 }
6564
6565
6566 /* Even if we don't call the stop function, we want to be sure we
6567 * have no OSMetaClass references before unloading the kext executable
6568 * from memory. OSMetaClasses may have pointers into the kext executable
6569 * and that would cause a panic on OSKext::free() when metaClasses is freed.
6570 */
6571 if (metaClasses) {
6572 metaClasses->flushCollection();
6573 }
6574
6575 /* Remove the kext from the list of loaded kexts, patch the gap
6576 * in the kmod_info_t linked list, and reset "kmod" to point to the
6577 * last loaded kext that isn't the fake kernel kext (sKernelKext).
6578 */
6579 index = sLoadedKexts->getNextIndexOfObject(this, 0);
6580 if (index != (unsigned int)-1) {
6581
6582 sLoadedKexts->removeObject(index);
6583
6584 OSKext * nextKext = OSDynamicCast(OSKext,
6585 sLoadedKexts->getObject(index));
6586
6587 if (nextKext) {
6588 if (index > 0) {
6589 OSKext * gapKext = OSDynamicCast(OSKext,
6590 sLoadedKexts->getObject(index - 1));
6591
6592 nextKext->kmod_info->next = gapKext->kmod_info;
6593
6594 } else /* index == 0 */ {
6595 nextKext->kmod_info->next = NULL;
6596 }
6597 }
6598
6599 OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
6600 if (lastKext && !lastKext->isKernel()) {
6601 kmod = lastKext->kmod_info;
6602 } else {
6603 kmod = NULL; // clear the global kmod variable
6604 }
6605 }
6606
6607 /* Clear out the kmod references that we're keeping for compatibility
6608 * with current panic backtrace code & kgmacros.
6609 * xxx - will want to update those bits sometime and remove this.
6610 */
6611 num_kmod_refs = getNumDependencies();
6612 if (num_kmod_refs && kmod_info && kmod_info->reference_list) {
6613 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
6614 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
6615 ref->info->reference_count--;
6616 }
6617 kfree(kmod_info->reference_list,
6618 num_kmod_refs * sizeof(kmod_reference_t));
6619 }
6620
6621 #if CONFIG_DTRACE
6622 unregisterWithDTrace();
6623 #endif /* CONFIG_DTRACE */
6624
6625 notifyKextUnloadObservers(this);
6626
6627 freeAccount = NULL;
6628 IOSimpleLockLock(sKextAccountsLock);
6629 account->kext = NULL;
6630 if (account->site.tag) account->site.flags |= VM_TAG_UNLOAD;
6631 else freeAccount = account;
6632 IOSimpleLockUnlock(sKextAccountsLock);
6633 if (freeAccount) IODelete(freeAccount, OSKextAccount, 1);
6634
6635 /* Unwire and free the linked executable.
6636 */
6637 if (linkedExecutable) {
6638 #if KASAN
6639 kasan_unload_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(), linkedExecutable->getLength());
6640 #endif
6641
6642 #if VM_MAPPED_KEXTS
6643 if (!isInterface()) {
6644 kernel_segment_command_t *seg = NULL;
6645 vm_map_t kext_map = kext_get_vm_map(kmod_info);
6646
6647 if (!kext_map) {
6648 OSKextLog(this,
6649 kOSKextLogErrorLevel |
6650 kOSKextLogLoadFlag,
6651 "Failed to free kext %s; couldn't find the kext map.",
6652 getIdentifierCString());
6653 result = kOSKextReturnInternalError;
6654 goto finish;
6655 }
6656
6657 OSKextLog(this,
6658 kOSKextLogProgressLevel |
6659 kOSKextLogLoadFlag,
6660 "Kext %s unwiring and unmapping linked executable.",
6661 getIdentifierCString());
6662
6663 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
6664 while (seg) {
6665 if (segmentShouldBeWired(seg)) {
6666 result = vm_map_unwire(kext_map, seg->vmaddr,
6667 seg->vmaddr + seg->vmsize, FALSE);
6668 if (result != KERN_SUCCESS) {
6669 OSKextLog(this,
6670 kOSKextLogErrorLevel |
6671 kOSKextLogLoadFlag,
6672 "Failed to unwire kext %s.",
6673 getIdentifierCString());
6674 result = kOSKextReturnInternalError;
6675 goto finish;
6676 }
6677 }
6678
6679 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
6680 }
6681 }
6682 #endif
6683 OSSafeReleaseNULL(linkedExecutable);
6684 }
6685
6686 /* An interface kext has a fake kmod_info that was allocated,
6687 * so we have to free it.
6688 */
6689 if (isInterface()) {
6690 kfree(kmod_info, sizeof(kmod_info_t));
6691 }
6692
6693 kmod_info = NULL;
6694
6695 flags.loaded = false;
6696 flushDependencies();
6697
6698 /* save a copy of the bundle ID for us to check when deciding to
6699 * rebuild the kernel cache file. If a kext was already in the kernel
6700 * cache and unloaded then later loaded we do not need to rebuild the
6701 * kernel cache. 9055303
6702 */
6703 if (isPrelinked()) {
6704 if (!_OSKextInUnloadedPrelinkedKexts(bundleID)) {
6705 IORecursiveLockLock(sKextLock);
6706 if (sUnloadedPrelinkedKexts) {
6707 sUnloadedPrelinkedKexts->setObject(bundleID);
6708 }
6709 IORecursiveLockUnlock(sKextLock);
6710 }
6711 }
6712
6713 OSKextLog(this,
6714 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
6715 "Kext %s unloaded.", getIdentifierCString());
6716
6717 queueKextNotification(kKextRequestPredicateUnloadNotification,
6718 OSDynamicCast(OSString, bundleID));
6719
6720 finish:
6721 OSKext::saveLoadedKextPanicList();
6722 OSKext::updateLoadedKextSummaries();
6723
6724 flags.unloading = 0;
6725 return result;
6726 }
6727
6728 /*********************************************************************
6729 * Assumes sKextLock is held.
6730 *********************************************************************/
6731 /* static */
6732 OSReturn
6733 OSKext::queueKextNotification(
6734 const char * notificationName,
6735 OSString * kextIdentifier)
6736 {
6737 OSReturn result = kOSReturnError;
6738 OSDictionary * loadRequest = NULL; // must release
6739
6740 if (!kextIdentifier) {
6741 result = kOSKextReturnInvalidArgument;
6742 goto finish;
6743 }
6744
6745 /* Create a new request unless one is already sitting
6746 * in sKernelRequests for this bundle identifier
6747 */
6748 result = _OSKextCreateRequest(notificationName, &loadRequest);
6749 if (result != kOSReturnSuccess) {
6750 goto finish;
6751 }
6752 if (!_OSKextSetRequestArgument(loadRequest,
6753 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
6754
6755 result = kOSKextReturnNoMemory;
6756 goto finish;
6757 }
6758 if (!sKernelRequests->setObject(loadRequest)) {
6759 result = kOSKextReturnNoMemory;
6760 goto finish;
6761 }
6762
6763 /* We might want to only queue the notification if kextd is active,
6764 * but that wouldn't work for embedded. Note that we don't care if
6765 * the ping immediately succeeds here so don't do anything with the
6766 * result of this call.
6767 */
6768 OSKext::pingKextd();
6769
6770 result = kOSReturnSuccess;
6771
6772 finish:
6773 OSSafeReleaseNULL(loadRequest);
6774
6775 return result;
6776 }
6777
6778 /*********************************************************************
6779 *********************************************************************/
6780 static void
6781 _OSKextConsiderDestroyingLinkContext(
6782 __unused thread_call_param_t p0,
6783 __unused thread_call_param_t p1)
6784 {
6785 /* Take multiple locks in the correct order.
6786 */
6787 IORecursiveLockLock(sKextLock);
6788 IORecursiveLockLock(sKextInnerLock);
6789
6790 /* The first time we destroy the kxldContext is in the first
6791 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
6792 * before calling this function. Thereafter any call to this function
6793 * will actually destroy the context.
6794 */
6795 if (sConsiderUnloadsCalled && sKxldContext) {
6796 kxld_destroy_context(sKxldContext);
6797 sKxldContext = NULL;
6798 }
6799
6800 /* Free the thread_call that was allocated to execute this function.
6801 */
6802 if (sDestroyLinkContextThread) {
6803 if (!thread_call_free(sDestroyLinkContextThread)) {
6804 OSKextLog(/* kext */ NULL,
6805 kOSKextLogErrorLevel |
6806 kOSKextLogGeneralFlag,
6807 "thread_call_free() failed for kext link context.");
6808 }
6809 sDestroyLinkContextThread = 0;
6810 }
6811
6812 IORecursiveLockUnlock(sKextInnerLock);
6813 IORecursiveLockUnlock(sKextLock);
6814
6815 return;
6816 }
6817
6818 /*********************************************************************
6819 * Destroying the kxldContext requires checking variables under both
6820 * sKextInnerLock and sKextLock, so we do it on a separate thread
6821 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
6822 * call relationship.
6823 *
6824 * This function must be invoked with sKextInnerLock held.
6825 * Do not call any function that takes sKextLock here!
6826 *********************************************************************/
6827 /* static */
6828 void
6829 OSKext::considerDestroyingLinkContext(void)
6830 {
6831 IORecursiveLockLock(sKextInnerLock);
6832
6833 /* If we have already queued a thread to destroy the link context,
6834 * don't bother resetting; that thread will take care of it.
6835 */
6836 if (sDestroyLinkContextThread) {
6837 goto finish;
6838 }
6839
6840 /* The function to be invoked in the thread will deallocate
6841 * this thread_call, so don't share it around.
6842 */
6843 sDestroyLinkContextThread = thread_call_allocate(
6844 &_OSKextConsiderDestroyingLinkContext, 0);
6845 if (!sDestroyLinkContextThread) {
6846 OSKextLog(/* kext */ NULL,
6847 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogLinkFlag,
6848 "Can't create thread to destroy kext link context.");
6849 goto finish;
6850 }
6851
6852 thread_call_enter(sDestroyLinkContextThread);
6853
6854 finish:
6855 IORecursiveLockUnlock(sKextInnerLock);
6856 return;
6857 }
6858
6859 #if PRAGMA_MARK
6860 #pragma mark Autounload
6861 #endif
6862 /*********************************************************************
6863 * This is a static method because the kext will be deallocated if it
6864 * does unload!
6865 *********************************************************************/
6866 /* static */
6867 OSReturn
6868 OSKext::autounloadKext(OSKext * aKext)
6869 {
6870 OSReturn result = kOSKextReturnInUse;
6871
6872 /* Check for external references to this kext (usu. dependents),
6873 * instances of defined classes (or classes derived from them),
6874 * outstanding requests.
6875 */
6876 if ((aKext->getRetainCount() > kOSKextMinLoadedRetainCount) ||
6877 !aKext->flags.autounloadEnabled ||
6878 aKext->isKernelComponent()) {
6879
6880 goto finish;
6881 }
6882
6883 /* Skip a delay-autounload kext, once.
6884 */
6885 if (aKext->flags.delayAutounload) {
6886 OSKextLog(aKext,
6887 kOSKextLogProgressLevel |
6888 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6889 "Kext %s has delayed autounload set; skipping and clearing flag.",
6890 aKext->getIdentifierCString());
6891 aKext->flags.delayAutounload = 0;
6892 goto finish;
6893 }
6894
6895 if (aKext->hasOSMetaClassInstances() ||
6896 aKext->countRequestCallbacks()) {
6897 goto finish;
6898 }
6899
6900 result = OSKext::removeKext(aKext);
6901
6902 finish:
6903 return result;
6904 }
6905
6906 /*********************************************************************
6907 *********************************************************************/
6908 void
6909 _OSKextConsiderUnloads(
6910 __unused thread_call_param_t p0,
6911 __unused thread_call_param_t p1)
6912 {
6913 bool didUnload = false;
6914 unsigned int count, i;
6915
6916 /* Take multiple locks in the correct order
6917 * (note also sKextSummaries lock further down).
6918 */
6919 IORecursiveLockLock(sKextLock);
6920 IORecursiveLockLock(sKextInnerLock);
6921
6922 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
6923
6924 /* If the system is powering down, don't try to unload anything.
6925 */
6926 if (sSystemSleep) {
6927 goto finish;
6928 }
6929
6930 OSKextLog(/* kext */ NULL,
6931 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
6932 "Checking for unused kexts to autounload.");
6933
6934 /*****
6935 * Remove any request callbacks marked as stale,
6936 * and mark as stale any currently in flight.
6937 */
6938 count = sRequestCallbackRecords->getCount();
6939 if (count) {
6940 i = count - 1;
6941 do {
6942 OSDictionary * callbackRecord = OSDynamicCast(OSDictionary,
6943 sRequestCallbackRecords->getObject(i));
6944 OSBoolean * stale = OSDynamicCast(OSBoolean,
6945 callbackRecord->getObject(kKextRequestStaleKey));
6946
6947 if (stale == kOSBooleanTrue) {
6948 OSKext::invokeRequestCallback(callbackRecord,
6949 kOSKextReturnTimeout);
6950 } else {
6951 callbackRecord->setObject(kKextRequestStaleKey,
6952 kOSBooleanTrue);
6953 }
6954 } while (i--);
6955 }
6956
6957 /*****
6958 * Make multiple passes through the array of loaded kexts until
6959 * we don't unload any. This handles unwinding of dependency
6960 * chains. We have to go *backwards* through the array because
6961 * kexts are removed from it when unloaded, and we cannot make
6962 * a copy or we'll mess up the retain counts we rely on to
6963 * check whether a kext will unload. If only we could have
6964 * nonretaining collections like CF has....
6965 */
6966 do {
6967 didUnload = false;
6968
6969 count = sLoadedKexts->getCount();
6970 if (count) {
6971 i = count - 1;
6972 do {
6973 OSKext * thisKext = OSDynamicCast(OSKext,
6974 sLoadedKexts->getObject(i));
6975 didUnload |= (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
6976 } while (i--);
6977 }
6978 } while (didUnload);
6979
6980 finish:
6981 sConsiderUnloadsPending = false;
6982 sConsiderUnloadsExecuted = true;
6983
6984 (void) OSKext::considerRebuildOfPrelinkedKernel();
6985
6986 IORecursiveLockUnlock(sKextInnerLock);
6987 IORecursiveLockUnlock(sKextLock);
6988
6989 return;
6990 }
6991
6992 /*********************************************************************
6993 * Do not call any function that takes sKextLock here!
6994 *********************************************************************/
6995 void OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
6996 {
6997 AbsoluteTime when;
6998
6999 IORecursiveLockLock(sKextInnerLock);
7000
7001 if (!sUnloadCallout) {
7002 sUnloadCallout = thread_call_allocate(&_OSKextConsiderUnloads, 0);
7003 }
7004
7005 /* we only reset delay value for unloading if we already have something
7006 * pending. rescheduleOnlyFlag should not start the count down.
7007 */
7008 if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
7009 goto finish;
7010 }
7011
7012 thread_call_cancel(sUnloadCallout);
7013 if (OSKext::getAutounloadEnabled() && !sSystemSleep) {
7014 clock_interval_to_deadline(sConsiderUnloadDelay,
7015 1000 * 1000 * 1000, &when);
7016
7017 OSKextLog(/* kext */ NULL,
7018 kOSKextLogProgressLevel |
7019 kOSKextLogLoadFlag,
7020 "%scheduling %sscan for unused kexts in %lu seconds.",
7021 sConsiderUnloadsPending ? "Res" : "S",
7022 sConsiderUnloadsCalled ? "" : "initial ",
7023 (unsigned long)sConsiderUnloadDelay);
7024
7025 sConsiderUnloadsPending = true;
7026 thread_call_enter_delayed(sUnloadCallout, when);
7027 }
7028
7029 finish:
7030 /* The kxld context should be reused throughout boot. We mark the end of
7031 * period as the first time considerUnloads() is called, and we destroy
7032 * the first kxld context in that function. Afterwards, it will be
7033 * destroyed in flushNonloadedKexts.
7034 */
7035 if (!sConsiderUnloadsCalled) {
7036 sConsiderUnloadsCalled = true;
7037 OSKext::considerDestroyingLinkContext();
7038 }
7039
7040 IORecursiveLockUnlock(sKextInnerLock);
7041 return;
7042 }
7043
7044 /*********************************************************************
7045 * Do not call any function that takes sKextLock here!
7046 *********************************************************************/
7047 extern "C" {
7048
7049 IOReturn OSKextSystemSleepOrWake(UInt32 messageType);
7050 IOReturn OSKextSystemSleepOrWake(UInt32 messageType)
7051 {
7052 IORecursiveLockLock(sKextInnerLock);
7053
7054 /* If the system is going to sleep, cancel the reaper thread timer,
7055 * and note that we're in a sleep state in case it just fired but hasn't
7056 * taken the lock yet. If we are coming back from sleep, just
7057 * clear the sleep flag; IOService's normal operation will cause
7058 * unloads to be considered soon enough.
7059 */
7060 if (messageType == kIOMessageSystemWillSleep) {
7061 if (sUnloadCallout) {
7062 thread_call_cancel(sUnloadCallout);
7063 }
7064 sSystemSleep = true;
7065 AbsoluteTime_to_scalar(&sLastWakeTime) = 0;
7066 } else if (messageType == kIOMessageSystemHasPoweredOn) {
7067 sSystemSleep = false;
7068 clock_get_uptime(&sLastWakeTime);
7069 }
7070 IORecursiveLockUnlock(sKextInnerLock);
7071
7072 return kIOReturnSuccess;
7073 }
7074
7075 };
7076
7077
7078 #if PRAGMA_MARK
7079 #pragma mark Prelinked Kernel
7080 #endif
7081 /*********************************************************************
7082 * Do not access sConsiderUnloads... variables other than
7083 * sConsiderUnloadsExecuted in this function. They are guarded by a
7084 * different lock.
7085 *********************************************************************/
7086 /* static */
7087 void
7088 OSKext::considerRebuildOfPrelinkedKernel(void)
7089 {
7090 static bool requestedPrelink = false;
7091 OSReturn checkResult = kOSReturnError;
7092 OSDictionary * prelinkRequest = NULL; // must release
7093 OSCollectionIterator * kextIterator = NULL; // must release
7094 const OSSymbol * thisID = NULL; // do not release
7095 bool doRebuild = false;
7096 AbsoluteTime my_abstime;
7097 UInt64 my_ns;
7098 SInt32 delta_secs;
7099
7100 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
7101 if (requestedPrelink || !sPrelinkBoot) {
7102 return;
7103 }
7104
7105 /* no direct return from this point */
7106 IORecursiveLockLock(sKextLock);
7107
7108 /* We need to wait for kextd to get up and running with unloads already done
7109 * and any new startup kexts loaded.
7110 */
7111 if (!sConsiderUnloadsExecuted ||
7112 !sDeferredLoadSucceeded) {
7113 goto finish;
7114 }
7115
7116 /* we really only care about boot / system start up related kexts so bail
7117 * if we're here after REBUILD_MAX_TIME.
7118 */
7119 if (!_OSKextInPrelinkRebuildWindow()) {
7120 OSKextLog(/* kext */ NULL,
7121 kOSKextLogArchiveFlag,
7122 "%s prebuild rebuild has expired",
7123 __FUNCTION__);
7124 requestedPrelink = true;
7125 goto finish;
7126 }
7127
7128 /* we do not want to trigger a rebuild if we get here too close to waking
7129 * up. (see radar 10233768)
7130 */
7131 IORecursiveLockLock(sKextInnerLock);
7132
7133 clock_get_uptime(&my_abstime);
7134 delta_secs = MINIMUM_WAKEUP_SECONDS + 1;
7135 if (AbsoluteTime_to_scalar(&sLastWakeTime) != 0) {
7136 SUB_ABSOLUTETIME(&my_abstime, &sLastWakeTime);
7137 absolutetime_to_nanoseconds(my_abstime, &my_ns);
7138 delta_secs = (SInt32)(my_ns / NSEC_PER_SEC);
7139 }
7140 IORecursiveLockUnlock(sKextInnerLock);
7141
7142 if (delta_secs < MINIMUM_WAKEUP_SECONDS) {
7143 /* too close to time of last wake from sleep */
7144 goto finish;
7145 }
7146 requestedPrelink = true;
7147
7148 /* Now it's time to see if we have a reason to rebuild. We may have done
7149 * some loads and unloads but the kernel cache didn't actually change.
7150 * We will rebuild if any kext is not marked prelinked AND is not in our
7151 * list of prelinked kexts that got unloaded. (see radar 9055303)
7152 */
7153 kextIterator = OSCollectionIterator::withCollection(sKextsByID);
7154 if (!kextIterator) {
7155 goto finish;
7156 }
7157
7158 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
7159 OSKext * thisKext; // do not release
7160
7161 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
7162 if (!thisKext || thisKext->isPrelinked() || thisKext->isKernel()) {
7163 continue;
7164 }
7165
7166 if (_OSKextInUnloadedPrelinkedKexts(thisKext->bundleID)) {
7167 continue;
7168 }
7169 /* kext is loaded and was not in current kernel cache so let's rebuild
7170 */
7171 doRebuild = true;
7172 OSKextLog(/* kext */ NULL,
7173 kOSKextLogArchiveFlag,
7174 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
7175 thisKext->bundleID->getCStringNoCopy());
7176 break;
7177 }
7178 sUnloadedPrelinkedKexts->flushCollection();
7179
7180 if (!doRebuild) {
7181 goto finish;
7182 }
7183
7184 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
7185 &prelinkRequest);
7186 if (checkResult != kOSReturnSuccess) {
7187 goto finish;
7188 }
7189
7190 if (!sKernelRequests->setObject(prelinkRequest)) {
7191 goto finish;
7192 }
7193
7194 OSKext::pingKextd();
7195
7196 finish:
7197 IORecursiveLockUnlock(sKextLock);
7198 OSSafeReleaseNULL(prelinkRequest);
7199 OSSafeReleaseNULL(kextIterator);
7200
7201 return;
7202 }
7203
7204 #if PRAGMA_MARK
7205 #pragma mark Dependencies
7206 #endif
7207 /*********************************************************************
7208 *********************************************************************/
7209 bool
7210 OSKext::resolveDependencies(
7211 OSArray * loopStack)
7212 {
7213 bool result = false;
7214 OSArray * localLoopStack = NULL; // must release
7215 bool addedToLoopStack = false;
7216 OSDictionary * libraries = NULL; // do not release
7217 OSCollectionIterator * libraryIterator = NULL; // must release
7218 OSString * libraryID = NULL; // do not release
7219 OSString * infoString = NULL; // do not release
7220 OSString * readableString = NULL; // do not release
7221 OSKext * libraryKext = NULL; // do not release
7222 bool hasRawKernelDependency = false;
7223 bool hasKernelDependency = false;
7224 bool hasKPIDependency = false;
7225 bool hasPrivateKPIDependency = false;
7226 unsigned int count;
7227
7228 /* A kernel component will automatically have this flag set,
7229 * and a loaded kext should also have it set (as should all its
7230 * loaded dependencies).
7231 */
7232 if (flags.hasAllDependencies) {
7233 result = true;
7234 goto finish;
7235 }
7236
7237 /* Check for loops in the dependency graph.
7238 */
7239 if (loopStack) {
7240 if (loopStack->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
7241 OSKextLog(this,
7242 kOSKextLogErrorLevel |
7243 kOSKextLogDependenciesFlag,
7244 "Kext %s has a dependency loop; can't resolve dependencies.",
7245 getIdentifierCString());
7246 goto finish;
7247 }
7248 } else {
7249 OSKextLog(this,
7250 kOSKextLogStepLevel |
7251 kOSKextLogDependenciesFlag,
7252 "Kext %s resolving dependencies.",
7253 getIdentifierCString());
7254
7255 loopStack = OSArray::withCapacity(6); // any small capacity will do
7256 if (!loopStack) {
7257 OSKextLog(this,
7258 kOSKextLogErrorLevel |
7259 kOSKextLogDependenciesFlag,
7260 "Kext %s can't create bookkeeping stack to resolve dependencies.",
7261 getIdentifierCString());
7262 goto finish;
7263 }
7264 localLoopStack = loopStack;
7265 }
7266 if (!loopStack->setObject(this)) {
7267 OSKextLog(this,
7268 kOSKextLogErrorLevel |
7269 kOSKextLogDependenciesFlag,
7270 "Kext %s - internal error resolving dependencies.",
7271 getIdentifierCString());
7272 goto finish;
7273 }
7274 addedToLoopStack = true;
7275
7276 /* Purge any existing kexts in the dependency list and start over.
7277 */
7278 flushDependencies();
7279 if (dependencies) {
7280 OSKextLog(this,
7281 kOSKextLogErrorLevel |
7282 kOSKextLogDependenciesFlag,
7283 "Kext %s - internal error resolving dependencies.",
7284 getIdentifierCString());
7285 }
7286
7287 libraries = OSDynamicCast(OSDictionary,
7288 getPropertyForHostArch(kOSBundleLibrariesKey));
7289 if (libraries == NULL || libraries->getCount() == 0) {
7290 OSKextLog(this,
7291 kOSKextLogErrorLevel |
7292 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
7293 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
7294 getIdentifierCString(), kOSBundleLibrariesKey);
7295 goto finish;
7296 }
7297
7298 /* Make a new array to hold the dependencies (flush freed the old one).
7299 */
7300 dependencies = OSArray::withCapacity(libraries->getCount());
7301 if (!dependencies) {
7302 OSKextLog(this,
7303 kOSKextLogErrorLevel |
7304 kOSKextLogDependenciesFlag,
7305 "Kext %s - can't allocate dependencies array.",
7306 getIdentifierCString());
7307 goto finish;
7308 }
7309
7310 // xxx - compat: We used to add an implicit dependency on kernel 6.0
7311 // xxx - compat: if none were declared.
7312
7313 libraryIterator = OSCollectionIterator::withCollection(libraries);
7314 if (!libraryIterator) {
7315 OSKextLog(this,
7316 kOSKextLogErrorLevel |
7317 kOSKextLogDependenciesFlag,
7318 "Kext %s - can't allocate dependencies iterator.",
7319 getIdentifierCString());
7320 goto finish;
7321 }
7322
7323 while ((libraryID = OSDynamicCast(OSString,
7324 libraryIterator->getNextObject()))) {
7325
7326 const char * library_id = libraryID->getCStringNoCopy();
7327
7328 OSString * libraryVersion = OSDynamicCast(OSString,
7329 libraries->getObject(libraryID));
7330 if (libraryVersion == NULL) {
7331 OSKextLog(this,
7332 kOSKextLogErrorLevel |
7333 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
7334 "Kext %s - illegal type in OSBundleLibraries.",
7335 getIdentifierCString());
7336 goto finish;
7337 }
7338
7339 OSKextVersion libraryVers =
7340 OSKextParseVersionString(libraryVersion->getCStringNoCopy());
7341 if (libraryVers == -1) {
7342 OSKextLog(this,
7343 kOSKextLogErrorLevel |
7344 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
7345 "Kext %s - invalid library version %s.",
7346 getIdentifierCString(),
7347 libraryVersion->getCStringNoCopy());
7348 goto finish;
7349 }
7350
7351 libraryKext = OSDynamicCast(OSKext, sKextsByID->getObject(libraryID));
7352 if (libraryKext == NULL) {
7353 OSKextLog(this,
7354 kOSKextLogErrorLevel |
7355 kOSKextLogDependenciesFlag,
7356 "Kext %s - library kext %s not found.",
7357 getIdentifierCString(), library_id);
7358 goto finish;
7359 }
7360
7361 if (!libraryKext->isCompatibleWithVersion(libraryVers)) {
7362 OSKextLog(this,
7363 kOSKextLogErrorLevel |
7364 kOSKextLogDependenciesFlag,
7365 "Kext %s - library kext %s not compatible "
7366 "with requested version %s.",
7367 getIdentifierCString(), library_id,
7368 libraryVersion->getCStringNoCopy());
7369 goto finish;
7370 }
7371
7372 /* If a nonprelinked library somehow got into the mix for a
7373 * prelinked kext, at any point in the chain, we must fail
7374 * because the prelinked relocs for the library will be all wrong.
7375 */
7376 if (this->isPrelinked() &&
7377 libraryKext->declaresExecutable() &&
7378 !libraryKext->isPrelinked()) {
7379
7380 OSKextLog(this,
7381 kOSKextLogErrorLevel |
7382 kOSKextLogDependenciesFlag,
7383 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
7384 getIdentifierCString(), library_id,
7385 libraryVersion->getCStringNoCopy());
7386 goto finish;
7387 }
7388
7389 if (!libraryKext->resolveDependencies(loopStack)) {
7390 goto finish;
7391 }
7392
7393 /* Add the library directly only if it has an executable to link.
7394 * Otherwise it's just used to collect other dependencies, so put
7395 * *its* dependencies on the list for this kext.
7396 */
7397 // xxx - We are losing info here; would like to make fake entries or
7398 // xxx - keep these in the dependency graph for loaded kexts.
7399 // xxx - I really want to make kernel components not a special case!
7400 if (libraryKext->declaresExecutable() ||
7401 libraryKext->isInterface()) {
7402
7403 if (dependencies->getNextIndexOfObject(libraryKext, 0) == (unsigned)-1) {
7404 dependencies->setObject(libraryKext);
7405
7406 OSKextLog(this,
7407 kOSKextLogDetailLevel |
7408 kOSKextLogDependenciesFlag,
7409 "Kext %s added dependency %s.",
7410 getIdentifierCString(),
7411 libraryKext->getIdentifierCString());
7412 }
7413 } else {
7414 int numLibDependencies = libraryKext->getNumDependencies();
7415 OSArray * libraryDependencies = libraryKext->getDependencies();
7416 int index;
7417
7418 if (numLibDependencies) {
7419 // xxx - this msg level should be 1 lower than the per-kext one
7420 OSKextLog(this,
7421 kOSKextLogDetailLevel |
7422 kOSKextLogDependenciesFlag,
7423 "Kext %s pulling %d dependencies from codeless library %s.",
7424 getIdentifierCString(),
7425 numLibDependencies,
7426 libraryKext->getIdentifierCString());
7427 }
7428 for (index = 0; index < numLibDependencies; index++) {
7429 OSKext * thisLibDependency = OSDynamicCast(OSKext,
7430 libraryDependencies->getObject(index));
7431 if (dependencies->getNextIndexOfObject(thisLibDependency, 0) == (unsigned)-1) {
7432 dependencies->setObject(thisLibDependency);
7433 OSKextLog(this,
7434 kOSKextLogDetailLevel |
7435 kOSKextLogDependenciesFlag,
7436 "Kext %s added dependency %s from codeless library %s.",
7437 getIdentifierCString(),
7438 thisLibDependency->getIdentifierCString(),
7439 libraryKext->getIdentifierCString());
7440 }
7441 }
7442 }
7443
7444 if ((strlen(library_id) == strlen(KERNEL_LIB)) &&
7445 0 == strncmp(library_id, KERNEL_LIB, sizeof(KERNEL_LIB)-1)) {
7446
7447 hasRawKernelDependency = true;
7448 } else if (STRING_HAS_PREFIX(library_id, KERNEL_LIB_PREFIX)) {
7449 hasKernelDependency = true;
7450 } else if (STRING_HAS_PREFIX(library_id, KPI_LIB_PREFIX)) {
7451 hasKPIDependency = true;
7452 if (!strncmp(library_id, PRIVATE_KPI, sizeof(PRIVATE_KPI)-1)) {
7453 hasPrivateKPIDependency = true;
7454 }
7455 }
7456 }
7457
7458 if (hasRawKernelDependency) {
7459 OSKextLog(this,
7460 kOSKextLogErrorLevel |
7461 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
7462 "Error - kext %s declares a dependency on %s, which is not permitted.",
7463 getIdentifierCString(), KERNEL_LIB);
7464 goto finish;
7465 }
7466 #if __LP64__
7467 if (hasKernelDependency) {
7468 OSKextLog(this,
7469 kOSKextLogErrorLevel |
7470 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
7471 "Error - kext %s declares %s dependencies. "
7472 "Only %s* dependencies are supported for 64-bit kexts.",
7473 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
7474 goto finish;
7475 }
7476 if (!hasKPIDependency) {
7477 OSKextLog(this,
7478 kOSKextLogWarningLevel |
7479 kOSKextLogDependenciesFlag,
7480 "Warning - kext %s declares no %s* dependencies. "
7481 "If it uses any KPIs, the link may fail with undefined symbols.",
7482 getIdentifierCString(), KPI_LIB_PREFIX);
7483 }
7484 #else /* __LP64__ */
7485 // xxx - will change to flatly disallow "kernel" dependencies at some point
7486 // xxx - is it invalid to do both "com.apple.kernel" and any
7487 // xxx - "com.apple.kernel.*"?
7488
7489 if (hasKernelDependency && hasKPIDependency) {
7490 OSKextLog(this,
7491 kOSKextLogWarningLevel |
7492 kOSKextLogDependenciesFlag,
7493 "Warning - kext %s has immediate dependencies on both "
7494 "%s* and %s* components; use only one style.",
7495 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
7496 }
7497
7498 if (!hasKernelDependency && !hasKPIDependency) {
7499 // xxx - do we want to use validation flag for these too?
7500 OSKextLog(this,
7501 kOSKextLogWarningLevel |
7502 kOSKextLogDependenciesFlag,
7503 "Warning - %s declares no kernel dependencies; using %s.",
7504 getIdentifierCString(), KERNEL6_LIB);
7505 OSKext * kernelKext = OSDynamicCast(OSKext,
7506 sKextsByID->getObject(KERNEL6_LIB));
7507 if (kernelKext) {
7508 dependencies->setObject(kernelKext);
7509 } else {
7510 OSKextLog(this,
7511 kOSKextLogErrorLevel |
7512 kOSKextLogDependenciesFlag,
7513 "Error - Library %s not found for %s.",
7514 KERNEL6_LIB, getIdentifierCString());
7515 }
7516 }
7517
7518 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
7519 * its indirect dependencies to simulate old-style linking. XXX - Should
7520 * check for duplicates.
7521 */
7522 if (!hasKPIDependency) {
7523 unsigned int i;
7524
7525 flags.hasBleedthrough = true;
7526
7527 count = getNumDependencies();
7528
7529 /* We add to the dependencies array in this loop, but do not iterate
7530 * past its original count.
7531 */
7532 for (i = 0; i < count; i++) {
7533 OSKext * dependencyKext = OSDynamicCast(OSKext,
7534 dependencies->getObject(i));
7535 dependencyKext->addBleedthroughDependencies(dependencies);
7536 }
7537 }
7538 #endif /* __LP64__ */
7539
7540 if (hasPrivateKPIDependency) {
7541 bool hasApplePrefix = false;
7542 bool infoCopyrightIsValid = false;
7543 bool readableCopyrightIsValid = false;
7544
7545 hasApplePrefix = STRING_HAS_PREFIX(getIdentifierCString(),
7546 APPLE_KEXT_PREFIX);
7547
7548 infoString = OSDynamicCast(OSString,
7549 getPropertyForHostArch("CFBundleGetInfoString"));
7550 if (infoString) {
7551 infoCopyrightIsValid =
7552 kxld_validate_copyright_string(infoString->getCStringNoCopy());
7553 }
7554
7555 readableString = OSDynamicCast(OSString,
7556 getPropertyForHostArch("NSHumanReadableCopyright"));
7557 if (readableString) {
7558 readableCopyrightIsValid =
7559 kxld_validate_copyright_string(readableString->getCStringNoCopy());
7560 }
7561
7562 if (!hasApplePrefix || (!infoCopyrightIsValid && !readableCopyrightIsValid)) {
7563 OSKextLog(this,
7564 kOSKextLogErrorLevel |
7565 kOSKextLogDependenciesFlag,
7566 "Error - kext %s declares a dependency on %s. "
7567 "Only Apple kexts may declare a dependency on %s.",
7568 getIdentifierCString(), PRIVATE_KPI, PRIVATE_KPI);
7569 goto finish;
7570 }
7571 }
7572
7573 result = true;
7574 flags.hasAllDependencies = 1;
7575
7576 finish:
7577
7578 if (addedToLoopStack) {
7579 count = loopStack->getCount();
7580 if (count > 0 && (this == loopStack->getObject(count - 1))) {
7581 loopStack->removeObject(count - 1);
7582 } else {
7583 OSKextLog(this,
7584 kOSKextLogErrorLevel |
7585 kOSKextLogDependenciesFlag,
7586 "Kext %s - internal error resolving dependencies.",
7587 getIdentifierCString());
7588 }
7589 }
7590
7591 if (result && localLoopStack) {
7592 OSKextLog(this,
7593 kOSKextLogStepLevel |
7594 kOSKextLogDependenciesFlag,
7595 "Kext %s successfully resolved dependencies.",
7596 getIdentifierCString());
7597 }
7598
7599 OSSafeReleaseNULL(localLoopStack);
7600 OSSafeReleaseNULL(libraryIterator);
7601
7602 return result;
7603 }
7604
7605 /*********************************************************************
7606 *********************************************************************/
7607 bool
7608 OSKext::addBleedthroughDependencies(OSArray * anArray)
7609 {
7610 bool result = false;
7611 unsigned int dependencyIndex, dependencyCount;
7612
7613 dependencyCount = getNumDependencies();
7614
7615 for (dependencyIndex = 0;
7616 dependencyIndex < dependencyCount;
7617 dependencyIndex++) {
7618
7619 OSKext * dependency = OSDynamicCast(OSKext,
7620 dependencies->getObject(dependencyIndex));
7621 if (!dependency) {
7622 OSKextLog(this,
7623 kOSKextLogErrorLevel |
7624 kOSKextLogDependenciesFlag,
7625 "Kext %s - internal error propagating compatibility dependencies.",
7626 getIdentifierCString());
7627 goto finish;
7628 }
7629 if (anArray->getNextIndexOfObject(dependency, 0) == (unsigned int)-1) {
7630 anArray->setObject(dependency);
7631 }
7632 dependency->addBleedthroughDependencies(anArray);
7633 }
7634
7635 result = true;
7636
7637 finish:
7638 return result;
7639 }
7640
7641 /*********************************************************************
7642 *********************************************************************/
7643 bool
7644 OSKext::flushDependencies(bool forceFlag)
7645 {
7646 bool result = false;
7647
7648 /* Only clear the dependencies if the kext isn't loaded;
7649 * we need the info for loaded kexts to track references.
7650 */
7651 if (!isLoaded() || forceFlag) {
7652 if (dependencies) {
7653 // xxx - check level
7654 OSKextLog(this,
7655 kOSKextLogProgressLevel |
7656 kOSKextLogDependenciesFlag,
7657 "Kext %s flushing dependencies.",
7658 getIdentifierCString());
7659 OSSafeReleaseNULL(dependencies);
7660
7661 }
7662 if (!isKernelComponent()) {
7663 flags.hasAllDependencies = 0;
7664 }
7665 result = true;
7666 }
7667
7668 return result;
7669 }
7670
7671 /*********************************************************************
7672 *********************************************************************/
7673 uint32_t
7674 OSKext::getNumDependencies(void)
7675 {
7676 if (!dependencies) {
7677 return 0;
7678 }
7679 return dependencies->getCount();
7680 }
7681
7682 /*********************************************************************
7683 *********************************************************************/
7684 OSArray *
7685 OSKext::getDependencies(void)
7686 {
7687 return dependencies;
7688 }
7689
7690 #if PRAGMA_MARK
7691 #pragma mark OSMetaClass Support
7692 #endif
7693 /*********************************************************************
7694 *********************************************************************/
7695 OSReturn
7696 OSKext::addClass(
7697 OSMetaClass * aClass,
7698 uint32_t numClasses)
7699 {
7700 OSReturn result = kOSMetaClassNoInsKModSet;
7701
7702 if (!metaClasses) {
7703 metaClasses = OSSet::withCapacity(numClasses);
7704 if (!metaClasses) {
7705 goto finish;
7706 }
7707 }
7708
7709 if (metaClasses->containsObject(aClass)) {
7710 OSKextLog(this,
7711 kOSKextLogWarningLevel |
7712 kOSKextLogLoadFlag,
7713 "Notice - kext %s has already registered class %s.",
7714 getIdentifierCString(),
7715 aClass->getClassName());
7716 result = kOSReturnSuccess;
7717 goto finish;
7718 }
7719
7720 if (!metaClasses->setObject(aClass)) {
7721 goto finish;
7722 } else {
7723 OSKextLog(this,
7724 kOSKextLogDetailLevel |
7725 kOSKextLogLoadFlag,
7726 "Kext %s registered class %s.",
7727 getIdentifierCString(),
7728 aClass->getClassName());
7729 }
7730
7731 if (!flags.autounloadEnabled) {
7732 const OSMetaClass * metaScan = NULL; // do not release
7733
7734 for (metaScan = aClass; metaScan; metaScan = metaScan->getSuperClass()) {
7735 if (metaScan == OSTypeID(IOService)) {
7736
7737 OSKextLog(this,
7738 kOSKextLogProgressLevel |
7739 kOSKextLogLoadFlag,
7740 "Kext %s has IOService subclass %s; enabling autounload.",
7741 getIdentifierCString(),
7742 aClass->getClassName());
7743
7744 flags.autounloadEnabled = 1;
7745 break;
7746 }
7747 }
7748 }
7749
7750 notifyAddClassObservers(this, aClass, flags);
7751
7752 result = kOSReturnSuccess;
7753
7754 finish:
7755 if (result != kOSReturnSuccess) {
7756 OSKextLog(this,
7757 kOSKextLogErrorLevel |
7758 kOSKextLogLoadFlag,
7759 "Kext %s failed to register class %s.",
7760 getIdentifierCString(),
7761 aClass->getClassName());
7762 }
7763
7764 return result;
7765 }
7766
7767 /*********************************************************************
7768 *********************************************************************/
7769 OSReturn
7770 OSKext::removeClass(
7771 OSMetaClass * aClass)
7772 {
7773 OSReturn result = kOSMetaClassNoKModSet;
7774
7775 if (!metaClasses) {
7776 goto finish;
7777 }
7778
7779 if (!metaClasses->containsObject(aClass)) {
7780 OSKextLog(this,
7781 kOSKextLogWarningLevel |
7782 kOSKextLogLoadFlag,
7783 "Notice - kext %s asked to unregister unknown class %s.",
7784 getIdentifierCString(),
7785 aClass->getClassName());
7786 result = kOSReturnSuccess;
7787 goto finish;
7788 }
7789
7790 OSKextLog(this,
7791 kOSKextLogDetailLevel |
7792 kOSKextLogLoadFlag,
7793 "Kext %s unregistering class %s.",
7794 getIdentifierCString(),
7795 aClass->getClassName());
7796
7797 metaClasses->removeObject(aClass);
7798
7799 notifyRemoveClassObservers(this, aClass, flags);
7800
7801 result = kOSReturnSuccess;
7802
7803 finish:
7804 if (result != kOSReturnSuccess) {
7805 OSKextLog(this,
7806 kOSKextLogErrorLevel |
7807 kOSKextLogLoadFlag,
7808 "Failed to unregister kext %s class %s.",
7809 getIdentifierCString(),
7810 aClass->getClassName());
7811 }
7812 return result;
7813 }
7814
7815 /*********************************************************************
7816 *********************************************************************/
7817 OSSet *
7818 OSKext::getMetaClasses(void)
7819 {
7820 return metaClasses;
7821 }
7822
7823 /*********************************************************************
7824 *********************************************************************/
7825 bool
7826 OSKext::hasOSMetaClassInstances(void)
7827 {
7828 bool result = false;
7829 OSCollectionIterator * classIterator = NULL; // must release
7830 OSMetaClass * checkClass = NULL; // do not release
7831
7832 if (!metaClasses) {
7833 goto finish;
7834 }
7835
7836 classIterator = OSCollectionIterator::withCollection(metaClasses);
7837 if (!classIterator) {
7838 // xxx - log alloc failure?
7839 goto finish;
7840 }
7841 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
7842 if (checkClass->getInstanceCount()) {
7843 result = true;
7844 goto finish;
7845 }
7846 }
7847
7848 finish:
7849
7850 OSSafeReleaseNULL(classIterator);
7851 return result;
7852 }
7853
7854 /*********************************************************************
7855 *********************************************************************/
7856 /* static */
7857 void
7858 OSKext::reportOSMetaClassInstances(
7859 const char * kextIdentifier,
7860 OSKextLogSpec msgLogSpec)
7861 {
7862 OSKext * theKext = NULL; // must release
7863
7864 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
7865 if (!theKext) {
7866 goto finish;
7867 }
7868
7869 theKext->reportOSMetaClassInstances(msgLogSpec);
7870 finish:
7871 OSSafeReleaseNULL(theKext);
7872 return;
7873 }
7874
7875 /*********************************************************************
7876 *********************************************************************/
7877 void
7878 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
7879 {
7880 OSCollectionIterator * classIterator = NULL; // must release
7881 OSMetaClass * checkClass = NULL; // do not release
7882
7883 if (!metaClasses) {
7884 goto finish;
7885 }
7886
7887 classIterator = OSCollectionIterator::withCollection(metaClasses);
7888 if (!classIterator) {
7889 goto finish;
7890 }
7891 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
7892 if (checkClass->getInstanceCount()) {
7893 OSKextLog(this,
7894 msgLogSpec,
7895 " Kext %s class %s has %d instance%s.",
7896 getIdentifierCString(),
7897 checkClass->getClassName(),
7898 checkClass->getInstanceCount(),
7899 checkClass->getInstanceCount() == 1 ? "" : "s");
7900 }
7901 }
7902
7903 finish:
7904 OSSafeReleaseNULL(classIterator);
7905 return;
7906 }
7907
7908 #if PRAGMA_MARK
7909 #pragma mark User-Space Requests
7910 #endif
7911 /*********************************************************************
7912 * XXX - this function is a big ugly mess
7913 *********************************************************************/
7914 /* static */
7915 OSReturn
7916 OSKext::handleRequest(
7917 host_priv_t hostPriv,
7918 OSKextLogSpec clientLogFilter,
7919 char * requestBuffer,
7920 uint32_t requestLength,
7921 char ** responseOut,
7922 uint32_t * responseLengthOut,
7923 char ** logInfoOut,
7924 uint32_t * logInfoLengthOut)
7925 {
7926 OSReturn result = kOSReturnError;
7927 kern_return_t kmem_result = KERN_FAILURE;
7928
7929 char * response = NULL; // returned by reference
7930 uint32_t responseLength = 0;
7931
7932 OSObject * parsedXML = NULL; // must release
7933 OSDictionary * requestDict = NULL; // do not release
7934 OSString * errorString = NULL; // must release
7935
7936 OSObject * responseObject = NULL; // must release
7937
7938 OSSerialize * serializer = NULL; // must release
7939
7940 OSArray * logInfoArray = NULL; // must release
7941
7942 OSString * predicate = NULL; // do not release
7943 OSString * kextIdentifier = NULL; // do not release
7944 OSArray * kextIdentifiers = NULL; // do not release
7945 OSKext * theKext = NULL; // do not release
7946 OSBoolean * boolArg = NULL; // do not release
7947
7948 IORecursiveLockLock(sKextLock);
7949
7950 if (responseOut) {
7951 *responseOut = NULL;
7952 *responseLengthOut = 0;
7953 }
7954 if (logInfoOut) {
7955 *logInfoOut = NULL;
7956 *logInfoLengthOut = 0;
7957 }
7958
7959 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
7960
7961 /* XML must be nul-terminated.
7962 */
7963 if (requestBuffer[requestLength - 1] != '\0') {
7964 OSKextLog(/* kext */ NULL,
7965 kOSKextLogErrorLevel |
7966 kOSKextLogIPCFlag,
7967 "Invalid request from user space (not nul-terminated).");
7968 result = kOSKextReturnBadData;
7969 goto finish;
7970 }
7971 parsedXML = OSUnserializeXML((const char *)requestBuffer, &errorString);
7972 if (parsedXML) {
7973 requestDict = OSDynamicCast(OSDictionary, parsedXML);
7974 }
7975 if (!requestDict) {
7976 const char * errorCString = "(unknown error)";
7977
7978 if (errorString && errorString->getCStringNoCopy()) {
7979 errorCString = errorString->getCStringNoCopy();
7980 } else if (parsedXML) {
7981 errorCString = "not a dictionary";
7982 }
7983 OSKextLog(/* kext */ NULL,
7984 kOSKextLogErrorLevel |
7985 kOSKextLogIPCFlag,
7986 "Error unserializing request from user space: %s.",
7987 errorCString);
7988 result = kOSKextReturnSerialization;
7989 goto finish;
7990 }
7991
7992 predicate = _OSKextGetRequestPredicate(requestDict);
7993 if (!predicate) {
7994 OSKextLog(/* kext */ NULL,
7995 kOSKextLogErrorLevel |
7996 kOSKextLogIPCFlag,
7997 "Recieved kext request from user space with no predicate.");
7998 result = kOSKextReturnInvalidArgument;
7999 goto finish;
8000 }
8001
8002 OSKextLog(/* kext */ NULL,
8003 kOSKextLogDebugLevel |
8004 kOSKextLogIPCFlag,
8005 "Received '%s' request from user space.",
8006 predicate->getCStringNoCopy());
8007
8008 result = kOSKextReturnNotPrivileged;
8009 if (hostPriv == HOST_PRIV_NULL) {
8010 /* must be root to use these kext requests */
8011 if (predicate->isEqualTo(kKextRequestPredicateUnload) ||
8012 predicate->isEqualTo(kKextRequestPredicateStart) ||
8013 predicate->isEqualTo(kKextRequestPredicateStop) ||
8014 predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
8015 predicate->isEqualTo(kKextRequestPredicateSendResource) ) {
8016 OSKextLog(/* kext */ NULL,
8017 kOSKextLogErrorLevel |
8018 kOSKextLogIPCFlag,
8019 "Access Failure - must be root user.");
8020 goto finish;
8021 }
8022 }
8023
8024 /* Get common args in anticipation of use.
8025 */
8026 kextIdentifier = OSDynamicCast(OSString, _OSKextGetRequestArgument(
8027 requestDict, kKextRequestArgumentBundleIdentifierKey));
8028 kextIdentifiers = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
8029 requestDict, kKextRequestArgumentBundleIdentifierKey));
8030 if (kextIdentifier) {
8031 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
8032 }
8033 boolArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
8034 requestDict, kKextRequestArgumentValueKey));
8035
8036 result = kOSKextReturnInvalidArgument;
8037
8038 if (predicate->isEqualTo(kKextRequestPredicateStart)) {
8039 if (!kextIdentifier) {
8040 OSKextLog(/* kext */ NULL,
8041 kOSKextLogErrorLevel |
8042 kOSKextLogIPCFlag,
8043 "Invalid arguments to kext start request.");
8044 } else if (!theKext) {
8045 OSKextLog(/* kext */ NULL,
8046 kOSKextLogErrorLevel |
8047 kOSKextLogIPCFlag,
8048 "Kext %s not found for start request.",
8049 kextIdentifier->getCStringNoCopy());
8050 result = kOSKextReturnNotFound;
8051 } else {
8052 result = theKext->start();
8053 }
8054
8055 } else if (predicate->isEqualTo(kKextRequestPredicateStop)) {
8056 if (!kextIdentifier) {
8057 OSKextLog(/* kext */ NULL,
8058 kOSKextLogErrorLevel |
8059 kOSKextLogIPCFlag,
8060 "Invalid arguments to kext stop request.");
8061 } else if (!theKext) {
8062 OSKextLog(/* kext */ NULL,
8063 kOSKextLogErrorLevel |
8064 kOSKextLogIPCFlag,
8065 "Kext %s not found for stop request.",
8066 kextIdentifier->getCStringNoCopy());
8067 result = kOSKextReturnNotFound;
8068 } else {
8069 result = theKext->stop();
8070 }
8071
8072 } else if (predicate->isEqualTo(kKextRequestPredicateUnload)) {
8073 if (!kextIdentifier) {
8074 OSKextLog(/* kext */ NULL,
8075 kOSKextLogErrorLevel |
8076 kOSKextLogIPCFlag,
8077 "Invalid arguments to kext unload request.");
8078 } else if (!theKext) {
8079 OSKextLog(/* kext */ NULL,
8080 kOSKextLogErrorLevel |
8081 kOSKextLogIPCFlag,
8082 "Kext %s not found for unload request.",
8083 kextIdentifier->getCStringNoCopy());
8084 result = kOSKextReturnNotFound;
8085 } else {
8086 OSBoolean * terminateFlag = OSDynamicCast(OSBoolean,
8087 _OSKextGetRequestArgument(requestDict,
8088 kKextRequestArgumentTerminateIOServicesKey));
8089 result = OSKext::removeKext(theKext, terminateFlag == kOSBooleanTrue);
8090 }
8091
8092 } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
8093 result = OSKext::dispatchResource(requestDict);
8094
8095 } else if (predicate->isEqualTo(kKextRequestPredicateGetUUIDByAddress)) {
8096
8097 OSNumber *lookupNum = NULL;
8098 lookupNum = OSDynamicCast(OSNumber,
8099 _OSKextGetRequestArgument(requestDict,
8100 kKextRequestArgumentLookupAddressKey));
8101
8102 responseObject = OSKext::copyKextUUIDForAddress(lookupNum);
8103 if (responseObject) {
8104 result = kOSReturnSuccess;
8105 } else {
8106 goto finish;
8107 }
8108
8109 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded) ||
8110 predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
8111 OSBoolean * delayAutounloadBool = NULL;
8112 OSObject * infoKeysRaw = NULL;
8113 OSArray * infoKeys = NULL;
8114 uint32_t infoKeysCount = 0;
8115
8116 delayAutounloadBool = OSDynamicCast(OSBoolean,
8117 _OSKextGetRequestArgument(requestDict,
8118 kKextRequestArgumentDelayAutounloadKey));
8119
8120 /* If asked to delay autounload, reset the timer if it's currently set.
8121 * (That is, don't schedule an unload if one isn't already pending.
8122 */
8123 if (delayAutounloadBool == kOSBooleanTrue) {
8124 OSKext::considerUnloads(/* rescheduleOnly? */ true);
8125 }
8126
8127 infoKeysRaw = _OSKextGetRequestArgument(requestDict,
8128 kKextRequestArgumentInfoKeysKey);
8129 infoKeys = OSDynamicCast(OSArray, infoKeysRaw);
8130 if (infoKeysRaw && !infoKeys) {
8131 OSKextLog(/* kext */ NULL,
8132 kOSKextLogErrorLevel |
8133 kOSKextLogIPCFlag,
8134 "Invalid arguments to kext info request.");
8135 goto finish;
8136 }
8137
8138 if (infoKeys) {
8139 infoKeysCount = infoKeys->getCount();
8140 for (uint32_t i = 0; i < infoKeysCount; i++) {
8141 if (!OSDynamicCast(OSString, infoKeys->getObject(i))) {
8142 OSKextLog(/* kext */ NULL,
8143 kOSKextLogErrorLevel |
8144 kOSKextLogIPCFlag,
8145 "Invalid arguments to kext info request.");
8146 goto finish;
8147 }
8148 }
8149 }
8150
8151 if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
8152 responseObject = OSKext::copyLoadedKextInfo(kextIdentifiers, infoKeys);
8153 }
8154 else if (predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
8155 responseObject = OSKext::copyLoadedKextInfoByUUID(kextIdentifiers, infoKeys);
8156 }
8157 if (!responseObject) {
8158 result = kOSKextReturnInternalError;
8159 } else {
8160 OSKextLog(/* kext */ NULL,
8161 kOSKextLogDebugLevel |
8162 kOSKextLogIPCFlag,
8163 "Returning loaded kext info.");
8164 result = kOSReturnSuccess;
8165 }
8166 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
8167
8168 /* Hand the current sKernelRequests array to the caller
8169 * (who must release it), and make a new one.
8170 */
8171 responseObject = sKernelRequests;
8172 sKernelRequests = OSArray::withCapacity(0);
8173 sPostedKextLoadIdentifiers->flushCollection();
8174 OSKextLog(/* kext */ NULL,
8175 kOSKextLogDebugLevel |
8176 kOSKextLogIPCFlag,
8177 "Returning kernel requests.");
8178 result = kOSReturnSuccess;
8179
8180 } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
8181
8182 /* Return the set of all requested bundle identifiers */
8183 responseObject = sAllKextLoadIdentifiers;
8184 responseObject->retain();
8185 OSKextLog(/* kext */ NULL,
8186 kOSKextLogDebugLevel |
8187 kOSKextLogIPCFlag,
8188 "Returning load requests.");
8189 result = kOSReturnSuccess;
8190 }
8191 else {
8192 OSKextLog(/* kext */ NULL,
8193 kOSKextLogDebugLevel |
8194 kOSKextLogIPCFlag,
8195 "Received '%s' invalid request from user space.",
8196 predicate->getCStringNoCopy());
8197 goto finish;
8198 }
8199
8200 /**********
8201 * Now we have handle the request, or not. Gather up the response & logging
8202 * info to ship to user space.
8203 *********/
8204
8205 /* Note: Nothing in OSKext is supposed to retain requestDict,
8206 * but you never know....
8207 */
8208 if (requestDict->getRetainCount() > 1) {
8209 OSKextLog(/* kext */ NULL,
8210 kOSKextLogWarningLevel |
8211 kOSKextLogIPCFlag,
8212 "Request from user space still retained by a kext; "
8213 "probable memory leak.");
8214 }
8215
8216 if (responseOut && responseObject) {
8217 serializer = OSSerialize::withCapacity(0);
8218 if (!serializer) {
8219 result = kOSKextReturnNoMemory;
8220 goto finish;
8221 }
8222
8223 if (!responseObject->serialize(serializer)) {
8224 OSKextLog(/* kext */ NULL,
8225 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
8226 "Failed to serialize response to request from user space.");
8227 result = kOSKextReturnSerialization;
8228 goto finish;
8229 }
8230
8231 response = (char *)serializer->text();
8232 responseLength = serializer->getLength();
8233 }
8234
8235 if (responseOut && response) {
8236 char * buffer;
8237
8238 /* This kmem_alloc sets the return value of the function.
8239 */
8240 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer,
8241 round_page(responseLength), VM_KERN_MEMORY_OSKEXT);
8242 if (kmem_result != KERN_SUCCESS) {
8243 OSKextLog(/* kext */ NULL,
8244 kOSKextLogErrorLevel |
8245 kOSKextLogIPCFlag,
8246 "Failed to copy response to request from user space.");
8247 result = kmem_result;
8248 goto finish;
8249 } else {
8250 /* 11981737 - clear uninitialized data in last page */
8251 bzero((void *)(buffer + responseLength),
8252 (round_page(responseLength) - responseLength));
8253 memcpy(buffer, response, responseLength);
8254 *responseOut = buffer;
8255 *responseLengthOut = responseLength;
8256 }
8257 }
8258
8259 finish:
8260
8261 /* Gather up the collected log messages for user space. Any messages
8262 * messages past this call will not make it up as log messages but
8263 * will be in the system log. Note that we ignore the return of the
8264 * serialize; it has no bearing on the operation at hand even if we
8265 * fail to get the log messages.
8266 */
8267 logInfoArray = OSKext::clearUserSpaceLogFilter();
8268
8269 if (logInfoArray && logInfoOut && logInfoLengthOut) {
8270 (void)OSKext::serializeLogInfo(logInfoArray,
8271 logInfoOut, logInfoLengthOut);
8272 }
8273
8274 IORecursiveLockUnlock(sKextLock);
8275
8276 OSSafeReleaseNULL(parsedXML);
8277 OSSafeReleaseNULL(errorString);
8278 OSSafeReleaseNULL(responseObject);
8279 OSSafeReleaseNULL(serializer);
8280 OSSafeReleaseNULL(logInfoArray);
8281
8282 return result;
8283 }
8284
8285
8286 // #include <InstrProfiling.h>
8287 extern "C" {
8288
8289 uint64_t __llvm_profile_get_size_for_buffer_internal(const char *DataBegin,
8290 const char *DataEnd,
8291 const char *CountersBegin,
8292 const char *CountersEnd ,
8293 const char *NamesBegin,
8294 const char *NamesEnd);
8295 int __llvm_profile_write_buffer_internal(char *Buffer,
8296 const char *DataBegin,
8297 const char *DataEnd,
8298 const char *CountersBegin,
8299 const char *CountersEnd ,
8300 const char *NamesBegin,
8301 const char *NamesEnd);
8302 }
8303
8304
8305 static
8306 void OSKextPgoMetadataPut(char *pBuffer,
8307 size_t *position,
8308 size_t bufferSize,
8309 uint32_t *num_pairs,
8310 const char *key,
8311 const char *value)
8312 {
8313 size_t strlen_key = strlen(key);
8314 size_t strlen_value = strlen(value);
8315 size_t len = strlen(key) + 1 + strlen(value) + 1;
8316 char *pos = pBuffer + *position;
8317 *position += len;
8318 if (pBuffer && bufferSize && *position <= bufferSize) {
8319 memcpy(pos, key, strlen_key); pos += strlen_key;
8320 *(pos++) = '=';
8321 memcpy(pos, value, strlen_value); pos += strlen_value;
8322 *(pos++) = 0;
8323 if (num_pairs) {
8324 (*num_pairs)++;
8325 }
8326 }
8327 }
8328
8329
8330 static
8331 void OSKextPgoMetadataPutMax(size_t *position, const char *key, size_t value_max)
8332 {
8333 *position += strlen(key) + 1 + value_max + 1;
8334 }
8335
8336
8337 static
8338 void OSKextPgoMetadataPutAll(OSKext *kext,
8339 uuid_t instance_uuid,
8340 char *pBuffer,
8341 size_t *position,
8342 size_t bufferSize,
8343 uint32_t *num_pairs)
8344 {
8345 _static_assert_1_arg(sizeof(clock_sec_t) % 2 == 0);
8346 //log_10 2^16 ≈ 4.82
8347 const size_t max_secs_string_size = 5 * sizeof(clock_sec_t)/2;
8348 const size_t max_timestamp_string_size = max_secs_string_size + 1 + 6;
8349
8350 if (!pBuffer) {
8351 OSKextPgoMetadataPutMax(position, "INSTANCE", 36);
8352 OSKextPgoMetadataPutMax(position, "UUID", 36);
8353 OSKextPgoMetadataPutMax(position, "TIMESTAMP", max_timestamp_string_size);
8354 } else {
8355 uuid_string_t instance_uuid_string;
8356 uuid_unparse(instance_uuid, instance_uuid_string);
8357 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
8358 "INSTANCE", instance_uuid_string);
8359
8360 OSData *uuid_data;
8361 uuid_t uuid;
8362 uuid_string_t uuid_string;
8363 uuid_data = kext->copyUUID();
8364 if (uuid_data) {
8365 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
8366 OSSafeReleaseNULL(uuid_data);
8367 uuid_unparse(uuid, uuid_string);
8368 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
8369 "UUID", uuid_string);
8370 }
8371
8372 clock_sec_t secs;
8373 clock_usec_t usecs;
8374 clock_get_calendar_microtime(&secs, &usecs);
8375 assert(usecs < 1000000);
8376 char timestamp[max_timestamp_string_size + 1];
8377 _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t));
8378 snprintf(timestamp, sizeof(timestamp), "%lu.%06d", (unsigned long)secs, (int)usecs);
8379 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
8380 "TIMESTAMP", timestamp);
8381 }
8382
8383 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
8384 "NAME", kext->getIdentifierCString());
8385
8386 char versionCString[kOSKextVersionMaxLength];
8387 OSKextVersionGetString(kext->getVersion(), versionCString, kOSKextVersionMaxLength);
8388 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
8389 "VERSION", versionCString);
8390
8391 }
8392
8393 static
8394 size_t OSKextPgoMetadataSize(OSKext *kext)
8395 {
8396 size_t position = 0;
8397 uuid_t fakeuuid = {};
8398 OSKextPgoMetadataPutAll(kext, fakeuuid, NULL, &position, 0, NULL);
8399 return position;
8400 }
8401
8402 int OSKextGrabPgoDataLocked(OSKext *kext,
8403 bool metadata,
8404 uuid_t instance_uuid,
8405 uint64_t *pSize,
8406 char *pBuffer,
8407 uint64_t bufferSize)
8408 {
8409 int err = 0;
8410
8411 kernel_section_t *sect_prf_data = NULL;
8412 kernel_section_t *sect_prf_name = NULL;
8413 kernel_section_t *sect_prf_cnts = NULL;
8414 uint64_t size;
8415 size_t metadata_size = 0;
8416
8417 sect_prf_data = kext->lookupSection("__DATA", "__llvm_prf_data");
8418 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_name");
8419 sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
8420
8421 if (!sect_prf_data || !sect_prf_name || !sect_prf_cnts) {
8422 err = ENOTSUP;
8423 goto out;
8424 }
8425
8426 size = __llvm_profile_get_size_for_buffer_internal(
8427 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
8428 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
8429 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
8430
8431 if (metadata) {
8432 metadata_size = OSKextPgoMetadataSize(kext);
8433 size += metadata_size;
8434 size += sizeof(pgo_metadata_footer);
8435 }
8436
8437
8438 if (pSize) {
8439 *pSize = size;
8440 }
8441
8442 if (pBuffer && bufferSize) {
8443 if (bufferSize < size) {
8444 err = ERANGE;
8445 goto out;
8446 }
8447
8448 err = __llvm_profile_write_buffer_internal(
8449 pBuffer,
8450 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
8451 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
8452 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
8453
8454 if (err) {
8455 err = EIO;
8456 goto out;
8457 }
8458
8459 if (metadata) {
8460 char *end_of_buffer = pBuffer + size;
8461 struct pgo_metadata_footer *footerp = (struct pgo_metadata_footer *) (end_of_buffer - sizeof(struct pgo_metadata_footer));
8462 char *metadata_buffer = end_of_buffer - (sizeof(struct pgo_metadata_footer) + metadata_size);
8463
8464 size_t metadata_position = 0;
8465 uint32_t num_pairs = 0;
8466 OSKextPgoMetadataPutAll(kext, instance_uuid, metadata_buffer, &metadata_position, metadata_size, &num_pairs);
8467 while (metadata_position < metadata_size) {
8468 metadata_buffer[metadata_position++] = 0;
8469 }
8470
8471 struct pgo_metadata_footer footer;
8472 footer.magic = htonl(0x6d657461);
8473 footer.number_of_pairs = htonl( num_pairs );
8474 footer.offset_to_pairs = htonl( sizeof(struct pgo_metadata_footer) + metadata_size );
8475 memcpy(footerp, &footer, sizeof(footer));
8476 }
8477
8478 }
8479
8480 out:
8481 return err;
8482 }
8483
8484
8485 int
8486 OSKextGrabPgoData(uuid_t uuid,
8487 uint64_t *pSize,
8488 char *pBuffer,
8489 uint64_t bufferSize,
8490 int wait_for_unload,
8491 int metadata)
8492 {
8493 int err = 0;
8494 OSKext *kext = NULL;
8495
8496
8497 IORecursiveLockLock(sKextLock);
8498
8499 kext = OSKext::lookupKextWithUUID(uuid);
8500 if (!kext) {
8501 err = ENOENT;
8502 goto out;
8503 }
8504
8505 if (wait_for_unload) {
8506 OSKextGrabPgoStruct s;
8507
8508 s.metadata = metadata;
8509 s.pSize = pSize;
8510 s.pBuffer = pBuffer;
8511 s.bufferSize = bufferSize;
8512 s.err = EINTR;
8513
8514 struct list_head *prev = &kext->pendingPgoHead;
8515 struct list_head *next = kext->pendingPgoHead.next;
8516
8517 s.list_head.prev = prev;
8518 s.list_head.next = next;
8519
8520 prev->next = &s.list_head;
8521 next->prev = &s.list_head;
8522
8523 kext->release();
8524 kext = NULL;
8525
8526 IORecursiveLockSleep(sKextLock, &s, THREAD_ABORTSAFE);
8527
8528 prev = s.list_head.prev;
8529 next = s.list_head.next;
8530
8531 prev->next = next;
8532 next->prev = prev;
8533
8534 err = s.err;
8535
8536 } else {
8537 err = OSKextGrabPgoDataLocked(kext, metadata, kext->instance_uuid, pSize, pBuffer, bufferSize);
8538 }
8539
8540 out:
8541 if (kext) {
8542 kext->release();
8543 }
8544
8545 IORecursiveLockUnlock(sKextLock);
8546
8547 return err;
8548 }
8549
8550 void
8551 OSKextResetPgoCountersLock()
8552 {
8553 IORecursiveLockLock(sKextLock);
8554 }
8555
8556 void
8557 OSKextResetPgoCountersUnlock()
8558 {
8559 IORecursiveLockUnlock(sKextLock);
8560 }
8561
8562
8563 extern unsigned int not_in_kdp;
8564
8565 void
8566 OSKextResetPgoCounters()
8567 {
8568 assert(!not_in_kdp);
8569 uint32_t count = sLoadedKexts->getCount();
8570 for (uint32_t i = 0; i < count; i++) {
8571 OSKext *kext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
8572 kernel_section_t *sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
8573 if (!sect_prf_cnts) {
8574 continue;
8575 }
8576 memset((void*)sect_prf_cnts->addr, 0, sect_prf_cnts->size);
8577 }
8578 }
8579
8580 OSDictionary *
8581 OSKext::copyLoadedKextInfoByUUID(
8582 OSArray * kextIdentifiers,
8583 OSArray * infoKeys)
8584 {
8585 OSDictionary * result = NULL;
8586 OSDictionary * kextInfo = NULL; // must release
8587 uint32_t count, i;
8588 uint32_t idCount = 0;
8589 uint32_t idIndex = 0;
8590
8591 IORecursiveLockLock(sKextLock);
8592
8593 #if CONFIG_MACF
8594 /* Is the calling process allowed to query kext info? */
8595 if (current_task() != kernel_task) {
8596 int macCheckResult = 0;
8597 kauth_cred_t cred = NULL;
8598
8599 cred = kauth_cred_get_with_ref();
8600 macCheckResult = mac_kext_check_query(cred);
8601 kauth_cred_unref(&cred);
8602
8603 if (macCheckResult != 0) {
8604 OSKextLog(/* kext */ NULL,
8605 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
8606 "Failed to query kext info (MAC policy error 0x%x).",
8607 macCheckResult);
8608 goto finish;
8609 }
8610 }
8611 #endif
8612
8613 /* Empty list of UUIDs is equivalent to no list (get all).
8614 */
8615 if (kextIdentifiers && !kextIdentifiers->getCount()) {
8616 kextIdentifiers = NULL;
8617 } else if (kextIdentifiers) {
8618 idCount = kextIdentifiers->getCount();
8619 }
8620
8621 /* Same for keys.
8622 */
8623 if (infoKeys && !infoKeys->getCount()) {
8624 infoKeys = NULL;
8625 }
8626
8627 count = sLoadedKexts->getCount();
8628 result = OSDictionary::withCapacity(count);
8629 if (!result) {
8630 goto finish;
8631 }
8632
8633 for (i = 0; i < count; i++) {
8634 OSKext *thisKext = NULL; // do not release
8635 Boolean includeThis = true;
8636 uuid_t thisKextUUID;
8637 OSData *uuid_data;
8638 uuid_string_t uuid_key;
8639
8640 if (kextInfo) {
8641 kextInfo->release();
8642 kextInfo = NULL;
8643 }
8644
8645 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
8646 if (!thisKext) {
8647 continue;
8648 }
8649
8650 uuid_data = thisKext->copyUUID();
8651 if (!uuid_data) {
8652 continue;
8653 }
8654
8655 memcpy(&thisKextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextUUID));
8656 OSSafeReleaseNULL(uuid_data);
8657
8658 uuid_unparse(thisKextUUID, uuid_key);
8659
8660 /* Skip current kext if we have a list of UUIDs and
8661 * it isn't in the list.
8662 */
8663 if (kextIdentifiers) {
8664 includeThis = false;
8665
8666 for (idIndex = 0; idIndex < idCount; idIndex++) {
8667 const OSString* wantedUUID = OSDynamicCast(OSString,
8668 kextIdentifiers->getObject(idIndex));
8669
8670 uuid_t uuid;
8671 uuid_parse(wantedUUID->getCStringNoCopy(), uuid);
8672
8673 if (0 == uuid_compare(uuid, thisKextUUID)) {
8674 includeThis = true;
8675 break;
8676 }
8677
8678 }
8679 }
8680
8681 if (!includeThis) {
8682 continue;
8683 }
8684
8685 kextInfo = thisKext->copyInfo(infoKeys);
8686 if (kextInfo) {
8687 result->setObject(uuid_key, kextInfo);
8688 }
8689 }
8690
8691 finish:
8692 IORecursiveLockUnlock(sKextLock);
8693
8694 if (kextInfo) kextInfo->release();
8695
8696 return result;
8697 }
8698
8699 /*********************************************************************
8700 *********************************************************************/
8701 /* static */
8702 OSDictionary *
8703 OSKext::copyLoadedKextInfo(
8704 OSArray * kextIdentifiers,
8705 OSArray * infoKeys)
8706 {
8707 OSDictionary * result = NULL;
8708 OSDictionary * kextInfo = NULL; // must release
8709 uint32_t count, i;
8710 uint32_t idCount = 0;
8711 uint32_t idIndex = 0;
8712
8713 IORecursiveLockLock(sKextLock);
8714
8715 #if CONFIG_MACF
8716 /* Is the calling process allowed to query kext info? */
8717 if (current_task() != kernel_task) {
8718 int macCheckResult = 0;
8719 kauth_cred_t cred = NULL;
8720
8721 cred = kauth_cred_get_with_ref();
8722 macCheckResult = mac_kext_check_query(cred);
8723 kauth_cred_unref(&cred);
8724
8725 if (macCheckResult != 0) {
8726 OSKextLog(/* kext */ NULL,
8727 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
8728 "Failed to query kext info (MAC policy error 0x%x).",
8729 macCheckResult);
8730 goto finish;
8731 }
8732 }
8733 #endif
8734
8735 /* Empty list of bundle ids is equivalent to no list (get all).
8736 */
8737 if (kextIdentifiers && !kextIdentifiers->getCount()) {
8738 kextIdentifiers = NULL;
8739 } else if (kextIdentifiers) {
8740 idCount = kextIdentifiers->getCount();
8741 }
8742
8743 /* Same for keys.
8744 */
8745 if (infoKeys && !infoKeys->getCount()) {
8746 infoKeys = NULL;
8747 }
8748
8749 count = sLoadedKexts->getCount();
8750 result = OSDictionary::withCapacity(count);
8751 if (!result) {
8752 goto finish;
8753 }
8754
8755 #if 0
8756 OSKextLog(/* kext */ NULL,
8757 kOSKextLogErrorLevel |
8758 kOSKextLogGeneralFlag,
8759 "kaslr: vm_kernel_slide 0x%lx \n",
8760 vm_kernel_slide);
8761 OSKextLog(/* kext */ NULL,
8762 kOSKextLogErrorLevel |
8763 kOSKextLogGeneralFlag,
8764 "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
8765 vm_kernel_stext, vm_kernel_etext);
8766 OSKextLog(/* kext */ NULL,
8767 kOSKextLogErrorLevel |
8768 kOSKextLogGeneralFlag,
8769 "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
8770 vm_kernel_base, vm_kernel_top);
8771 OSKextLog(/* kext */ NULL,
8772 kOSKextLogErrorLevel |
8773 kOSKextLogGeneralFlag,
8774 "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
8775 vm_kext_base, vm_kext_top);
8776 OSKextLog(/* kext */ NULL,
8777 kOSKextLogErrorLevel |
8778 kOSKextLogGeneralFlag,
8779 "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
8780 vm_prelink_stext, vm_prelink_etext);
8781 OSKextLog(/* kext */ NULL,
8782 kOSKextLogErrorLevel |
8783 kOSKextLogGeneralFlag,
8784 "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
8785 vm_prelink_sinfo, vm_prelink_einfo);
8786 OSKextLog(/* kext */ NULL,
8787 kOSKextLogErrorLevel |
8788 kOSKextLogGeneralFlag,
8789 "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
8790 vm_slinkedit, vm_elinkedit);
8791 #endif
8792
8793 for (i = 0; i < count; i++) {
8794 OSKext * thisKext = NULL; // do not release
8795 Boolean includeThis = true;
8796
8797 if (kextInfo) {
8798 kextInfo->release();
8799 kextInfo = NULL;
8800 }
8801 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
8802 if (!thisKext) {
8803 continue;
8804 }
8805
8806 /* Skip current kext if we have a list of bundle IDs and
8807 * it isn't in the list.
8808 */
8809 if (kextIdentifiers) {
8810 const OSString * thisKextID = thisKext->getIdentifier();
8811
8812 includeThis = false;
8813
8814 for (idIndex = 0; idIndex < idCount; idIndex++) {
8815 const OSString * thisRequestID = OSDynamicCast(OSString,
8816 kextIdentifiers->getObject(idIndex));
8817 if (thisKextID->isEqualTo(thisRequestID)) {
8818 includeThis = true;
8819 break;
8820 }
8821 }
8822 }
8823
8824 if (!includeThis) {
8825 continue;
8826 }
8827
8828 kextInfo = thisKext->copyInfo(infoKeys);
8829 if (kextInfo) {
8830 result->setObject(thisKext->getIdentifier(), kextInfo);
8831 }
8832 }
8833
8834 finish:
8835 IORecursiveLockUnlock(sKextLock);
8836
8837 if (kextInfo) kextInfo->release();
8838
8839 return result;
8840 }
8841
8842 /*********************************************************************
8843 * Any info that needs to do allocations must goto finish on alloc
8844 * failure. Info that is just a lookup should just not set the object
8845 * if the info does not exist.
8846 *********************************************************************/
8847 #define _OSKextLoadInfoDictCapacity (12)
8848
8849 OSDictionary *
8850 OSKext::copyInfo(OSArray * infoKeys)
8851 {
8852 OSDictionary * result = NULL;
8853 bool success = false;
8854 OSData * headerData = NULL; // must release
8855 OSData * logData = NULL; // must release
8856 OSNumber * cpuTypeNumber = NULL; // must release
8857 OSNumber * cpuSubtypeNumber = NULL; // must release
8858 OSString * versionString = NULL; // do not release
8859 uint32_t executablePathCStringSize = 0;
8860 char * executablePathCString = NULL; // must release
8861 OSString * executablePathString = NULL; // must release
8862 OSData * uuid = NULL; // must release
8863 OSNumber * scratchNumber = NULL; // must release
8864 OSArray * dependencyLoadTags = NULL; // must release
8865 OSCollectionIterator * metaClassIterator = NULL; // must release
8866 OSArray * metaClassInfo = NULL; // must release
8867 OSDictionary * metaClassDict = NULL; // must release
8868 OSMetaClass * thisMetaClass = NULL; // do not release
8869 OSString * metaClassName = NULL; // must release
8870 OSString * superclassName = NULL; // must release
8871 uint32_t count, i;
8872
8873 result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
8874 if (!result) {
8875 goto finish;
8876 }
8877
8878
8879 /* Empty keys means no keys, but NULL is quicker to check.
8880 */
8881 if (infoKeys && !infoKeys->getCount()) {
8882 infoKeys = NULL;
8883 }
8884
8885 /* Headers, CPU type, and CPU subtype.
8886 */
8887 if (!infoKeys ||
8888 _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey) ||
8889 _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey) ||
8890 _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey) ||
8891 _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey))
8892 {
8893
8894 if (linkedExecutable && !isInterface()) {
8895
8896 kernel_mach_header_t *kext_mach_hdr = (kernel_mach_header_t *)
8897 linkedExecutable->getBytesNoCopy();
8898
8899 #if !SECURE_KERNEL
8900 // do not return macho header info on shipping iOS - 19095897
8901 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey)) {
8902 kernel_mach_header_t * temp_kext_mach_hdr;
8903 struct load_command * lcp;
8904
8905 headerData = OSData::withBytes(kext_mach_hdr,
8906 (u_int) (sizeof(*kext_mach_hdr) + kext_mach_hdr->sizeofcmds));
8907 if (!headerData) {
8908 goto finish;
8909 }
8910
8911 // unslide any vmaddrs we return to userspace - 10726716
8912 temp_kext_mach_hdr = (kernel_mach_header_t *)
8913 headerData->getBytesNoCopy();
8914 if (temp_kext_mach_hdr == NULL) {
8915 goto finish;
8916 }
8917
8918 lcp = (struct load_command *) (temp_kext_mach_hdr + 1);
8919 for (i = 0; i < temp_kext_mach_hdr->ncmds; i++) {
8920 if (lcp->cmd == LC_SEGMENT_KERNEL) {
8921 kernel_segment_command_t * segp;
8922 kernel_section_t * secp;
8923
8924 segp = (kernel_segment_command_t *) lcp;
8925 // 10543468 - if we jettisoned __LINKEDIT clear size info
8926 if (flags.jettisonLinkeditSeg) {
8927 if (strncmp(segp->segname, SEG_LINKEDIT, sizeof(segp->segname)) == 0) {
8928 segp->vmsize = 0;
8929 segp->fileoff = 0;
8930 segp->filesize = 0;
8931 }
8932 }
8933
8934 #if 0
8935 OSKextLog(/* kext */ NULL,
8936 kOSKextLogErrorLevel |
8937 kOSKextLogGeneralFlag,
8938 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
8939 __FUNCTION__, segp->segname, segp->vmaddr,
8940 VM_KERNEL_UNSLIDE(segp->vmaddr),
8941 segp->vmsize, segp->nsects);
8942 if ( (VM_KERNEL_IS_SLID(segp->vmaddr) == false) &&
8943 (VM_KERNEL_IS_KEXT(segp->vmaddr) == false) &&
8944 (VM_KERNEL_IS_PRELINKTEXT(segp->vmaddr) == false) &&
8945 (VM_KERNEL_IS_PRELINKINFO(segp->vmaddr) == false) &&
8946 (VM_KERNEL_IS_KEXT_LINKEDIT(segp->vmaddr) == false) ) {
8947 OSKextLog(/* kext */ NULL,
8948 kOSKextLogErrorLevel |
8949 kOSKextLogGeneralFlag,
8950 "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
8951 __FUNCTION__, segp->vmaddr, vm_kext_base, vm_kext_top);
8952 }
8953 #endif
8954 segp->vmaddr = VM_KERNEL_UNSLIDE(segp->vmaddr);
8955
8956 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
8957 secp->addr = VM_KERNEL_UNSLIDE(secp->addr);
8958 }
8959 }
8960 lcp = (struct load_command *)((caddr_t)lcp + lcp->cmdsize);
8961 }
8962 result->setObject(kOSBundleMachOHeadersKey, headerData);
8963 }
8964 #endif // SECURE_KERNEL
8965
8966 if (_OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
8967 osLogDataHeaderRef *header;
8968 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
8969
8970 void *os_log_data = NULL;
8971 void *cstring_data = NULL;
8972 unsigned long os_log_size = 0;
8973 unsigned long cstring_size = 0;
8974 uint32_t os_log_offset = 0;
8975 uint32_t cstring_offset = 0;
8976 bool res;
8977
8978 os_log_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__os_log", &os_log_size);
8979 os_log_offset = getsectoffsetfromheader(kext_mach_hdr, "__TEXT", "__os_log");
8980 cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__cstring", &cstring_size);
8981 cstring_offset = getsectoffsetfromheader(kext_mach_hdr, "__TEXT", "__cstring");
8982
8983 header = (osLogDataHeaderRef *) headerBytes;
8984 header->version = OS_LOG_HDR_VERSION;
8985 header->sect_count = NUM_OS_LOG_SECTIONS;
8986 header->sections[OS_LOG_SECT_IDX].sect_offset = os_log_offset;
8987 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) os_log_size;
8988 header->sections[CSTRING_SECT_IDX].sect_offset = cstring_offset;
8989 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) cstring_size;
8990
8991
8992 logData = OSData::withBytes(header, (u_int) (sizeof(osLogDataHeaderRef)));
8993 if (!logData) {
8994 goto finish;
8995 }
8996 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
8997 if (!res) {
8998 goto finish;
8999 }
9000 if (os_log_data) {
9001 res = logData->appendBytes(os_log_data, (u_int)header->sections[OS_LOG_SECT_IDX].sect_size);
9002 if (!res) {
9003 goto finish;
9004 }
9005 }
9006 if (cstring_data) {
9007 res = logData->appendBytes(cstring_data, (u_int)header->sections[CSTRING_SECT_IDX].sect_size);
9008 if (!res) {
9009 goto finish;
9010 }
9011 }
9012 result->setObject(kOSBundleLogStringsKey, logData);
9013 }
9014
9015 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey)) {
9016 cpuTypeNumber = OSNumber::withNumber(
9017 (uint64_t) kext_mach_hdr->cputype,
9018 8 * sizeof(kext_mach_hdr->cputype));
9019 if (!cpuTypeNumber) {
9020 goto finish;
9021 }
9022 result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber);
9023 }
9024
9025 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
9026 cpuSubtypeNumber = OSNumber::withNumber(
9027 (uint64_t) kext_mach_hdr->cpusubtype,
9028 8 * sizeof(kext_mach_hdr->cpusubtype));
9029 if (!cpuSubtypeNumber) {
9030 goto finish;
9031 }
9032 result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber);
9033 }
9034 }
9035 }
9036
9037 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
9038 */
9039 result->setObject(kCFBundleIdentifierKey, bundleID);
9040
9041 /* CFBundleVersion.
9042 */
9043 if (!infoKeys || _OSArrayContainsCString(infoKeys, kCFBundleVersionKey)) {
9044 versionString = OSDynamicCast(OSString,
9045 getPropertyForHostArch(kCFBundleVersionKey));
9046 if (versionString) {
9047 result->setObject(kCFBundleVersionKey, versionString);
9048 }
9049 }
9050
9051 /* OSBundleCompatibleVersion.
9052 */
9053 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCompatibleVersionKey)) {
9054 versionString = OSDynamicCast(OSString,
9055 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
9056 if (versionString) {
9057 result->setObject(kOSBundleCompatibleVersionKey, versionString);
9058 }
9059 }
9060
9061 /* Path.
9062 */
9063 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePathKey)) {
9064 if (path) {
9065 result->setObject(kOSBundlePathKey, path);
9066 }
9067 }
9068
9069
9070 /* OSBundleExecutablePath.
9071 */
9072 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecutablePathKey)) {
9073 if (path && executableRelPath) {
9074
9075 uint32_t pathLength = path->getLength(); // gets incremented below
9076
9077 // +1 for slash, +1 for \0
9078 executablePathCStringSize = pathLength + executableRelPath->getLength() + 2;
9079
9080 executablePathCString = (char *)kalloc_tag((executablePathCStringSize) *
9081 sizeof(char), VM_KERN_MEMORY_OSKEXT); // +1 for \0
9082 if (!executablePathCString) {
9083 goto finish;
9084 }
9085 strlcpy(executablePathCString, path->getCStringNoCopy(),
9086 executablePathCStringSize);
9087 executablePathCString[pathLength++] = '/';
9088 executablePathCString[pathLength++] = '\0';
9089 strlcat(executablePathCString, executableRelPath->getCStringNoCopy(),
9090 executablePathCStringSize);
9091
9092 executablePathString = OSString::withCString(executablePathCString);
9093
9094 if (!executablePathString) {
9095 goto finish;
9096 }
9097
9098 result->setObject(kOSBundleExecutablePathKey, executablePathString);
9099 }
9100 }
9101
9102 /* UUID, if the kext has one.
9103 */
9104 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleUUIDKey)) {
9105 uuid = copyUUID();
9106 if (uuid) {
9107 result->setObject(kOSBundleUUIDKey, uuid);
9108 }
9109 }
9110
9111 /*****
9112 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
9113 */
9114 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKernelResourceKey)) {
9115 result->setObject(kOSKernelResourceKey,
9116 isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
9117 }
9118
9119 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleIsInterfaceKey)) {
9120 result->setObject(kOSBundleIsInterfaceKey,
9121 isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
9122 }
9123
9124 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePrelinkedKey)) {
9125 result->setObject(kOSBundlePrelinkedKey,
9126 isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
9127 }
9128
9129 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleStartedKey)) {
9130 result->setObject(kOSBundleStartedKey,
9131 isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
9132 }
9133
9134 /* LoadTag (Index).
9135 */
9136 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadTagKey)) {
9137 scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
9138 /* numBits */ 8 * sizeof(loadTag));
9139 if (!scratchNumber) {
9140 goto finish;
9141 }
9142 result->setObject(kOSBundleLoadTagKey, scratchNumber);
9143 OSSafeReleaseNULL(scratchNumber);
9144 }
9145
9146 /* LoadAddress, LoadSize.
9147 */
9148 if (!infoKeys ||
9149 _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey) ||
9150 _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey) ||
9151 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey) ||
9152 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey) ||
9153 _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey))
9154 {
9155 if (isInterface() || linkedExecutable) {
9156 /* These go to userspace via serialization, so we don't want any doubts
9157 * about their size.
9158 */
9159 uint64_t loadAddress = 0;
9160 uint32_t loadSize = 0;
9161 uint32_t wiredSize = 0;
9162 uint64_t execLoadAddress = 0;
9163 uint32_t execLoadSize = 0;
9164
9165 /* Interfaces always report 0 load address & size.
9166 * Just the way they roll.
9167 *
9168 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
9169 * xxx - shouldn't have one!
9170 */
9171 if (linkedExecutable /* && !isInterface() */) {
9172 kernel_mach_header_t *mh = NULL;
9173 kernel_segment_command_t *seg = NULL;
9174
9175 loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
9176 mh = (kernel_mach_header_t *)loadAddress;
9177 loadAddress = VM_KERNEL_UNSLIDE(loadAddress);
9178 loadSize = linkedExecutable->getLength();
9179
9180 /* Walk through the kext, looking for the first executable
9181 * segment in case we were asked for its size/address.
9182 */
9183 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
9184 if (seg->initprot & VM_PROT_EXECUTE) {
9185 execLoadAddress = VM_KERNEL_UNSLIDE(seg->vmaddr);
9186 execLoadSize = seg->vmsize;
9187 break;
9188 }
9189 }
9190
9191 /* If we have a kmod_info struct, calculated the wired size
9192 * from that. Otherwise it's the full load size.
9193 */
9194 if (kmod_info) {
9195 wiredSize = loadSize - kmod_info->hdr_size;
9196 } else {
9197 wiredSize = loadSize;
9198 }
9199 }
9200
9201 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey)) {
9202 scratchNumber = OSNumber::withNumber(
9203 (unsigned long long)(loadAddress),
9204 /* numBits */ 8 * sizeof(loadAddress));
9205 if (!scratchNumber) {
9206 goto finish;
9207 }
9208 result->setObject(kOSBundleLoadAddressKey, scratchNumber);
9209 OSSafeReleaseNULL(scratchNumber);
9210 }
9211 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey)) {
9212 scratchNumber = OSNumber::withNumber(
9213 (unsigned long long)(execLoadAddress),
9214 /* numBits */ 8 * sizeof(execLoadAddress));
9215 if (!scratchNumber) {
9216 goto finish;
9217 }
9218 result->setObject(kOSBundleExecLoadAddressKey, scratchNumber);
9219 OSSafeReleaseNULL(scratchNumber);
9220 }
9221 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey)) {
9222 scratchNumber = OSNumber::withNumber(
9223 (unsigned long long)(loadSize),
9224 /* numBits */ 8 * sizeof(loadSize));
9225 if (!scratchNumber) {
9226 goto finish;
9227 }
9228 result->setObject(kOSBundleLoadSizeKey, scratchNumber);
9229 OSSafeReleaseNULL(scratchNumber);
9230 }
9231 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey)) {
9232 scratchNumber = OSNumber::withNumber(
9233 (unsigned long long)(execLoadSize),
9234 /* numBits */ 8 * sizeof(execLoadSize));
9235 if (!scratchNumber) {
9236 goto finish;
9237 }
9238 result->setObject(kOSBundleExecLoadSizeKey, scratchNumber);
9239 OSSafeReleaseNULL(scratchNumber);
9240 }
9241 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
9242 scratchNumber = OSNumber::withNumber(
9243 (unsigned long long)(wiredSize),
9244 /* numBits */ 8 * sizeof(wiredSize));
9245 if (!scratchNumber) {
9246 goto finish;
9247 }
9248 result->setObject(kOSBundleWiredSizeKey, scratchNumber);
9249 OSSafeReleaseNULL(scratchNumber);
9250 }
9251 }
9252 }
9253
9254 /* OSBundleDependencies. In descending order for
9255 * easy compatibility with kextstat(8).
9256 */
9257 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleDependenciesKey)) {
9258 if ((count = getNumDependencies())) {
9259 dependencyLoadTags = OSArray::withCapacity(count);
9260 result->setObject(kOSBundleDependenciesKey, dependencyLoadTags);
9261
9262 i = count - 1;
9263 do {
9264 OSKext * dependency = OSDynamicCast(OSKext,
9265 dependencies->getObject(i));
9266
9267 OSSafeReleaseNULL(scratchNumber);
9268
9269 if (!dependency) {
9270 continue;
9271 }
9272 scratchNumber = OSNumber::withNumber(
9273 (unsigned long long)dependency->getLoadTag(),
9274 /* numBits*/ 8 * sizeof(loadTag));
9275 if (!scratchNumber) {
9276 goto finish;
9277 }
9278 dependencyLoadTags->setObject(scratchNumber);
9279 } while (i--);
9280 }
9281 }
9282
9283 OSSafeReleaseNULL(scratchNumber);
9284
9285 /* OSBundleMetaClasses.
9286 */
9287 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleClassesKey)) {
9288 if (metaClasses && metaClasses->getCount()) {
9289 metaClassIterator = OSCollectionIterator::withCollection(metaClasses);
9290 metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
9291 if (!metaClassIterator || !metaClassInfo) {
9292 goto finish;
9293 }
9294 result->setObject(kOSBundleClassesKey, metaClassInfo);
9295
9296 while ( (thisMetaClass = OSDynamicCast(OSMetaClass,
9297 metaClassIterator->getNextObject())) ) {
9298
9299 OSSafeReleaseNULL(metaClassDict);
9300 OSSafeReleaseNULL(scratchNumber);
9301 OSSafeReleaseNULL(metaClassName);
9302 OSSafeReleaseNULL(superclassName);
9303
9304 metaClassDict = OSDictionary::withCapacity(3);
9305 if (!metaClassDict) {
9306 goto finish;
9307 }
9308
9309 metaClassName = OSString::withCString(thisMetaClass->getClassName());
9310 if (thisMetaClass->getSuperClass()) {
9311 superclassName = OSString::withCString(
9312 thisMetaClass->getSuperClass()->getClassName());
9313 }
9314 scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
9315 8 * sizeof(unsigned int));
9316
9317 /* Bail if any of the essentials is missing. The root class lacks a superclass,
9318 * of course.
9319 */
9320 if (!metaClassDict || !metaClassName || !scratchNumber) {
9321 goto finish;
9322 }
9323
9324 metaClassInfo->setObject(metaClassDict);
9325 metaClassDict->setObject(kOSMetaClassNameKey, metaClassName);
9326 if (superclassName) {
9327 metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName);
9328 }
9329 metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber);
9330 }
9331 }
9332 }
9333
9334 /* OSBundleRetainCount.
9335 */
9336 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleRetainCountKey)) {
9337 OSSafeReleaseNULL(scratchNumber);
9338 {
9339 int kextRetainCount = getRetainCount() - 1;
9340 if (isLoaded()) {
9341 kextRetainCount--;
9342 }
9343 scratchNumber = OSNumber::withNumber(
9344 (int)kextRetainCount,
9345 /* numBits*/ 8 * sizeof(int));
9346 if (scratchNumber) {
9347 result->setObject(kOSBundleRetainCountKey, scratchNumber);
9348 }
9349 }
9350 }
9351
9352 success = true;
9353
9354 finish:
9355 OSSafeReleaseNULL(headerData);
9356 OSSafeReleaseNULL(logData);
9357 OSSafeReleaseNULL(cpuTypeNumber);
9358 OSSafeReleaseNULL(cpuSubtypeNumber);
9359 OSSafeReleaseNULL(executablePathString);
9360 if (executablePathCString) kfree(executablePathCString, executablePathCStringSize);
9361 OSSafeReleaseNULL(uuid);
9362 OSSafeReleaseNULL(scratchNumber);
9363 OSSafeReleaseNULL(dependencyLoadTags);
9364 OSSafeReleaseNULL(metaClassIterator);
9365 OSSafeReleaseNULL(metaClassInfo);
9366 OSSafeReleaseNULL(metaClassDict);
9367 OSSafeReleaseNULL(metaClassName);
9368 OSSafeReleaseNULL(superclassName);
9369 if (!success) {
9370 OSSafeReleaseNULL(result);
9371 }
9372 return result;
9373 }
9374
9375 /*********************************************************************
9376 *********************************************************************/
9377 /* static */
9378 OSReturn
9379 OSKext::requestResource(
9380 const char * kextIdentifierCString,
9381 const char * resourceNameCString,
9382 OSKextRequestResourceCallback callback,
9383 void * context,
9384 OSKextRequestTag * requestTagOut)
9385 {
9386 OSReturn result = kOSReturnError;
9387 OSKext * callbackKext = NULL; // must release (looked up)
9388
9389 OSKextRequestTag requestTag = -1;
9390 OSNumber * requestTagNum = NULL; // must release
9391
9392 OSDictionary * requestDict = NULL; // must release
9393 OSString * kextIdentifier = NULL; // must release
9394 OSString * resourceName = NULL; // must release
9395
9396 OSDictionary * callbackRecord = NULL; // must release
9397 OSData * callbackWrapper = NULL; // must release
9398
9399 OSData * contextWrapper = NULL; // must release
9400
9401 IORecursiveLockLock(sKextLock);
9402
9403 if (requestTagOut) {
9404 *requestTagOut = kOSKextRequestTagInvalid;
9405 }
9406
9407 /* If requests to user space are disabled, don't go any further */
9408 if (!sKernelRequestsEnabled) {
9409 OSKextLog(/* kext */ NULL,
9410 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
9411 "Can't request resource %s for %s - requests to user space are disabled.",
9412 resourceNameCString,
9413 kextIdentifierCString);
9414 result = kOSKextReturnDisabled;
9415 goto finish;
9416 }
9417
9418 if (!kextIdentifierCString || !resourceNameCString || !callback) {
9419 result = kOSKextReturnInvalidArgument;
9420 goto finish;
9421 }
9422
9423 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
9424 if (!callbackKext) {
9425 OSKextLog(/* kext */ NULL,
9426 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
9427 "Resource request has bad callback address.");
9428 result = kOSKextReturnInvalidArgument;
9429 goto finish;
9430 }
9431 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
9432 OSKextLog(/* kext */ NULL,
9433 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
9434 "Resource request callback is in a kext that is not started.");
9435 result = kOSKextReturnInvalidArgument;
9436 goto finish;
9437 }
9438
9439 /* Do not allow any new requests to be made on a kext that is unloading.
9440 */
9441 if (callbackKext->flags.stopping) {
9442 result = kOSKextReturnStopping;
9443 goto finish;
9444 }
9445
9446 /* If we're wrapped the next available request tag around to the negative
9447 * numbers, we can't service any more requests.
9448 */
9449 if (sNextRequestTag == kOSKextRequestTagInvalid) {
9450 OSKextLog(/* kext */ NULL,
9451 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
9452 "No more request tags available; restart required.");
9453 result = kOSKextReturnNoResources;
9454 goto finish;
9455 }
9456 requestTag = sNextRequestTag++;
9457
9458 result = _OSKextCreateRequest(kKextRequestPredicateRequestResource,
9459 &requestDict);
9460 if (result != kOSReturnSuccess) {
9461 goto finish;
9462 }
9463
9464 kextIdentifier = OSString::withCString(kextIdentifierCString);
9465 resourceName = OSString::withCString(resourceNameCString);
9466 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
9467 8 * sizeof(requestTag));
9468 if (!kextIdentifier ||
9469 !resourceName ||
9470 !requestTagNum ||
9471 !_OSKextSetRequestArgument(requestDict,
9472 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
9473 !_OSKextSetRequestArgument(requestDict,
9474 kKextRequestArgumentNameKey, resourceName) ||
9475 !_OSKextSetRequestArgument(requestDict,
9476 kKextRequestArgumentRequestTagKey, requestTagNum)) {
9477
9478 result = kOSKextReturnNoMemory;
9479 goto finish;
9480 }
9481
9482 callbackRecord = OSDynamicCast(OSDictionary, requestDict->copyCollection());
9483 if (!callbackRecord) {
9484 result = kOSKextReturnNoMemory;
9485 goto finish;
9486 }
9487 // we validate callback address at call time
9488 callbackWrapper = OSData::withBytes((void *)&callback, sizeof(void *));
9489 if (context) {
9490 contextWrapper = OSData::withBytes((void *)&context, sizeof(void *));
9491 }
9492 if (!callbackWrapper || !_OSKextSetRequestArgument(callbackRecord,
9493 kKextRequestArgumentCallbackKey, callbackWrapper)) {
9494
9495 result = kOSKextReturnNoMemory;
9496 goto finish;
9497 }
9498
9499 if (context) {
9500 if (!contextWrapper || !_OSKextSetRequestArgument(callbackRecord,
9501 kKextRequestArgumentContextKey, contextWrapper)) {
9502
9503 result = kOSKextReturnNoMemory;
9504 goto finish;
9505 }
9506 }
9507
9508 /* Only post the requests after all the other potential failure points
9509 * have been passed.
9510 */
9511 if (!sKernelRequests->setObject(requestDict) ||
9512 !sRequestCallbackRecords->setObject(callbackRecord)) {
9513
9514 result = kOSKextReturnNoMemory;
9515 goto finish;
9516 }
9517
9518 OSKext::pingKextd();
9519
9520 result = kOSReturnSuccess;
9521 if (requestTagOut) {
9522 *requestTagOut = requestTag;
9523 }
9524
9525 finish:
9526
9527 /* If we didn't succeed, yank the request & callback
9528 * from their holding arrays.
9529 */
9530 if (result != kOSReturnSuccess) {
9531 unsigned int index;
9532
9533 index = sKernelRequests->getNextIndexOfObject(requestDict, 0);
9534 if (index != (unsigned int)-1) {
9535 sKernelRequests->removeObject(index);
9536 }
9537 index = sRequestCallbackRecords->getNextIndexOfObject(callbackRecord, 0);
9538 if (index != (unsigned int)-1) {
9539 sRequestCallbackRecords->removeObject(index);
9540 }
9541 }
9542
9543 OSKext::considerUnloads(/* rescheduleOnly? */ true);
9544
9545 IORecursiveLockUnlock(sKextLock);
9546
9547 if (callbackKext) callbackKext->release();
9548 if (requestTagNum) requestTagNum->release();
9549
9550 if (requestDict) requestDict->release();
9551 if (kextIdentifier) kextIdentifier->release();
9552 if (resourceName) resourceName->release();
9553
9554 if (callbackRecord) callbackRecord->release();
9555 if (callbackWrapper) callbackWrapper->release();
9556 if (contextWrapper) contextWrapper->release();
9557
9558 return result;
9559 }
9560
9561 /*********************************************************************
9562 * Assumes sKextLock is held.
9563 *********************************************************************/
9564 /* static */
9565 OSReturn
9566 OSKext::dequeueCallbackForRequestTag(
9567 OSKextRequestTag requestTag,
9568 OSDictionary ** callbackRecordOut)
9569 {
9570 OSReturn result = kOSReturnError;
9571 OSNumber * requestTagNum = NULL; // must release
9572
9573 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
9574 8 * sizeof(requestTag));
9575 if (!requestTagNum) {
9576 goto finish;
9577 }
9578
9579 result = OSKext::dequeueCallbackForRequestTag(requestTagNum,
9580 callbackRecordOut);
9581
9582 finish:
9583 OSSafeReleaseNULL(requestTagNum);
9584
9585 return result;
9586 }
9587
9588 /*********************************************************************
9589 * Assumes sKextLock is held.
9590 *********************************************************************/
9591 /* static */
9592 OSReturn
9593 OSKext::dequeueCallbackForRequestTag(
9594 OSNumber * requestTagNum,
9595 OSDictionary ** callbackRecordOut)
9596 {
9597 OSReturn result = kOSKextReturnInvalidArgument;
9598 OSDictionary * callbackRecord = NULL; // retain if matched!
9599 OSNumber * callbackTagNum = NULL; // do not release
9600 unsigned int count, i;
9601
9602 result = kOSReturnError;
9603 count = sRequestCallbackRecords->getCount();
9604 for (i = 0; i < count; i++) {
9605 callbackRecord = OSDynamicCast(OSDictionary,
9606 sRequestCallbackRecords->getObject(i));
9607 if (!callbackRecord) {
9608 goto finish;
9609 }
9610
9611 /* If we don't find a tag, we basically have a leak here. Maybe
9612 * we should just remove it.
9613 */
9614 callbackTagNum = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(
9615 callbackRecord, kKextRequestArgumentRequestTagKey));
9616 if (!callbackTagNum) {
9617 goto finish;
9618 }
9619
9620 /* We could be even more paranoid and check that all the incoming
9621 * args match what's in the callback record.
9622 */
9623 if (callbackTagNum->isEqualTo(requestTagNum)) {
9624 if (callbackRecordOut) {
9625 *callbackRecordOut = callbackRecord;
9626 callbackRecord->retain();
9627 }
9628 sRequestCallbackRecords->removeObject(i);
9629 result = kOSReturnSuccess;
9630 goto finish;
9631 }
9632 }
9633 result = kOSKextReturnNotFound;
9634
9635 finish:
9636 return result;
9637 }
9638
9639
9640 /*********************************************************************
9641 * Busy timeout triage
9642 *********************************************************************/
9643 /* static */
9644 bool
9645 OSKext::isWaitingKextd(void)
9646 {
9647 return sRequestCallbackRecords && sRequestCallbackRecords->getCount();
9648 }
9649
9650 /*********************************************************************
9651 * Assumes sKextLock is held.
9652 *********************************************************************/
9653 /* static */
9654 OSReturn
9655 OSKext::dispatchResource(OSDictionary * requestDict)
9656 {
9657 OSReturn result = kOSReturnError;
9658 OSDictionary * callbackRecord = NULL; // must release
9659 OSNumber * requestTag = NULL; // do not release
9660 OSNumber * requestResult = NULL; // do not release
9661 OSData * dataObj = NULL; // do not release
9662 uint32_t dataLength = 0;
9663 const void * dataPtr = NULL; // do not free
9664 OSData * callbackWrapper = NULL; // do not release
9665 OSKextRequestResourceCallback callback = NULL;
9666 OSData * contextWrapper = NULL; // do not release
9667 void * context = NULL; // do not free
9668 OSKext * callbackKext = NULL; // must release (looked up)
9669
9670 /* Get the args from the request. Right now we need the tag
9671 * to look up the callback record, and the result for invoking the callback.
9672 */
9673 requestTag = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
9674 kKextRequestArgumentRequestTagKey));
9675 requestResult = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
9676 kKextRequestArgumentResultKey));
9677 if (!requestTag || !requestResult) {
9678 result = kOSKextReturnInvalidArgument;
9679 goto finish;
9680 }
9681
9682 /* Look for a callback record matching this request's tag.
9683 */
9684 result = dequeueCallbackForRequestTag(requestTag, &callbackRecord);
9685 if (result != kOSReturnSuccess) {
9686 goto finish;
9687 }
9688
9689 /*****
9690 * Get the context pointer of the callback record (if there is one).
9691 */
9692 contextWrapper = OSDynamicCast(OSData, _OSKextGetRequestArgument(callbackRecord,
9693 kKextRequestArgumentContextKey));
9694 context = _OSKextExtractPointer(contextWrapper);
9695 if (contextWrapper && !context) {
9696 goto finish;
9697 }
9698
9699 callbackWrapper = OSDynamicCast(OSData,
9700 _OSKextGetRequestArgument(callbackRecord,
9701 kKextRequestArgumentCallbackKey));
9702 callback = (OSKextRequestResourceCallback)
9703 _OSKextExtractPointer(callbackWrapper);
9704 if (!callback) {
9705 goto finish;
9706 }
9707
9708 /* Check for a data obj. We might not have one and that's ok, that means
9709 * we didn't find the requested resource, and we still have to tell the
9710 * caller that via the callback.
9711 */
9712 dataObj = OSDynamicCast(OSData, _OSKextGetRequestArgument(requestDict,
9713 kKextRequestArgumentValueKey));
9714 if (dataObj) {
9715 dataPtr = dataObj->getBytesNoCopy();
9716 dataLength = dataObj->getLength();
9717 }
9718
9719 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
9720 if (!callbackKext) {
9721 OSKextLog(/* kext */ NULL,
9722 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
9723 "Can't invoke callback for resource request; ");
9724 goto finish;
9725 }
9726 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
9727 OSKextLog(/* kext */ NULL,
9728 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
9729 "Can't invoke kext resource callback; ");
9730 goto finish;
9731 }
9732
9733 (void)callback(requestTag->unsigned32BitValue(),
9734 (OSReturn)requestResult->unsigned32BitValue(),
9735 dataPtr, dataLength, context);
9736
9737 result = kOSReturnSuccess;
9738
9739 finish:
9740 if (callbackKext) callbackKext->release();
9741 if (callbackRecord) callbackRecord->release();
9742
9743 return result;
9744 }
9745
9746 /*********************************************************************
9747 *********************************************************************/
9748 /* static */
9749 void
9750 OSKext::invokeRequestCallback(
9751 OSDictionary * callbackRecord,
9752 OSReturn callbackResult)
9753 {
9754 OSString * predicate = _OSKextGetRequestPredicate(callbackRecord);
9755 OSNumber * resultNum = NULL; // must release
9756
9757 if (!predicate) {
9758 goto finish;
9759 }
9760
9761 resultNum = OSNumber::withNumber((long long unsigned int)callbackResult,
9762 8 * sizeof(callbackResult));
9763 if (!resultNum) {
9764 goto finish;
9765 }
9766
9767 /* Insert the result into the callback record and dispatch it as if it
9768 * were the reply coming down from user space.
9769 */
9770 _OSKextSetRequestArgument(callbackRecord, kKextRequestArgumentResultKey,
9771 resultNum);
9772
9773 if (predicate->isEqualTo(kKextRequestPredicateRequestResource)) {
9774 /* This removes the pending callback record.
9775 */
9776 OSKext::dispatchResource(callbackRecord);
9777 }
9778
9779 finish:
9780 if (resultNum) resultNum->release();
9781 return;
9782 }
9783
9784 /*********************************************************************
9785 * Assumes sKextLock is held.
9786 *********************************************************************/
9787 /* static */
9788 OSReturn
9789 OSKext::cancelRequest(
9790 OSKextRequestTag requestTag,
9791 void ** contextOut)
9792 {
9793 OSReturn result = kOSKextReturnNoMemory;
9794 OSDictionary * callbackRecord = NULL; // must release
9795 OSData * contextWrapper = NULL; // do not release
9796
9797 IORecursiveLockLock(sKextLock);
9798 result = OSKext::dequeueCallbackForRequestTag(requestTag,
9799 &callbackRecord);
9800 IORecursiveLockUnlock(sKextLock);
9801
9802 if (result == kOSReturnSuccess && contextOut) {
9803 contextWrapper = OSDynamicCast(OSData,
9804 _OSKextGetRequestArgument(callbackRecord,
9805 kKextRequestArgumentContextKey));
9806 *contextOut = _OSKextExtractPointer(contextWrapper);
9807 }
9808
9809 if (callbackRecord) callbackRecord->release();
9810
9811 return result;
9812 }
9813
9814 /*********************************************************************
9815 * Assumes sKextLock is held.
9816 *********************************************************************/
9817 void
9818 OSKext::invokeOrCancelRequestCallbacks(
9819 OSReturn callbackResult,
9820 bool invokeFlag)
9821 {
9822 unsigned int count, i;
9823
9824 count = sRequestCallbackRecords->getCount();
9825 if (!count) {
9826 goto finish;
9827 }
9828
9829 i = count - 1;
9830 do {
9831 OSDictionary * request = OSDynamicCast(OSDictionary,
9832 sRequestCallbackRecords->getObject(i));
9833
9834 if (!request) {
9835 continue;
9836 }
9837 OSData * callbackWrapper = OSDynamicCast(OSData,
9838 _OSKextGetRequestArgument(request,
9839 kKextRequestArgumentCallbackKey));
9840
9841 if (!callbackWrapper) {
9842 sRequestCallbackRecords->removeObject(i);
9843 continue;
9844 }
9845
9846 vm_address_t callbackAddress = (vm_address_t)
9847 _OSKextExtractPointer(callbackWrapper);
9848
9849 if ((kmod_info->address <= callbackAddress) &&
9850 (callbackAddress < (kmod_info->address + kmod_info->size))) {
9851
9852 if (invokeFlag) {
9853 /* This removes the callback record.
9854 */
9855 invokeRequestCallback(request, callbackResult);
9856 } else {
9857 sRequestCallbackRecords->removeObject(i);
9858 }
9859 }
9860 } while (i--);
9861
9862 finish:
9863 return;
9864 }
9865
9866 /*********************************************************************
9867 * Assumes sKextLock is held.
9868 *********************************************************************/
9869 uint32_t
9870 OSKext::countRequestCallbacks(void)
9871 {
9872 uint32_t result = 0;
9873 unsigned int count, i;
9874
9875 count = sRequestCallbackRecords->getCount();
9876 if (!count) {
9877 goto finish;
9878 }
9879
9880 i = count - 1;
9881 do {
9882 OSDictionary * request = OSDynamicCast(OSDictionary,
9883 sRequestCallbackRecords->getObject(i));
9884
9885 if (!request) {
9886 continue;
9887 }
9888 OSData * callbackWrapper = OSDynamicCast(OSData,
9889 _OSKextGetRequestArgument(request,
9890 kKextRequestArgumentCallbackKey));
9891
9892 if (!callbackWrapper) {
9893 continue;
9894 }
9895
9896 vm_address_t callbackAddress = (vm_address_t)
9897 _OSKextExtractPointer(callbackWrapper);
9898
9899 if ((kmod_info->address <= callbackAddress) &&
9900 (callbackAddress < (kmod_info->address + kmod_info->size))) {
9901
9902 result++;
9903 }
9904 } while (i--);
9905
9906 finish:
9907 return result;
9908 }
9909
9910 /*********************************************************************
9911 *********************************************************************/
9912 static OSReturn _OSKextCreateRequest(
9913 const char * predicate,
9914 OSDictionary ** requestP)
9915 {
9916 OSReturn result = kOSKextReturnNoMemory;
9917 OSDictionary * request = NULL; // must release on error
9918
9919 request = OSDictionary::withCapacity(2);
9920 if (!request) {
9921 goto finish;
9922 }
9923 result = _OSDictionarySetCStringValue(request,
9924 kKextRequestPredicateKey, predicate);
9925 if (result != kOSReturnSuccess) {
9926 goto finish;
9927 }
9928 result = kOSReturnSuccess;
9929
9930 finish:
9931 if (result != kOSReturnSuccess) {
9932 if (request) request->release();
9933 } else {
9934 *requestP = request;
9935 }
9936
9937 return result;
9938 }
9939
9940 /*********************************************************************
9941 *********************************************************************/
9942 static OSString * _OSKextGetRequestPredicate(OSDictionary * requestDict)
9943 {
9944 return OSDynamicCast(OSString,
9945 requestDict->getObject(kKextRequestPredicateKey));
9946 }
9947
9948 /*********************************************************************
9949 *********************************************************************/
9950 static OSObject * _OSKextGetRequestArgument(
9951 OSDictionary * requestDict,
9952 const char * argName)
9953 {
9954 OSDictionary * args = OSDynamicCast(OSDictionary,
9955 requestDict->getObject(kKextRequestArgumentsKey));
9956 if (args) {
9957 return args->getObject(argName);
9958 }
9959 return NULL;
9960 }
9961
9962 /*********************************************************************
9963 *********************************************************************/
9964 static bool _OSKextSetRequestArgument(
9965 OSDictionary * requestDict,
9966 const char * argName,
9967 OSObject * value)
9968 {
9969 OSDictionary * args = OSDynamicCast(OSDictionary,
9970 requestDict->getObject(kKextRequestArgumentsKey));
9971 if (!args) {
9972 args = OSDictionary::withCapacity(2);
9973 if (!args) {
9974 goto finish;
9975 }
9976 requestDict->setObject(kKextRequestArgumentsKey, args);
9977 args->release();
9978 }
9979 if (args) {
9980 return args->setObject(argName, value);
9981 }
9982 finish:
9983 return false;
9984 }
9985
9986 /*********************************************************************
9987 *********************************************************************/
9988 static void * _OSKextExtractPointer(OSData * wrapper)
9989 {
9990 void * result = NULL;
9991 const void * resultPtr = NULL;
9992
9993 if (!wrapper) {
9994 goto finish;
9995 }
9996 resultPtr = wrapper->getBytesNoCopy();
9997 result = *(void **)resultPtr;
9998 finish:
9999 return result;
10000 }
10001
10002 /*********************************************************************
10003 *********************************************************************/
10004 static OSReturn _OSDictionarySetCStringValue(
10005 OSDictionary * dict,
10006 const char * cKey,
10007 const char * cValue)
10008 {
10009 OSReturn result = kOSKextReturnNoMemory;
10010 const OSSymbol * key = NULL; // must release
10011 OSString * value = NULL; // must release
10012
10013 key = OSSymbol::withCString(cKey);
10014 value = OSString::withCString(cValue);
10015 if (!key || !value) {
10016 goto finish;
10017 }
10018 if (dict->setObject(key, value)) {
10019 result = kOSReturnSuccess;
10020 }
10021
10022 finish:
10023 if (key) key->release();
10024 if (value) value->release();
10025
10026 return result;
10027 }
10028
10029 /*********************************************************************
10030 *********************************************************************/
10031 static bool _OSArrayContainsCString(
10032 OSArray * array,
10033 const char * cString)
10034 {
10035 bool result = false;
10036 const OSSymbol * symbol = NULL;
10037 uint32_t count, i;
10038
10039 if (!array || !cString) {
10040 goto finish;
10041 }
10042
10043 symbol = OSSymbol::withCStringNoCopy(cString);
10044 if (!symbol) {
10045 goto finish;
10046 }
10047
10048 count = array->getCount();
10049 for (i = 0; i < count; i++) {
10050 OSObject * thisObject = array->getObject(i);
10051 if (symbol->isEqualTo(thisObject)) {
10052 result = true;
10053 goto finish;
10054 }
10055 }
10056
10057 finish:
10058 if (symbol) symbol->release();
10059 return result;
10060 }
10061
10062 /*********************************************************************
10063 * We really only care about boot / system start up related kexts.
10064 * We return true if we're less than REBUILD_MAX_TIME since start up,
10065 * otherwise return false.
10066 *********************************************************************/
10067 bool _OSKextInPrelinkRebuildWindow(void)
10068 {
10069 static bool outside_the_window = false;
10070 AbsoluteTime my_abstime;
10071 UInt64 my_ns;
10072 SInt32 my_secs;
10073
10074 if (outside_the_window) {
10075 return(false);
10076 }
10077 clock_get_uptime(&my_abstime);
10078 absolutetime_to_nanoseconds(my_abstime, &my_ns);
10079 my_secs = (SInt32)(my_ns / NSEC_PER_SEC);
10080 if (my_secs > REBUILD_MAX_TIME) {
10081 outside_the_window = true;
10082 return(false);
10083 }
10084 return(true);
10085 }
10086
10087 /*********************************************************************
10088 *********************************************************************/
10089 bool _OSKextInUnloadedPrelinkedKexts( const OSSymbol * theBundleID )
10090 {
10091 int unLoadedCount, i;
10092 bool result = false;
10093
10094 IORecursiveLockLock(sKextLock);
10095
10096 if (sUnloadedPrelinkedKexts == NULL) {
10097 goto finish;
10098 }
10099 unLoadedCount = sUnloadedPrelinkedKexts->getCount();
10100 if (unLoadedCount == 0) {
10101 goto finish;
10102 }
10103
10104 for (i = 0; i < unLoadedCount; i++) {
10105 const OSSymbol * myBundleID; // do not release
10106
10107 myBundleID = OSDynamicCast(OSSymbol, sUnloadedPrelinkedKexts->getObject(i));
10108 if (!myBundleID) continue;
10109 if (theBundleID->isEqualTo(myBundleID->getCStringNoCopy())) {
10110 result = true;
10111 break;
10112 }
10113 }
10114 finish:
10115 IORecursiveLockUnlock(sKextLock);
10116 return(result);
10117 }
10118
10119 #if PRAGMA_MARK
10120 #pragma mark Personalities (IOKit Drivers)
10121 #endif
10122 /*********************************************************************
10123 *********************************************************************/
10124 /* static */
10125 OSArray *
10126 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag)
10127 {
10128 OSArray * result = NULL; // returned
10129 OSCollectionIterator * kextIterator = NULL; // must release
10130 OSArray * personalities = NULL; // must release
10131 OSCollectionIterator * personalitiesIterator = NULL; // must release
10132
10133 OSString * kextID = NULL; // do not release
10134 OSKext * theKext = NULL; // do not release
10135
10136 IORecursiveLockLock(sKextLock);
10137
10138 /* Let's conservatively guess that any given kext has around 3
10139 * personalities for now.
10140 */
10141 result = OSArray::withCapacity(sKextsByID->getCount() * 3);
10142 if (!result) {
10143 goto finish;
10144 }
10145
10146 kextIterator = OSCollectionIterator::withCollection(sKextsByID);
10147 if (!kextIterator) {
10148 goto finish;
10149 }
10150
10151 while ((kextID = OSDynamicCast(OSString, kextIterator->getNextObject()))) {
10152 if (personalitiesIterator) {
10153 personalitiesIterator->release();
10154 personalitiesIterator = NULL;
10155 }
10156 if (personalities) {
10157 personalities->release();
10158 personalities = NULL;
10159 }
10160
10161 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextID));
10162 if (!sSafeBoot || !filterSafeBootFlag || theKext->isLoadableInSafeBoot()) {
10163 personalities = theKext->copyPersonalitiesArray();
10164 if (!personalities) {
10165 continue;
10166 }
10167 result->merge(personalities);
10168 } else {
10169 // xxx - check for better place to put this log msg
10170 OSKextLog(theKext,
10171 kOSKextLogWarningLevel |
10172 kOSKextLogLoadFlag,
10173 "Kext %s is not loadable during safe boot; "
10174 "omitting its personalities.",
10175 theKext->getIdentifierCString());
10176 }
10177
10178 }
10179
10180 finish:
10181 IORecursiveLockUnlock(sKextLock);
10182
10183 if (kextIterator) kextIterator->release();
10184 if (personalitiesIterator) personalitiesIterator->release();
10185 if (personalities) personalities->release();
10186
10187 return result;
10188 }
10189
10190 /*********************************************************************
10191 *********************************************************************/
10192 /* static */
10193 void
10194 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching)
10195 {
10196 int numPersonalities = 0;
10197
10198 OSKextLog(/* kext */ NULL,
10199 kOSKextLogStepLevel |
10200 kOSKextLogLoadFlag,
10201 "Sending all eligible registered kexts' personalities "
10202 "to the IOCatalogue %s.",
10203 startMatching ? "and starting matching" : "but not starting matching");
10204
10205 OSArray * personalities = OSKext::copyAllKextPersonalities(
10206 /* filterSafeBootFlag */ true);
10207
10208 if (personalities) {
10209 gIOCatalogue->addDrivers(personalities, startMatching);
10210 numPersonalities = personalities->getCount();
10211 personalities->release();
10212 }
10213
10214 OSKextLog(/* kext */ NULL,
10215 kOSKextLogStepLevel |
10216 kOSKextLogLoadFlag,
10217 "%d kext personalit%s sent to the IOCatalogue; %s.",
10218 numPersonalities, numPersonalities > 0 ? "ies" : "y",
10219 startMatching ? "matching started" : "matching not started");
10220 return;
10221 }
10222
10223 /*********************************************************************
10224 * Do not make a deep copy, just convert the IOKitPersonalities dict
10225 * to an array for sending to the IOCatalogue.
10226 *********************************************************************/
10227 OSArray *
10228 OSKext::copyPersonalitiesArray(void)
10229 {
10230 OSArray * result = NULL;
10231 OSDictionary * personalities = NULL; // do not release
10232 OSCollectionIterator * personalitiesIterator = NULL; // must release
10233
10234 OSString * personalityName = NULL; // do not release
10235 OSString * personalityBundleIdentifier = NULL; // do not release
10236
10237 personalities = OSDynamicCast(OSDictionary,
10238 getPropertyForHostArch(kIOKitPersonalitiesKey));
10239 if (!personalities) {
10240 goto finish;
10241 }
10242
10243 result = OSArray::withCapacity(personalities->getCount());
10244 if (!result) {
10245 goto finish;
10246 }
10247
10248 personalitiesIterator =
10249 OSCollectionIterator::withCollection(personalities);
10250 if (!personalitiesIterator) {
10251 goto finish;
10252 }
10253 while ((personalityName = OSDynamicCast(OSString,
10254 personalitiesIterator->getNextObject()))) {
10255
10256 OSDictionary * personality = OSDynamicCast(OSDictionary,
10257 personalities->getObject(personalityName));
10258
10259 /******
10260 * If the personality doesn't have a CFBundleIdentifier, or if it
10261 * differs from the kext's, insert the kext's ID so we can find it.
10262 * The publisher ID is used to remove personalities from bundles
10263 * correctly.
10264 */
10265 personalityBundleIdentifier = OSDynamicCast(OSString,
10266 personality->getObject(kCFBundleIdentifierKey));
10267
10268 if (!personalityBundleIdentifier) {
10269 personality->setObject(kCFBundleIdentifierKey, bundleID);
10270 } else if (!personalityBundleIdentifier->isEqualTo(bundleID)) {
10271 personality->setObject(kIOPersonalityPublisherKey, bundleID);
10272 }
10273
10274 result->setObject(personality);
10275 }
10276
10277 finish:
10278 if (personalitiesIterator) personalitiesIterator->release();
10279
10280 return result;
10281 }
10282
10283 /*********************************************************************
10284 Might want to change this to a bool return?
10285 *********************************************************************/
10286 OSReturn
10287 OSKext::sendPersonalitiesToCatalog(
10288 bool startMatching,
10289 OSArray * personalityNames)
10290 {
10291 OSReturn result = kOSReturnSuccess;
10292 OSArray * personalitiesToSend = NULL; // must release
10293 OSDictionary * kextPersonalities = NULL; // do not release
10294 int count, i;
10295
10296 if (!sLoadEnabled) {
10297 OSKextLog(this,
10298 kOSKextLogErrorLevel |
10299 kOSKextLogLoadFlag,
10300 "Kext loading is disabled (attempt to start matching for kext %s).",
10301 getIdentifierCString());
10302 result = kOSKextReturnDisabled;
10303 goto finish;
10304 }
10305
10306 if (sSafeBoot && !isLoadableInSafeBoot()) {
10307 OSKextLog(this,
10308 kOSKextLogErrorLevel |
10309 kOSKextLogLoadFlag,
10310 "Kext %s is not loadable during safe boot; "
10311 "not sending personalities to the IOCatalogue.",
10312 getIdentifierCString());
10313 result = kOSKextReturnNotLoadable;
10314 goto finish;
10315 }
10316
10317 if (!personalityNames || !personalityNames->getCount()) {
10318 personalitiesToSend = copyPersonalitiesArray();
10319 } else {
10320 kextPersonalities = OSDynamicCast(OSDictionary,
10321 getPropertyForHostArch(kIOKitPersonalitiesKey));
10322 if (!kextPersonalities || !kextPersonalities->getCount()) {
10323 // not an error
10324 goto finish;
10325 }
10326 personalitiesToSend = OSArray::withCapacity(0);
10327 if (!personalitiesToSend) {
10328 result = kOSKextReturnNoMemory;
10329 goto finish;
10330 }
10331 count = personalityNames->getCount();
10332 for (i = 0; i < count; i++) {
10333 OSString * name = OSDynamicCast(OSString,
10334 personalityNames->getObject(i));
10335 if (!name) {
10336 continue;
10337 }
10338 OSDictionary * personality = OSDynamicCast(OSDictionary,
10339 kextPersonalities->getObject(name));
10340 if (personality) {
10341 personalitiesToSend->setObject(personality);
10342 }
10343 }
10344 }
10345 if (personalitiesToSend) {
10346 unsigned numPersonalities = personalitiesToSend->getCount();
10347 OSKextLog(this,
10348 kOSKextLogStepLevel |
10349 kOSKextLogLoadFlag,
10350 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
10351 getIdentifierCString(),
10352 numPersonalities,
10353 numPersonalities > 1 ? "ies" : "y",
10354 startMatching ? " and starting matching" : " but not starting matching");
10355 gIOCatalogue->addDrivers(personalitiesToSend, startMatching);
10356 }
10357 finish:
10358 if (personalitiesToSend) {
10359 personalitiesToSend->release();
10360 }
10361 return result;
10362 }
10363
10364 /*********************************************************************
10365 * xxx - We should allow removing the kext's declared personalities,
10366 * xxx - even with other bundle identifiers.
10367 *********************************************************************/
10368 void
10369 OSKext::removePersonalitiesFromCatalog(void)
10370 {
10371 OSDictionary * personality = NULL; // do not release
10372
10373 personality = OSDictionary::withCapacity(1);
10374 if (!personality) {
10375 goto finish;
10376 }
10377 personality->setObject(kCFBundleIdentifierKey, getIdentifier());
10378
10379 OSKextLog(this,
10380 kOSKextLogStepLevel |
10381 kOSKextLogLoadFlag,
10382 "Kext %s removing all personalities naming it from the IOCatalogue.",
10383 getIdentifierCString());
10384
10385 /* Have the IOCatalog remove all personalities matching this kext's
10386 * bundle ID and trigger matching anew.
10387 */
10388 gIOCatalogue->removeDrivers(personality, /* startMatching */ true);
10389
10390 finish:
10391 if (personality) personality->release();
10392
10393 return;
10394 }
10395
10396
10397 #if PRAGMA_MARK
10398 #pragma mark Logging
10399 #endif
10400 /*********************************************************************
10401 * Do not call any function that takes sKextLock here!
10402 *********************************************************************/
10403 /* static */
10404 OSKextLogSpec
10405 OSKext::setUserSpaceLogFilter(
10406 OSKextLogSpec newUserLogFilter,
10407 bool captureFlag)
10408 {
10409 OSKextLogSpec result;
10410 bool allocError = false;
10411
10412 /* Do not call any function that takes sKextLoggingLock during
10413 * this critical block. That means do logging after.
10414 */
10415 IOLockLock(sKextLoggingLock);
10416
10417 result = sUserSpaceKextLogFilter;
10418 sUserSpaceKextLogFilter = newUserLogFilter;
10419
10420 if (newUserLogFilter && captureFlag &&
10421 !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
10422
10423 // xxx - do some measurements for a good initial capacity?
10424 sUserSpaceLogSpecArray = OSArray::withCapacity(0);
10425 sUserSpaceLogMessageArray = OSArray::withCapacity(0);
10426
10427 if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
10428 OSSafeReleaseNULL(sUserSpaceLogSpecArray);
10429 OSSafeReleaseNULL(sUserSpaceLogMessageArray);
10430 allocError = true;
10431 }
10432 }
10433
10434 IOLockUnlock(sKextLoggingLock);
10435
10436 /* If the config flag itself is changing, log the state change
10437 * going both ways, before setting up the user-space log arrays,
10438 * so that this is only logged in the kernel.
10439 */
10440 if (result != newUserLogFilter) {
10441 OSKextLog(/* kext */ NULL,
10442 kOSKextLogDebugLevel |
10443 kOSKextLogGeneralFlag,
10444 "User-space log flags changed from 0x%x to 0x%x.",
10445 result, newUserLogFilter);
10446 }
10447 if (allocError) {
10448 OSKextLog(/* kext */ NULL,
10449 kOSKextLogErrorLevel |
10450 kOSKextLogGeneralFlag,
10451 "Failed to allocate user-space log message arrays.");
10452 }
10453
10454 return result;
10455 }
10456
10457 /*********************************************************************
10458 * Do not call any function that takes sKextLock here!
10459 *********************************************************************/
10460 /* static */
10461 OSArray *
10462 OSKext::clearUserSpaceLogFilter(void)
10463 {
10464 OSArray * result = NULL;
10465 OSKextLogSpec oldLogFilter;
10466 OSKextLogSpec newLogFilter = kOSKextLogSilentFilter;
10467
10468 /* Do not call any function that takes sKextLoggingLock during
10469 * this critical block. That means do logging after.
10470 */
10471 IOLockLock(sKextLoggingLock);
10472
10473 result = OSArray::withCapacity(2);
10474 if (result) {
10475 result->setObject(sUserSpaceLogSpecArray);
10476 result->setObject(sUserSpaceLogMessageArray);
10477 }
10478 OSSafeReleaseNULL(sUserSpaceLogSpecArray);
10479 OSSafeReleaseNULL(sUserSpaceLogMessageArray);
10480
10481 oldLogFilter = sUserSpaceKextLogFilter;
10482 sUserSpaceKextLogFilter = newLogFilter;
10483
10484 IOLockUnlock(sKextLoggingLock);
10485
10486 /* If the config flag itself is changing, log the state change
10487 * going both ways, after tearing down the user-space log
10488 * arrays, so this is only logged within the kernel.
10489 */
10490 if (oldLogFilter != newLogFilter) {
10491 OSKextLog(/* kext */ NULL,
10492 kOSKextLogDebugLevel |
10493 kOSKextLogGeneralFlag,
10494 "User-space log flags changed from 0x%x to 0x%x.",
10495 oldLogFilter, newLogFilter);
10496 }
10497
10498 return result;
10499 }
10500
10501
10502 /*********************************************************************
10503 * Do not call any function that takes sKextLock here!
10504 *********************************************************************/
10505 /* static */
10506 OSKextLogSpec
10507 OSKext::getUserSpaceLogFilter(void)
10508 {
10509 OSKextLogSpec result;
10510
10511 IOLockLock(sKextLoggingLock);
10512 result = sUserSpaceKextLogFilter;
10513 IOLockUnlock(sKextLoggingLock);
10514
10515 return result;
10516 }
10517
10518 /*********************************************************************
10519 * This function is called by OSMetaClass during kernel C++ setup.
10520 * Be careful what you access here; assume only OSKext::initialize()
10521 * has been called.
10522 *
10523 * Do not call any function that takes sKextLock here!
10524 *********************************************************************/
10525 #define VTRESET "\033[0m"
10526
10527 #define VTBOLD "\033[1m"
10528 #define VTUNDER "\033[4m"
10529
10530 #define VTRED "\033[31m"
10531 #define VTGREEN "\033[32m"
10532 #define VTYELLOW "\033[33m"
10533 #define VTBLUE "\033[34m"
10534 #define VTMAGENTA "\033[35m"
10535 #define VTCYAN "\033[36m"
10536
10537 inline const char * colorForFlags(OSKextLogSpec flags)
10538 {
10539 OSKextLogSpec logLevel = flags & kOSKextLogLevelMask;
10540
10541 switch (logLevel) {
10542 case kOSKextLogErrorLevel:
10543 return VTRED VTBOLD;
10544 case kOSKextLogWarningLevel:
10545 return VTRED;
10546 case kOSKextLogBasicLevel:
10547 return VTYELLOW VTUNDER;
10548 case kOSKextLogProgressLevel:
10549 return VTYELLOW;
10550 case kOSKextLogStepLevel:
10551 return VTGREEN;
10552 case kOSKextLogDetailLevel:
10553 return VTCYAN;
10554 case kOSKextLogDebugLevel:
10555 return VTMAGENTA;
10556 default:
10557 return ""; // white
10558 }
10559 }
10560
10561 inline bool logSpecMatch(
10562 OSKextLogSpec msgLogSpec,
10563 OSKextLogSpec logFilter)
10564 {
10565 OSKextLogSpec filterKextGlobal = logFilter & kOSKextLogKextOrGlobalMask;
10566 OSKextLogSpec filterLevel = logFilter & kOSKextLogLevelMask;
10567 OSKextLogSpec filterFlags = logFilter & kOSKextLogFlagsMask;
10568
10569 OSKextLogSpec msgKextGlobal = msgLogSpec & kOSKextLogKextOrGlobalMask;
10570 OSKextLogSpec msgLevel = msgLogSpec & kOSKextLogLevelMask;
10571 OSKextLogSpec msgFlags = msgLogSpec & kOSKextLogFlagsMask;
10572
10573 /* Explicit messages always get logged.
10574 */
10575 if (msgLevel == kOSKextLogExplicitLevel) {
10576 return true;
10577 }
10578
10579 /* Warnings and errors are logged regardless of the flags.
10580 */
10581 if (msgLevel <= kOSKextLogBasicLevel && (msgLevel <= filterLevel)) {
10582 return true;
10583 }
10584
10585 /* A verbose message that isn't for a logging-enabled kext and isn't global
10586 * does *not* get logged.
10587 */
10588 if (!msgKextGlobal && !filterKextGlobal) {
10589 return false;
10590 }
10591
10592 /* Warnings and errors are logged regardless of the flags.
10593 * All other messages must fit the flags and
10594 * have a level at or below the filter.
10595 *
10596 */
10597 if ((msgFlags & filterFlags) && (msgLevel <= filterLevel)) {
10598 return true;
10599 }
10600 return false;
10601 }
10602
10603 extern "C" {
10604
10605 void
10606 OSKextLog(
10607 OSKext * aKext,
10608 OSKextLogSpec msgLogSpec,
10609 const char * format, ...)
10610 {
10611 va_list argList;
10612
10613 va_start(argList, format);
10614 OSKextVLog(aKext, msgLogSpec, format, argList);
10615 va_end(argList);
10616 }
10617
10618 void
10619 OSKextVLog(
10620 OSKext * aKext,
10621 OSKextLogSpec msgLogSpec,
10622 const char * format,
10623 va_list srcArgList)
10624 {
10625 extern int disableConsoleOutput;
10626
10627 bool logForKernel = false;
10628 bool logForUser = false;
10629 va_list argList;
10630 char stackBuffer[120];
10631 uint32_t length = 0;
10632 char * allocBuffer = NULL; // must kfree
10633 OSNumber * logSpecNum = NULL; // must release
10634 OSString * logString = NULL; // must release
10635 char * buffer = stackBuffer; // do not free
10636
10637 IOLockLock(sKextLoggingLock);
10638
10639 /* Set the kext/global bit in the message spec if we have no
10640 * kext or if the kext requests logging.
10641 */
10642 if (!aKext || aKext->flags.loggingEnabled) {
10643 msgLogSpec = msgLogSpec | kOSKextLogKextOrGlobalMask;
10644 }
10645
10646 logForKernel = logSpecMatch(msgLogSpec, sKernelLogFilter);
10647 if (sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
10648 logForUser = logSpecMatch(msgLogSpec, sUserSpaceKextLogFilter);
10649 }
10650
10651 if (! (logForKernel || logForUser) ) {
10652 goto finish;
10653 }
10654
10655 /* No goto from here until past va_end()!
10656 */
10657 va_copy(argList, srcArgList);
10658 length = vsnprintf(stackBuffer, sizeof(stackBuffer), format, argList);
10659 va_end(argList);
10660
10661 if (length + 1 >= sizeof(stackBuffer)) {
10662 allocBuffer = (char *)kalloc_tag((length + 1) * sizeof(char), VM_KERN_MEMORY_OSKEXT);
10663 if (!allocBuffer) {
10664 goto finish;
10665 }
10666
10667 /* No goto from here until past va_end()!
10668 */
10669 va_copy(argList, srcArgList);
10670 vsnprintf(allocBuffer, length + 1, format, argList);
10671 va_end(argList);
10672
10673 buffer = allocBuffer;
10674 }
10675
10676 /* If user space wants the log message, queue it up.
10677 */
10678 if (logForUser && sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
10679 logSpecNum = OSNumber::withNumber(msgLogSpec, 8 * sizeof(msgLogSpec));
10680 logString = OSString::withCString(buffer);
10681 if (logSpecNum && logString) {
10682 sUserSpaceLogSpecArray->setObject(logSpecNum);
10683 sUserSpaceLogMessageArray->setObject(logString);
10684 }
10685 }
10686
10687 /* Always log messages from the kernel according to the kernel's
10688 * log flags.
10689 */
10690 if (logForKernel) {
10691
10692 /* If we are in console mode and have a custom log filter,
10693 * colorize the log message.
10694 */
10695 if (!disableConsoleOutput && sBootArgLogFilterFound) {
10696 const char * color = ""; // do not free
10697 color = colorForFlags(msgLogSpec);
10698 printf("%s%s%s\n", colorForFlags(msgLogSpec),
10699 buffer, color[0] ? VTRESET : "");
10700 } else {
10701 printf("%s\n", buffer);
10702 }
10703 }
10704
10705 finish:
10706 IOLockUnlock(sKextLoggingLock);
10707
10708 if (allocBuffer) {
10709 kfree(allocBuffer, (length + 1) * sizeof(char));
10710 }
10711 OSSafeReleaseNULL(logString);
10712 OSSafeReleaseNULL(logSpecNum);
10713 return;
10714 }
10715
10716 #if KASLR_IOREG_DEBUG
10717
10718 #define IOLOG_INDENT( the_indention ) \
10719 { \
10720 int i; \
10721 for ( i = 0; i < (the_indention); i++ ) { \
10722 IOLog(" "); \
10723 } \
10724 }
10725
10726 extern vm_offset_t vm_kernel_stext;
10727 extern vm_offset_t vm_kernel_etext;
10728 extern mach_vm_offset_t kext_alloc_base;
10729 extern mach_vm_offset_t kext_alloc_max;
10730
10731 bool ScanForAddrInObject(OSObject * theObject,
10732 int indent );
10733
10734 bool ScanForAddrInObject(OSObject * theObject,
10735 int indent)
10736 {
10737 const OSMetaClass * myTypeID;
10738 OSCollectionIterator * myIter;
10739 OSSymbol * myKey;
10740 OSObject * myValue;
10741 bool myResult = false;
10742
10743 if ( theObject == NULL ) {
10744 IOLog("%s: theObject is NULL \n",
10745 __FUNCTION__);
10746 return myResult;
10747 }
10748
10749 myTypeID = OSTypeIDInst(theObject);
10750
10751 if ( myTypeID == OSTypeID(OSDictionary) ) {
10752 OSDictionary * myDictionary;
10753
10754 myDictionary = OSDynamicCast(OSDictionary, theObject);
10755 myIter = OSCollectionIterator::withCollection( myDictionary );
10756 if ( myIter == NULL )
10757 return myResult;
10758 myIter->reset();
10759
10760 while ( (myKey = OSDynamicCast(OSSymbol, myIter->getNextObject())) ) {
10761 bool myTempResult;
10762
10763 myValue = myDictionary->getObject(myKey);
10764 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
10765 if (myTempResult) {
10766 // if we ever get a true result return true
10767 myResult = true;
10768 IOLOG_INDENT(indent);
10769 IOLog("OSDictionary key \"%s\" \n", myKey->getCStringNoCopy());
10770 }
10771 }
10772 myIter->release();
10773 }
10774 else if ( myTypeID == OSTypeID(OSArray) ) {
10775 OSArray * myArray;
10776
10777 myArray = OSDynamicCast(OSArray, theObject);
10778 myIter = OSCollectionIterator::withCollection(myArray);
10779 if ( myIter == NULL )
10780 return myResult;
10781 myIter->reset();
10782
10783 while ( (myValue = myIter->getNextObject()) ) {
10784 bool myTempResult;
10785 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
10786 if (myTempResult) {
10787 // if we ever get a true result return true
10788 myResult = true;
10789 IOLOG_INDENT(indent);
10790 IOLog("OSArray: \n");
10791 }
10792 }
10793 myIter->release();
10794 }
10795 else if ( myTypeID == OSTypeID(OSString) || myTypeID == OSTypeID(OSSymbol) ) {
10796
10797 // should we look for addresses in strings?
10798 }
10799 else if ( myTypeID == OSTypeID(OSData) ) {
10800
10801 void * * myPtrPtr;
10802 unsigned int myLen;
10803 OSData * myDataObj;
10804
10805 myDataObj = OSDynamicCast(OSData, theObject);
10806 myPtrPtr = (void * *) myDataObj->getBytesNoCopy();
10807 myLen = myDataObj->getLength();
10808
10809 if (myPtrPtr && myLen && myLen > 7) {
10810 int i;
10811 int myPtrCount = (myLen / sizeof(void *));
10812
10813 for (i = 0; i < myPtrCount; i++) {
10814 UInt64 numberValue = (UInt64) *(myPtrPtr);
10815
10816 if ( kext_alloc_max != 0 &&
10817 numberValue >= kext_alloc_base &&
10818 numberValue < kext_alloc_max ) {
10819
10820 OSKext * myKext = NULL; // must release (looked up)
10821 // IOLog("found OSData %p in kext map %p to %p \n",
10822 // *(myPtrPtr),
10823 // (void *) kext_alloc_base,
10824 // (void *) kext_alloc_max);
10825
10826 myKext = OSKext::lookupKextWithAddress( (vm_address_t) *(myPtrPtr) );
10827 if (myKext) {
10828 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
10829 *(myPtrPtr),
10830 myKext->getIdentifierCString());
10831 myKext->release();
10832 }
10833 myResult = true;
10834 }
10835 if ( vm_kernel_etext != 0 &&
10836 numberValue >= vm_kernel_stext &&
10837 numberValue < vm_kernel_etext ) {
10838 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
10839 *(myPtrPtr),
10840 (void *) vm_kernel_stext,
10841 (void *) vm_kernel_etext);
10842 myResult = true;
10843 }
10844 myPtrPtr++;
10845 }
10846 }
10847 }
10848 else if ( myTypeID == OSTypeID(OSBoolean) ) {
10849
10850 // do nothing here...
10851 }
10852 else if ( myTypeID == OSTypeID(OSNumber) ) {
10853
10854 OSNumber * number = OSDynamicCast(OSNumber, theObject);
10855
10856 UInt64 numberValue = number->unsigned64BitValue();
10857
10858 if ( kext_alloc_max != 0 &&
10859 numberValue >= kext_alloc_base &&
10860 numberValue < kext_alloc_max ) {
10861
10862 OSKext * myKext = NULL; // must release (looked up)
10863 IOLog("found OSNumber in kext map %p to %p \n",
10864 (void *) kext_alloc_base,
10865 (void *) kext_alloc_max);
10866 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
10867
10868 myKext = OSKext::lookupKextWithAddress( (vm_address_t) numberValue );
10869 if (myKext) {
10870 IOLog("found in kext \"%s\" \n",
10871 myKext->getIdentifierCString());
10872 myKext->release();
10873 }
10874
10875 myResult = true;
10876 }
10877 if ( vm_kernel_etext != 0 &&
10878 numberValue >= vm_kernel_stext &&
10879 numberValue < vm_kernel_etext ) {
10880 IOLog("found OSNumber in kernel text segment %p to %p \n",
10881 (void *) vm_kernel_stext,
10882 (void *) vm_kernel_etext);
10883 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
10884 myResult = true;
10885 }
10886 }
10887 #if 0
10888 else {
10889 const OSMetaClass* myMetaClass = NULL;
10890
10891 myMetaClass = theObject->getMetaClass();
10892 if ( myMetaClass ) {
10893 IOLog("class %s \n", myMetaClass->getClassName() );
10894 }
10895 else {
10896 IOLog("Unknown object \n" );
10897 }
10898 }
10899 #endif
10900
10901 return myResult;
10902 }
10903 #endif // KASLR_KEXT_DEBUG
10904
10905 }; /* extern "C" */
10906
10907 #if PRAGMA_MARK
10908 #pragma mark Backtrace Dump & kmod_get_info() support
10909 #endif
10910 /*********************************************************************
10911 * This function must be safe to call in panic context.
10912 *********************************************************************/
10913 /* static */
10914 void
10915 OSKext::printKextsInBacktrace(
10916 vm_offset_t * addr,
10917 unsigned int cnt,
10918 int (* printf_func)(const char *fmt, ...),
10919 uint32_t flags)
10920 {
10921 addr64_t summary_page = 0;
10922 addr64_t last_summary_page = 0;
10923 bool found_kmod = false;
10924 u_int i = 0;
10925
10926 if (kPrintKextsLock & flags) {
10927 if (!sKextSummariesLock) return;
10928 IOLockLock(sKextSummariesLock);
10929 }
10930
10931 if (!gLoadedKextSummaries) {
10932 (*printf_func)(" can't perform kext scan: no kext summary");
10933 goto finish;
10934 }
10935
10936 summary_page = trunc_page((addr64_t)(uintptr_t)gLoadedKextSummaries);
10937 last_summary_page = round_page(summary_page + sLoadedKextSummariesAllocSize);
10938 for (; summary_page < last_summary_page; summary_page += PAGE_SIZE) {
10939 if (pmap_find_phys(kernel_pmap, summary_page) == 0) {
10940 (*printf_func)(" can't perform kext scan: "
10941 "missing kext summary page %p", summary_page);
10942 goto finish;
10943 }
10944 }
10945
10946 for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
10947 OSKextLoadedKextSummary * summary;
10948
10949 summary = gLoadedKextSummaries->summaries + i;
10950 if (!summary->address) {
10951 continue;
10952 }
10953
10954 if (!summaryIsInBacktrace(summary, addr, cnt)) {
10955 continue;
10956 }
10957
10958 if (!found_kmod) {
10959 if (!(kPrintKextsTerse & flags)) {
10960 (*printf_func)(" Kernel Extensions in backtrace:\n");
10961 }
10962 found_kmod = true;
10963 }
10964
10965 printSummary(summary, printf_func, flags);
10966 }
10967
10968 finish:
10969 if (kPrintKextsLock & flags) {
10970 IOLockUnlock(sKextSummariesLock);
10971 }
10972
10973 return;
10974 }
10975
10976 /*********************************************************************
10977 * This function must be safe to call in panic context.
10978 *********************************************************************/
10979 /* static */
10980 boolean_t
10981 OSKext::summaryIsInBacktrace(
10982 OSKextLoadedKextSummary * summary,
10983 vm_offset_t * addr,
10984 unsigned int cnt)
10985 {
10986 u_int i = 0;
10987
10988 for (i = 0; i < cnt; i++) {
10989 vm_offset_t kscan_addr = addr[i];
10990 if ((kscan_addr >= summary->address) &&
10991 (kscan_addr < (summary->address + summary->size)))
10992 {
10993 return TRUE;
10994 }
10995 }
10996
10997 return FALSE;
10998 }
10999
11000 /*
11001 * Get the kext summary object for the kext where 'addr' lies. Must be called with
11002 * sKextSummariesLock held.
11003 */
11004 OSKextLoadedKextSummary *
11005 OSKext::summaryForAddress(const uintptr_t addr)
11006 {
11007 for (unsigned i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
11008
11009 OSKextLoadedKextSummary *summary = &gLoadedKextSummaries->summaries[i];
11010 if (!summary->address) {
11011 continue;
11012 }
11013
11014 #if VM_MAPPED_KEXTS
11015 /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
11016 * support split kexts, but we also may unmap the kexts, which can
11017 * race with the above codepath (see OSKext::unload). As such,
11018 * use a simple range lookup if we are using VM_MAPPED_KEXTS.
11019 */
11020 if ((addr >= summary->address) && (addr < (summary->address + summary->size))) {
11021 return summary;
11022 }
11023 #else
11024 kernel_mach_header_t *mh = (kernel_mach_header_t *)summary->address;
11025 kernel_segment_command_t *seg;
11026
11027 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
11028 if ((addr >= seg->vmaddr) && (addr < (seg->vmaddr + seg->vmsize))) {
11029 return summary;
11030 }
11031 }
11032 #endif
11033 }
11034
11035 /* addr did not map to any kext */
11036 return NULL;
11037 }
11038
11039 /* static */
11040 void *
11041 OSKext::kextForAddress(const void *addr)
11042 {
11043 void *image = NULL;
11044
11045 if (((vm_offset_t)(uintptr_t)addr >= vm_kernel_stext) &&
11046 ((vm_offset_t)(uintptr_t)addr < vm_kernel_etext)) {
11047 return (void *)&_mh_execute_header;
11048 }
11049
11050 if (!sKextSummariesLock) {
11051 return NULL;
11052 }
11053 IOLockLock(sKextSummariesLock);
11054 OSKextLoadedKextSummary *summary = OSKext::summaryForAddress((uintptr_t)addr);
11055 if (summary) {
11056 image = (void *)summary->address;
11057 }
11058 IOLockUnlock(sKextSummariesLock);
11059
11060 return image;
11061 }
11062
11063 /*********************************************************************
11064 * scan list of loaded kext summaries looking for a load address match and if
11065 * found return the UUID C string. If not found then set empty string.
11066 *********************************************************************/
11067 static void findSummaryUUID(
11068 uint32_t tag_ID,
11069 uuid_string_t uuid);
11070
11071 static void findSummaryUUID(
11072 uint32_t tag_ID,
11073 uuid_string_t uuid)
11074 {
11075 u_int i;
11076
11077 uuid[0] = 0x00; // default to no UUID
11078
11079 for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
11080 OSKextLoadedKextSummary * summary;
11081
11082 summary = gLoadedKextSummaries->summaries + i;
11083
11084 if (summary->loadTag == tag_ID) {
11085 (void) uuid_unparse(summary->uuid, uuid);
11086 break;
11087 }
11088 }
11089 return;
11090 }
11091
11092 /*********************************************************************
11093 * This function must be safe to call in panic context.
11094 *********************************************************************/
11095 void OSKext::printSummary(
11096 OSKextLoadedKextSummary * summary,
11097 int (* printf_func)(const char *fmt, ...),
11098 uint32_t flags)
11099 {
11100 kmod_reference_t * kmod_ref = NULL;
11101 uuid_string_t uuid;
11102 char version[kOSKextVersionMaxLength];
11103 uint64_t tmpAddr;
11104
11105 if (!OSKextVersionGetString(summary->version, version, sizeof(version))) {
11106 strlcpy(version, "unknown version", sizeof(version));
11107 }
11108 (void) uuid_unparse(summary->uuid, uuid);
11109
11110 if (kPrintKextsUnslide & flags) {
11111 tmpAddr = VM_KERNEL_UNSLIDE(summary->address);
11112 }
11113 else {
11114 tmpAddr = summary->address;
11115 }
11116 (*printf_func)("%s%s(%s)[%s]@0x%llx->0x%llx\n",
11117 (kPrintKextsTerse & flags) ? "" : " ",
11118 summary->name, version, uuid,
11119 tmpAddr, tmpAddr + summary->size - 1);
11120
11121 if (kPrintKextsTerse & flags) return;
11122
11123 /* print dependency info */
11124 for (kmod_ref = (kmod_reference_t *) summary->reference_list;
11125 kmod_ref;
11126 kmod_ref = kmod_ref->next) {
11127 kmod_info_t * rinfo;
11128
11129 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_ref)) == 0) {
11130 (*printf_func)(" kmod dependency scan stopped "
11131 "due to missing dependency page: %p\n",
11132 (kPrintKextsUnslide & flags) ? (void *)VM_KERNEL_UNSLIDE(kmod_ref) : kmod_ref);
11133 break;
11134 }
11135 rinfo = kmod_ref->info;
11136
11137 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
11138 (*printf_func)(" kmod dependency scan stopped "
11139 "due to missing kmod page: %p\n",
11140 (kPrintKextsUnslide & flags) ? (void *)VM_KERNEL_UNSLIDE(rinfo) : rinfo);
11141 break;
11142 }
11143
11144 if (!rinfo->address) {
11145 continue; // skip fake entries for built-ins
11146 }
11147
11148 /* locate UUID in gLoadedKextSummaries */
11149 findSummaryUUID(rinfo->id, uuid);
11150
11151 if (kPrintKextsUnslide & flags) {
11152 tmpAddr = VM_KERNEL_UNSLIDE(rinfo->address);
11153 }
11154 else {
11155 tmpAddr = rinfo->address;
11156 }
11157 (*printf_func)(" dependency: %s(%s)[%s]@%p\n",
11158 rinfo->name, rinfo->version, uuid, tmpAddr);
11159 }
11160 return;
11161 }
11162
11163
11164 /*******************************************************************************
11165 * substitute() looks at an input string (a pointer within a larger buffer)
11166 * for a match to a substring, and on match it writes the marker & substitution
11167 * character to an output string, updating the scan (from) and
11168 * output (to) indexes as appropriate.
11169 *******************************************************************************/
11170 static int substitute(
11171 const char * scan_string,
11172 char * string_out,
11173 uint32_t * to_index,
11174 uint32_t * from_index,
11175 const char * substring,
11176 char marker,
11177 char substitution);
11178
11179 /* string_out must be at least KMOD_MAX_NAME bytes.
11180 */
11181 static int
11182 substitute(
11183 const char * scan_string,
11184 char * string_out,
11185 uint32_t * to_index,
11186 uint32_t * from_index,
11187 const char * substring,
11188 char marker,
11189 char substitution)
11190 {
11191 uint32_t substring_length = strnlen(substring, KMOD_MAX_NAME - 1);
11192
11193 /* On a substring match, append the marker (if there is one) and then
11194 * the substitution character, updating the output (to) index accordingly.
11195 * Then update the input (from) length by the length of the substring
11196 * that got replaced.
11197 */
11198 if (!strncmp(scan_string, substring, substring_length)) {
11199 if (marker) {
11200 string_out[(*to_index)++] = marker;
11201 }
11202 string_out[(*to_index)++] = substitution;
11203 (*from_index) += substring_length;
11204 return 1;
11205 }
11206 return 0;
11207 }
11208
11209 /*******************************************************************************
11210 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
11211 * KMOD_MAX_NAME characters and performs various substitutions of common
11212 * prefixes & substrings as defined by tables in kext_panic_report.h.
11213 *******************************************************************************/
11214 static void compactIdentifier(
11215 const char * identifier,
11216 char * identifier_out,
11217 char ** identifier_out_end);
11218
11219 static void
11220 compactIdentifier(
11221 const char * identifier,
11222 char * identifier_out,
11223 char ** identifier_out_end)
11224 {
11225 uint32_t from_index, to_index;
11226 uint32_t scan_from_index = 0;
11227 uint32_t scan_to_index = 0;
11228 subs_entry_t * subs_entry = NULL;
11229 int did_sub = 0;
11230
11231 from_index = to_index = 0;
11232 identifier_out[0] = '\0';
11233
11234 /* Replace certain identifier prefixes with shorter @+character sequences.
11235 * Check the return value of substitute() so we only replace the prefix.
11236 */
11237 for (subs_entry = &kext_identifier_prefix_subs[0];
11238 subs_entry->substring && !did_sub;
11239 subs_entry++) {
11240
11241 did_sub = substitute(identifier, identifier_out,
11242 &scan_to_index, &scan_from_index,
11243 subs_entry->substring, /* marker */ '\0', subs_entry->substitute);
11244 }
11245 did_sub = 0;
11246
11247 /* Now scan through the identifier looking for the common substrings
11248 * and replacing them with shorter !+character sequences via substitute().
11249 */
11250 for (/* see above */;
11251 scan_from_index < KMOD_MAX_NAME - 1 && identifier[scan_from_index];
11252 /* see loop */) {
11253
11254 const char * scan_string = &identifier[scan_from_index];
11255
11256 did_sub = 0;
11257
11258 if (scan_from_index) {
11259 for (subs_entry = &kext_identifier_substring_subs[0];
11260 subs_entry->substring && !did_sub;
11261 subs_entry++) {
11262
11263 did_sub = substitute(scan_string, identifier_out,
11264 &scan_to_index, &scan_from_index,
11265 subs_entry->substring, '!', subs_entry->substitute);
11266 }
11267 }
11268
11269 /* If we didn't substitute, copy the input character to the output.
11270 */
11271 if (!did_sub) {
11272 identifier_out[scan_to_index++] = identifier[scan_from_index++];
11273 }
11274 }
11275
11276 identifier_out[scan_to_index] = '\0';
11277 if (identifier_out_end) {
11278 *identifier_out_end = &identifier_out[scan_to_index];
11279 }
11280
11281 return;
11282 }
11283
11284 /*******************************************************************************
11285 * assemble_identifier_and_version() adds to a string buffer a compacted
11286 * bundle identifier followed by a version string.
11287 *******************************************************************************/
11288
11289 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
11290 */
11291 static int assemble_identifier_and_version(
11292 kmod_info_t * kmod_info,
11293 char * identPlusVers,
11294 int bufSize);
11295
11296 static int
11297 assemble_identifier_and_version(
11298 kmod_info_t * kmod_info,
11299 char * identPlusVers,
11300 int bufSize)
11301 {
11302 int result = 0;
11303
11304 compactIdentifier(kmod_info->name, identPlusVers, NULL);
11305 result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
11306 identPlusVers[result++] = '\t'; // increment for real char
11307 identPlusVers[result] = '\0'; // don't increment for nul char
11308 result = strlcat(identPlusVers, kmod_info->version, bufSize);
11309 if (result >= bufSize) {
11310 identPlusVers[bufSize - 1] = '\0';
11311 result = bufSize - 1;
11312 }
11313
11314 return result;
11315 }
11316
11317 /*******************************************************************************
11318 * Assumes sKextLock is held.
11319 *******************************************************************************/
11320 /* static */
11321 int
11322 OSKext::saveLoadedKextPanicListTyped(
11323 const char * prefix,
11324 int invertFlag,
11325 int libsFlag,
11326 char * paniclist,
11327 uint32_t list_size)
11328 {
11329 int result = -1;
11330 unsigned int count, i;
11331
11332 count = sLoadedKexts->getCount();
11333 if (!count) {
11334 goto finish;
11335 }
11336
11337 i = count - 1;
11338 do {
11339 OSObject * rawKext = sLoadedKexts->getObject(i);
11340 OSKext * theKext = OSDynamicCast(OSKext, rawKext);
11341 int match;
11342 uint32_t identPlusVersLength;
11343 uint32_t tempLen;
11344 char identPlusVers[2*KMOD_MAX_NAME];
11345
11346 if (!rawKext) {
11347 printf("OSKext::saveLoadedKextPanicListTyped - "
11348 "NULL kext in loaded kext list; continuing\n");
11349 continue;
11350 }
11351
11352 if (!theKext) {
11353 printf("OSKext::saveLoadedKextPanicListTyped - "
11354 "Kext type cast failed in loaded kext list; continuing\n");
11355 continue;
11356 }
11357
11358 /* Skip all built-in kexts.
11359 */
11360 if (theKext->isKernelComponent()) {
11361 continue;
11362 }
11363
11364 kmod_info_t * kmod_info = theKext->kmod_info;
11365
11366 /* Filter for kmod name (bundle identifier).
11367 */
11368 match = !strncmp(kmod_info->name, prefix, strnlen(prefix, KMOD_MAX_NAME));
11369 if ((match && invertFlag) || (!match && !invertFlag)) {
11370 continue;
11371 }
11372
11373 /* Filter for libraries (kexts that have a compatible version).
11374 */
11375 if ((libsFlag == 0 && theKext->getCompatibleVersion() > 1) ||
11376 (libsFlag == 1 && theKext->getCompatibleVersion() < 1)) {
11377
11378 continue;
11379 }
11380
11381 if (!kmod_info ||
11382 !pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_info))) {
11383
11384 printf("kext scan stopped due to missing kmod_info page: %p\n",
11385 kmod_info);
11386 goto finish;
11387 }
11388
11389 identPlusVersLength = assemble_identifier_and_version(kmod_info,
11390 identPlusVers,
11391 sizeof(identPlusVers));
11392 if (!identPlusVersLength) {
11393 printf("error saving loaded kext info\n");
11394 goto finish;
11395 }
11396
11397 /* make sure everything fits and we null terminate.
11398 */
11399 tempLen = strlcat(paniclist, identPlusVers, list_size);
11400 if (tempLen >= list_size) {
11401 // panic list is full, keep it and null terminate
11402 paniclist[list_size - 1] = 0x00;
11403 result = 0;
11404 goto finish;
11405 }
11406 tempLen = strlcat(paniclist, "\n", list_size);
11407 if (tempLen >= list_size) {
11408 // panic list is full, keep it and null terminate
11409 paniclist[list_size - 1] = 0x00;
11410 result = 0;
11411 goto finish;
11412 }
11413 } while (i--);
11414
11415 result = 0;
11416 finish:
11417
11418 return result;
11419 }
11420
11421 /*********************************************************************
11422 *********************************************************************/
11423 /* static */
11424 void
11425 OSKext::saveLoadedKextPanicList(void)
11426 {
11427 char * newlist = NULL;
11428 uint32_t newlist_size = 0;
11429
11430 newlist_size = KEXT_PANICLIST_SIZE;
11431 newlist = (char *)kalloc_tag(newlist_size, VM_KERN_MEMORY_OSKEXT);
11432
11433 if (!newlist) {
11434 OSKextLog(/* kext */ NULL,
11435 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
11436 "Couldn't allocate kext panic log buffer.");
11437 goto finish;
11438 }
11439
11440 newlist[0] = '\0';
11441
11442 // non-"com.apple." kexts
11443 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
11444 /* libs? */ -1, newlist, newlist_size) != 0) {
11445
11446 goto finish;
11447 }
11448 // "com.apple." nonlibrary kexts
11449 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
11450 /* libs? */ 0, newlist, newlist_size) != 0) {
11451
11452 goto finish;
11453 }
11454 // "com.apple." library kexts
11455 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
11456 /* libs? */ 1, newlist, newlist_size) != 0) {
11457
11458 goto finish;
11459 }
11460
11461 if (loaded_kext_paniclist) {
11462 kfree(loaded_kext_paniclist, loaded_kext_paniclist_size);
11463 }
11464 loaded_kext_paniclist = newlist;
11465 newlist = NULL;
11466 loaded_kext_paniclist_size = newlist_size;
11467
11468 finish:
11469 if (newlist) {
11470 kfree(newlist, newlist_size);
11471 }
11472 return;
11473 }
11474
11475 /*********************************************************************
11476 * Assumes sKextLock is held.
11477 *********************************************************************/
11478 void
11479 OSKext::savePanicString(bool isLoading)
11480 {
11481 u_long len;
11482
11483 if (!kmod_info) {
11484 return; // do not goto finish here b/c of lock
11485 }
11486
11487 len = assemble_identifier_and_version( kmod_info,
11488 (isLoading) ? last_loaded_str_buf : last_unloaded_str_buf,
11489 (isLoading) ? sizeof(last_loaded_str_buf) : sizeof(last_unloaded_str_buf) );
11490 if (!len) {
11491 printf("error saving unloaded kext info\n");
11492 goto finish;
11493 }
11494
11495 if (isLoading) {
11496 last_loaded_strlen = len;
11497 last_loaded_address = (void *)kmod_info->address;
11498 last_loaded_size = kmod_info->size;
11499 clock_get_uptime(&last_loaded_timestamp);
11500 } else {
11501 last_unloaded_strlen = len;
11502 last_unloaded_address = (void *)kmod_info->address;
11503 last_unloaded_size = kmod_info->size;
11504 clock_get_uptime(&last_unloaded_timestamp);
11505 }
11506
11507 finish:
11508 return;
11509 }
11510
11511 /*********************************************************************
11512 *********************************************************************/
11513 /* static */
11514 void
11515 OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
11516 {
11517 if (last_loaded_strlen) {
11518 printf_func("last loaded kext at %llu: %.*s (addr %p, size %lu)\n",
11519 AbsoluteTime_to_scalar(&last_loaded_timestamp),
11520 last_loaded_strlen, last_loaded_str_buf,
11521 last_loaded_address, last_loaded_size);
11522 }
11523
11524 if (last_unloaded_strlen) {
11525 printf_func("last unloaded kext at %llu: %.*s (addr %p, size %lu)\n",
11526 AbsoluteTime_to_scalar(&last_unloaded_timestamp),
11527 last_unloaded_strlen, last_unloaded_str_buf,
11528 last_unloaded_address, last_unloaded_size);
11529 }
11530
11531 printf_func("loaded kexts:\n");
11532 if (loaded_kext_paniclist &&
11533 pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
11534 loaded_kext_paniclist[0]) {
11535
11536 printf_func("%.*s",
11537 strnlen(loaded_kext_paniclist, loaded_kext_paniclist_size),
11538 loaded_kext_paniclist);
11539 } else {
11540 printf_func("(none)\n");
11541 }
11542 return;
11543 }
11544
11545 /*********************************************************************
11546 * Assumes sKextLock is held.
11547 *********************************************************************/
11548 /* static */
11549 void
11550 OSKext::updateLoadedKextSummaries(void)
11551 {
11552 kern_return_t result = KERN_FAILURE;
11553 OSKextLoadedKextSummaryHeader *summaryHeader = NULL;
11554 OSKextLoadedKextSummaryHeader *summaryHeaderAlloc = NULL;
11555 OSKext *aKext;
11556 vm_map_offset_t start, end;
11557 size_t summarySize = 0;
11558 size_t size;
11559 u_int count;
11560 u_int maxKexts;
11561 u_int i, j;
11562 OSKextActiveAccount * accountingList;
11563 OSKextActiveAccount * prevAccountingList;
11564 uint32_t idx, accountingListAlloc, accountingListCount, prevAccountingListCount;
11565
11566 prevAccountingList = NULL;
11567 prevAccountingListCount = 0;
11568
11569 #if DEVELOPMENT || DEBUG
11570 if (IORecursiveLockHaveLock(sKextLock) == false) {
11571 panic("sKextLock must be held");
11572 }
11573 #endif
11574
11575 IOLockLock(sKextSummariesLock);
11576
11577 count = sLoadedKexts->getCount();
11578 for (i = 0, maxKexts = 0; i < count; ++i) {
11579 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
11580 maxKexts += (aKext && aKext->isExecutable());
11581 }
11582
11583 if (!maxKexts) goto finish;
11584 if (maxKexts < kOSKextTypicalLoadCount) maxKexts = kOSKextTypicalLoadCount;
11585
11586 /* Calculate the size needed for the new summary headers.
11587 */
11588
11589 size = sizeof(*gLoadedKextSummaries);
11590 size += maxKexts * sizeof(*gLoadedKextSummaries->summaries);
11591 size = round_page(size);
11592
11593 if (gLoadedKextSummaries == NULL || sLoadedKextSummariesAllocSize < size) {
11594 if (gLoadedKextSummaries) {
11595 kmem_free(kernel_map, (vm_offset_t)gLoadedKextSummaries, sLoadedKextSummariesAllocSize);
11596 gLoadedKextSummaries = NULL;
11597 gLoadedKextSummariesTimestamp = mach_absolute_time();
11598 sLoadedKextSummariesAllocSize = 0;
11599 }
11600 result = kmem_alloc(kernel_map, (vm_offset_t *)&summaryHeaderAlloc, size, VM_KERN_MEMORY_OSKEXT);
11601 if (result != KERN_SUCCESS) goto finish;
11602 summaryHeader = summaryHeaderAlloc;
11603 summarySize = size;
11604 }
11605 else {
11606 summaryHeader = gLoadedKextSummaries;
11607 summarySize = sLoadedKextSummariesAllocSize;
11608
11609 start = (vm_map_offset_t) summaryHeader;
11610 end = start + summarySize;
11611 result = vm_map_protect(kernel_map,
11612 start,
11613 end,
11614 VM_PROT_DEFAULT,
11615 FALSE);
11616 if (result != KERN_SUCCESS) goto finish;
11617 }
11618
11619 /* Populate the summary header.
11620 */
11621
11622 bzero(summaryHeader, summarySize);
11623 summaryHeader->version = kOSKextLoadedKextSummaryVersion;
11624 summaryHeader->entry_size = sizeof(OSKextLoadedKextSummary);
11625
11626 /* Populate each kext summary.
11627 */
11628
11629 count = sLoadedKexts->getCount();
11630 accountingListAlloc = 0;
11631 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
11632 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
11633 if (!aKext || !aKext->isExecutable()) {
11634 continue;
11635 }
11636
11637 aKext->updateLoadedKextSummary(&summaryHeader->summaries[j++]);
11638 summaryHeader->numSummaries++;
11639 accountingListAlloc++;
11640 }
11641
11642 accountingList = IONew(typeof(accountingList[0]), accountingListAlloc);
11643 accountingListCount = 0;
11644 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
11645 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
11646 if (!aKext || !aKext->isExecutable()) {
11647 continue;
11648 }
11649
11650 OSKextActiveAccount activeAccount;
11651 aKext->updateActiveAccount(&activeAccount);
11652 // order by address
11653 for (idx = 0; idx < accountingListCount; idx++)
11654 {
11655 if (activeAccount.address < accountingList[idx].address) break;
11656 }
11657 bcopy(&accountingList[idx], &accountingList[idx + 1], (accountingListCount - idx) * sizeof(accountingList[0]));
11658 accountingList[idx] = activeAccount;
11659 accountingListCount++;
11660 }
11661 assert(accountingListCount == accountingListAlloc);
11662 /* Write protect the buffer and move it into place.
11663 */
11664
11665 start = (vm_map_offset_t) summaryHeader;
11666 end = start + summarySize;
11667
11668 result = vm_map_protect(kernel_map, start, end, VM_PROT_READ, FALSE);
11669 if (result != KERN_SUCCESS)
11670 goto finish;
11671
11672 gLoadedKextSummaries = summaryHeader;
11673 gLoadedKextSummariesTimestamp = mach_absolute_time();
11674 sLoadedKextSummariesAllocSize = summarySize;
11675 summaryHeaderAlloc = NULL;
11676
11677 /* Call the magic breakpoint function through a static function pointer so
11678 * the compiler can't optimize the function away.
11679 */
11680 if (sLoadedKextSummariesUpdated) (*sLoadedKextSummariesUpdated)();
11681
11682 IOSimpleLockLock(sKextAccountsLock);
11683 prevAccountingList = sKextAccounts;
11684 prevAccountingListCount = sKextAccountsCount;
11685 sKextAccounts = accountingList;
11686 sKextAccountsCount = accountingListCount;
11687 IOSimpleLockUnlock(sKextAccountsLock);
11688
11689 finish:
11690 IOLockUnlock(sKextSummariesLock);
11691
11692 /* If we had to allocate a new buffer but failed to generate the summaries,
11693 * free that now.
11694 */
11695 if (summaryHeaderAlloc) {
11696 kmem_free(kernel_map, (vm_offset_t)summaryHeaderAlloc, summarySize);
11697 }
11698 if (prevAccountingList) {
11699 IODelete(prevAccountingList, typeof(accountingList[0]), prevAccountingListCount);
11700 }
11701
11702 return;
11703 }
11704
11705 /*********************************************************************
11706 *********************************************************************/
11707 void
11708 OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary *summary)
11709 {
11710 OSData *uuid;
11711
11712 strlcpy(summary->name, getIdentifierCString(),
11713 sizeof(summary->name));
11714
11715 uuid = copyUUID();
11716 if (uuid) {
11717 memcpy(summary->uuid, uuid->getBytesNoCopy(), sizeof(summary->uuid));
11718 OSSafeReleaseNULL(uuid);
11719 }
11720
11721 summary->address = kmod_info->address;
11722 summary->size = kmod_info->size;
11723 summary->version = getVersion();
11724 summary->loadTag = kmod_info->id;
11725 summary->flags = 0;
11726 summary->reference_list = (uint64_t) kmod_info->reference_list;
11727
11728 return;
11729 }
11730
11731 /*********************************************************************
11732 *********************************************************************/
11733
11734 void
11735 OSKext::updateActiveAccount(OSKextActiveAccount *accountp)
11736 {
11737 kernel_mach_header_t *hdr = NULL;
11738 kernel_segment_command_t *seg = NULL;
11739
11740 hdr = (kernel_mach_header_t *)kmod_info->address;
11741
11742 if (getcommandfromheader(hdr, LC_SEGMENT_SPLIT_INFO)) {
11743 /* If this kext supports split segments, use the first
11744 * executable segment as the range for instructions
11745 * (and thus for backtracing.
11746 */
11747 for (seg = firstsegfromheader(hdr); seg != NULL; seg = nextsegfromheader(hdr, seg)) {
11748 if (seg->initprot & VM_PROT_EXECUTE) {
11749 break;
11750 }
11751 }
11752 }
11753
11754 bzero(accountp, sizeof(*accountp));
11755 if (seg) {
11756 accountp->address = seg->vmaddr;
11757 if (accountp->address) {
11758 accountp->address_end = seg->vmaddr + seg->vmsize;
11759 }
11760 } else {
11761 /* For non-split kexts and for kexts without executable
11762 * segments, just use the kmod_info range (as the kext
11763 * is either all in one range or should not show up in
11764 * instruction backtraces).
11765 */
11766 accountp->address = kmod_info->address;
11767 if (accountp->address) {
11768 accountp->address_end = kmod_info->address + kmod_info->size;
11769 }
11770 }
11771 accountp->account = this->account;
11772 }
11773
11774 extern "C" const vm_allocation_site_t *
11775 OSKextGetAllocationSiteForCaller(uintptr_t address)
11776 {
11777 OSKextActiveAccount * active;
11778 vm_allocation_site_t * site;
11779 vm_allocation_site_t * releasesite;
11780
11781 uint32_t baseIdx;
11782 uint32_t lim;
11783
11784 IOSimpleLockLock(sKextAccountsLock);
11785 site = releasesite = NULL;
11786
11787 // bsearch sKextAccounts list
11788 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1)
11789 {
11790 active = &sKextAccounts[baseIdx + (lim >> 1)];
11791 if ((address >= active->address) && (address < active->address_end))
11792 {
11793 site = &active->account->site;
11794 if (!site->tag) vm_tag_alloc_locked(site, &releasesite);
11795 break;
11796 }
11797 else if (address > active->address)
11798 {
11799 // move right
11800 baseIdx += (lim >> 1) + 1;
11801 lim--;
11802 }
11803 // else move left
11804 }
11805 IOSimpleLockUnlock(sKextAccountsLock);
11806 if (releasesite) kern_allocation_name_release(releasesite);
11807
11808 return (site);
11809 }
11810
11811 extern "C" uint32_t
11812 OSKextGetKmodIDForSite(const vm_allocation_site_t * site, char * name, vm_size_t namelen)
11813 {
11814 OSKextAccount * account = (typeof(account)) site;
11815 const char * kname;
11816
11817 if (name)
11818 {
11819 if (account->kext) kname = account->kext->getIdentifierCString();
11820 else kname = "<>";
11821 strlcpy(name, kname, namelen);
11822 }
11823
11824 return (account->loadTag);
11825 }
11826
11827 extern "C" void
11828 OSKextFreeSite(vm_allocation_site_t * site)
11829 {
11830 OSKextAccount * freeAccount = (typeof(freeAccount)) site;
11831 IODelete(freeAccount, OSKextAccount, 1);
11832 }
11833
11834 /*********************************************************************
11835 *********************************************************************/
11836
11837 #if CONFIG_KEC_FIPS
11838
11839 #if PRAGMA_MARK
11840 #pragma mark Kernel External Components for FIPS compliance
11841 #endif
11842
11843 /*********************************************************************
11844 * Kernel External Components for FIPS compliance (KEC_FIPS)
11845 *********************************************************************/
11846 static void *
11847 GetAppleTEXTHashForKext(OSKext * theKext, OSDictionary *theInfoDict)
11848 {
11849 AppleTEXTHash_t my_ath = {2, 0, NULL};
11850 AppleTEXTHash_t * my_athp = NULL; // do not release
11851 OSData * segmentHash = NULL; // do not release
11852
11853 if (theKext == NULL || theInfoDict == NULL) {
11854 return(NULL);
11855 }
11856
11857 // Get the part of the plist associate with kAppleTextHashesKey and let
11858 // the crypto library do further parsing (slice/architecture)
11859 segmentHash = OSDynamicCast(OSData, theInfoDict->getObject(kAppleTextHashesKey));
11860 // Support for ATH v1 while rolling out ATH v2 without revision locking submissions
11861 // Remove this when v2 PLIST are supported
11862 if (segmentHash == NULL) {
11863 // If this fails, we may be dealing with a v1 PLIST
11864 OSDictionary * textHashDict = NULL; // do not release
11865 textHashDict = OSDynamicCast(OSDictionary, theInfoDict->getObject(kAppleTextHashesKey));
11866 if (textHashDict == NULL) {
11867 return(NULL);
11868 }
11869 my_ath.ath_version=1;
11870 segmentHash = OSDynamicCast(OSData,textHashDict->getObject(ARCHNAME));
11871 } // end of v2 rollout
11872
11873 if (segmentHash == NULL) {
11874 return(NULL);
11875 }
11876
11877 // KEC_FIPS type kexts never unload so we don't have to clean up our
11878 // AppleTEXTHash_t
11879 if (kmem_alloc(kernel_map, (vm_offset_t *) &my_athp,
11880 sizeof(AppleTEXTHash_t), VM_KERN_MEMORY_OSKEXT) != KERN_SUCCESS) {
11881 return(NULL);
11882 }
11883
11884 memcpy(my_athp, &my_ath, sizeof(my_ath));
11885 my_athp->ath_length = segmentHash->getLength();
11886 if (my_athp->ath_length > 0) {
11887 my_athp->ath_hash = (void *)segmentHash->getBytesNoCopy();
11888 }
11889
11890 #if 0
11891 OSKextLog(theKext,
11892 kOSKextLogErrorLevel |
11893 kOSKextLogGeneralFlag,
11894 "Kext %s ath_version %d ath_length %d ath_hash %p",
11895 theKext->getIdentifierCString(),
11896 my_athp->ath_version,
11897 my_athp->ath_length,
11898 my_athp->ath_hash);
11899 #endif
11900
11901 return( (void *) my_athp );
11902 }
11903
11904 #endif // CONFIG_KEC_FIPS
11905
11906 #if CONFIG_IMAGEBOOT
11907 int OSKextGetUUIDForName(const char *name, uuid_t uuid)
11908 {
11909 OSKext *kext = OSKext::lookupKextWithIdentifier(name);
11910 if (!kext) {
11911 return 1;
11912 }
11913
11914 OSData *uuid_data = kext->copyUUID();
11915 if (uuid_data) {
11916 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_t));
11917 OSSafeReleaseNULL(uuid_data);
11918 return 0;
11919 }
11920
11921 return 1;
11922 }
11923 #endif