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