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