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