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