xref: /xnu-11215/libkern/c++/OSKext.cpp (revision 2dd95c5f)
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 (!sLoadEnabled) {
3953         if (!isLoaded() || (!isStarted() && startOpt != kOSKextExcludeNone) ||
3954             (startMatchingOpt != kOSKextExcludeNone)) {
3955 
3956             OSKextLog(this,
3957                 kOSKextLogErrorLevel |
3958                 kOSKextLogLoadFlag,
3959                 "Kext loading is disabled "
3960                 "(attempt to load/start/start matching for kext %s).",
3961                 getIdentifierCString());
3962         }
3963         result = kOSKextReturnDisabled;
3964         goto finish;
3965     }
3966 
3967     if (isLoaded()) {
3968         alreadyLoaded = true;
3969         result = kOSReturnSuccess;
3970 
3971         OSKextLog(this,
3972             kOSKextLogDebugLevel |
3973             kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
3974             "Kext %s is already loaded.",
3975             getIdentifierCString());
3976         goto loaded;
3977     }
3978 
3979    /* If we've pushed the next available load tag to the invalid value,
3980     * we can't load any more kexts.
3981     */
3982     if (sNextLoadTag == kOSKextInvalidLoadTag) {
3983         OSKextLog(this,
3984             kOSKextLogErrorLevel |
3985             kOSKextLogLoadFlag,
3986             "Can't load kext %s - no more load tags to assign.",
3987             getIdentifierCString());
3988         result = kOSKextReturnNoResources;
3989         goto finish;
3990     }
3991 
3992    /* This is a bit of a hack, because we shouldn't be handling
3993     * personalities within the load function.
3994     */
3995     if (!declaresExecutable()) {
3996         result = kOSReturnSuccess;
3997         goto loaded;
3998     }
3999 
4000    /* Are we in safe boot?
4001     */
4002     if (sSafeBoot && !isLoadableInSafeBoot()) {
4003         OSKextLog(this,
4004             kOSKextLogErrorLevel |
4005             kOSKextLogLoadFlag,
4006             "Can't load kext %s - not loadable during safe boot.",
4007             getIdentifierCString());
4008         result = kOSKextReturnBootLevel;
4009         goto finish;
4010     }
4011 
4012     OSKextLog(this,
4013         kOSKextLogProgressLevel | kOSKextLogLoadFlag,
4014         "Loading kext %s.",
4015         getIdentifierCString());
4016 
4017 
4018     if (!sKxldContext) {
4019         kxldResult = kxld_create_context(&sKxldContext, &kern_allocate,
4020             &kxld_log_callback, /* Flags */ (KXLDFlags) 0,
4021             /* cputype */ 0, /* cpusubtype */ 0);
4022         if (kxldResult) {
4023             OSKextLog(this,
4024                 kOSKextLogErrorLevel |
4025                 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
4026                 "Can't load kext %s - failed to create link context.",
4027                 getIdentifierCString());
4028             result = kOSKextReturnNoMemory;
4029             goto finish;
4030         }
4031     }
4032 
4033     /* We only need to resolve dependencies once for the whole graph, but
4034      * resolveDependencies will just return if there's no work to do, so it's
4035      * safe to call it more than once.
4036      */
4037     if (!resolveDependencies()) {
4038         // xxx - check resolveDependencies() for log msg
4039         OSKextLog(this,
4040             kOSKextLogErrorLevel |
4041             kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4042             "Can't load kext %s - failed to resolve library dependencies.",
4043             getIdentifierCString());
4044         result = kOSKextReturnDependencies;
4045         goto finish;
4046     }
4047 
4048    /* If we are excluding just the kext being loaded now (and not its
4049     * dependencies), drop the exclusion level to none so dependencies
4050     * start and/or add their personalities.
4051     */
4052     if (dependenciesStartOpt == kOSKextExcludeKext) {
4053         dependenciesStartOpt = kOSKextExcludeNone;
4054     }
4055 
4056     if (dependenciesStartMatchingOpt == kOSKextExcludeKext) {
4057         dependenciesStartMatchingOpt = kOSKextExcludeNone;
4058     }
4059 
4060    /* Load the dependencies, recursively.
4061     */
4062     count = getNumDependencies();
4063     for (i = 0; i < count; i++) {
4064         OSKext * dependency = OSDynamicCast(OSKext,
4065             dependencies->getObject(i));
4066         if (dependency == NULL) {
4067             OSKextLog(this,
4068                 kOSKextLogErrorLevel |
4069                 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4070                 "Internal error loading kext %s; dependency disappeared.",
4071                 getIdentifierCString());
4072             result = kOSKextReturnInternalError;
4073             goto finish;
4074         }
4075 
4076        /* Dependencies must be started accorting to the opt,
4077         * but not given the personality names of the main kext.
4078         */
4079         result = dependency->load(dependenciesStartOpt,
4080             dependenciesStartMatchingOpt,
4081             /* personalityNames */ NULL);
4082         if (result != KERN_SUCCESS) {
4083             OSKextLog(this,
4084                 kOSKextLogErrorLevel |
4085                 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4086                 "Dependency %s of kext %s failed to load.",
4087                 dependency->getIdentifierCString(),
4088                 getIdentifierCString());
4089 
4090             OSKext::removeKext(dependency,
4091                 /* terminateService/removePersonalities */ true);
4092             result = kOSKextReturnDependencyLoadError;
4093 
4094             goto finish;
4095         }
4096     }
4097 
4098     result = loadExecutable();
4099     if (result != KERN_SUCCESS) {
4100         goto finish;
4101     }
4102 
4103     flags.loaded = true;
4104 
4105    /* Add the kext to the list of loaded kexts and update the kmod_info
4106     * struct to point to that of the last loaded kext (which is the way
4107     * it's always been done, though I'd rather do them in order now).
4108     */
4109     lastLoadedKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
4110     sLoadedKexts->setObject(this);
4111 
4112    /* Keep the kernel itself out of the kmod list.
4113     */
4114     if (lastLoadedKext == sKernelKext) {
4115         lastLoadedKext = NULL;
4116     }
4117 
4118     if (lastLoadedKext) {
4119         kmod_info->next = lastLoadedKext->kmod_info;
4120     }
4121 
4122    /* Make the global kmod list point at the just-loaded kext. Note that the
4123     * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
4124     * although we do report it in kextstat these days by using the newer
4125     * OSArray of loaded kexts, which does contain it.
4126     *
4127     * (The OSKext object representing the kernel doesn't even have a kmod_info
4128     * struct, though I suppose we could stick a pointer to it from the
4129     * static struct in OSRuntime.cpp.)
4130     */
4131     kmod = kmod_info;
4132 
4133    /* Save the list of loaded kexts in case we panic.
4134     */
4135     clock_get_uptime(&last_loaded_timestamp);
4136     OSKext::saveLoadedKextPanicList();
4137 
4138 loaded:
4139    /* This is a bit of a hack, because we shouldn't be handling
4140     * personalities within the load function.
4141     */
4142     if (declaresExecutable() && (startOpt == kOSKextExcludeNone)) {
4143         result = start();
4144         if (result != kOSReturnSuccess) {
4145             OSKextLog(this,
4146                 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
4147                 "Kext %s start failed (result 0x%x).",
4148                 getIdentifierCString(), result);
4149             result = kOSKextReturnStartStopError;
4150         }
4151     }
4152 
4153    /* If not excluding matching, send the personalities to the kernel.
4154     * This never affects the result of the load operation.
4155     */
4156     if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
4157         sendPersonalitiesToCatalog(true, personalityNames);
4158     }
4159 
4160 finish:
4161     if (result != kOSReturnSuccess) {
4162         OSKextLog(this,
4163             kOSKextLogErrorLevel |
4164             kOSKextLogLoadFlag,
4165             "Kext %s failed to load (0x%x).",
4166             getIdentifierCString(), (int)result);
4167     } else if (!alreadyLoaded) {
4168         OSKextLog(this,
4169             kOSKextLogProgressLevel |
4170             kOSKextLogLoadFlag,
4171             "Kext %s loaded.",
4172             getIdentifierCString());
4173     }
4174     return result;
4175 }
4176 
4177 /*********************************************************************
4178 * called only by load()
4179 *********************************************************************/
4180 OSReturn
4181 OSKext::loadExecutable()
4182 {
4183     OSReturn              result             = kOSReturnError;
4184     kern_return_t         kxldResult;
4185     u_char            **  kxlddeps           = NULL;  // must kfree
4186     uint32_t              num_kxlddeps       = 0;
4187     uint32_t              num_kmod_refs      = 0;
4188     u_char              * linkStateBytes     = NULL;  // do not free
4189     u_long                linkStateLength    = 0;
4190     u_char             ** linkStateBytesPtr  = NULL;  // do not free
4191     u_long              * linkStateLengthPtr = NULL;  // do not free
4192     struct mach_header ** kxldHeaderPtr      = NULL;  // do not free
4193     struct mach_header  * kxld_header        = NULL;  // xxx - need to free here?
4194     OSData              * theExecutable      = NULL;  // do not release
4195     OSString            * versString         = NULL;  // do not release
4196     const char          * versCString        = NULL;  // do not free
4197     const char          * string             = NULL;  // do not free
4198     unsigned int          i;
4199 
4200    /* We need the version string for a variety of bits below.
4201     */
4202     versString = OSDynamicCast(OSString,
4203         getPropertyForHostArch(kCFBundleVersionKey));
4204     if (!versString) {
4205         goto finish;
4206     }
4207     versCString = versString->getCStringNoCopy();
4208 
4209     if (isKernelComponent()) {
4210        if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
4211            if (strncmp(versCString, KERNEL6_VERSION, strlen(KERNEL6_VERSION))) {
4212                 OSKextLog(this,
4213                     kOSKextLogErrorLevel |
4214                     kOSKextLogLoadFlag,
4215                     "Kernel component %s has incorrect version %s; "
4216                     "expected %s.",
4217                     getIdentifierCString(),
4218                     versCString, KERNEL6_VERSION);
4219                result = kOSKextReturnInternalError;
4220                goto finish;
4221            } else if (strcmp(versCString, osrelease)) {
4222                 OSKextLog(this,
4223                     kOSKextLogErrorLevel |
4224                     kOSKextLogLoadFlag,
4225                     "Kernel component %s has incorrect version %s; "
4226                     "expected %s.",
4227                     getIdentifierCString(),
4228                     versCString, osrelease);
4229                result = kOSKextReturnInternalError;
4230                goto finish;
4231            }
4232        }
4233     }
4234 
4235     if (isPrelinked()) {
4236         goto register_kmod;
4237     }
4238 
4239     theExecutable = getExecutable();
4240     if (!theExecutable) {
4241         if (declaresExecutable()) {
4242             OSKextLog(this,
4243                 kOSKextLogErrorLevel |
4244                 kOSKextLogLoadFlag,
4245                 "Can't load kext %s - executable is missing.",
4246                 getIdentifierCString());
4247             result = kOSKextReturnValidation;
4248             goto finish;
4249         }
4250         goto register_kmod;
4251     }
4252 
4253     if (isKernelComponent()) {
4254         num_kxlddeps = 1; // the kernel itself
4255     } else {
4256         num_kxlddeps = getNumDependencies();
4257     }
4258     if (!num_kxlddeps) {
4259         OSKextLog(this,
4260             kOSKextLogErrorLevel |
4261             kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4262             "Can't load kext %s - it has no library dependencies.",
4263             getIdentifierCString());
4264         goto finish;
4265     }
4266     kxlddeps = (u_char **)kalloc(num_kxlddeps * sizeof(*kxlddeps));
4267     if (!kxlddeps) {
4268         OSKextLog(this,
4269             kOSKextLogErrorLevel |
4270             kOSKextLogLoadFlag | kOSKextLogLinkFlag,
4271             "Can't allocate link context to load kext %s.",
4272             getIdentifierCString());
4273         goto finish;
4274     }
4275 
4276     if (isKernelComponent()) {
4277         OSData * kernelLinkState = OSKext::getKernelLinkState();
4278         kxlddeps[0] = (u_char *)kernelLinkState->getBytesNoCopy();
4279     } else for (i = 0; i < num_kxlddeps; i++) {
4280         OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
4281         if (!dependency->linkState) {
4282             // xxx - maybe we should panic here
4283             OSKextLog(this,
4284                 kOSKextLogErrorLevel |
4285                 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
4286                 "Can't load kext %s - link state missing.",
4287                 getIdentifierCString());
4288             goto finish;
4289         }
4290         kxlddeps[i] = (u_char *)dependency->linkState->getBytesNoCopy();
4291         assert(kxlddeps[i]);
4292     }
4293 
4294    /* We only need link state for a library kext.
4295     */
4296     if (compatibleVersion > -1 && (declaresExecutable() || isKernelComponent())) {
4297         linkStateBytesPtr = &linkStateBytes;
4298         linkStateLengthPtr = &linkStateLength;
4299     }
4300 
4301    /* We only need the linked executable for a real kext.
4302     */
4303     if (!isInterface()) {
4304         kxldHeaderPtr = &kxld_header;
4305     }
4306 
4307 #if DEBUG
4308     OSKextLog(this,
4309         kOSKextLogExplicitLevel |
4310         kOSKextLogLoadFlag | kOSKextLogLinkFlag,
4311         "Kext %s - calling kxld_link_file:\n"
4312         "    kxld_context: %p\n"
4313         "    executable: %p    executable_length: %d\n"
4314         "    user_data: %p\n"
4315         "    kxld_dependencies: %p    num_dependencies: %d\n"
4316         "    kxld_header_ptr: %p    kmod_info_ptr: %p\n"
4317         "    link_state_ptr: %p    link_state_length_ptr: %p",
4318         getIdentifierCString(), kxldContext,
4319         theExecutable->getBytesNoCopy(), theExecutable->getLength(),
4320         this, kxlddeps, num_kxlddeps,
4321         kxldHeaderPtr, kernelKmodInfoPtr,
4322         linkStateBytesPtr, linkStateLengthPtr);
4323 #endif
4324 
4325    /* After this call, the linkedExecutable instance variable
4326     * should exist.
4327     */
4328     kxldResult = kxld_link_file(sKxldContext,
4329         (u_char *)theExecutable->getBytesNoCopy(),
4330         theExecutable->getLength(),
4331         getIdentifierCString(), this, kxlddeps, num_kxlddeps,
4332         (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info,
4333         linkStateBytesPtr, linkStateLengthPtr,
4334         /* symbolFile */ NULL, /* symbolFileSize */ NULL);
4335 
4336     if (kxldResult != KERN_SUCCESS) {
4337         // xxx - add kxldResult here?
4338         OSKextLog(this,
4339             kOSKextLogErrorLevel |
4340             kOSKextLogLoadFlag,
4341             "Can't load kext %s - link failed.",
4342             getIdentifierCString());
4343         result = kOSKextReturnLinkError;
4344         goto finish;
4345     }
4346 
4347    /* If we got a link state, wrap it in an OSData and keep it
4348     * around for later use linking other kexts that depend on this kext.
4349     */
4350     if (linkStateBytes && linkStateLength > 0) {
4351         linkState = OSData::withBytesNoCopy(linkStateBytes, linkStateLength);
4352         assert(linkState);
4353         linkState->setDeallocFunction(&osdata_kmem_free);
4354     }
4355 
4356    /* If this isn't an interface, We've written data & instructions into kernel
4357     * memory, so flush the data cache and invalidate the instruction cache.
4358     */
4359     if (!isInterface()) {
4360         flush_dcache(kmod_info->address, kmod_info->size, false);
4361         invalidate_icache(kmod_info->address, kmod_info->size, false);
4362     }
4363 
4364 register_kmod:
4365 
4366     if (isInterface()) {
4367 
4368        /* Whip up a fake kmod_info entry for the interface kext.
4369         */
4370         kmod_info = (kmod_info_t *)kalloc(sizeof(kmod_info_t));
4371         if (!kmod_info) {
4372             result = KERN_MEMORY_ERROR;
4373             goto finish;
4374         }
4375 
4376        /* A pseudokext has almost nothing in its kmod_info struct.
4377         */
4378         bzero(kmod_info, sizeof(kmod_info_t));
4379 
4380         kmod_info->info_version = KMOD_INFO_VERSION;
4381 
4382        /* An interface kext doesn't have a linkedExecutable, so save a
4383         * copy of the UUID out of the original executable via copyUUID()
4384         * while we still have the original executable.
4385         */
4386         interfaceUUID = copyUUID();
4387     }
4388 
4389     kmod_info->id = loadTag = sNextLoadTag++;
4390     kmod_info->reference_count = 0;  // KMOD_DECL... sets it to -1 (invalid).
4391 
4392    /* Stamp the bundle ID and version from the OSKext over anything
4393     * resident inside the kmod_info.
4394     */
4395     string = getIdentifierCString();
4396     strlcpy(kmod_info->name, string, sizeof(kmod_info->name));
4397 
4398     string = versCString;
4399     strlcpy(kmod_info->version, string, sizeof(kmod_info->version));
4400 
4401    /* Add the dependencies' kmod_info structs as kmod_references.
4402     */
4403     num_kmod_refs = getNumDependencies();
4404     if (num_kmod_refs) {
4405         kmod_info->reference_list = (kmod_reference_t *)kalloc(
4406             num_kmod_refs * sizeof(kmod_reference_t));
4407         if (!kmod_info->reference_list) {
4408             result = KERN_MEMORY_ERROR;
4409             goto finish;
4410         }
4411         bzero(kmod_info->reference_list,
4412             num_kmod_refs * sizeof(kmod_reference_t));
4413         for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
4414             kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
4415             OSKext * refKext = OSDynamicCast(OSKext, dependencies->getObject(refIndex));
4416             ref->info = refKext->kmod_info;
4417             ref->info->reference_count++;
4418 
4419             if (refIndex + 1 < num_kmod_refs) {
4420                 ref->next = kmod_info->reference_list + refIndex + 1;
4421             }
4422         }
4423     }
4424 
4425     if (!isInterface() && linkedExecutable) {
4426         OSKextLog(this,
4427             kOSKextLogProgressLevel |
4428             kOSKextLogLoadFlag,
4429             "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
4430             kmod_info->name,
4431             (unsigned)kmod_info->size / PAGE_SIZE,
4432             (unsigned long)kmod_info->address,
4433             (unsigned)kmod_info->id);
4434     }
4435 
4436     result = setVMProtections();
4437     if (result != KERN_SUCCESS) {
4438         goto finish;
4439     }
4440 
4441     result = kOSReturnSuccess;
4442 
4443 finish:
4444     if (kxlddeps) kfree(kxlddeps, (num_kxlddeps * sizeof(void *)));
4445 
4446    /* We no longer need the unrelocated executable (which the linker
4447     * has altered anyhow).
4448     */
4449     setExecutable(NULL);
4450 
4451     if (result != kOSReturnSuccess) {
4452         OSKextLog(this,
4453             kOSKextLogErrorLevel |
4454             kOSKextLogLoadFlag,
4455             "Failed to load executable for kext %s.",
4456             getIdentifierCString());
4457 
4458         if (kmod_info && kmod_info->reference_list) {
4459             kfree(kmod_info->reference_list,
4460                 num_kmod_refs * sizeof(kmod_reference_t));
4461         }
4462         if (isInterface()) {
4463             kfree(kmod_info, sizeof(kmod_info_t));
4464         }
4465         kmod_info = NULL;
4466         if (linkedExecutable) {
4467             linkedExecutable->release();
4468             linkedExecutable = NULL;
4469         }
4470     }
4471 
4472     return result;
4473 }
4474 
4475 /*********************************************************************
4476 * xxx - initWithPrelinkedInfoDict doesn't use this
4477 *********************************************************************/
4478 void
4479 OSKext::setLinkedExecutable(OSData * anExecutable)
4480 {
4481     if (linkedExecutable) {
4482         panic("Attempt to set linked executable on kext "
4483             "that already has one (%s).\n",
4484             getIdentifierCString());
4485     }
4486     linkedExecutable = anExecutable;
4487     linkedExecutable->retain();
4488     return;
4489 }
4490 
4491 /*********************************************************************
4492 * called only by loadExecutable()
4493 *********************************************************************/
4494 OSReturn
4495 OSKext::setVMProtections(void)
4496 {
4497     vm_map_t                    kext_map        = NULL;
4498     kernel_segment_command_t  * seg             = NULL;
4499     vm_map_offset_t             start           = 0;
4500     vm_map_offset_t             end             = 0;
4501     OSReturn                    result          = kOSReturnError;
4502 
4503     if (!kmod_info->address && !kmod_info->size) {
4504         result = kOSReturnSuccess;
4505         goto finish;
4506     }
4507 
4508     /* Get the kext's vm map */
4509     kext_map = kext_get_vm_map(kmod_info);
4510     if (!kext_map) {
4511         result = KERN_MEMORY_ERROR;
4512         goto finish;
4513     }
4514 
4515     /* XXX: On arm, the vme covering the prelinked kernel (really, the whole
4516      * range from 0xc0000000 to a little over 0xe0000000) has maxprot set to 0
4517      * so the vm_map_protect calls below fail
4518      * I believe this happens in the call to vm_map_enter in kmem_init but I
4519      * need to confirm.
4520      */
4521     /* Protect the headers as read-only; they do not need to be wired */
4522     result = vm_map_protect(kext_map, kmod_info->address,
4523         kmod_info->address + kmod_info->hdr_size, VM_PROT_READ, TRUE);
4524     if (result != KERN_SUCCESS) {
4525         goto finish;
4526     }
4527 
4528     /* Set the VM protections and wire down each of the segments */
4529     seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
4530     while (seg) {
4531         start = round_page(seg->vmaddr);
4532         end = trunc_page(seg->vmaddr + seg->vmsize);
4533 
4534         result = vm_map_protect(kext_map, start, end, seg->maxprot, TRUE);
4535         if (result != KERN_SUCCESS) {
4536             OSKextLog(this,
4537                 kOSKextLogErrorLevel |
4538                 kOSKextLogLoadFlag,
4539                 "Kext %s failed to set maximum VM protections "
4540                 "for segment %s - 0x%x.",
4541                 getIdentifierCString(), seg->segname, (int)result);
4542             goto finish;
4543         }
4544 
4545         result = vm_map_protect(kext_map, start, end, seg->initprot, FALSE);
4546         if (result != KERN_SUCCESS) {
4547             OSKextLog(this,
4548                 kOSKextLogErrorLevel |
4549                 kOSKextLogLoadFlag,
4550                 "Kext %s failed to set initial VM protections "
4551                 "for segment %s - 0x%x.",
4552                 getIdentifierCString(), seg->segname, (int)result);
4553             goto finish;
4554         }
4555 
4556         result = vm_map_wire(kext_map, start, end, seg->initprot, FALSE);
4557         if (result != KERN_SUCCESS) {
4558             goto finish;
4559         }
4560 
4561         seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
4562     }
4563 
4564 finish:
4565     return result;
4566 }
4567 
4568 /*********************************************************************
4569 *********************************************************************/
4570 OSReturn
4571 OSKext::validateKextMapping(bool startFlag)
4572 {
4573     OSReturn                              result      = kOSReturnError;
4574     const char                          * whichOp = startFlag ? "start" : "stop";
4575     kern_return_t                         kern_result = 0;
4576     vm_map_t                              kext_map    = NULL;
4577     mach_vm_address_t                     address     = 0;
4578     mach_vm_size_t                        size        = 0;
4579     uint32_t                              depth       = 0;
4580     mach_msg_type_number_t                count;
4581     vm_region_submap_short_info_data_64_t info;
4582 
4583     count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
4584     bzero(&info, sizeof(info));
4585 
4586    // xxx - do we need a distinct OSReturn value for these or is "bad data"
4587    // xxx - sufficient?
4588 
4589    /* Verify that the kmod_info and start/stop pointers are non-NULL.
4590     */
4591     if (!kmod_info) {
4592         OSKextLog(this,
4593             kOSKextLogErrorLevel |
4594             kOSKextLogLoadFlag,
4595             "Kext %s - NULL kmod_info pointer.",
4596             getIdentifierCString());
4597         result = kOSKextReturnBadData;
4598         goto finish;
4599     }
4600 
4601     if (startFlag) {
4602         address = (mach_vm_address_t)kmod_info->start;
4603     } else {
4604         address = (mach_vm_address_t)kmod_info->stop;
4605     }
4606 
4607     if (!address) {
4608         OSKextLog(this,
4609             kOSKextLogErrorLevel |
4610             kOSKextLogLoadFlag,
4611             "Kext %s - NULL module %s pointer.",
4612             getIdentifierCString(), whichOp);
4613         result = kOSKextReturnBadData;
4614         goto finish;
4615     }
4616 
4617     kext_map = kext_get_vm_map(kmod_info);
4618     depth = (kernel_map == kext_map) ? 1 : 2;
4619 
4620    /* Verify that the start/stop function lies within the kext's address range.
4621     */
4622     if (address < kmod_info->address + kmod_info->hdr_size ||
4623         kmod_info->address + kmod_info->size <= address)
4624     {
4625         OSKextLog(this,
4626             kOSKextLogErrorLevel |
4627             kOSKextLogLoadFlag,
4628             "Kext %s module %s pointer is outside of kext range "
4629             "(%s %p - kext at %p-%p)..",
4630             getIdentifierCString(),
4631             whichOp,
4632             whichOp,
4633             (void *)address,
4634             (void *)kmod_info->address,
4635             (void *)(kmod_info->address + kmod_info->size));
4636         result = kOSKextReturnBadData;
4637         goto finish;
4638     }
4639 
4640    /* Only do these checks before calling the start function;
4641     * If anything goes wrong with the mapping while the kext is running,
4642     * we'll likely have panicked well before any attempt to stop the kext.
4643     */
4644     if (startFlag) {
4645 
4646        /* Verify that the start/stop function is executable.
4647         */
4648         kern_result = mach_vm_region_recurse(kernel_map, &address, &size, &depth,
4649             (vm_region_recurse_info_t)&info, &count);
4650         if (kern_result != KERN_SUCCESS) {
4651             OSKextLog(this,
4652                 kOSKextLogErrorLevel |
4653                 kOSKextLogLoadFlag,
4654                 "Kext %s - bad %s pointer %p.",
4655                 getIdentifierCString(),
4656                 whichOp, (void *)address);
4657             result = kOSKextReturnBadData;
4658             goto finish;
4659         }
4660 
4661         if (!(info.protection & VM_PROT_EXECUTE)) {
4662             OSKextLog(this,
4663                 kOSKextLogErrorLevel |
4664                 kOSKextLogLoadFlag,
4665                 "Kext %s - memory region containing module %s function "
4666                 "is not executable.",
4667                 getIdentifierCString(), whichOp);
4668             result = kOSKextReturnBadData;
4669             goto finish;
4670         }
4671 
4672        /* Verify that the kext is backed by physical memory.
4673         */
4674         for (address = kmod_info->address;
4675              address < round_page(kmod_info->address + kmod_info->size);
4676              address += PAGE_SIZE)
4677         {
4678             if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
4679                 OSKextLog(this,
4680                     kOSKextLogErrorLevel |
4681                     kOSKextLogLoadFlag,
4682                     "Kext %s - page %p is not backed by physical memory.",
4683                     getIdentifierCString(),
4684                     (void *)address);
4685                 result = kOSKextReturnBadData;
4686                 goto finish;
4687             }
4688         }
4689     }
4690 
4691     result = kOSReturnSuccess;
4692 finish:
4693     return result;
4694 }
4695 
4696 /*********************************************************************
4697 *********************************************************************/
4698 OSReturn
4699 OSKext::start(bool startDependenciesFlag)
4700 {
4701     OSReturn                            result = kOSReturnError;
4702     kern_return_t                       (* startfunc)(kmod_info_t *, void *);
4703     unsigned int                        i, count;
4704     void                              * kmodStartData      = NULL;  // special handling needed
4705 #if CONFIG_MACF_KEXT
4706     mach_msg_type_number_t              kmodStartDataCount = 0;
4707 #endif /* CONFIG_MACF_KEXT */
4708 
4709     if (isStarted() || isInterface() || isKernelComponent()) {
4710         result = kOSReturnSuccess;
4711         goto finish;
4712     }
4713 
4714     if (!isLoaded()) {
4715         OSKextLog(this,
4716             kOSKextLogErrorLevel |
4717             kOSKextLogLoadFlag,
4718             "Attempt to start nonloaded kext %s.",
4719             getIdentifierCString());
4720         result = kOSKextReturnInvalidArgument;
4721         goto finish;
4722     }
4723 
4724     result = validateKextMapping(/* start? */ true);
4725     if (result != kOSReturnSuccess) {
4726         goto finish;
4727     }
4728 
4729     startfunc = kmod_info->start;
4730 
4731     count = getNumDependencies();
4732     for (i = 0; i < count; i++) {
4733         OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
4734         if (dependency == NULL) {
4735             OSKextLog(this,
4736                 kOSKextLogErrorLevel |
4737                 kOSKextLogLoadFlag,
4738                 "Kext %s start - internal error, dependency disappeared.",
4739                 getIdentifierCString());
4740             goto finish;
4741         }
4742         if (!dependency->isStarted()) {
4743             if (startDependenciesFlag) {
4744                 OSReturn dependencyResult =
4745                     dependency->start(startDependenciesFlag);
4746                 if (dependencyResult != KERN_SUCCESS) {
4747                     OSKextLog(this,
4748                         kOSKextLogErrorLevel |
4749                         kOSKextLogLoadFlag,
4750                         "Kext %s start - dependency %s failed to start (error 0x%x).",
4751                         getIdentifierCString(),
4752                         dependency->getIdentifierCString(),
4753                         dependencyResult);
4754                     goto finish;
4755                 }
4756             } else {
4757                 OSKextLog(this,
4758                     kOSKextLogErrorLevel |
4759                     kOSKextLogLoadFlag,
4760                     "Not starting %s - dependency %s not started yet.",
4761                     getIdentifierCString(),
4762                     dependency->getIdentifierCString());
4763                 result = kOSKextReturnStartStopError;  // xxx - make new return?
4764                 goto finish;
4765             }
4766         }
4767     }
4768 
4769 #if CONFIG_MACF_KEXT
4770    /* See if the kext has any MAC framework module data in its plist.
4771     * This is passed in as arg #2 of the kext's start routine,
4772     * which is otherwise reserved for any other kext.
4773     */
4774     kmodStartData = MACFCopyModuleDataForKext(this, &kmodStartDataCount);
4775 #endif /* CONFIG_MACF_KEXT */
4776 
4777     OSKextLog(this,
4778         kOSKextLogDetailLevel |
4779         kOSKextLogLoadFlag,
4780         "Kext %s calling module start function.",
4781         getIdentifierCString());
4782 
4783     flags.starting = 1;
4784 
4785 #if !__i386__ && !__ppc__
4786     result = OSRuntimeInitializeCPP(kmod_info, NULL);
4787     if (result == KERN_SUCCESS) {
4788 #endif
4789 
4790         result = startfunc(kmod_info, kmodStartData);
4791 
4792 #if !__i386__ && !__ppc__
4793         if (result != KERN_SUCCESS) {
4794             (void) OSRuntimeFinalizeCPP(kmod_info, NULL);
4795         }
4796     }
4797 #endif
4798 
4799     flags.starting = 0;
4800 
4801    /* On success overlap the setting of started/starting. On failure just
4802     * clear starting.
4803     */
4804     if (result == KERN_SUCCESS) {
4805         flags.started = 1;
4806 
4807         // xxx - log start error from kernel?
4808         OSKextLog(this,
4809             kOSKextLogProgressLevel |
4810             kOSKextLogLoadFlag,
4811             "Kext %s is now started.",
4812             getIdentifierCString());
4813     } else {
4814         invokeOrCancelRequestCallbacks(
4815             /* result not actually used */ kOSKextReturnStartStopError,
4816             /* invokeFlag */ false);
4817         OSKextLog(this,
4818             kOSKextLogProgressLevel |
4819             kOSKextLogLoadFlag,
4820             "Kext %s did not start (return code 0x%x).",
4821             getIdentifierCString(), result);
4822     }
4823 
4824 finish:
4825 #if CONFIG_MACF_KEXT
4826    /* Free the module data for a MAC framework kext. When we start using
4827     * param #2 we'll have to distinguish and free/release appropriately.
4828     *
4829     * xxx - I'm pretty sure the old codepath freed the data and that it's
4830     * xxx - up to the kext to copy it.
4831     */
4832     if (kmodStartData) {
4833         kmem_free(kernel_map, (vm_offset_t)kmodStartData, kmodStartDataCount);
4834     }
4835 #endif /* CONFIG_MACF_KEXT */
4836 
4837     return result;
4838 }
4839 
4840 /*********************************************************************
4841 *********************************************************************/
4842 /* static */
4843 bool OSKext::canUnloadKextWithIdentifier(
4844     OSString * kextIdentifier,
4845     bool       checkClassesFlag)
4846 {
4847     bool     result = false;
4848     OSKext * aKext  = NULL;  // do not release
4849 
4850     IORecursiveLockLock(sKextLock);
4851 
4852     aKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
4853 
4854     if (!aKext) {
4855         goto finish;  // can't unload what's not loaded
4856     }
4857 
4858     if (aKext->isLoaded()) {
4859         if (aKext->getRetainCount() > kOSKextMinLoadedRetainCount) {
4860             goto finish;
4861         }
4862         if (checkClassesFlag && aKext->hasOSMetaClassInstances()) {
4863             goto finish;
4864         }
4865     }
4866 
4867     result = true;
4868 
4869 finish:
4870     IORecursiveLockUnlock(sKextLock);
4871     return result;
4872 }
4873 
4874 /*********************************************************************
4875 *********************************************************************/
4876 OSReturn
4877 OSKext::stop(void)
4878 {
4879     OSReturn result = kOSReturnError;
4880     kern_return_t (*stopfunc)(kmod_info_t *, void *);
4881 
4882     if (!isStarted() || isInterface()) {
4883         result = kOSReturnSuccess;
4884         goto finish;
4885     }
4886 
4887     if (!isLoaded()) {
4888         OSKextLog(this,
4889             kOSKextLogErrorLevel |
4890             kOSKextLogLoadFlag,
4891             "Attempt to stop nonloaded kext %s.",
4892             getIdentifierCString());
4893         result = kOSKextReturnInvalidArgument;
4894         goto finish;
4895     }
4896 
4897    /* Refuse to stop if we have clients or instances. It is up to
4898     * the caller to make sure those aren't true.
4899     */
4900     if (getRetainCount() > kOSKextMinLoadedRetainCount) {
4901         OSKextLog(this,
4902             kOSKextLogErrorLevel |
4903             kOSKextLogLoadFlag,
4904             "Kext %s - C++ instances; can't stop.",
4905             getIdentifierCString());
4906         result = kOSKextReturnInUse;
4907         goto finish;
4908     }
4909 
4910     if (getRetainCount() > kOSKextMinLoadedRetainCount) {
4911 
4912         OSKextLog(this,
4913             kOSKextLogErrorLevel |
4914             kOSKextLogLoadFlag,
4915             "Kext %s - has references (linkage or tracking object); "
4916             "can't stop.",
4917             getIdentifierCString());
4918         result = kOSKextReturnInUse;
4919         goto finish;
4920     }
4921 
4922    /* Note: If validateKextMapping fails on the stop & unload path,
4923     * we are in serious trouble and a kernel panic is likely whether
4924     * we stop & unload the kext or not.
4925     */
4926     result = validateKextMapping(/* start? */ false);
4927     if (result != kOSReturnSuccess) {
4928         goto finish;
4929     }
4930 
4931    /* Save the list of loaded kexts in case we panic.
4932     */
4933     OSKext::saveUnloadedKextPanicList(this);
4934 
4935     stopfunc = kmod_info->stop;
4936     if (stopfunc) {
4937         OSKextLog(this,
4938             kOSKextLogDetailLevel |
4939             kOSKextLogLoadFlag,
4940             "Kext %s calling module stop function.",
4941             getIdentifierCString());
4942 
4943         flags.stopping = 1;
4944 
4945         result = stopfunc(kmod_info, /* userData */ NULL);
4946 #if !__i386__ && !__ppc__
4947         if (result == KERN_SUCCESS) {
4948             result = OSRuntimeFinalizeCPP(kmod_info, NULL);
4949         }
4950 #endif
4951 
4952         flags.stopping = 0;
4953 
4954         if (result == KERN_SUCCESS) {
4955             flags.started = 0;
4956 
4957             OSKextLog(this,
4958                 kOSKextLogDetailLevel |
4959                 kOSKextLogLoadFlag,
4960                 "Kext %s is now stopped and ready to unload.",
4961                 getIdentifierCString());
4962         } else {
4963             OSKextLog(this,
4964                 kOSKextLogErrorLevel |
4965                 kOSKextLogLoadFlag,
4966                 "Kext %s did not stop (return code 0x%x).",
4967                 getIdentifierCString(), result);
4968             result = kOSKextReturnStartStopError;
4969         }
4970     }
4971 
4972 finish:
4973     return result;
4974 }
4975 
4976 /*********************************************************************
4977 *********************************************************************/
4978 OSReturn
4979 OSKext::unload(void)
4980 {
4981     OSReturn     result = kOSReturnError;
4982     unsigned int index;
4983     uint32_t     num_kmod_refs = 0;
4984 
4985     if (!sUnloadEnabled) {
4986         OSKextLog(this,
4987             kOSKextLogErrorLevel |
4988             kOSKextLogLoadFlag,
4989             "Kext unloading is disabled (%s).",
4990             this->getIdentifierCString());
4991 
4992         result = kOSKextReturnDisabled;
4993         goto finish;
4994     }
4995 
4996    /* Refuse to unload if we have clients or instances. It is up to
4997     * the caller to make sure those aren't true.
4998     */
4999     if (getRetainCount() > kOSKextMinLoadedRetainCount) {
5000         // xxx - Don't log under errors? this is more of an info thing
5001         OSKextLog(this,
5002             kOSKextLogErrorLevel |
5003             kOSKextLogKextBookkeepingFlag,
5004             "Can't unload kext %s; outstanding references (linkage or tracking object).",
5005             getIdentifierCString());
5006         result = kOSKextReturnInUse;
5007         goto finish;
5008     }
5009 
5010 
5011     if (hasOSMetaClassInstances()) {
5012         OSKextLog(this,
5013             kOSKextLogErrorLevel |
5014             kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5015             "Can't unload kext %s; classes have instances:",
5016             getIdentifierCString());
5017         reportOSMetaClassInstances(kOSKextLogErrorLevel |
5018             kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag);
5019         result = kOSKextReturnInUse;
5020         goto finish;
5021     }
5022 
5023     if (!isLoaded()) {
5024         result = kOSReturnSuccess;
5025         goto finish;
5026     }
5027 
5028     if (isKernelComponent()) {
5029         result = kOSKextReturnInvalidArgument;
5030         goto finish;
5031     }
5032 
5033    /* Note that the kext is unloading before running any code that
5034     * might be in the kext (request callbacks, module stop function).
5035     * We will deny certain requests made against a kext in the process
5036     * of unloading.
5037     */
5038     flags.unloading = 1;
5039 
5040     if (isStarted()) {
5041         result = stop();
5042         if (result != KERN_SUCCESS) {
5043             OSKextLog(this,
5044                 kOSKextLogErrorLevel |
5045                 kOSKextLogLoadFlag,
5046                 "Kext %s can't unload - module stop returned 0x%x.",
5047                 getIdentifierCString(), (unsigned)result);
5048             result = kOSKextReturnStartStopError;
5049             goto finish;
5050         }
5051     }
5052 
5053     OSKextLog(this,
5054         kOSKextLogProgressLevel |
5055         kOSKextLogLoadFlag,
5056         "Kext %s unloading.",
5057         getIdentifierCString());
5058 
5059    /* Even if we don't call the stop function, we want to be sure we
5060     * have no OSMetaClass references before unloading the kext executable
5061     * from memory. OSMetaClasses may have pointers into the kext executable
5062     * and that would cause a panic on OSKext::free() when metaClasses is freed.
5063     */
5064     if (metaClasses) {
5065         metaClasses->flushCollection();
5066     }
5067 
5068    /* Remove the kext from the list of loaded kexts, patch the gap
5069     * in the kmod_info_t linked list, and reset "kmod" to point to the
5070     * last loaded kext that isn't the fake kernel kext (sKernelKext).
5071     */
5072     index = sLoadedKexts->getNextIndexOfObject(this, 0);
5073     if (index != (unsigned int)-1) {
5074 
5075         sLoadedKexts->removeObject(index);
5076 
5077         OSKext * nextKext = OSDynamicCast(OSKext,
5078             sLoadedKexts->getObject(index));
5079 
5080         if (nextKext) {
5081             if (index > 0) {
5082                 OSKext * gapKext = OSDynamicCast(OSKext,
5083                     sLoadedKexts->getObject(index - 1));
5084 
5085                 nextKext->kmod_info->next = gapKext->kmod_info;
5086 
5087             } else /* index == 0 */ {
5088                 nextKext->kmod_info->next = NULL;
5089             }
5090         }
5091 
5092         OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
5093         if (lastKext && lastKext != sKernelKext) {
5094             kmod = lastKext->kmod_info;
5095         } else {
5096             kmod = NULL;  // clear the global kmod variable
5097         }
5098     }
5099 
5100    /* Clear out the kmod references that we're keeping for compatibility
5101     * with current panic backtrace code & kgmacros.
5102     * xxx - will want to update those bits sometime and remove this.
5103     */
5104     num_kmod_refs = getNumDependencies();
5105     if (num_kmod_refs && kmod_info && kmod_info->reference_list) {
5106         for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
5107             kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
5108             ref->info->reference_count--;
5109         }
5110         kfree(kmod_info->reference_list,
5111             num_kmod_refs * sizeof(kmod_reference_t));
5112     }
5113 
5114    /* If we have a linked executable, release & clear it, and then
5115     * unwire & deallocate the buffer the OSData wrapped.
5116     */
5117     if (linkedExecutable) {
5118         vm_map_t kext_map;
5119 
5120        /* linkedExecutable is just a wrapper for the executable and doesn't
5121         * free it.
5122         */
5123         linkedExecutable->release();
5124         linkedExecutable = NULL;
5125 
5126         OSKextLog(this,
5127             kOSKextLogProgressLevel |
5128             kOSKextLogLoadFlag,
5129             "Kext %s unwiring and unmapping linked executable.",
5130             getIdentifierCString());
5131 
5132         kext_map = kext_get_vm_map(kmod_info);
5133         if (kext_map) {
5134             // xxx - do we have to do this before freeing? Why can't we just free it?
5135             // xxx - we should be able to set a dealloc func on the linkedExecutable
5136             result = vm_map_unwire(kext_map,
5137                 kmod_info->address + kmod_info->hdr_size,
5138                 kmod_info->address + kmod_info->size, FALSE);
5139             if (result == KERN_SUCCESS) {
5140                 kext_free(kmod_info->address, kmod_info->size);
5141             }
5142         }
5143     }
5144 
5145    /* An interface kext has a fake kmod_info that was allocated,
5146     * so we have to free it.
5147     */
5148     if (isInterface()) {
5149         kfree(kmod_info, sizeof(kmod_info_t));
5150     }
5151 
5152     kmod_info = NULL;
5153 
5154     flags.loaded = false;
5155     flushDependencies();
5156 
5157     OSKextLog(this,
5158         kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5159         "Kext %s unloaded.", getIdentifierCString());
5160 
5161 finish:
5162     OSKext::saveLoadedKextPanicList();
5163 
5164     flags.unloading = 0;
5165     return result;
5166 }
5167 
5168 /*********************************************************************
5169 *********************************************************************/
5170 static void
5171 _OSKextConsiderDestroyingLinkContext(
5172     __unused thread_call_param_t p0,
5173     __unused thread_call_param_t p1)
5174 {
5175    /* Once both recursive locks are taken in correct order, we shouldn't
5176     * have to worry about further recursive lock takes.
5177     */
5178     IORecursiveLockLock(sKextLock);
5179     IORecursiveLockLock(sKextInnerLock);
5180 
5181    /* The first time we destroy the kxldContext is in the first
5182     * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
5183     * before calling this function. Thereafter any call to this function
5184     * will actually destroy the context.
5185     */
5186     if (sConsiderUnloadsCalled && sKxldContext) {
5187         kxld_destroy_context(sKxldContext);
5188         sKxldContext = NULL;
5189     }
5190 
5191    /* Free the thread_call that was allocated to execute this function.
5192     */
5193     if (sDestroyLinkContextThread) {
5194         if (!thread_call_free(sDestroyLinkContextThread)) {
5195             OSKextLog(/* kext */ NULL,
5196                 kOSKextLogErrorLevel |
5197                 kOSKextLogGeneralFlag,
5198                 "thread_call_free() failed for kext link context.");
5199         }
5200         sDestroyLinkContextThread = 0;
5201     }
5202 
5203     IORecursiveLockUnlock(sKextInnerLock);
5204     IORecursiveLockUnlock(sKextLock);
5205 
5206     return;
5207 }
5208 
5209 /*********************************************************************
5210 * Destroying the kxldContext requires checking variables under both
5211 * sKextInnerLock and sKextLock, so we do it on a separate thread
5212 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
5213 * call relationship.
5214 *
5215 * Do not call any function that takes sKextLock here! This function
5216 * can be invoked with sKextInnerLock, and the two must always
5217 * be taken in the order: sKextLock -> sKextInnerLock.
5218 *********************************************************************/
5219 /* static */
5220 void
5221 OSKext::considerDestroyingLinkContext(void)
5222 {
5223     IORecursiveLockLock(sKextInnerLock);
5224 
5225    /* If we have already queued a thread to destroy the link context,
5226     * don't bother resetting; that thread will take care of it.
5227     */
5228     if (sDestroyLinkContextThread) {
5229         goto finish;
5230     }
5231 
5232    /* The function to be invoked in the thread will deallocate
5233     * this thread_call, so don't share it around.
5234     */
5235     sDestroyLinkContextThread = thread_call_allocate(
5236         &_OSKextConsiderDestroyingLinkContext, 0);
5237     if (!sDestroyLinkContextThread) {
5238         OSKextLog(/* kext */ NULL,
5239             kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogLinkFlag,
5240             "Can't create thread to destroy kext link context.");
5241         goto finish;
5242     }
5243 
5244     thread_call_enter(sDestroyLinkContextThread);
5245 
5246 finish:
5247     IORecursiveLockUnlock(sKextInnerLock);
5248     return;
5249 }
5250 
5251 /*********************************************************************
5252 *********************************************************************/
5253 OSData *
5254 OSKext::getKernelLinkState()
5255 {
5256     kern_return_t   kxldResult;
5257     u_char        * kernel          = NULL;
5258     size_t          kernelLength;
5259     u_char        * linkStateBytes  = NULL;
5260     u_long          linkStateLength;
5261     OSData        * linkState       = NULL;
5262 
5263     if (sKernelKext && sKernelKext->linkState) {
5264         goto finish;
5265     }
5266 
5267     kernel = (u_char *)&_mh_execute_header;
5268     kernelLength = getlastaddr() - (vm_offset_t)kernel;
5269 
5270     kxldResult = kxld_link_file(sKxldContext,
5271         kernel,
5272         kernelLength,
5273         kOSKextKernelIdentifier,
5274         /* callbackData */ NULL,
5275         /* dependencies */ NULL,
5276         /* numDependencies */ 0,
5277         /* linkedObjectOut */ NULL,
5278         /* kmod_info_kern out */ NULL,
5279         &linkStateBytes,
5280         &linkStateLength,
5281         /* symbolFile */ NULL,
5282         /* symbolFileSize */ NULL);
5283     if (kxldResult) {
5284         panic("Can't generate kernel link state; no kexts can be loaded.");
5285         goto finish;
5286     }
5287 
5288     linkState = OSData::withBytesNoCopy(linkStateBytes, linkStateLength);
5289     linkState->setDeallocFunction(&osdata_kmem_free);
5290     sKernelKext->linkState = linkState;
5291 
5292 finish:
5293     return sKernelKext->linkState;
5294 }
5295 
5296 #if PRAGMA_MARK
5297 #pragma mark Autounload
5298 #endif
5299 /*********************************************************************
5300 * This is a static method because the kext will be deallocated if it
5301 * does unload!
5302 *********************************************************************/
5303 OSReturn
5304 OSKext::autounloadKext(OSKext * aKext)
5305 {
5306     OSReturn result = kOSKextReturnInUse;
5307 
5308    /* Check for external references to this kext (usu. dependents),
5309     * instances of defined classes (or classes derived from them),
5310     * outstanding requests.
5311     */
5312     if ((aKext->getRetainCount() > kOSKextMinLoadedRetainCount) ||
5313         !aKext->flags.autounloadEnabled ||
5314         aKext->isKernelComponent()) {
5315 
5316         goto finish;
5317     }
5318 
5319    /* Skip a delay-autounload kext, once.
5320     */
5321     if (aKext->flags.delayAutounload) {
5322         OSKextLog(aKext,
5323             kOSKextLogProgressLevel |
5324             kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5325             "Kext %s has delayed autounload set; skipping and clearing flag.",
5326             aKext->getIdentifierCString());
5327         aKext->flags.delayAutounload = 0;
5328         goto finish;
5329     }
5330 
5331     if (aKext->hasOSMetaClassInstances() ||
5332         aKext->countRequestCallbacks()) {
5333         goto finish;
5334     }
5335 
5336     result = OSKext::removeKext(aKext);
5337 
5338 finish:
5339 
5340     return result;
5341 }
5342 
5343 /*********************************************************************
5344 *********************************************************************/
5345 void
5346 _OSKextConsiderUnloads(
5347     __unused thread_call_param_t p0,
5348     __unused thread_call_param_t p1)
5349 {
5350     bool         didUnload = false;
5351     unsigned int count, i;
5352 
5353    /* Once both recursive locks are taken in correct order, we shouldn't
5354     * have to worry about further recursive lock takes.
5355     */
5356     IORecursiveLockLock(sKextLock);
5357     IORecursiveLockLock(sKextInnerLock);
5358 
5359     OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
5360 
5361    /* If the system is powering down, don't try to unload anything.
5362     */
5363     if (sSystemSleep) {
5364         goto finish;
5365     }
5366 
5367     OSKextLog(/* kext */ NULL,
5368         kOSKextLogProgressLevel |
5369         kOSKextLogLoadFlag,
5370         "Checking for unused kexts to autounload.");
5371 
5372    /*****
5373     * Remove any request callbacks marked as stale,
5374     * and mark as stale any currently in flight.
5375     */
5376     count = sRequestCallbackRecords->getCount();
5377     if (count) {
5378         i = count - 1;
5379         do {
5380             OSDictionary * callbackRecord = OSDynamicCast(OSDictionary,
5381                 sRequestCallbackRecords->getObject(i));
5382             OSBoolean * stale = OSDynamicCast(OSBoolean,
5383                 callbackRecord->getObject(kKextRequestStaleKey));
5384 
5385             if (stale && stale->isTrue()) {
5386                 OSKext::invokeRequestCallback(callbackRecord,
5387                     kOSKextReturnTimeout);
5388             } else {
5389                 callbackRecord->setObject(kKextRequestStaleKey,
5390                     kOSBooleanTrue);
5391             }
5392         } while (i--);
5393     }
5394 
5395    /*****
5396     * Make multiple passes through the array of loaded kexts until
5397     * we don't unload any. This handles unwinding of dependency
5398     * chains. We have to go *backwards* through the array because
5399     * kexts are removed from it when unloaded, and we cannot make
5400     * a copy or we'll mess up the retain counts we rely on to
5401     * check whether a kext will unload. If only we could have
5402     * nonretaining collections like CF has....
5403     */
5404     do {
5405         didUnload = false;
5406 
5407         count = sLoadedKexts->getCount();
5408         if (count) {
5409             i = count - 1;
5410             do {
5411                 OSKext * thisKext = OSDynamicCast(OSKext,
5412                     sLoadedKexts->getObject(i));
5413                 didUnload = (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
5414             } while (i--);
5415         }
5416     } while (didUnload);
5417 
5418 finish:
5419     sConsiderUnloadsPending = false;
5420     sConsiderUnloadsExecuted = true;
5421 
5422     (void) OSKext::considerRebuildOfPrelinkedKernel();
5423 
5424     IORecursiveLockUnlock(sKextInnerLock);
5425     IORecursiveLockUnlock(sKextLock);
5426 
5427     return;
5428 }
5429 
5430 /*********************************************************************
5431 * Do not call any function that takes sKextLock here!
5432 *********************************************************************/
5433 void OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
5434 {
5435     AbsoluteTime when;
5436 
5437     IORecursiveLockLock(sKextInnerLock);
5438 
5439     if (!sUnloadCallout) {
5440         sUnloadCallout = thread_call_allocate(&_OSKextConsiderUnloads, 0);
5441     }
5442 
5443     if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
5444         goto finish;
5445     }
5446 
5447     thread_call_cancel(sUnloadCallout);
5448     if (OSKext::getAutounloadEnabled() && !sSystemSleep) {
5449         clock_interval_to_deadline(sConsiderUnloadDelay,
5450             1000 * 1000 * 1000, &when);
5451 
5452         OSKextLog(/* kext */ NULL,
5453             kOSKextLogProgressLevel |
5454             kOSKextLogLoadFlag,
5455             "%scheduling %sscan for unused kexts in %lu seconds.",
5456             sConsiderUnloadsPending ? "Res" : "S",
5457             sConsiderUnloadsCalled ? "" : "initial ",
5458             (unsigned long)sConsiderUnloadDelay);
5459 
5460         sConsiderUnloadsPending = true;
5461         thread_call_enter_delayed(sUnloadCallout, when);
5462     }
5463 
5464 finish:
5465    /* The kxld context should be reused throughout boot.  We mark the end of
5466     * period as the first time considerUnloads() is called, and we destroy
5467     * the first kxld context in that function.  Afterwards, it will be
5468     * destroyed in flushNonloadedKexts.
5469     */
5470     if (!sConsiderUnloadsCalled) {
5471         sConsiderUnloadsCalled = true;
5472         OSKext::considerDestroyingLinkContext();
5473     }
5474 
5475     IORecursiveLockUnlock(sKextInnerLock);
5476     return;
5477 }
5478 
5479 /*********************************************************************
5480 * Do not call any function that takes sKextLock here!
5481 *********************************************************************/
5482 extern "C" {
5483 
5484 IOReturn OSKextSystemSleepOrWake(UInt32 messageType)
5485 {
5486     IORecursiveLockLock(sKextInnerLock);
5487 
5488    /* If the system is going to sleep, cancel the reaper thread timer,
5489     * and note that we're in a sleep state in case it just fired but hasn't
5490     * taken the lock yet. If we are coming back from sleep, just
5491     * clear the sleep flag; IOService's normal operation will cause
5492     * unloads to be considered soon enough.
5493     */
5494     if (messageType == kIOMessageSystemWillSleep) {
5495         if (sUnloadCallout) {
5496             thread_call_cancel(sUnloadCallout);
5497         }
5498         sSystemSleep = true;
5499     } else if (messageType == kIOMessageSystemHasPoweredOn) {
5500         sSystemSleep = false;
5501     }
5502     IORecursiveLockUnlock(sKextInnerLock);
5503 
5504     return kIOReturnSuccess;
5505 }
5506 
5507 };
5508 
5509 
5510 #if PRAGMA_MARK
5511 #pragma mark Prelinked Kernel
5512 #endif
5513 /*********************************************************************
5514 * Do not access sConsiderUnloads... variables other than
5515 * sConsiderUnloadsExecuted in this function. They are guarded by a
5516 * different lock.
5517 *********************************************************************/
5518 /* static */
5519 void
5520 OSKext::considerRebuildOfPrelinkedKernel(void)
5521 {
5522     OSReturn       checkResult      = kOSReturnError;
5523     static bool    requestedPrelink = false;
5524     OSDictionary * prelinkRequest   = NULL;  // must release
5525 
5526     IORecursiveLockLock(sKextLock);
5527 
5528     if (!sDeferredLoadSucceeded || !sConsiderUnloadsExecuted ||
5529         sSafeBoot || requestedPrelink)
5530     {
5531         goto finish;
5532     }
5533 
5534     OSKextLog(/* kext */ NULL,
5535         kOSKextLogProgressLevel |
5536         kOSKextLogArchiveFlag,
5537         "Requesting build of prelinked kernel.");
5538 
5539     checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
5540         &prelinkRequest);
5541     if (checkResult != kOSReturnSuccess) {
5542         goto finish;
5543     }
5544 
5545     if (!sKernelRequests->setObject(prelinkRequest)) {
5546         goto finish;
5547     }
5548 
5549     OSKextPingKextd();
5550     requestedPrelink = true;
5551 
5552 finish:
5553     IORecursiveLockUnlock(sKextLock);
5554     OSSafeRelease(prelinkRequest);
5555     return;
5556 }
5557 
5558 #if PRAGMA_MARK
5559 #pragma mark Dependencies
5560 #endif
5561 /*********************************************************************
5562 *********************************************************************/
5563 bool
5564 OSKext::resolveDependencies(
5565     OSArray * loopStack)
5566 {
5567     bool                   result                   = false;
5568     OSArray              * localLoopStack           = NULL;   // must release
5569     bool                   addedToLoopStack         = false;
5570     OSDictionary         * libraries                = NULL;   // do not release
5571     OSCollectionIterator * libraryIterator          = NULL;   // must release
5572     OSString             * libraryID                = NULL;   // do not release
5573     OSString             * infoString               = NULL;   // do not release
5574     OSString             * readableString           = NULL;   // do not release
5575     OSKext               * libraryKext              = NULL;   // do not release
5576     bool                   hasRawKernelDependency   = false;
5577     bool                   hasKernelDependency      = false;
5578     bool                   hasKPIDependency         = false;
5579     bool                   hasPrivateKPIDependency  = false;
5580     unsigned int           count;
5581 
5582    /* A kernel component will automatically have this flag set,
5583     * and a loaded kext should also have it set (as should all its
5584     * loaded dependencies).
5585     */
5586     if (flags.hasAllDependencies) {
5587         result = true;
5588         goto finish;
5589     }
5590 
5591    /* Check for loops in the dependency graph.
5592     */
5593     if (loopStack) {
5594         if (loopStack->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
5595             OSKextLog(this,
5596                 kOSKextLogErrorLevel |
5597                 kOSKextLogDependenciesFlag,
5598                 "Kext %s has a dependency loop; can't resolve dependencies.",
5599                 getIdentifierCString());
5600             goto finish;
5601         }
5602     } else {
5603         OSKextLog(this,
5604             kOSKextLogStepLevel |
5605             kOSKextLogDependenciesFlag,
5606             "Kext %s resolving dependencies.",
5607             getIdentifierCString());
5608 
5609         loopStack = OSArray::withCapacity(6);  // any small capacity will do
5610         if (!loopStack) {
5611             OSKextLog(this,
5612                 kOSKextLogErrorLevel |
5613                 kOSKextLogDependenciesFlag,
5614                 "Kext %s can't create bookkeeping stack to resolve dependencies.",
5615                 getIdentifierCString());
5616             goto finish;
5617         }
5618         localLoopStack = loopStack;
5619     }
5620     if (!loopStack->setObject(this)) {
5621         OSKextLog(this,
5622             kOSKextLogErrorLevel |
5623             kOSKextLogDependenciesFlag,
5624             "Kext %s - internal error resolving dependencies.",
5625             getIdentifierCString());
5626         goto finish;
5627     }
5628     addedToLoopStack = true;
5629 
5630    /* Purge any existing kexts in the dependency list and start over.
5631     */
5632     flushDependencies();
5633     if (dependencies) {
5634         OSKextLog(this,
5635             kOSKextLogErrorLevel |
5636             kOSKextLogDependenciesFlag,
5637             "Kext %s - internal error resolving dependencies.",
5638             getIdentifierCString());
5639     }
5640 
5641     libraries = OSDynamicCast(OSDictionary,
5642         getPropertyForHostArch(kOSBundleLibrariesKey));
5643     if (libraries == NULL || libraries->getCount() == 0) {
5644         OSKextLog(this,
5645             kOSKextLogErrorLevel |
5646             kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
5647             "Kext %s - can't resolve dependencies; %s missing/invalid type.",
5648             getIdentifierCString(), kOSBundleLibrariesKey);
5649         goto finish;
5650     }
5651 
5652    /* Make a new array to hold the dependencies (flush freed the old one).
5653     */
5654     dependencies = OSArray::withCapacity(libraries->getCount());
5655     if (!dependencies) {
5656         OSKextLog(this,
5657             kOSKextLogErrorLevel |
5658             kOSKextLogDependenciesFlag,
5659             "Kext %s - can't allocate dependencies array.",
5660             getIdentifierCString());
5661         goto finish;
5662     }
5663 
5664     // xxx - compat: We used to add an implicit dependency on kernel 6.0
5665     // xxx - compat: if none were declared.
5666 
5667     libraryIterator = OSCollectionIterator::withCollection(libraries);
5668     if (!libraryIterator) {
5669         OSKextLog(this,
5670             kOSKextLogErrorLevel |
5671             kOSKextLogDependenciesFlag,
5672             "Kext %s - can't allocate dependencies iterator.",
5673             getIdentifierCString());
5674         goto finish;
5675     }
5676 
5677     while ((libraryID = OSDynamicCast(OSString,
5678            libraryIterator->getNextObject()))) {
5679 
5680        const char * library_id = libraryID->getCStringNoCopy();
5681 
5682         OSString * libraryVersion = OSDynamicCast(OSString,
5683             libraries->getObject(libraryID));
5684         if (libraryVersion == NULL) {
5685             OSKextLog(this,
5686                 kOSKextLogErrorLevel |
5687                 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
5688                 "Kext %s - illegal type in OSBundleLibraries.",
5689                 getIdentifierCString());
5690             goto finish;
5691         }
5692 
5693         OSKextVersion libraryVers =
5694             OSKextParseVersionString(libraryVersion->getCStringNoCopy());
5695         if (libraryVers == -1) {
5696             OSKextLog(this,
5697                 kOSKextLogErrorLevel |
5698                 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
5699                 "Kext %s - invalid library version %s.",
5700                 getIdentifierCString(),
5701                 libraryVersion->getCStringNoCopy());
5702             goto finish;
5703         }
5704 
5705         libraryKext = OSDynamicCast(OSKext, sKextsByID->getObject(libraryID));
5706         if (libraryKext == NULL) {
5707             OSKextLog(this,
5708                 kOSKextLogErrorLevel |
5709                 kOSKextLogDependenciesFlag,
5710                 "Kext %s - library kext %s not found.",
5711                 getIdentifierCString(), library_id);
5712             goto finish;
5713         }
5714 
5715         if (!libraryKext->isCompatibleWithVersion(libraryVers)) {
5716             OSKextLog(this,
5717                 kOSKextLogErrorLevel |
5718                 kOSKextLogDependenciesFlag,
5719                 "Kext %s - library kext %s not compatible "
5720                 "with requested version %s.",
5721                 getIdentifierCString(), library_id,
5722                 libraryVersion->getCStringNoCopy());
5723             goto finish;
5724         }
5725 
5726         if (!libraryKext->resolveDependencies(loopStack)) {
5727             goto finish;
5728         }
5729 
5730        /* Add the library directly only if it has an executable to link.
5731         * Otherwise it's just used to collect other dependencies, so put
5732         * *its* dependencies on the list for this kext.
5733         */
5734         // xxx - We are losing info here; would like to make fake entries or
5735         // xxx - keep these in the dependency graph for loaded kexts.
5736         // xxx - I really want to make kernel components not a special case!
5737         if (libraryKext->declaresExecutable() ||
5738             libraryKext->isInterface()) {
5739 
5740             if (dependencies->getNextIndexOfObject(libraryKext, 0) == (unsigned)-1) {
5741                 dependencies->setObject(libraryKext);
5742 
5743                 OSKextLog(this,
5744                     kOSKextLogDetailLevel |
5745                     kOSKextLogDependenciesFlag,
5746                     "Kext %s added dependency %s.",
5747                     getIdentifierCString(),
5748                     libraryKext->getIdentifierCString());
5749             }
5750         } else {
5751             int       numLibDependencies  = libraryKext->getNumDependencies();
5752             OSArray * libraryDependencies = libraryKext->getDependencies();
5753             int       index;
5754 
5755             if (numLibDependencies) {
5756                 // xxx - this msg level should be 1 lower than the per-kext one
5757                 OSKextLog(this,
5758                     kOSKextLogDetailLevel |
5759                     kOSKextLogDependenciesFlag,
5760                     "Kext %s pulling %d dependencies from codeless library %s.",
5761                     getIdentifierCString(),
5762                     numLibDependencies,
5763                     libraryKext->getIdentifierCString());
5764             }
5765             for (index = 0; index < numLibDependencies; index++) {
5766                 OSKext * thisLibDependency = OSDynamicCast(OSKext,
5767                     libraryDependencies->getObject(index));
5768                 if (dependencies->getNextIndexOfObject(thisLibDependency, 0) == (unsigned)-1) {
5769                     dependencies->setObject(thisLibDependency);
5770                     OSKextLog(this,
5771                         kOSKextLogDetailLevel |
5772                         kOSKextLogDependenciesFlag,
5773                         "Kext %s added dependency %s from codeless library %s.",
5774                         getIdentifierCString(),
5775                         thisLibDependency->getIdentifierCString(),
5776                         libraryKext->getIdentifierCString());
5777                 }
5778             }
5779         }
5780 
5781         if ((strlen(library_id) == strlen(KERNEL_LIB)) &&
5782             0 == strncmp(library_id, KERNEL_LIB, sizeof(KERNEL_LIB)-1)) {
5783 
5784             hasRawKernelDependency = true;
5785         } else if (STRING_HAS_PREFIX(library_id, KERNEL_LIB_PREFIX)) {
5786             hasKernelDependency = true;
5787         } else if (STRING_HAS_PREFIX(library_id, KPI_LIB_PREFIX)) {
5788             hasKPIDependency = true;
5789             if (!strncmp(library_id, PRIVATE_KPI, sizeof(PRIVATE_KPI)-1)) {
5790                 hasPrivateKPIDependency = true;
5791             }
5792         }
5793     }
5794 
5795 #if __LP64__
5796     if (hasRawKernelDependency || hasKernelDependency) {
5797         OSKextLog(this,
5798             kOSKextLogErrorLevel |
5799             kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
5800             "Error - kext %s declares %s dependencies. "
5801             "Only %s* dependencies are supported for 64-bit kexts.",
5802             getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
5803         goto finish;
5804     }
5805     if (!hasKPIDependency) {
5806         OSKextLog(this,
5807             kOSKextLogWarningLevel |
5808             kOSKextLogDependenciesFlag,
5809             "Warning - kext %s declares no %s* dependencies. "
5810             "If it uses any KPIs, the link may fail with undefined symbols.",
5811             getIdentifierCString(), KPI_LIB_PREFIX);
5812     }
5813 #else /* __LP64__ */
5814     // xxx - will change to flatly disallow "kernel" dependencies at some point
5815     // xxx - is it invalid to do both "com.apple.kernel" and any
5816     // xxx - "com.apple.kernel.*"?
5817 
5818     if (hasRawKernelDependency && hasKernelDependency) {
5819         OSKextLog(this,
5820             kOSKextLogErrorLevel |
5821             kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
5822             "Error - kext %s declares dependencies on both "
5823             "%s and %s.",
5824             getIdentifierCString(), KERNEL_LIB, KERNEL6_LIB);
5825         goto finish;
5826     }
5827 
5828     if ((hasRawKernelDependency || hasKernelDependency) && hasKPIDependency) {
5829         OSKextLog(this,
5830             kOSKextLogWarningLevel |
5831             kOSKextLogDependenciesFlag,
5832             "Warning - kext %s has immediate dependencies on both "
5833             "%s* and %s* components; use only one style.",
5834             getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
5835     }
5836 
5837     if (!hasRawKernelDependency && !hasKernelDependency && !hasKPIDependency) {
5838         // xxx - do we want to use validation flag for these too?
5839         OSKextLog(this,
5840             kOSKextLogWarningLevel |
5841             kOSKextLogDependenciesFlag,
5842             "Warning - %s declares no kernel dependencies; using %s.",
5843             getIdentifierCString(), KERNEL6_LIB);
5844         OSKext * kernelKext = OSDynamicCast(OSKext,
5845             sKextsByID->getObject(KERNEL6_LIB));
5846         if (kernelKext) {
5847             dependencies->setObject(kernelKext);
5848         } else {
5849             OSKextLog(this,
5850                 kOSKextLogErrorLevel |
5851                 kOSKextLogDependenciesFlag,
5852                 "Error - Library %s not found for %s.",
5853                 KERNEL6_LIB, getIdentifierCString());
5854         }
5855     }
5856 
5857    /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
5858     * its indirect dependencies to simulate old-style linking.  XXX - Should
5859     * check for duplicates.
5860     */
5861     if (!hasRawKernelDependency && !hasKPIDependency) {
5862         unsigned int i;
5863 
5864         count = getNumDependencies();
5865 
5866        /* We add to the dependencies array in this loop, but do not iterate
5867         * past its original count.
5868         */
5869         for (i = 0; i < count; i++) {
5870             OSKext * dependencyKext = OSDynamicCast(OSKext,
5871                 dependencies->getObject(i));
5872             dependencyKext->addBleedthroughDependencies(dependencies);
5873         }
5874     }
5875 #endif /* __LP64__ */
5876 
5877     if (hasPrivateKPIDependency) {
5878         bool hasApplePrefix = false;
5879         bool infoCopyrightIsValid = false;
5880         bool readableCopyrightIsValid = false;
5881 
5882         hasApplePrefix = STRING_HAS_PREFIX(getIdentifierCString(),
5883             APPLE_KEXT_PREFIX);
5884 
5885         infoString = OSDynamicCast(OSString,
5886             getPropertyForHostArch("CFBundleGetInfoString"));
5887         if (infoString) {
5888             infoCopyrightIsValid =
5889                 kxld_validate_copyright_string(infoString->getCStringNoCopy());
5890         }
5891 
5892         readableString = OSDynamicCast(OSString,
5893             getPropertyForHostArch("NSHumanReadableCopyright"));
5894         if (readableString) {
5895             readableCopyrightIsValid =
5896                 kxld_validate_copyright_string(readableString->getCStringNoCopy());
5897         }
5898 
5899         if (!hasApplePrefix || (!infoCopyrightIsValid && !readableCopyrightIsValid)) {
5900             OSKextLog(this,
5901                 kOSKextLogErrorLevel |
5902                 kOSKextLogDependenciesFlag,
5903                 "Error - kext %s declares a dependency on %s. "
5904                   "Only Apple kexts may declare a dependency on %s.",
5905                   getIdentifierCString(), PRIVATE_KPI, PRIVATE_KPI);
5906             goto finish;
5907         }
5908     }
5909 
5910     result = true;
5911     flags.hasAllDependencies = 1;
5912 
5913 finish:
5914 
5915     if (addedToLoopStack) {
5916         count = loopStack->getCount();
5917         if (count > 0 && (this == loopStack->getObject(count - 1))) {
5918             loopStack->removeObject(count - 1);
5919         } else {
5920             OSKextLog(this,
5921                 kOSKextLogErrorLevel |
5922                 kOSKextLogDependenciesFlag,
5923                 "Kext %s - internal error resolving dependencies.",
5924                 getIdentifierCString());
5925         }
5926     }
5927 
5928     if (result && localLoopStack) {
5929         OSKextLog(this,
5930             kOSKextLogStepLevel |
5931             kOSKextLogDependenciesFlag,
5932             "Kext %s successfully resolved dependencies.",
5933             getIdentifierCString());
5934     }
5935 
5936     OSSafeRelease(localLoopStack);
5937     OSSafeRelease(libraryIterator);
5938 
5939     return result;
5940 }
5941 
5942 /*********************************************************************
5943 *********************************************************************/
5944 bool
5945 OSKext::addBleedthroughDependencies(OSArray * anArray)
5946 {
5947     bool result = false;
5948     unsigned int dependencyIndex, dependencyCount;
5949 
5950     dependencyCount = getNumDependencies();
5951 
5952     for (dependencyIndex = 0;
5953          dependencyIndex < dependencyCount;
5954          dependencyIndex++) {
5955 
5956         OSKext * dependency = OSDynamicCast(OSKext,
5957             dependencies->getObject(dependencyIndex));
5958         if (!dependency) {
5959             OSKextLog(this,
5960                 kOSKextLogErrorLevel |
5961                 kOSKextLogDependenciesFlag,
5962                 "Kext %s - internal error propagating compatibility dependencies.",
5963                 getIdentifierCString());
5964             goto finish;
5965         }
5966         if (anArray->getNextIndexOfObject(dependency, 0) == (unsigned int)-1) {
5967             anArray->setObject(dependency);
5968         }
5969         dependency->addBleedthroughDependencies(anArray);
5970     }
5971 
5972     result = true;
5973 
5974 finish:
5975     return result;
5976 }
5977 
5978 /*********************************************************************
5979 *********************************************************************/
5980 bool
5981 OSKext::flushDependencies(bool forceFlag)
5982 {
5983     bool result = false;
5984 
5985    /* Only clear the dependencies if the kext isn't loaded;
5986     * we need the info for loaded kexts to track references.
5987     */
5988     if (!isLoaded() || forceFlag) {
5989         if (dependencies) {
5990             // xxx - check level
5991             OSKextLog(this,
5992                 kOSKextLogProgressLevel |
5993                 kOSKextLogDependenciesFlag,
5994                 "Kext %s flushing dependencies.",
5995                 getIdentifierCString());
5996             OSSafeReleaseNULL(dependencies);
5997 
5998         }
5999         if (!isKernelComponent()) {
6000             flags.hasAllDependencies = 0;
6001         }
6002         result = true;
6003     }
6004 
6005     return result;
6006 }
6007 
6008 /*********************************************************************
6009 *********************************************************************/
6010 uint32_t
6011 OSKext::getNumDependencies(void)
6012 {
6013     if (!dependencies) {
6014         return 0;
6015     }
6016     return dependencies->getCount();
6017 }
6018 
6019 /*********************************************************************
6020 *********************************************************************/
6021 OSArray *
6022 OSKext::getDependencies(void)
6023 {
6024     return dependencies;
6025 }
6026 
6027 #if PRAGMA_MARK
6028 #pragma mark OSMetaClass Support
6029 #endif
6030 /*********************************************************************
6031 *********************************************************************/
6032 OSReturn
6033 OSKext::addClass(
6034     OSMetaClass * aClass,
6035     uint32_t      numClasses)
6036 {
6037     OSReturn result = kOSMetaClassNoInsKModSet;
6038 
6039     if (!metaClasses) {
6040         metaClasses = OSSet::withCapacity(numClasses);
6041         if (!metaClasses) {
6042             goto finish;
6043         }
6044     }
6045 
6046     if (metaClasses->containsObject(aClass)) {
6047         OSKextLog(this,
6048             kOSKextLogWarningLevel |
6049             kOSKextLogLoadFlag,
6050             "Notice - kext %s has already registered class %s.",
6051             getIdentifierCString(),
6052             aClass->getClassName());
6053         result = kOSReturnSuccess;
6054         goto finish;
6055     }
6056 
6057     if (!metaClasses->setObject(aClass)) {
6058         goto finish;
6059     } else {
6060         OSKextLog(this,
6061             kOSKextLogDetailLevel |
6062             kOSKextLogLoadFlag,
6063             "Kext %s registered class %s.",
6064             getIdentifierCString(),
6065             aClass->getClassName());
6066     }
6067 
6068     if (!flags.autounloadEnabled) {
6069         const OSMetaClass * metaScan  = NULL;  // do not release
6070 
6071         for (metaScan = aClass; metaScan; metaScan = metaScan->getSuperClass()) {
6072             if (metaScan == OSTypeID(IOService)) {
6073 
6074                 OSKextLog(this,
6075                     kOSKextLogProgressLevel |
6076                     kOSKextLogLoadFlag,
6077                     "Kext %s has IOService subclass %s; enabling autounload.",
6078                     getIdentifierCString(),
6079                     aClass->getClassName());
6080 
6081                 flags.autounloadEnabled = 1;
6082                 break;
6083             }
6084         }
6085     }
6086 
6087     result = kOSReturnSuccess;
6088 
6089 finish:
6090     if (result != kOSReturnSuccess) {
6091         OSKextLog(this,
6092             kOSKextLogErrorLevel |
6093             kOSKextLogLoadFlag,
6094             "Kext %s failed to register class %s.",
6095             getIdentifierCString(),
6096             aClass->getClassName());
6097     }
6098 
6099     return result;
6100 }
6101 
6102 /*********************************************************************
6103 *********************************************************************/
6104 OSReturn
6105 OSKext::removeClass(
6106     OSMetaClass * aClass)
6107 {
6108     OSReturn result = kOSMetaClassNoKModSet;
6109 
6110     if (!metaClasses) {
6111         goto finish;
6112     }
6113 
6114     if (!metaClasses->containsObject(aClass)) {
6115         OSKextLog(this,
6116             kOSKextLogWarningLevel |
6117             kOSKextLogLoadFlag,
6118             "Notice - kext %s asked to unregister unknown class %s.",
6119             getIdentifierCString(),
6120             aClass->getClassName());
6121         result = kOSReturnSuccess;
6122         goto finish;
6123     }
6124 
6125     OSKextLog(this,
6126         kOSKextLogDetailLevel |
6127         kOSKextLogLoadFlag,
6128         "Kext %s unregistering class %s.",
6129         getIdentifierCString(),
6130         aClass->getClassName());
6131 
6132     metaClasses->removeObject(aClass);
6133 
6134     result = kOSReturnSuccess;
6135 
6136 finish:
6137     if (result != kOSReturnSuccess) {
6138         OSKextLog(this,
6139             kOSKextLogErrorLevel |
6140             kOSKextLogLoadFlag,
6141             "Failed to unregister kext %s class %s.",
6142             getIdentifierCString(),
6143             aClass->getClassName());
6144     }
6145     return result;
6146 }
6147 
6148 /*********************************************************************
6149 *********************************************************************/
6150 OSSet *
6151 OSKext::getMetaClasses(void)
6152 {
6153     return metaClasses;
6154 }
6155 
6156 /*********************************************************************
6157 *********************************************************************/
6158 bool
6159 OSKext::hasOSMetaClassInstances(void)
6160 {
6161     bool                   result        = false;
6162     OSCollectionIterator * classIterator = NULL;  // must release
6163     OSMetaClass          * checkClass    = NULL;  // do not release
6164 
6165     if (!metaClasses) {
6166         goto finish;
6167     }
6168 
6169     classIterator = OSCollectionIterator::withCollection(metaClasses);
6170     if (!classIterator) {
6171         // xxx - log alloc failure?
6172         goto finish;
6173     }
6174     while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
6175         if (checkClass->getInstanceCount()) {
6176             result = true;
6177             goto finish;
6178         }
6179     }
6180 
6181 finish:
6182 
6183     OSSafeRelease(classIterator);
6184     return result;
6185 }
6186 
6187 /*********************************************************************
6188 *********************************************************************/
6189 /* static */
6190 void
6191 OSKext::reportOSMetaClassInstances(
6192     const char     * kextIdentifier,
6193     OSKextLogSpec    msgLogSpec)
6194 {
6195     OSKext * theKext = NULL; // must release
6196 
6197     theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
6198     if (!theKext) {
6199         goto finish;
6200     }
6201 
6202     theKext->reportOSMetaClassInstances(msgLogSpec);
6203 finish:
6204     OSSafeRelease(theKext);
6205     return;
6206 }
6207 
6208 /*********************************************************************
6209 *********************************************************************/
6210 void
6211 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
6212 {
6213     OSCollectionIterator * classIterator = NULL;  // must release
6214     OSMetaClass          * checkClass    = NULL;  // do not release
6215 
6216     if (!metaClasses) {
6217         goto finish;
6218     }
6219 
6220     classIterator = OSCollectionIterator::withCollection(metaClasses);
6221     if (!classIterator) {
6222         goto finish;
6223     }
6224     while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
6225         if (checkClass->getInstanceCount()) {
6226             OSKextLog(this,
6227                 msgLogSpec,
6228                 "    Kext %s class %s has %d instance%s.",
6229                 getIdentifierCString(),
6230                 checkClass->getClassName(),
6231                 checkClass->getInstanceCount(),
6232                 checkClass->getInstanceCount() == 1 ? "" : "s");
6233         }
6234     }
6235 
6236 finish:
6237     OSSafeRelease(classIterator);
6238     return;
6239 }
6240 
6241 #if PRAGMA_MARK
6242 #pragma mark User-Space Requests
6243 #endif
6244 /*********************************************************************
6245 * XXX - this function is a big ugly mess
6246 *********************************************************************/
6247 /* static */
6248 OSReturn
6249 OSKext::handleRequest(
6250     host_priv_t     hostPriv,
6251     OSKextLogSpec   clientLogFilter,
6252     char          * requestBuffer,
6253     uint32_t        requestLength,
6254     char         ** responseOut,
6255     uint32_t      * responseLengthOut,
6256     char         ** logInfoOut,
6257     uint32_t      * logInfoLengthOut)
6258 {
6259     OSReturn       result             = kOSReturnError;
6260     kern_return_t  kmem_result        = KERN_FAILURE;
6261 
6262     char         * response           = NULL;  // returned by reference
6263     uint32_t       responseLength     = 0;
6264 
6265     OSObject     * parsedXML      = NULL;  // must release
6266     OSDictionary * requestDict        = NULL;  // do not release
6267     OSString     * errorString        = NULL;  // must release
6268 
6269     OSData       * responseData       = NULL;  // must release
6270     OSObject     * responseObject = NULL;  // must release
6271 
6272     OSSerialize  * serializer         = NULL;  // must release
6273 
6274     OSArray      * logInfoArray       = NULL;  // must release
6275 
6276     OSString     * predicate          = NULL;  // do not release
6277     OSString     * kextIdentifier     = NULL;  // do not release
6278     OSArray      * kextIdentifiers    = NULL;  // do not release
6279     OSKext       * theKext            = NULL;  // do not release
6280     OSBoolean    * boolArg            = NULL;  // do not release
6281 
6282     IORecursiveLockLock(sKextLock);
6283 
6284     if (responseOut) {
6285         *responseOut = NULL;
6286         *responseLengthOut = 0;
6287     }
6288     if (logInfoOut) {
6289         *logInfoOut = NULL;
6290         *logInfoLengthOut = 0;
6291     }
6292 
6293     OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
6294 
6295    /* XML must be nul-terminated.
6296     */
6297     if (requestBuffer[requestLength - 1] != '\0') {
6298         OSKextLog(/* kext */ NULL,
6299             kOSKextLogErrorLevel |
6300             kOSKextLogIPCFlag,
6301             "Invalid request from user space (not nul-terminated).");
6302         result = kOSKextReturnBadData;
6303         goto finish;
6304     }
6305     parsedXML = OSUnserializeXML((const char *)requestBuffer, &errorString);
6306     if (parsedXML) {
6307         requestDict = OSDynamicCast(OSDictionary, parsedXML);
6308     }
6309     if (!requestDict) {
6310         const char * errorCString = "(unknown error)";
6311 
6312         if (errorString && errorString->getCStringNoCopy()) {
6313             errorCString = errorString->getCStringNoCopy();
6314         } else if (parsedXML) {
6315             errorCString = "not a dictionary";
6316         }
6317         OSKextLog(/* kext */ NULL,
6318             kOSKextLogErrorLevel |
6319             kOSKextLogIPCFlag,
6320             "Error unserializing request from user space: %s.",
6321             errorCString);
6322         result = kOSKextReturnSerialization;
6323         goto finish;
6324     }
6325 
6326     predicate = _OSKextGetRequestPredicate(requestDict);
6327     if (!predicate) {
6328         OSKextLog(/* kext */ NULL,
6329             kOSKextLogErrorLevel |
6330             kOSKextLogIPCFlag,
6331             "Recieved kext request from user space with no predicate.");
6332         result = kOSKextReturnInvalidArgument;
6333         goto finish;
6334     }
6335 
6336     OSKextLog(/* kext */ NULL,
6337         kOSKextLogDebugLevel |
6338         kOSKextLogIPCFlag,
6339         "Received '%s' request from user space.",
6340         predicate->getCStringNoCopy());
6341 
6342     result = kOSKextReturnNotPrivileged;
6343     if (hostPriv == HOST_PRIV_NULL) {
6344         if (!predicate->isEqualTo(kKextRequestPredicateGetLoaded) &&
6345             !predicate->isEqualTo(kKextRequestPredicateGetKernelLinkState) &&
6346             !predicate->isEqualTo(kKextRequestPredicateGetKernelLoadAddress)) {
6347 
6348             goto finish;
6349         }
6350     }
6351 
6352    /* Get common args in anticipation of use.
6353     */
6354     kextIdentifier = OSDynamicCast(OSString, _OSKextGetRequestArgument(
6355         requestDict, kKextRequestArgumentBundleIdentifierKey));
6356     kextIdentifiers = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
6357         requestDict, kKextRequestArgumentBundleIdentifierKey));
6358     if (kextIdentifier) {
6359         theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
6360     }
6361     boolArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
6362         requestDict, kKextRequestArgumentValueKey));
6363 
6364     result = kOSKextReturnInvalidArgument;
6365 
6366     if (predicate->isEqualTo(kKextRequestPredicateStart)) {
6367         if (!kextIdentifier) {
6368             OSKextLog(/* kext */ NULL,
6369                 kOSKextLogErrorLevel |
6370                 kOSKextLogIPCFlag,
6371                 "Invalid arguments to kext start request.");
6372         } else if (!theKext) {
6373             OSKextLog(/* kext */ NULL,
6374                 kOSKextLogErrorLevel |
6375                 kOSKextLogIPCFlag,
6376                 "Kext %s not found for start request.",
6377                 kextIdentifier->getCStringNoCopy());
6378             result = kOSKextReturnNotFound;
6379         } else {
6380             result = theKext->start();
6381         }
6382 
6383     } else if (predicate->isEqualTo(kKextRequestPredicateStop)) {
6384         if (!kextIdentifier) {
6385             OSKextLog(/* kext */ NULL,
6386                 kOSKextLogErrorLevel |
6387                 kOSKextLogIPCFlag,
6388                 "Invalid arguments to kext stop request.");
6389         } else if (!theKext) {
6390             OSKextLog(/* kext */ NULL,
6391                 kOSKextLogErrorLevel |
6392                 kOSKextLogIPCFlag,
6393                 "Kext %s not found for stop request.",
6394                 kextIdentifier->getCStringNoCopy());
6395             result = kOSKextReturnNotFound;
6396         } else {
6397             result = theKext->stop();
6398         }
6399 
6400     } else if (predicate->isEqualTo(kKextRequestPredicateUnload)) {
6401         if (!kextIdentifier) {
6402             OSKextLog(/* kext */ NULL,
6403                 kOSKextLogErrorLevel |
6404                 kOSKextLogIPCFlag,
6405                 "Invalid arguments to kext unload request.");
6406         } else if (!theKext) {
6407             OSKextLog(/* kext */ NULL,
6408                 kOSKextLogErrorLevel |
6409                 kOSKextLogIPCFlag,
6410                 "Kext %s not found for unload request.",
6411                 kextIdentifier->getCStringNoCopy());
6412             result = kOSKextReturnNotFound;
6413         } else {
6414             OSBoolean * terminateFlag = OSDynamicCast(OSBoolean,
6415                 _OSKextGetRequestArgument(requestDict,
6416                     kKextRequestArgumentTerminateIOServicesKey));
6417             result = OSKext::removeKext(theKext, terminateFlag == kOSBooleanTrue);
6418         }
6419 
6420     } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
6421         result = OSKext::dispatchResource(requestDict);
6422 
6423     } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
6424         OSBoolean * delayAutounloadBool = NULL;
6425 
6426         delayAutounloadBool = OSDynamicCast(OSBoolean,
6427             _OSKextGetRequestArgument(requestDict,
6428                 kKextRequestArgumentDelayAutounloadKey));
6429 
6430        /* If asked to delay autounload, reset the timer if it's currently set.
6431         * (That is, don't schedule an unload if one isn't already pending.
6432         */
6433         if (delayAutounloadBool == kOSBooleanTrue) {
6434             OSKext::considerUnloads(/* rescheduleOnly? */ true);
6435         }
6436 
6437         responseObject = OSDynamicCast(OSObject,
6438             OSKext::copyLoadedKextInfo(kextIdentifiers));
6439         if (!responseObject) {
6440             result = kOSKextReturnInternalError;
6441         } else {
6442             OSKextLog(/* kext */ NULL,
6443                 kOSKextLogDebugLevel |
6444                 kOSKextLogIPCFlag,
6445                 "Returning loaded kext info.");
6446             result = kOSReturnSuccess;
6447         }
6448 
6449     } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelLoadAddress)) {
6450         OSNumber * addressNum = NULL;  // released as responseObject
6451         kernel_segment_command_t * textseg = getsegbyname("__TEXT");
6452 
6453         if (!textseg) {
6454             OSKextLog(/* kext */ NULL,
6455                 kOSKextLogErrorLevel |
6456                 kOSKextLogGeneralFlag | kOSKextLogIPCFlag,
6457                 "Can't find text segment for kernel load address.");
6458             result = kOSReturnError;
6459             goto finish;
6460         }
6461 
6462         OSKextLog(/* kext */ NULL,
6463             kOSKextLogDebugLevel |
6464             kOSKextLogIPCFlag,
6465             "Returning kernel load address 0x%llx.",
6466             (unsigned long long)textseg->vmaddr);
6467         addressNum = OSNumber::withNumber((long long unsigned int)textseg->vmaddr,
6468             8 * sizeof(long long unsigned int));
6469         responseObject = OSDynamicCast(OSObject, addressNum);
6470         result = kOSReturnSuccess;
6471 
6472     } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelLinkState)) {
6473         OSKextLog(/* kext */ NULL,
6474             kOSKextLogDebugLevel |
6475             kOSKextLogIPCFlag,
6476             "Returning kernel link state.");
6477         responseData = sKernelKext->linkState;
6478         responseData->retain();
6479         result = kOSReturnSuccess;
6480 
6481     } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
6482 
6483        /* Hand the current sKernelRequests array to the caller
6484         * (who must release it), and make a new one.
6485         */
6486         responseObject = OSDynamicCast(OSObject, sKernelRequests);
6487         sKernelRequests = OSArray::withCapacity(0);
6488         sPostedKextLoadIdentifiers->flushCollection();
6489         OSKextLog(/* kext */ NULL,
6490             kOSKextLogDebugLevel |
6491             kOSKextLogIPCFlag,
6492             "Returning kernel requests.");
6493         result = kOSReturnSuccess;
6494 
6495     } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
6496 
6497         /* Return the set of all requested bundle identifiers */
6498         responseObject = OSDynamicCast(OSObject, sAllKextLoadIdentifiers);
6499         responseObject->retain();
6500         OSKextLog(/* kext */ NULL,
6501             kOSKextLogDebugLevel |
6502             kOSKextLogIPCFlag,
6503             "Returning load requests.");
6504         result = kOSReturnSuccess;
6505     }
6506 
6507    /**********
6508     * Now we have handle the request, or not. Gather up the response & logging
6509     * info to ship to user space.
6510     *********/
6511 
6512    /* Note: Nothing in OSKext is supposed to retain requestDict,
6513     * but you never know....
6514     */
6515     if (requestDict->getRetainCount() > 1) {
6516         OSKextLog(/* kext */ NULL,
6517             kOSKextLogWarningLevel |
6518             kOSKextLogIPCFlag,
6519             "Request from user space still retained by a kext; "
6520             "probable memory leak.");
6521     }
6522 
6523     if (responseData && responseObject) {
6524         OSKextLog(/* kext */ NULL,
6525             kOSKextLogErrorLevel |
6526             kOSKextLogIPCFlag,
6527             "Mistakenly generated both data & plist responses to user request "
6528             "(returning only data).");
6529     }
6530 
6531     if (responseData && responseData->getLength() && responseOut) {
6532 
6533         response = (char *)responseData->getBytesNoCopy();
6534         responseLength = responseData->getLength();
6535     } else if (responseOut && responseObject) {
6536         serializer = OSSerialize::withCapacity(0);
6537         if (!serializer) {
6538             result = kOSKextReturnNoMemory;
6539             goto finish;
6540         }
6541 
6542         if (!responseObject->serialize(serializer)) {
6543             OSKextLog(/* kext */ NULL,
6544                 kOSKextLogErrorLevel |
6545                 kOSKextLogIPCFlag,
6546                 "Failed to serialize response to request from user space.");
6547             result = kOSKextReturnSerialization;
6548             goto finish;
6549         }
6550 
6551         response = (char *)serializer->text();
6552         responseLength = serializer->getLength();
6553     }
6554 
6555     if (responseOut && response) {
6556         char * buffer;
6557 
6558        /* This kmem_alloc sets the return value of the function.
6559         */
6560         kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer,
6561             responseLength);
6562         if (kmem_result != KERN_SUCCESS) {
6563             OSKextLog(/* kext */ NULL,
6564                 kOSKextLogErrorLevel |
6565                 kOSKextLogIPCFlag,
6566                 "Failed to copy response to request from user space.");
6567             result = kmem_result;
6568             goto finish;
6569         } else {
6570             memcpy(buffer, response, responseLength);
6571             *responseOut = buffer;
6572             *responseLengthOut = responseLength;
6573         }
6574     }
6575 
6576 finish:
6577 
6578    /* Gather up the collected log messages for user space. Any messages
6579     * messages past this call will not make it up as log messages but
6580     * will be in the system log. Note that we ignore the return of the
6581     * serialize; it has no bearing on the operation at hand even if we
6582     * fail to get the log messages.
6583     */
6584     logInfoArray = OSKext::clearUserSpaceLogFilter();
6585 
6586     if (logInfoArray && logInfoOut && logInfoLengthOut) {
6587         (void)OSKext::serializeLogInfo(logInfoArray,
6588             logInfoOut, logInfoLengthOut);
6589     }
6590 
6591     IORecursiveLockUnlock(sKextLock);
6592 
6593     OSSafeRelease(requestDict);
6594     OSSafeRelease(errorString);
6595     OSSafeRelease(responseData);
6596     OSSafeRelease(responseObject);
6597     OSSafeRelease(serializer);
6598     OSSafeRelease(logInfoArray);
6599 
6600     return result;
6601 }
6602 
6603 /*********************************************************************
6604 *********************************************************************/
6605 /* static */
6606 OSArray *
6607 OSKext::copyLoadedKextInfo(OSArray * kextIdentifiers)
6608 {
6609     OSArray      * result = NULL;
6610     OSDictionary * kextInfo = NULL;  // must release
6611     uint32_t       count, i;
6612     uint32_t       idCount = 0;
6613     uint32_t       idIndex = 0;
6614 
6615     IORecursiveLockLock(sKextLock);
6616 
6617    /* Empty list of bundle ids is equivalent to no list (get all).
6618     */
6619     if (kextIdentifiers && !kextIdentifiers->getCount()) {
6620         kextIdentifiers = NULL;
6621     } else if (kextIdentifiers) {
6622         idCount = kextIdentifiers->getCount();
6623     }
6624 
6625     count = sLoadedKexts->getCount();
6626     result = OSArray::withCapacity(count);
6627     if (!result) {
6628         goto finish;
6629     }
6630     for (i = 0; i < count; i++) {
6631         OSKext   * thisKext     = NULL;  // do not release
6632         Boolean    includeThis  = true;
6633 
6634         if (kextInfo) {
6635             kextInfo->release();
6636             kextInfo = NULL;
6637         }
6638         thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
6639         if (!thisKext) {
6640             continue;
6641         }
6642 
6643        /* Skip current kext if we have a list of bundle IDs and
6644         * it isn't in the list.
6645         */
6646         if (kextIdentifiers) {
6647             const OSString * thisKextID = thisKext->getIdentifier();
6648 
6649             includeThis = false;
6650 
6651             for (idIndex = 0; idIndex < idCount; idIndex++) {
6652                 const OSString * thisRequestID = OSDynamicCast(OSString,
6653                     kextIdentifiers->getObject(idIndex));
6654                 if (thisKextID->isEqualTo(thisRequestID)) {
6655                     includeThis = true;
6656                     break;
6657                 }
6658             }
6659         }
6660 
6661         if (!includeThis) {
6662             continue;
6663         }
6664 
6665         kextInfo = thisKext->copyInfo();
6666         result->setObject(kextInfo);
6667     }
6668 
6669 finish:
6670     IORecursiveLockUnlock(sKextLock);
6671 
6672     if (kextInfo) kextInfo->release();
6673 
6674     return result;
6675 }
6676 
6677 /*********************************************************************
6678 Load Tag
6679 Bundle ID
6680 Bundle Version
6681 Path
6682 Load Address
6683 Load Size
6684 Wired Size
6685 Version
6686 Dependency Load Tags
6687 # Dependent References
6688 UUID
6689 RetainCount
6690 *********************************************************************/
6691 #define _OSKextLoadInfoDictCapacity   (12)
6692 
6693 OSDictionary *
6694 OSKext::copyInfo(void)
6695 {
6696     OSDictionary         * result             = NULL;
6697     bool                   success            = false;
6698     OSNumber             * cpuTypeNumber      = NULL;  // must release
6699     OSNumber             * cpuSubtypeNumber   = NULL;  // must release
6700     OSString             * versionString      = NULL;  // do not release
6701     OSData               * uuid               = NULL;  // must release
6702     OSNumber             * scratchNumber      = NULL;  // must release
6703     OSArray              * dependencyLoadTags = NULL;  // must release
6704     OSCollectionIterator * metaClassIterator  = NULL;  // must release
6705     OSArray              * metaClassInfo      = NULL;  // must release
6706     OSDictionary         * metaClassDict      = NULL;  // must release
6707     OSMetaClass          * thisMetaClass      = NULL;  // do not release
6708     OSString             * metaClassName      = NULL;  // must release
6709     OSString             * superclassName     = NULL;  // must release
6710     uint32_t               count, i;
6711 
6712     result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
6713     if (!result) {
6714         goto finish;
6715     }
6716 
6717    /* CPU Type & Subtype.
6718     * Use the CPU type of the kernel for all (loaded) kexts.
6719     * xxx - should we not include this for the kernel components,
6720     * xxx - or for any interface? they have mach-o files, they're just weird.
6721     */
6722     if (linkedExecutable || (this == sKernelKext)) {
6723 
6724         cpuTypeNumber = OSNumber::withNumber(
6725             (long long unsigned int)_mh_execute_header.cputype,
6726             8 * sizeof(_mh_execute_header.cputype));
6727         if (cpuTypeNumber) {
6728             result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber);
6729         }
6730     }
6731 
6732     // I don't want to rely on a mach header for nonkernel kexts, yet
6733     if (this == sKernelKext) {
6734         cpuSubtypeNumber = OSNumber::withNumber(
6735             (long long unsigned int)_mh_execute_header.cputype,
6736             8 * sizeof(_mh_execute_header.cputype));
6737         if (cpuSubtypeNumber) {
6738             result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber);
6739         }
6740     }
6741 
6742    /* CFBundleIdentifier.
6743     */
6744     result->setObject(kCFBundleIdentifierKey, bundleID);
6745 
6746    /* CFBundleVersion.
6747     */
6748     versionString = OSDynamicCast(OSString,
6749         getPropertyForHostArch(kCFBundleVersionKey));
6750     if (versionString) {
6751         result->setObject(kCFBundleVersionKey, versionString);
6752     }
6753 
6754    /* OSBundleCompatibleVersion.
6755     */
6756     versionString = OSDynamicCast(OSString,
6757         getPropertyForHostArch(kOSBundleCompatibleVersionKey));
6758     if (versionString) {
6759         result->setObject(kOSBundleCompatibleVersionKey, versionString);
6760     }
6761 
6762    /* Path.
6763     */
6764     if (path) {
6765         result->setObject(kOSBundlePathKey, path);
6766     }
6767 
6768    /* UUID.
6769     */
6770     uuid = copyUUID();
6771     if (uuid) {
6772         result->setObject(kOSBundleUUIDKey, uuid);
6773     }
6774 
6775    /*****
6776     * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
6777     */
6778     result->setObject(kOSKernelResourceKey,
6779         isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
6780 
6781     result->setObject(kOSBundleIsInterfaceKey,
6782         isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
6783 
6784     result->setObject(kOSBundlePrelinkedKey,
6785         isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
6786 
6787     result->setObject(kOSBundleStartedKey,
6788         isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
6789 
6790    /* LoadTag (Index).
6791     */
6792     scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
6793         /* numBits */ 8 * sizeof(loadTag));
6794     if (scratchNumber) {
6795         result->setObject(kOSBundleLoadTagKey, scratchNumber);
6796         OSSafeReleaseNULL(scratchNumber);
6797     }
6798 
6799    /* LoadAddress, LoadSize.
6800     */
6801     if (isInterface() || linkedExecutable) {
6802        /* These go to userspace via serialization, so we don't want any doubts
6803         * about their size.
6804         */
6805         uint64_t    loadAddress = 0;
6806         uint32_t    loadSize    = 0;
6807         uint32_t    wiredSize   = 0;
6808 
6809        /* Interfaces always report 0 load address & size.
6810         * Just the way they roll.
6811         *
6812         * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
6813         * xxx - shouldn't have one!
6814         */
6815         if (linkedExecutable /* && !isInterface() */) {
6816             loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
6817             loadSize = linkedExecutable->getLength();
6818 
6819            /* If we have a kmod_info struct, calculated the wired size
6820             * from that. Otherwise it's the full load size.
6821             */
6822             if (kmod_info) {
6823                 wiredSize = loadSize - kmod_info->hdr_size;
6824             } else {
6825                 wiredSize = loadSize;
6826             }
6827         }
6828 
6829         scratchNumber = OSNumber::withNumber(
6830             (unsigned long long)(loadAddress),
6831             /* numBits */ 8 * sizeof(loadAddress));
6832         if (scratchNumber) {
6833             result->setObject(kOSBundleLoadAddressKey, scratchNumber);
6834             OSSafeReleaseNULL(scratchNumber);
6835         }
6836         scratchNumber = OSNumber::withNumber(
6837             (unsigned long long)(loadSize),
6838             /* numBits */ 8 * sizeof(loadSize));
6839         if (scratchNumber) {
6840             result->setObject(kOSBundleLoadSizeKey, scratchNumber);
6841             OSSafeReleaseNULL(scratchNumber);
6842         }
6843         scratchNumber = OSNumber::withNumber(
6844             (unsigned long long)(wiredSize),
6845             /* numBits */ 8 * sizeof(wiredSize));
6846         if (scratchNumber) {
6847             result->setObject(kOSBundleWiredSizeKey, scratchNumber);
6848             OSSafeReleaseNULL(scratchNumber);
6849         }
6850     }
6851 
6852    /* OSBundleDependencies. In descending order for
6853     * easy compatibility with kextstat(8).
6854     */
6855     if ((count = getNumDependencies())) {
6856         dependencyLoadTags = OSArray::withCapacity(count);
6857         result->setObject(kOSBundleDependenciesKey, dependencyLoadTags);
6858 
6859         i = count - 1;
6860         do {
6861             OSKext * dependency = OSDynamicCast(OSKext,
6862                 dependencies->getObject(i));
6863 
6864             OSSafeReleaseNULL(scratchNumber);
6865 
6866             if (!dependency) {
6867                 continue;
6868             }
6869             scratchNumber = OSNumber::withNumber(
6870                 (unsigned long long)dependency->getLoadTag(),
6871                 /* numBits*/ 8 * sizeof(loadTag));
6872             if (scratchNumber) {
6873                 dependencyLoadTags->setObject(scratchNumber);
6874             }
6875         } while (i--);
6876     }
6877 
6878     OSSafeReleaseNULL(scratchNumber);
6879 
6880    /* OSBundleMetaClasses.
6881     */
6882     if (metaClasses && metaClasses->getCount()) {
6883         metaClassIterator = OSCollectionIterator::withCollection(metaClasses);
6884         metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
6885         if (!metaClassIterator || !metaClassInfo) {
6886             goto finish;
6887         }
6888         result->setObject(kOSBundleClassesKey, metaClassInfo);
6889 
6890         while ( (thisMetaClass = OSDynamicCast(OSMetaClass,
6891             metaClassIterator->getNextObject())) ) {
6892 
6893             OSSafeReleaseNULL(metaClassDict);
6894             OSSafeReleaseNULL(metaClassName);
6895             OSSafeReleaseNULL(superclassName);
6896             OSSafeReleaseNULL(scratchNumber);
6897 
6898             metaClassDict = OSDictionary::withCapacity(3);
6899             if (!metaClassDict) {
6900                 goto finish;
6901             }
6902 
6903             metaClassName = OSString::withCString(thisMetaClass->getClassName());
6904             if (thisMetaClass->getSuperClass()) {
6905                 superclassName = OSString::withCString(
6906                     thisMetaClass->getSuperClass()->getClassName());
6907             }
6908             scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
6909                 8 * sizeof(unsigned int));
6910             if (!metaClassDict || !metaClassName || !superclassName ||
6911                 !scratchNumber) {
6912 
6913                 goto finish;
6914             }
6915 
6916             metaClassInfo->setObject(metaClassDict);
6917             metaClassDict->setObject(kOSMetaClassNameKey, metaClassName);
6918             metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName);
6919             metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber);
6920         }
6921     }
6922 
6923    /* OSBundleRetainCount.
6924     */
6925     OSSafeReleaseNULL(scratchNumber);
6926     {
6927         int extRetainCount = getRetainCount() - 1;
6928         if (isLoaded()) {
6929             extRetainCount--;
6930         }
6931         scratchNumber = OSNumber::withNumber(
6932             (int)extRetainCount,
6933             /* numBits*/ 8 * sizeof(int));
6934         if (scratchNumber) {
6935             result->setObject(kOSBundleRetainCountKey, scratchNumber);
6936         }
6937     }
6938 
6939     success = true;
6940 finish:
6941     OSSafeRelease(cpuTypeNumber);
6942     OSSafeRelease(cpuSubtypeNumber);
6943     OSSafeRelease(uuid);
6944     OSSafeRelease(scratchNumber);
6945     OSSafeRelease(dependencyLoadTags);
6946     OSSafeRelease(metaClassIterator);
6947     OSSafeRelease(metaClassInfo);
6948     OSSafeRelease(metaClassDict);
6949     OSSafeRelease(metaClassName);
6950     OSSafeRelease(superclassName);
6951     if (!success) {
6952         OSSafeReleaseNULL(result);
6953     }
6954     return result;
6955 }
6956 
6957 /*********************************************************************
6958 *********************************************************************/
6959 /* static */
6960 OSReturn
6961 OSKext::requestResource(
6962     const char                    * kextIdentifierCString,
6963     const char                    * resourceNameCString,
6964     OSKextRequestResourceCallback   callback,
6965     void                          * context,
6966     OSKextRequestTag              * requestTagOut)
6967 {
6968     OSReturn           result          = kOSReturnError;
6969     OSKext           * callbackKext    = NULL;  // must release (looked up)
6970 
6971     OSKextRequestTag   requestTag      = -1;
6972     OSNumber         * requestTagNum   = NULL;  // must release
6973 
6974     OSDictionary     * requestDict     = NULL;  // must release
6975     OSString         * kextIdentifier  = NULL;  // must release
6976     OSString         * resourceName    = NULL;  // must release
6977 
6978     OSDictionary     * callbackRecord  = NULL;  // must release
6979     OSData           * callbackWrapper = NULL;  // must release
6980 
6981     OSData           * contextWrapper  = NULL;  // must release
6982 
6983     IORecursiveLockLock(sKextLock);
6984 
6985     if (requestTagOut) {
6986         *requestTagOut = kOSKextRequestTagInvalid;
6987     }
6988 
6989     if (!kextIdentifierCString || !resourceNameCString || !callback) {
6990         result = kOSKextReturnInvalidArgument;
6991         goto finish;
6992     }
6993 
6994     callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
6995     if (!callbackKext) {
6996         OSKextLog(/* kext */ NULL,
6997             kOSKextLogErrorLevel | kOSKextLogIPCFlag,
6998             "Resource request has bad callback address.");
6999         result = kOSKextReturnInvalidArgument;
7000         goto finish;
7001     }
7002     if (!callbackKext->flags.starting && !callbackKext->flags.started) {
7003         OSKextLog(/* kext */ NULL,
7004             kOSKextLogErrorLevel | kOSKextLogIPCFlag,
7005             "Resource request callback is in a kext that is not started.");
7006         result = kOSKextReturnInvalidArgument;
7007         goto finish;
7008     }
7009 
7010    /* Do not allow any new requests to be made on a kext that is unloading.
7011     */
7012     if (callbackKext->flags.stopping) {
7013         result = kOSKextReturnStopping;
7014         goto finish;
7015     }
7016 
7017    /* If we're wrapped the next available request tag around to the negative
7018     * numbers, we can't service any more requests.
7019     */
7020     if (sNextRequestTag == kOSKextRequestTagInvalid) {
7021         OSKextLog(/* kext */ NULL,
7022             kOSKextLogErrorLevel | kOSKextLogIPCFlag,
7023             "No more request tags available; restart required.");
7024         result = kOSKextReturnNoResources;
7025         goto finish;
7026     }
7027     requestTag = sNextRequestTag++;
7028 
7029     result = _OSKextCreateRequest(kKextRequestPredicateRequestResource,
7030         &requestDict);
7031     if (result != kOSReturnSuccess) {
7032         goto finish;
7033     }
7034 
7035     kextIdentifier = OSString::withCString(kextIdentifierCString);
7036     resourceName   = OSString::withCString(resourceNameCString);
7037     requestTagNum  = OSNumber::withNumber((long long unsigned int)requestTag,
7038         8 * sizeof(requestTag));
7039     if (!kextIdentifier ||
7040         !resourceName   ||
7041         !requestTagNum  ||
7042         !_OSKextSetRequestArgument(requestDict,
7043             kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
7044         !_OSKextSetRequestArgument(requestDict,
7045             kKextRequestArgumentNameKey, resourceName) ||
7046         !_OSKextSetRequestArgument(requestDict,
7047             kKextRequestArgumentRequestTagKey, requestTagNum)) {
7048 
7049         result = kOSKextReturnNoMemory;
7050         goto finish;
7051     }
7052 
7053     callbackRecord = OSDynamicCast(OSDictionary, requestDict->copyCollection());
7054     if (!callbackRecord) {
7055         result = kOSKextReturnNoMemory;
7056         goto finish;
7057     }
7058     // we validate callback address at call time
7059     callbackWrapper = OSData::withBytes((void *)&callback, sizeof(void *));
7060     if (context) {
7061         contextWrapper = OSData::withBytes((void *)&context, sizeof(void *));
7062     }
7063     if (!callbackWrapper || !_OSKextSetRequestArgument(callbackRecord,
7064             kKextRequestArgumentCallbackKey, callbackWrapper)) {
7065 
7066         result = kOSKextReturnNoMemory;
7067         goto finish;
7068     }
7069 
7070     if (context) {
7071         if (!contextWrapper || !_OSKextSetRequestArgument(callbackRecord,
7072             kKextRequestArgumentContextKey, contextWrapper)) {
7073 
7074             result = kOSKextReturnNoMemory;
7075             goto finish;
7076         }
7077     }
7078 
7079    /* Only post the requests after all the other potential failure points
7080     * have been passed.
7081     */
7082     if (!sKernelRequests->setObject(requestDict) ||
7083         !sRequestCallbackRecords->setObject(callbackRecord)) {
7084 
7085         result = kOSKextReturnNoMemory;
7086         goto finish;
7087     }
7088 
7089     OSKextPingKextd();
7090 
7091     result = kOSReturnSuccess;
7092     if (requestTagOut) {
7093         *requestTagOut = requestTag;
7094     }
7095 
7096 finish:
7097 
7098    /* If we didn't succeed, yank the request & callback
7099     * from their holding arrays.
7100     */
7101     if (result != kOSReturnSuccess) {
7102         unsigned int index;
7103 
7104         index = sKernelRequests->getNextIndexOfObject(requestDict, 0);
7105         if (index != (unsigned int)-1) {
7106             sKernelRequests->removeObject(index);
7107         }
7108         index = sRequestCallbackRecords->getNextIndexOfObject(callbackRecord, 0);
7109         if (index != (unsigned int)-1) {
7110             sRequestCallbackRecords->removeObject(index);
7111         }
7112     }
7113 
7114     OSKext::considerUnloads(/* rescheduleOnly? */ true);
7115 
7116     IORecursiveLockUnlock(sKextLock);
7117 
7118     if (callbackKext)    callbackKext->release();
7119     if (requestTagNum)   requestTagNum->release();
7120 
7121     if (requestDict)     requestDict->release();
7122     if (kextIdentifier)  kextIdentifier->release();
7123     if (resourceName)    resourceName->release();
7124 
7125     if (callbackRecord)  callbackRecord->release();
7126     if (callbackWrapper) callbackWrapper->release();
7127     if (contextWrapper)  contextWrapper->release();
7128 
7129     return result;
7130 }
7131 
7132 /*********************************************************************
7133 *********************************************************************/
7134 /* static */
7135 OSReturn
7136 OSKext::dequeueCallbackForRequestTag(
7137     OSKextRequestTag    requestTag,
7138     OSDictionary     ** callbackRecordOut)
7139 {
7140     OSReturn   result = kOSReturnError;
7141     OSNumber * requestTagNum  = NULL;  // must release
7142 
7143     requestTagNum  = OSNumber::withNumber((long long unsigned int)requestTag,
7144         8 * sizeof(requestTag));
7145     if (!requestTagNum) {
7146         goto finish;
7147     }
7148 
7149     result = OSKext::dequeueCallbackForRequestTag(requestTagNum,
7150         callbackRecordOut);
7151 
7152 finish:
7153     OSSafeRelease(requestTagNum);
7154 
7155     return result;
7156 }
7157 
7158 /*********************************************************************
7159 *********************************************************************/
7160 /* static */
7161 OSReturn
7162 OSKext::dequeueCallbackForRequestTag(
7163     OSNumber     *    requestTagNum,
7164     OSDictionary ** callbackRecordOut)
7165 {
7166     OSReturn        result          = kOSKextReturnInvalidArgument;
7167     OSDictionary  * callbackRecord  = NULL;  // retain if matched!
7168     OSNumber      * callbackTagNum  = NULL;  // do not release
7169     unsigned int    count, i;
7170 
7171     IORecursiveLockLock(sKextLock);
7172 
7173     result = kOSReturnError;
7174     count = sRequestCallbackRecords->getCount();
7175     for (i = 0; i < count; i++) {
7176         callbackRecord = OSDynamicCast(OSDictionary,
7177             sRequestCallbackRecords->getObject(i));
7178         if (!callbackRecord) {
7179             goto finish;
7180         }
7181 
7182        /* If we don't find a tag, we basically have a leak here. Maybe
7183         * we should just remove it.
7184         */
7185         callbackTagNum = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(
7186             callbackRecord, kKextRequestArgumentRequestTagKey));
7187         if (!callbackTagNum) {
7188             goto finish;
7189         }
7190 
7191        /* We could be even more paranoid and check that all the incoming
7192         * args match what's in the callback record.
7193         */
7194         if (callbackTagNum->isEqualTo(requestTagNum)) {
7195             if (callbackRecordOut) {
7196                 *callbackRecordOut = callbackRecord;
7197                 callbackRecord->retain();
7198             }
7199             sRequestCallbackRecords->removeObject(i);
7200             result = kOSReturnSuccess;
7201             goto finish;
7202         }
7203     }
7204     result = kOSKextReturnNotFound;
7205 
7206 finish:
7207     IORecursiveLockUnlock(sKextLock);
7208     return result;
7209 }
7210 
7211 /*********************************************************************
7212 *********************************************************************/
7213 /* static */
7214 OSReturn
7215 OSKext::dispatchResource(OSDictionary * requestDict)
7216 {
7217     OSReturn                        result          = kOSReturnError;
7218     OSDictionary                  * callbackRecord  = NULL;  // must release
7219     OSNumber                      * requestTag      = NULL;  // do not release
7220     OSNumber                      * requestResult   = NULL;  // do not release
7221     OSData                        * dataObj         = NULL;  // do not release
7222     uint32_t                        dataLength      = 0;
7223     const void                    * dataPtr         = NULL;  // do not free
7224     OSData                        * callbackWrapper = NULL;  // do not release
7225     OSKextRequestResourceCallback   callback        = NULL;
7226     OSData                        * contextWrapper  = NULL;  // do not release
7227     void                          * context         = NULL;  // do not free
7228     OSKext                        * callbackKext    = NULL;  // must release (looked up)
7229 
7230     IORecursiveLockLock(sKextLock);
7231 
7232    /* Get the args from the request. Right now we need the tag
7233     * to look up the callback record, and the result for invoking the callback.
7234     */
7235     requestTag = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
7236         kKextRequestArgumentRequestTagKey));
7237     requestResult = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
7238         kKextRequestArgumentResultKey));
7239     if (!requestTag || !requestResult) {
7240         result = kOSKextReturnInvalidArgument;
7241         goto finish;
7242     }
7243 
7244    /* Look for a callback record matching this request's tag.
7245     */
7246     result = dequeueCallbackForRequestTag(requestTag, &callbackRecord);
7247     if (result != kOSReturnSuccess) {
7248         goto finish;
7249     }
7250 
7251    /*****
7252     * Get the context pointer of the callback record (if there is one).
7253     */
7254     contextWrapper = OSDynamicCast(OSData, _OSKextGetRequestArgument(callbackRecord,
7255         kKextRequestArgumentContextKey));
7256     context = _OSKextExtractPointer(contextWrapper);
7257     if (contextWrapper && !context) {
7258         goto finish;
7259     }
7260 
7261     callbackWrapper = OSDynamicCast(OSData,
7262         _OSKextGetRequestArgument(callbackRecord,
7263             kKextRequestArgumentCallbackKey));
7264     callback = (OSKextRequestResourceCallback)
7265         _OSKextExtractPointer(callbackWrapper);
7266     if (!callback) {
7267         goto finish;
7268     }
7269 
7270    /* Check for a data obj. We might not have one and that's ok, that means
7271     * we didn't find the requested resource, and we still have to tell the
7272     * caller that via the callback.
7273     */
7274     dataObj = OSDynamicCast(OSData, _OSKextGetRequestArgument(requestDict,
7275         kKextRequestArgumentValueKey));
7276     if (dataObj) {
7277         dataPtr = dataObj->getBytesNoCopy();
7278         dataLength = dataObj->getLength();
7279     }
7280 
7281     callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
7282     if (!callbackKext) {
7283         OSKextLog(/* kext */ NULL,
7284             kOSKextLogErrorLevel | kOSKextLogIPCFlag,
7285             "Can't invoke callback for resource request; "
7286             "no kext loaded at callback address %p.",
7287             callback);
7288         goto finish;
7289     }
7290     if (!callbackKext->flags.starting && !callbackKext->flags.started) {
7291         OSKextLog(/* kext */ NULL,
7292             kOSKextLogErrorLevel | kOSKextLogIPCFlag,
7293             "Can't invoke kext resource callback; "
7294             "kext at callback address %p is not running.",
7295             callback);
7296         goto finish;
7297     }
7298 
7299     (void)callback(requestTag->unsigned32BitValue(),
7300         (OSReturn)requestResult->unsigned32BitValue(),
7301         dataPtr, dataLength, context);
7302 
7303     result = kOSReturnSuccess;
7304 
7305 finish:
7306     if (callbackKext)   callbackKext->release();
7307     if (callbackRecord) callbackRecord->release();
7308 
7309     IORecursiveLockUnlock(sKextLock);
7310     return result;
7311 }
7312 
7313 /*********************************************************************
7314 *********************************************************************/
7315 /* static */
7316 void
7317 OSKext::invokeRequestCallback(
7318     OSDictionary * callbackRecord,
7319     OSReturn       callbackResult)
7320 {
7321     OSString * predicate  = _OSKextGetRequestPredicate(callbackRecord);
7322     OSNumber * resultNum  = NULL;  // must release
7323 
7324     if (!predicate) {
7325         goto finish;
7326     }
7327 
7328     resultNum  = OSNumber::withNumber((long long unsigned int)callbackResult,
7329         8 * sizeof(callbackResult));
7330     if (!resultNum) {
7331         goto finish;
7332     }
7333 
7334    /* Insert the result into the callback record and dispatch it as if it
7335     * were the reply coming down from user space.
7336     */
7337     _OSKextSetRequestArgument(callbackRecord, kKextRequestArgumentResultKey,
7338         resultNum);
7339 
7340     if (predicate->isEqualTo(kKextRequestPredicateRequestResource)) {
7341        /* This removes the pending callback record.
7342         */
7343         OSKext::dispatchResource(callbackRecord);
7344     }
7345 
7346 finish:
7347     if (resultNum) resultNum->release();
7348     return;
7349 }
7350 
7351 /*********************************************************************
7352 *********************************************************************/
7353 /* static */
7354 OSReturn
7355 OSKext::cancelRequest(
7356     OSKextRequestTag    requestTag,
7357     void             ** contextOut)
7358 {
7359     OSReturn       result         = kOSKextReturnNoMemory;
7360     OSDictionary * callbackRecord = NULL;  // must release
7361     OSData       * contextWrapper = NULL;  // do not release
7362 
7363     result = OSKext::dequeueCallbackForRequestTag(requestTag,
7364         &callbackRecord);
7365 
7366     if (result == kOSReturnSuccess && contextOut) {
7367         contextWrapper = OSDynamicCast(OSData,
7368             _OSKextGetRequestArgument(callbackRecord,
7369                 kKextRequestArgumentContextKey));
7370         *contextOut = _OSKextExtractPointer(contextWrapper);
7371     }
7372 
7373     if (callbackRecord) callbackRecord->release();
7374 
7375     return result;
7376 }
7377 
7378 /*********************************************************************
7379 *********************************************************************/
7380 void
7381 OSKext::invokeOrCancelRequestCallbacks(
7382     OSReturn callbackResult,
7383     bool     invokeFlag)
7384 {
7385     unsigned int count, i;
7386 
7387     IORecursiveLockLock(sKextLock);
7388 
7389     count = sRequestCallbackRecords->getCount();
7390     if (!count) {
7391         goto finish;
7392     }
7393 
7394     i = count - 1;
7395     do {
7396         OSDictionary * request = OSDynamicCast(OSDictionary,
7397             sRequestCallbackRecords->getObject(i));
7398 
7399         if (!request) {
7400             continue;
7401         }
7402         OSData * callbackWrapper = OSDynamicCast(OSData,
7403             _OSKextGetRequestArgument(request,
7404                 kKextRequestArgumentCallbackKey));
7405 
7406         if (!callbackWrapper) {
7407             sRequestCallbackRecords->removeObject(i);
7408             continue;
7409         }
7410 
7411         vm_address_t callbackAddress = (vm_address_t)
7412             _OSKextExtractPointer(callbackWrapper);
7413 
7414         if ((kmod_info->address <= callbackAddress) &&
7415             (callbackAddress < (kmod_info->address + kmod_info->size))) {
7416 
7417             if (invokeFlag) {
7418                /* This removes the callback record.
7419                 */
7420                 invokeRequestCallback(request, callbackResult);
7421             } else {
7422                 sRequestCallbackRecords->removeObject(i);
7423             }
7424         }
7425     } while (i--);
7426 
7427 finish:
7428     IORecursiveLockUnlock(sKextLock);
7429     return;
7430 }
7431 
7432 /*********************************************************************
7433 *********************************************************************/
7434 uint32_t
7435 OSKext::countRequestCallbacks(void)
7436 {
7437     uint32_t     result = 0;
7438     unsigned int count, i;
7439 
7440     IORecursiveLockLock(sKextLock);
7441 
7442     count = sRequestCallbackRecords->getCount();
7443     if (!count) {
7444         goto finish;
7445     }
7446 
7447     i = count - 1;
7448     do {
7449         OSDictionary * request = OSDynamicCast(OSDictionary,
7450             sRequestCallbackRecords->getObject(i));
7451 
7452         if (!request) {
7453             continue;
7454         }
7455         OSData * callbackWrapper = OSDynamicCast(OSData,
7456             _OSKextGetRequestArgument(request,
7457                 kKextRequestArgumentCallbackKey));
7458 
7459         if (!callbackWrapper) {
7460             continue;
7461         }
7462 
7463         vm_address_t callbackAddress = (vm_address_t)
7464             _OSKextExtractPointer(callbackWrapper);
7465 
7466         if ((kmod_info->address <= callbackAddress) &&
7467             (callbackAddress < (kmod_info->address + kmod_info->size))) {
7468 
7469             result++;
7470         }
7471     } while (i--);
7472 
7473 finish:
7474     IORecursiveLockUnlock(sKextLock);
7475     return result;
7476 }
7477 
7478 /*********************************************************************
7479 *********************************************************************/
7480 static OSReturn _OSKextCreateRequest(
7481     const char    * predicate,
7482     OSDictionary ** requestP)
7483 {
7484     OSReturn result = kOSKextReturnNoMemory;
7485     OSDictionary * request = NULL;  // must release on error
7486     OSDictionary * args = NULL;     // must release
7487 
7488     request = OSDictionary::withCapacity(2);
7489     if (!request) {
7490         goto finish;
7491     }
7492     result = _OSDictionarySetCStringValue(request,
7493         kKextRequestPredicateKey, predicate);
7494     if (result != kOSReturnSuccess) {
7495         goto finish;
7496     }
7497     result = kOSReturnSuccess;
7498 
7499 finish:
7500     if (result != kOSReturnSuccess) {
7501         if (request) request->release();
7502     } else {
7503         *requestP = request;
7504     }
7505     if (args) args->release();
7506 
7507     return result;
7508 }
7509 
7510 /*********************************************************************
7511 *********************************************************************/
7512 static OSString * _OSKextGetRequestPredicate(OSDictionary * requestDict)
7513 {
7514     return OSDynamicCast(OSString,
7515         requestDict->getObject(kKextRequestPredicateKey));
7516 }
7517 
7518 /*********************************************************************
7519 *********************************************************************/
7520 static OSObject * _OSKextGetRequestArgument(
7521     OSDictionary * requestDict,
7522     const char   * argName)
7523 {
7524     OSDictionary * args = OSDynamicCast(OSDictionary,
7525         requestDict->getObject(kKextRequestArgumentsKey));
7526     if (args) {
7527         return args->getObject(argName);
7528     }
7529     return NULL;
7530 }
7531 
7532 /*********************************************************************
7533 *********************************************************************/
7534 static bool _OSKextSetRequestArgument(
7535     OSDictionary * requestDict,
7536     const char   * argName,
7537     OSObject     * value)
7538 {
7539     OSDictionary * args = OSDynamicCast(OSDictionary,
7540         requestDict->getObject(kKextRequestArgumentsKey));
7541     if (!args) {
7542         args = OSDictionary::withCapacity(2);
7543         if (!args) {
7544             goto finish;
7545         }
7546         requestDict->setObject(kKextRequestArgumentsKey, args);
7547         args->release();
7548     }
7549     if (args) {
7550         return args->setObject(argName, value);
7551     }
7552 finish:
7553     return false;
7554 }
7555 
7556 /*********************************************************************
7557 *********************************************************************/
7558 static void * _OSKextExtractPointer(OSData * wrapper)
7559 {
7560     void       * result = NULL;
7561     const void * resultPtr = NULL;
7562 
7563     if (!wrapper) {
7564         goto finish;
7565     }
7566     resultPtr = wrapper->getBytesNoCopy();
7567     result = *(void **)resultPtr;
7568 finish:
7569     return result;
7570 }
7571 
7572 /*********************************************************************
7573 *********************************************************************/
7574 static OSReturn _OSDictionarySetCStringValue(
7575     OSDictionary * dict,
7576     const char   * cKey,
7577     const char   * cValue)
7578 {
7579     OSReturn result = kOSKextReturnNoMemory;
7580     const OSSymbol * key = NULL;  // must release
7581     OSString * value = NULL;  // must release
7582 
7583     key = OSSymbol::withCString(cKey);
7584     value = OSString::withCString(cValue);
7585     if (!key || !value) {
7586         goto finish;
7587     }
7588     if (dict->setObject(key, value)) {
7589         result = kOSReturnSuccess;
7590     }
7591 
7592 finish:
7593     if (key)   key->release();
7594     if (value) value->release();
7595 
7596     return result;
7597 }
7598 
7599 #if PRAGMA_MARK
7600 #pragma mark Personalities (IOKit Drivers)
7601 #endif
7602 /*********************************************************************
7603 *********************************************************************/
7604 /* static */
7605 OSArray *
7606 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag)
7607 {
7608     OSArray              * result                = NULL;  // returned
7609     OSCollectionIterator * kextIterator          = NULL;  // must release
7610     OSArray              * personalities         = NULL;  // must release
7611     OSCollectionIterator * personalitiesIterator = NULL;  // must release
7612 
7613     OSString             * kextID                = NULL;  // do not release
7614     OSKext               * theKext               = NULL;  // do not release
7615 
7616     IORecursiveLockLock(sKextLock);
7617 
7618    /* Let's conservatively guess that any given kext has around 3
7619     * personalities for now.
7620     */
7621     result = OSArray::withCapacity(sKextsByID->getCount() * 3);
7622     if (!result) {
7623         goto finish;
7624     }
7625 
7626     kextIterator = OSCollectionIterator::withCollection(sKextsByID);
7627     if (!kextIterator) {
7628         goto finish;
7629     }
7630 
7631     while ((kextID = OSDynamicCast(OSString, kextIterator->getNextObject()))) {
7632         if (personalitiesIterator) {
7633             personalitiesIterator->release();
7634             personalitiesIterator = NULL;
7635         }
7636         if (personalities) {
7637             personalities->release();
7638             personalities = NULL;
7639         }
7640 
7641         theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextID));
7642         if (!sSafeBoot || !filterSafeBootFlag || theKext->isLoadableInSafeBoot()) {
7643             personalities = theKext->copyPersonalitiesArray();
7644             if (!personalities) {
7645                 continue;
7646             }
7647             result->merge(personalities);
7648         } else {
7649             // xxx - check for better place to put this log msg
7650             OSKextLog(theKext,
7651                 kOSKextLogWarningLevel |
7652                 kOSKextLogLoadFlag,
7653                 "Kext %s is not loadable during safe boot; "
7654                 "omitting its personalities.",
7655                 theKext->getIdentifierCString());
7656         }
7657 
7658     }
7659 
7660 finish:
7661     IORecursiveLockUnlock(sKextLock);
7662 
7663     if (kextIterator)          kextIterator->release();
7664     if (personalitiesIterator) personalitiesIterator->release();
7665     if (personalities)         personalities->release();
7666 
7667     return result;
7668 }
7669 
7670 /*********************************************************************
7671 *********************************************************************/
7672 /* static */
7673 void
7674 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching)
7675 {
7676     int numPersonalities = 0;
7677 
7678     OSKextLog(/* kext */ NULL,
7679         kOSKextLogStepLevel |
7680         kOSKextLogLoadFlag,
7681         "Sending all eligible registered kexts' personalities "
7682         "to the IOCatalogue %s.",
7683         startMatching ? "and starting matching" : "but not starting matching");
7684 
7685     OSArray * personalities = OSKext::copyAllKextPersonalities(
7686         /* filterSafeBootFlag */ true);
7687 
7688     if (personalities) {
7689         gIOCatalogue->addDrivers(personalities, startMatching);
7690         numPersonalities = personalities->getCount();
7691         personalities->release();
7692     }
7693 
7694     OSKextLog(/* kext */ NULL,
7695         kOSKextLogStepLevel |
7696         kOSKextLogLoadFlag,
7697         "%d kext personalit%s sent to the IOCatalogue; %s.",
7698         numPersonalities, numPersonalities > 0 ? "ies" : "y",
7699         startMatching ? "matching started" : "matching not started");
7700     return;
7701 }
7702 
7703 /*********************************************************************
7704 * Do not make a deep copy, just convert the IOKitPersonalities dict
7705 * to an array for sending to the IOCatalogue.
7706 *********************************************************************/
7707 OSArray *
7708 OSKext::copyPersonalitiesArray(void)
7709 {
7710     OSArray              * result                      = NULL;
7711     OSDictionary         * personalities               = NULL;  // do not release
7712     OSCollectionIterator * personalitiesIterator       = NULL;  // must release
7713 
7714     OSString             * personalityName             = NULL;  // do not release
7715     OSString             * personalityBundleIdentifier = NULL;  // do not release
7716 
7717     personalities = OSDynamicCast(OSDictionary,
7718         getPropertyForHostArch(kIOKitPersonalitiesKey));
7719     if (!personalities) {
7720         goto finish;
7721     }
7722 
7723     result = OSArray::withCapacity(personalities->getCount());
7724     if (!result) {
7725         goto finish;
7726     }
7727 
7728     personalitiesIterator =
7729         OSCollectionIterator::withCollection(personalities);
7730     if (!personalitiesIterator) {
7731         goto finish;
7732     }
7733     while ((personalityName = OSDynamicCast(OSString,
7734             personalitiesIterator->getNextObject()))) {
7735 
7736         OSDictionary * personality = OSDynamicCast(OSDictionary,
7737             personalities->getObject(personalityName));
7738 
7739        /******
7740         * If the personality doesn't have a CFBundleIdentifier, or if it
7741         * differs from the kext's, insert the kext's ID so we can find it.
7742         * The publisher ID is used to remove personalities from bundles
7743         * correctly.
7744         */
7745         personalityBundleIdentifier = OSDynamicCast(OSString,
7746             personality->getObject(kCFBundleIdentifierKey));
7747 
7748         if (!personalityBundleIdentifier) {
7749             personality->setObject(kCFBundleIdentifierKey, bundleID);
7750         } else if (!personalityBundleIdentifier->isEqualTo(bundleID)) {
7751             personality->setObject(kIOPersonalityPublisherKey, bundleID);
7752         }
7753 
7754         result->setObject(personality);
7755     }
7756 
7757 finish:
7758     if (personalitiesIterator) personalitiesIterator->release();
7759 
7760     return result;
7761 }
7762 
7763 /*********************************************************************
7764 Might want to change this to a bool return?
7765 *********************************************************************/
7766 void
7767 OSKext::sendPersonalitiesToCatalog(
7768     bool      startMatching,
7769     OSArray * personalityNames)
7770 {
7771     OSArray      * personalitiesToSend     = NULL;  // must release
7772     OSDictionary * kextPersonalities = NULL;  // do not release
7773     int            count, i;
7774 
7775     if (sSafeBoot && !isLoadableInSafeBoot()) {
7776         OSKextLog(this,
7777             kOSKextLogErrorLevel |
7778             kOSKextLogLoadFlag,
7779             "Kext %s is not loadable during safe boot; "
7780             "not sending personalities to the IOCatalogue.",
7781             getIdentifierCString());
7782         return;
7783     }
7784 
7785     if (!personalityNames || !personalityNames->getCount()) {
7786         personalitiesToSend = copyPersonalitiesArray();
7787     } else {
7788         kextPersonalities = OSDynamicCast(OSDictionary,
7789             getPropertyForHostArch(kIOKitPersonalitiesKey));
7790         if (!kextPersonalities || !kextPersonalities->getCount()) {
7791             goto finish;
7792         }
7793         personalitiesToSend = OSArray::withCapacity(0);
7794         if (!personalitiesToSend) {
7795             goto finish;
7796         }
7797         count = personalityNames->getCount();
7798         for (i = 0; i < count; i++) {
7799             OSString * name = OSDynamicCast(OSString,
7800                 personalityNames->getObject(i));
7801             if (!name) {
7802                 continue;
7803             }
7804             OSDictionary * personality = OSDynamicCast(OSDictionary,
7805                 kextPersonalities->getObject(name));
7806             if (personality) {
7807                 personalitiesToSend->setObject(personality);
7808             }
7809         }
7810     }
7811     if (personalitiesToSend) {
7812         unsigned numPersonalities = personalitiesToSend->getCount();
7813         OSKextLog(this,
7814             kOSKextLogStepLevel |
7815             kOSKextLogLoadFlag,
7816             "Kext %s sending %d personalit%s to the IOCatalogue%s.",
7817             getIdentifierCString(),
7818             numPersonalities,
7819             numPersonalities > 1 ? "ies" : "y",
7820             startMatching ? " and starting matching" : " but not starting matching");
7821         gIOCatalogue->addDrivers(personalitiesToSend, startMatching);
7822     }
7823 finish:
7824     if (personalitiesToSend) {
7825         personalitiesToSend->release();
7826     }
7827     return;
7828 }
7829 
7830 /*********************************************************************
7831 *********************************************************************/
7832 void
7833 OSKext::removePersonalitiesFromCatalog(void)
7834 {
7835     OSDictionary * personality = NULL;   // do not release
7836 
7837     personality = OSDictionary::withCapacity(1);
7838     if (!personality) {
7839         goto finish;
7840     }
7841     personality->setObject(kCFBundleIdentifierKey, getIdentifier());
7842 
7843     OSKextLog(this,
7844         kOSKextLogStepLevel |
7845         kOSKextLogLoadFlag,
7846         "Kext %s removing all personalities naming it from the IOCatalogue.",
7847         getIdentifierCString());
7848 
7849    /* Have the IOCatalog remove all personalities matching this kext's
7850     * bundle ID and trigger matching anew.
7851     */
7852     gIOCatalogue->removeDrivers(personality, /* startMatching */ true);
7853 
7854  finish:
7855     if (personality) personality->release();
7856 
7857     return;
7858 }
7859 
7860 
7861 #if PRAGMA_MARK
7862 #pragma mark Logging
7863 #endif
7864 /*********************************************************************
7865 * Do not call any function that takes sKextLock here!
7866 *********************************************************************/
7867 /* static */
7868 OSKextLogSpec
7869 OSKext::setUserSpaceLogFilter(
7870     OSKextLogSpec   userLogFilter,
7871     bool            captureFlag)
7872 {
7873     OSKextLogSpec result;
7874 
7875     IORecursiveLockLock(sKextInnerLock);
7876 
7877     result = sUserSpaceKextLogFilter;
7878     sUserSpaceKextLogFilter = userLogFilter;
7879 
7880    /* If the config flag itself is changing, log the state change
7881     * going both ways, before setting up the user-space log arrays,
7882     * so that this is only logged in the kernel.
7883     */
7884     if (sUserSpaceKextLogFilter != result) {
7885         OSKextLog(/* kext */ NULL,
7886             kOSKextLogDebugLevel |
7887             kOSKextLogGeneralFlag,
7888             "User-space log flags changed from 0x%x to 0x%x.",
7889             result, sUserSpaceKextLogFilter);
7890     }
7891 
7892     if (userLogFilter && captureFlag &&
7893         !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
7894 
7895         // xxx - do some measurements for a good initial capacity?
7896         sUserSpaceLogSpecArray = OSArray::withCapacity(0);
7897         sUserSpaceLogMessageArray = OSArray::withCapacity(0);
7898 
7899         if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
7900             OSKextLog(/* kext */ NULL,
7901                 kOSKextLogErrorLevel |
7902                 kOSKextLogGeneralFlag,
7903                 "Failed to allocate user-space log message arrays.");
7904             OSSafeReleaseNULL(sUserSpaceLogSpecArray);
7905             OSSafeReleaseNULL(sUserSpaceLogMessageArray);
7906         }
7907     }
7908 
7909     IORecursiveLockUnlock(sKextInnerLock);
7910 
7911     return result;
7912 }
7913 
7914 /*********************************************************************
7915 * Do not call any function that takes sKextLock here!
7916 *********************************************************************/
7917 /* static */
7918 OSArray *
7919 OSKext::clearUserSpaceLogFilter(void)
7920 {
7921     OSArray        * result        = NULL;
7922     OSKextLogSpec   oldLogFilter;
7923 
7924     IORecursiveLockLock(sKextInnerLock);
7925 
7926     result = OSArray::withCapacity(2);
7927     if (result) {
7928         result->setObject(sUserSpaceLogSpecArray);
7929         result->setObject(sUserSpaceLogMessageArray);
7930     }
7931     OSSafeReleaseNULL(sUserSpaceLogSpecArray);
7932     OSSafeReleaseNULL(sUserSpaceLogMessageArray);
7933 
7934     oldLogFilter = sUserSpaceKextLogFilter;
7935     sUserSpaceKextLogFilter = kOSKextLogSilentFilter;
7936 
7937    /* If the config flag itself is changing, log the state change
7938     * going both ways, after tearing down the user-space log
7939     * arrays, so this is only logged within the kernel.
7940     */
7941     if (oldLogFilter != sUserSpaceKextLogFilter) {
7942         OSKextLog(/* kext */ NULL,
7943             kOSKextLogDebugLevel |
7944             kOSKextLogGeneralFlag,
7945             "User-space log flags changed from 0x%x to 0x%x.",
7946             oldLogFilter, sUserSpaceKextLogFilter);
7947     }
7948 
7949     IORecursiveLockUnlock(sKextInnerLock);
7950 
7951     return result;
7952 }
7953 
7954 /*********************************************************************
7955 * Do not call any function that takes sKextLock here!
7956 *********************************************************************/
7957 /* static */
7958 OSKextLogSpec
7959 OSKext::getUserSpaceLogFilter(void)
7960 {
7961     OSKextLogSpec result;
7962 
7963     IORecursiveLockLock(sKextInnerLock);
7964     result = sUserSpaceKextLogFilter;
7965     IORecursiveLockUnlock(sKextInnerLock);
7966 
7967     return result;
7968 }
7969 
7970 /*********************************************************************
7971 * This function is called by OSMetaClass during kernel C++ setup.
7972 * Be careful what you access here; assume only OSKext::initialize()
7973 * has been called.
7974 *
7975 * Do not call any function that takes sKextLock here!
7976 *********************************************************************/
7977 #define VTRESET   "\033[0m"
7978 
7979 #define VTBOLD    "\033[1m"
7980 #define VTUNDER   "\033[4m"
7981 
7982 #define VTRED     "\033[31m"
7983 #define VTGREEN   "\033[32m"
7984 #define VTYELLOW  "\033[33m"
7985 #define VTBLUE    "\033[34m"
7986 #define VTMAGENTA "\033[35m"
7987 #define VTCYAN    "\033[36m"
7988 
7989 inline const char * colorForFlags(OSKextLogSpec flags)
7990 {
7991     OSKextLogSpec logLevel = flags & kOSKextLogLevelMask;
7992 
7993     switch (logLevel) {
7994     case kOSKextLogErrorLevel:
7995         return VTRED VTBOLD;
7996         break;
7997     case kOSKextLogWarningLevel:
7998         return VTRED;
7999         break;
8000     case kOSKextLogBasicLevel:
8001         return VTYELLOW VTUNDER;
8002         break;
8003     case kOSKextLogProgressLevel:
8004         return VTYELLOW;
8005         break;
8006     case kOSKextLogStepLevel:
8007         return VTGREEN;
8008         break;
8009     case kOSKextLogDetailLevel:
8010         return VTCYAN;
8011         break;
8012     case kOSKextLogDebugLevel:
8013         return VTMAGENTA;
8014         break;
8015     default:
8016         return "";  // white
8017         break;
8018     }
8019     return "";
8020 }
8021 
8022 inline bool logSpecMatch(
8023     OSKextLogSpec msgLogSpec,
8024     OSKextLogSpec logFilter)
8025 {
8026     OSKextLogSpec filterKextGlobal  = logFilter & kOSKextLogKextOrGlobalMask;
8027     OSKextLogSpec filterLevel       = logFilter & kOSKextLogLevelMask;
8028     OSKextLogSpec filterFlags       = logFilter & kOSKextLogFlagsMask;
8029 
8030     OSKextLogSpec msgKextGlobal    = msgLogSpec & kOSKextLogKextOrGlobalMask;
8031     OSKextLogSpec msgLevel         = msgLogSpec & kOSKextLogLevelMask;
8032     OSKextLogSpec msgFlags         = msgLogSpec & kOSKextLogFlagsMask;
8033 
8034    /* Explicit messages always get logged.
8035     */
8036     if (msgLevel == kOSKextLogExplicitLevel) {
8037         return true;
8038     }
8039 
8040    /* Warnings and errors are logged regardless of the flags.
8041     */
8042     if (msgLevel <= kOSKextLogBasicLevel && (msgLevel <= filterLevel)) {
8043         return true;
8044     }
8045 
8046    /* A verbose message that isn't for a logging-enabled kext and isn't global
8047     * does *not* get logged.
8048     */
8049     if (!msgKextGlobal && !filterKextGlobal) {
8050         return false;
8051     }
8052 
8053    /* Warnings and errors are logged regardless of the flags.
8054     * All other messages must fit the flags and
8055     * have a level at or below the filter.
8056     *
8057     */
8058     if ((msgFlags & filterFlags) && (msgLevel <= filterLevel)) {
8059         return true;
8060     }
8061     return false;
8062 }
8063 
8064 extern "C" {
8065 
8066 void
8067 OSKextLog(
8068     OSKext         * aKext,
8069     OSKextLogSpec    msgLogSpec,
8070     const char     * format, ...)
8071 {
8072     va_list argList;
8073 
8074     va_start(argList, format);
8075     OSKextVLog(aKext, msgLogSpec, format, argList);
8076     va_end(argList);
8077 }
8078 
8079 void
8080 OSKextVLog(
8081     OSKext         * aKext,
8082     OSKextLogSpec    msgLogSpec,
8083     const char     * format,
8084     va_list    srcArgList)
8085 {
8086     extern int       disableConsoleOutput;
8087 
8088     bool             logForKernel       = false;
8089     bool             logForUser         = false;
8090     va_list          argList;
8091     char             stackBuffer[120];
8092     uint32_t         length            = 0;
8093     char           * allocBuffer       = NULL;         // must kfree
8094     OSNumber       * logSpecNum        = NULL;         // must release
8095     OSString       * logString         = NULL;         // must release
8096     char           * buffer            = stackBuffer;  // do not free
8097 
8098     IORecursiveLockLock(sKextInnerLock);
8099 
8100    /* Set the kext/global bit in the message spec if we have no
8101     * kext or if the kext requests logging.
8102     */
8103     if (!aKext || aKext->flags.loggingEnabled) {
8104         msgLogSpec = msgLogSpec | kOSKextLogKextOrGlobalMask;
8105     }
8106 
8107     logForKernel = logSpecMatch(msgLogSpec, sKernelLogFilter);
8108     if (sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
8109         logForUser = logSpecMatch(msgLogSpec, sUserSpaceKextLogFilter);
8110     }
8111 
8112     if (! (logForKernel || logForUser) ) {
8113         goto finish;
8114     }
8115 
8116    /* No goto from here until past va_end()!
8117     */
8118     va_copy(argList, srcArgList);
8119     length = vsnprintf(stackBuffer, sizeof(stackBuffer), format, argList);
8120     va_end(argList);
8121 
8122     if (length + 1 >= sizeof(stackBuffer)) {
8123         allocBuffer = (char *)kalloc((length + 1) * sizeof(char));
8124         if (!allocBuffer) {
8125             goto finish;
8126         }
8127 
8128        /* No goto from here until past va_end()!
8129         */
8130         va_copy(argList, srcArgList);
8131         vsnprintf(allocBuffer, length + 1, format, argList);
8132         va_end(argList);
8133 
8134         buffer = allocBuffer;
8135     }
8136 
8137    /* If user space wants the log message, queue it up.
8138     */
8139     if (logForUser && sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
8140         logSpecNum = OSNumber::withNumber(msgLogSpec, 8 * sizeof(msgLogSpec));
8141         logString = OSString::withCString(buffer);
8142         if (logSpecNum && logString) {
8143             sUserSpaceLogSpecArray->setObject(logSpecNum);
8144             sUserSpaceLogMessageArray->setObject(logString);
8145         }
8146     }
8147 
8148    /* Always log messages from the kernel according to the kernel's
8149     * log flags.
8150     */
8151     if (logForKernel) {
8152 
8153        /* If we are in console mode and have a custom log filter,
8154         * colorize the log message.
8155         */
8156         if (!disableConsoleOutput && sBootArgLogFilterFound) {
8157             const char * color = "";  // do not free
8158             color = colorForFlags(msgLogSpec);
8159             printf("%s%s%s\n", colorForFlags(msgLogSpec),
8160                 buffer, color[0] ? VTRESET : "");
8161         } else {
8162             printf("%s\n", buffer);
8163         }
8164     }
8165 
8166 finish:
8167     if (allocBuffer) {
8168         kfree(allocBuffer, (length + 1) * sizeof(char));
8169     }
8170     OSSafeRelease(logString);
8171     OSSafeRelease(logSpecNum);
8172     IORecursiveLockUnlock(sKextInnerLock);
8173     return;
8174 }
8175 
8176 }; /* extern "C" */
8177 
8178 #if PRAGMA_MARK
8179 #pragma mark Backtrace Dump & kmod_get_info() support
8180 #endif
8181 /*********************************************************************
8182 *********************************************************************/
8183 /* static */
8184 void
8185 OSKext::printKextsInBacktrace(
8186     vm_offset_t  * addr,
8187     unsigned int   cnt,
8188     int         (* printf_func)(const char *fmt, ...),
8189     bool           lockFlag)
8190 {
8191     vm_offset_t      * kscan_addr = NULL;
8192     kmod_info_t      * k = NULL;
8193     kmod_reference_t * r = NULL;
8194     unsigned int       i;
8195     int                found_kmod = 0;
8196 
8197     if (lockFlag) {
8198         IORecursiveLockLock(sKextLock);
8199     }
8200 
8201     for (k = kmod; k; k = k->next) {
8202         if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)k)) == 0) {
8203             (*printf_func)("         kmod scan stopped due to missing "
8204                 "kmod page: %p\n", k);
8205             break;
8206         }
8207         if (!k->address) {
8208             continue; // skip fake entries for built-in kernel components
8209         }
8210         for (i = 0, kscan_addr = addr; i < cnt; i++, kscan_addr++) {
8211             if ((*kscan_addr >= k->address) &&
8212                 (*kscan_addr < (k->address + k->size))) {
8213 
8214                 if (!found_kmod) {
8215                     (*printf_func)("      Kernel Extensions in backtrace "
8216                         "(with dependencies):\n");
8217                 }
8218                 found_kmod = 1;
8219                 (*printf_func)("         %s(%s)@%p->%p\n",
8220                     k->name, k->version, k->address, k->address + k->size - 1);
8221 
8222                 for (r = k->reference_list; r; r = r->next) {
8223                     kmod_info_t * rinfo;
8224 
8225                     if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)r)) == 0) {
8226                         (*printf_func)("            kmod dependency scan stopped "
8227                             "due to missing dependency page: %p\n", r);
8228                         break;
8229                     }
8230 
8231                     rinfo = r->info;
8232 
8233                     if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
8234                         (*printf_func)("            kmod dependency scan stopped "
8235                             "due to missing kmod page: %p\n", rinfo);
8236                         break;
8237                     }
8238 
8239                     if (!rinfo->address) {
8240                         continue; // skip fake entries for built-ins
8241                     }
8242 
8243                     (*printf_func)("            dependency: %s(%s)@%p\n",
8244                         rinfo->name, rinfo->version, rinfo->address);
8245                 }
8246 
8247                 break;  // only report this kmod for one backtrace address
8248             }
8249         }
8250     }
8251 
8252     if (lockFlag) {
8253         IORecursiveLockUnlock(sKextLock);
8254     }
8255 
8256     return;
8257 }
8258 
8259 /*******************************************************************************
8260 * substitute() looks at an input string (a pointer within a larger buffer)
8261 * for a match to a substring, and on match it writes the marker & substitution
8262 * character to an output string, updating the scan (from) and
8263 * output (to) indexes as appropriate.
8264 *******************************************************************************/
8265 static int substitute(
8266     const char * scan_string,
8267     char       * string_out,
8268     uint32_t   * to_index,
8269     uint32_t   * from_index,
8270     const char * substring,
8271     char         marker,
8272     char         substitution);
8273 
8274 /* string_out must be at least KMOD_MAX_NAME bytes.
8275  */
8276 static int
8277 substitute(
8278     const char * scan_string,
8279     char       * string_out,
8280     uint32_t   * to_index,
8281     uint32_t   * from_index,
8282     const char * substring,
8283     char         marker,
8284     char         substitution)
8285 {
8286     uint32_t substring_length = strnlen(substring, KMOD_MAX_NAME - 1);
8287 
8288    /* On a substring match, append the marker (if there is one) and then
8289     * the substitution character, updating the output (to) index accordingly.
8290     * Then update the input (from) length by the length of the substring
8291     * that got replaced.
8292     */
8293     if (!strncmp(scan_string, substring, substring_length)) {
8294         if (marker) {
8295             string_out[(*to_index)++] = marker;
8296         }
8297         string_out[(*to_index)++] = substitution;
8298         (*from_index) += substring_length;
8299         return 1;
8300     }
8301     return 0;
8302 }
8303 
8304 /*******************************************************************************
8305 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
8306 * KMOD_MAX_NAME characters and performs various substitutions of common
8307 * prefixes & substrings as defined by tables in kext_panic_report.h.
8308 *******************************************************************************/
8309 static void compactIdentifier(
8310     const char * identifier,
8311     char       * identifier_out,
8312     char      ** identifier_out_end);
8313 
8314 static void
8315 compactIdentifier(
8316     const char * identifier,
8317     char       * identifier_out,
8318     char      ** identifier_out_end)
8319 {
8320     uint32_t       from_index, to_index;
8321     uint32_t       scan_from_index = 0;
8322     uint32_t       scan_to_index   = 0;
8323     subs_entry_t * subs_entry    = NULL;
8324     int            did_sub       = 0;
8325 
8326     from_index = to_index = 0;
8327     identifier_out[0] = '\0';
8328 
8329    /* Replace certain identifier prefixes with shorter @+character sequences.
8330     * Check the return value of substitute() so we only replace the prefix.
8331     */
8332     for (subs_entry = &kext_identifier_prefix_subs[0];
8333          subs_entry->substring && !did_sub;
8334          subs_entry++) {
8335 
8336         did_sub = substitute(identifier, identifier_out,
8337             &scan_to_index, &scan_from_index,
8338             subs_entry->substring, /* marker */ '\0', subs_entry->substitute);
8339     }
8340     did_sub = 0;
8341 
8342    /* Now scan through the identifier looking for the common substrings
8343     * and replacing them with shorter !+character sequences via substitute().
8344     */
8345     for (/* see above */;
8346          scan_from_index < KMOD_MAX_NAME - 1 && identifier[scan_from_index];
8347          /* see loop */) {
8348 
8349         const char   * scan_string = &identifier[scan_from_index];
8350 
8351         did_sub = 0;
8352 
8353         if (scan_from_index) {
8354             for (subs_entry = &kext_identifier_substring_subs[0];
8355                  subs_entry->substring && !did_sub;
8356                  subs_entry++) {
8357 
8358                 did_sub = substitute(scan_string, identifier_out,
8359                     &scan_to_index, &scan_from_index,
8360                     subs_entry->substring, '!', subs_entry->substitute);
8361             }
8362         }
8363 
8364        /* If we didn't substitute, copy the input character to the output.
8365         */
8366         if (!did_sub) {
8367             identifier_out[scan_to_index++] = identifier[scan_from_index++];
8368         }
8369     }
8370 
8371     identifier_out[scan_to_index] = '\0';
8372     if (identifier_out_end) {
8373         *identifier_out_end = &identifier_out[scan_to_index];
8374     }
8375 
8376     return;
8377 }
8378 
8379 /*******************************************************************************
8380 * assemble_identifier_and_version() adds to a string buffer a compacted
8381 * bundle identifier followed by a version string.
8382 *******************************************************************************/
8383 
8384 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
8385  */
8386 static int assemble_identifier_and_version(
8387     kmod_info_t * kmod_info,
8388     char        * identPlusVers);
8389 static int
8390 assemble_identifier_and_version(
8391     kmod_info_t * kmod_info,
8392     char        * identPlusVers)
8393 {
8394     int result = 0;
8395 
8396     compactIdentifier(kmod_info->name, identPlusVers, NULL);
8397     result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
8398     identPlusVers[result++] = '\t';  // increment for real char
8399     identPlusVers[result] = '\0';    // don't increment for nul char
8400     result = strlcat(identPlusVers, kmod_info->version, KMOD_MAX_NAME);
8401 
8402     return result;
8403 }
8404 
8405 /*******************************************************************************
8406 *******************************************************************************/
8407 #define LAST_LOADED " - last loaded "
8408 #define LAST_LOADED_TS_WIDTH  (16)
8409 
8410 /* static */
8411 uint32_t
8412 OSKext::saveLoadedKextPanicListTyped(
8413     const char * prefix,
8414     int          invertFlag,
8415     int          libsFlag,
8416     char       * paniclist,
8417     uint32_t     list_size,
8418     uint32_t   * list_length_ptr)
8419 {
8420     uint32_t      result = 0;
8421     int           error  = 0;
8422     unsigned int  count, i;
8423 
8424     count = sLoadedKexts->getCount();
8425     if (!count) {
8426         goto finish;
8427     }
8428 
8429     i = count - 1;
8430     do {
8431         OSKext      * theKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
8432         kmod_info_t * kmod_info = theKext->kmod_info;
8433         int           match;
8434         char          identPlusVers[2*KMOD_MAX_NAME];
8435         uint32_t      identPlusVersLength;
8436         char          timestampBuffer[17]; // enough for a uint64_t
8437 
8438        /* Skip all built-in kexts.
8439         */
8440         if (theKext->isKernelComponent()) {
8441             continue;
8442         }
8443 
8444        /* Filter for kmod name (bundle identifier).
8445         */
8446         match = !strncmp(kmod_info->name, prefix, strnlen(prefix, KMOD_MAX_NAME));
8447         if ((match && invertFlag) || (!match && !invertFlag)) {
8448             continue;
8449         }
8450 
8451        /* Filter for libraries (kexts that have a compatible version).
8452         */
8453         if ((libsFlag == 0 && theKext->getCompatibleVersion() > 1) ||
8454             (libsFlag == 1 && theKext->getCompatibleVersion() < 1)) {
8455 
8456             continue;
8457         }
8458 
8459         if (!kmod_info ||
8460             !pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_info))) {
8461 
8462             printf("kext scan stopped due to missing kmod_info page: %p\n",
8463                 kmod_info);
8464             error = 1;
8465             goto finish;
8466         }
8467 
8468         identPlusVersLength = assemble_identifier_and_version(kmod_info,
8469             identPlusVers);
8470         if (!identPlusVersLength) {
8471             printf("error saving loaded kext info\n");
8472             goto finish;
8473         }
8474 
8475        /* We're going to note the last-loaded kext in the list.
8476         */
8477         if (i + 1 == count) {
8478             snprintf(timestampBuffer, sizeof(timestampBuffer), "%llu",
8479                 AbsoluteTime_to_scalar(&last_loaded_timestamp));
8480             identPlusVersLength += sizeof(LAST_LOADED) - 1 +
8481                 strnlen(timestampBuffer, sizeof(timestampBuffer));
8482         }
8483 
8484        /* Adding 1 for the newline.
8485         */
8486         if (*list_length_ptr + identPlusVersLength + 1 >= list_size) {
8487             goto finish;
8488         }
8489 
8490         *list_length_ptr = strlcat(paniclist, identPlusVers, list_size);
8491         if (i + 1 == count) {
8492             *list_length_ptr = strlcat(paniclist, LAST_LOADED, list_size);
8493             *list_length_ptr = strlcat(paniclist, timestampBuffer, list_size);
8494         }
8495         *list_length_ptr = strlcat(paniclist, "\n", list_size);
8496 
8497     } while (i--);
8498 
8499 finish:
8500     if (!error) {
8501         if (*list_length_ptr + 1 <= list_size) {
8502             result = list_size - (*list_length_ptr + 1);
8503         }
8504     }
8505 
8506     return result;
8507 }
8508 
8509 /*********************************************************************
8510 *********************************************************************/
8511 /* static */
8512 void
8513 OSKext::saveLoadedKextPanicList(void)
8514 {
8515     char     * newlist        = NULL;
8516     uint32_t   newlist_size   = 0;
8517     uint32_t   newlist_length = 0;
8518 
8519     IORecursiveLockLock(sKextLock);
8520 
8521     newlist_length = 0;
8522     newlist_size = KEXT_PANICLIST_SIZE;
8523     newlist = (char *)kalloc(newlist_size);
8524 
8525     if (!newlist) {
8526         OSKextLog(/* kext */ NULL,
8527             kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
8528             "Couldn't allocate kext panic log buffer.");
8529         goto finish;
8530     }
8531 
8532     newlist[0] = '\0';
8533 
8534     // non-"com.apple." kexts
8535     if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
8536         /* libs? */ -1, newlist, newlist_size, &newlist_length)) {
8537 
8538         goto finish;
8539     }
8540     // "com.apple." nonlibrary kexts
8541     if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
8542         /* libs? */ 0, newlist, newlist_size, &newlist_length)) {
8543 
8544         goto finish;
8545     }
8546     // "com.apple." library kexts
8547     if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
8548         /* libs? */ 1, newlist, newlist_size, &newlist_length)) {
8549 
8550         goto finish;
8551     }
8552 
8553     if (loaded_kext_paniclist) {
8554         kfree(loaded_kext_paniclist, loaded_kext_paniclist_size);
8555     }
8556     loaded_kext_paniclist = newlist;
8557     loaded_kext_paniclist_size = newlist_size;
8558     loaded_kext_paniclist_length = newlist_length;
8559 
8560 finish:
8561     IORecursiveLockUnlock(sKextLock);
8562     return;
8563 }
8564 
8565 /*********************************************************************
8566 *********************************************************************/
8567 /* static */
8568 void
8569 OSKext::saveUnloadedKextPanicList(OSKext * aKext)
8570 {
8571     char     * newlist        = NULL;
8572     uint32_t   newlist_size   = 0;
8573     uint32_t   newlist_length = 0;
8574     char       identPlusVers[2*KMOD_MAX_NAME];
8575     uint32_t   identPlusVersLength;
8576 
8577     if (!aKext->kmod_info) {
8578         return;  // do not goto finish here b/c of lock
8579     }
8580 
8581     IORecursiveLockLock(sKextLock);
8582 
8583     clock_get_uptime(&last_unloaded_timestamp);
8584     last_unloaded_address = (void *)aKext->kmod_info->address;
8585     last_unloaded_size = aKext->kmod_info->size;
8586 
8587 
8588     identPlusVersLength = assemble_identifier_and_version(aKext->kmod_info,
8589         identPlusVers);
8590     if (!identPlusVersLength) {
8591         printf("error saving unloaded kext info\n");
8592         goto finish;
8593     }
8594 
8595     newlist_length = identPlusVersLength;
8596     newlist_size = newlist_length + 1;
8597     newlist = (char *)kalloc(newlist_size);
8598 
8599     if (!newlist) {
8600         printf("couldn't allocate kext panic log buffer\n");
8601         goto finish;
8602     }
8603 
8604     newlist[0] = '\0';
8605 
8606     strlcpy(newlist, identPlusVers, newlist_size);
8607 
8608     if (unloaded_kext_paniclist) {
8609         kfree(unloaded_kext_paniclist, unloaded_kext_paniclist_size);
8610     }
8611     unloaded_kext_paniclist = newlist;
8612     unloaded_kext_paniclist_size = newlist_size;
8613     unloaded_kext_paniclist_length = newlist_length;
8614 
8615 finish:
8616     IORecursiveLockUnlock(sKextLock);
8617     return;
8618 }
8619 
8620 /*********************************************************************
8621 *********************************************************************/
8622 #if __LP64__
8623 #define __kLoadSizeEscape  "0x%lld"
8624 #else
8625 #define __kLoadSizeEscape  "0x%ld"
8626 #endif /* __LP64__ */
8627 
8628 /* static */
8629 void
8630 OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
8631 {
8632     printf_func("unloaded kexts:\n");
8633     if (unloaded_kext_paniclist &&
8634         pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) unloaded_kext_paniclist) &&
8635         unloaded_kext_paniclist[0]) {
8636 
8637         printf_func(
8638             "%.*s (addr %p, size " __kLoadSizeEscape ") - last unloaded %llu\n",
8639             unloaded_kext_paniclist_length, unloaded_kext_paniclist,
8640             last_unloaded_address, last_unloaded_size,
8641             AbsoluteTime_to_scalar(&last_unloaded_timestamp));
8642     } else {
8643         printf_func("(none)\n");
8644     }
8645     printf_func("loaded kexts:\n");
8646     if (loaded_kext_paniclist &&
8647         pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
8648         loaded_kext_paniclist[0]) {
8649 
8650         printf_func("%.*s", loaded_kext_paniclist_length, loaded_kext_paniclist);
8651     } else {
8652         printf_func("(none)\n");
8653     }
8654     return;
8655 }
8656 
8657 /*********************************************************************
8658 *********************************************************************/
8659 #if __ppc__ || __i386__
8660 /* static */
8661 kern_return_t
8662 OSKext::getKmodInfo(
8663     kmod_info_array_t      * kmodList,
8664     mach_msg_type_number_t * kmodCount)
8665 {
8666     kern_return_t result = KERN_FAILURE;
8667     vm_offset_t data;
8668     kmod_info_t * k, * kmod_info_scan_ptr;
8669     kmod_reference_t * r, * ref_scan_ptr;
8670     int ref_count;
8671     unsigned size = 0;
8672 
8673     *kmodList = (kmod_info_t *)0;
8674     *kmodCount = 0;
8675 
8676     IORecursiveLockLock(sKextLock);
8677 
8678     k = kmod;
8679     while (k) {
8680         size += sizeof(kmod_info_t);
8681         r = k->reference_list;
8682         while (r) {
8683             size +=sizeof(kmod_reference_t);
8684             r = r->next;
8685         }
8686         k = k->next;
8687     }
8688     if (!size) {
8689         result = KERN_SUCCESS;
8690         goto finish;
8691     }
8692 
8693     result = kmem_alloc(kernel_map, &data, size);
8694     if (result != KERN_SUCCESS) {
8695         goto finish;
8696     }
8697 
8698    /* Copy each kmod_info struct sequentially into the data buffer.
8699     * Set each struct's nonzero 'next' pointer back to itself as a sentinel;
8700     * the kernel space address is used to match refs, and a zero 'next' flags
8701     * the end of kmod_infos in the data buffer and the beginning of references.
8702     */
8703     k = kmod;
8704     kmod_info_scan_ptr = (kmod_info_t *)data;
8705     while (k) {
8706         *kmod_info_scan_ptr = *k;
8707         if (k->next) {
8708             kmod_info_scan_ptr->next = k;
8709         }
8710         kmod_info_scan_ptr++;
8711         k = k->next;
8712     }
8713 
8714    /* Now add references after the kmod_info structs in the same buffer.
8715     * Update each kmod_info with the ref_count so we can associate
8716     * references with kmod_info structs.
8717     */
8718     k = kmod;
8719     ref_scan_ptr = (kmod_reference_t *)kmod_info_scan_ptr;
8720     kmod_info_scan_ptr = (kmod_info_t *)data;
8721     while (k) {
8722         r = k->reference_list;
8723         ref_count = 0;
8724         while (r) {
8725            /* Note the last kmod_info in the data buffer has its next == 0.
8726             * Since there can only be one like that,
8727             * this case is handled by the caller.
8728             */
8729             *ref_scan_ptr = *r;
8730             ref_scan_ptr++;
8731             r = r->next;
8732             ref_count++;
8733         }
8734        /* Stuff the # of refs into the 'reference_list' field of the kmod_info
8735         * struct for the client to interpret.
8736         */
8737         kmod_info_scan_ptr->reference_list = (kmod_reference_t *)(long)ref_count;
8738         kmod_info_scan_ptr++;
8739         k = k->next;
8740     }
8741 
8742     result = vm_map_copyin(kernel_map, data, size, TRUE, (vm_map_copy_t *)kmodList);
8743     if (result != KERN_SUCCESS) {
8744         goto finish;
8745     }
8746 
8747     *kmodCount = size;
8748     result = KERN_SUCCESS;
8749 
8750 finish:
8751     IORecursiveLockUnlock(sKextLock);
8752 
8753     if (result != KERN_SUCCESS && data) {
8754         kmem_free(kernel_map, data, size);
8755         *kmodList = (kmod_info_t *)0;
8756         *kmodCount = 0;
8757     }
8758     return result;
8759 }
8760 #endif /* __ppc__ || __i386__ */
8761 #if PRAGMA_MARK
8762 #pragma mark MAC Framework Support
8763 #endif
8764 /*********************************************************************
8765 *********************************************************************/
8766 #if CONFIG_MACF_KEXT
8767 /* MAC Framework support */
8768 
8769 /*
8770  * define IOC_DEBUG to display run-time debugging information
8771  * #define IOC_DEBUG 1
8772  */
8773 
8774 #ifdef IOC_DEBUG
8775 #define DPRINTF(x)    printf x
8776 #else
8777 #define IOC_DEBUG
8778 #define DPRINTF(x)
8779 #endif
8780 
8781 /*********************************************************************
8782 *********************************************************************/
8783 static bool
8784 MACFObjectIsPrimitiveType(OSObject * obj)
8785 {
8786     const OSMetaClass * typeID = NULL;  // do not release
8787 
8788     typeID = OSTypeIDInst(obj);
8789     if (typeID == OSTypeID(OSString) || typeID == OSTypeID(OSNumber) ||
8790         typeID == OSTypeID(OSBoolean) || typeID == OSTypeID(OSData)) {
8791 
8792         return true;
8793     }
8794     return false;
8795 }
8796 
8797 /*********************************************************************
8798 *********************************************************************/
8799 static int
8800 MACFLengthForObject(OSObject * obj)
8801 {
8802     const OSMetaClass * typeID = NULL;  // do not release
8803     int len;
8804 
8805     typeID = OSTypeIDInst(obj);
8806     if (typeID == OSTypeID(OSString)) {
8807         OSString * stringObj = OSDynamicCast(OSString, obj);
8808         len = stringObj->getLength() + 1;
8809     } else if (typeID == OSTypeID(OSNumber)) {
8810         len = sizeof("4294967295");    /* UINT32_MAX */
8811     } else if (typeID == OSTypeID(OSBoolean)) {
8812         OSBoolean * boolObj = OSDynamicCast(OSBoolean, obj);
8813         len = boolObj->isTrue() ? sizeof("true") : sizeof("false");
8814     } else if (typeID == OSTypeID(OSData)) {
8815         OSData * dataObj = OSDynamicCast(OSData, obj);
8816         len = dataObj->getLength();
8817     } else {
8818         len = 0;
8819     }
8820     return len;
8821 }
8822 
8823 /*********************************************************************
8824 *********************************************************************/
8825 static void
8826 MACFInitElementFromObject(
8827     struct mac_module_data_element * element,
8828     OSObject                       * value)
8829 {
8830     const OSMetaClass * typeID = NULL;  // do not release
8831 
8832     typeID = OSTypeIDInst(value);
8833     if (typeID == OSTypeID(OSString)) {
8834         OSString * stringObj = OSDynamicCast(OSString, value);
8835         element->value_type = MAC_DATA_TYPE_PRIMITIVE;
8836         element->value_size = stringObj->getLength() + 1;
8837         DPRINTF(("osdict: string %s size %d\n",
8838             stringObj->getCStringNoCopy(), element->value_size));
8839         memcpy(element->value, stringObj->getCStringNoCopy(),
8840             element->value_size);
8841     } else if (typeID == OSTypeID(OSNumber)) {
8842         OSNumber * numberObj = OSDynamicCast(OSNumber, value);
8843         element->value_type = MAC_DATA_TYPE_PRIMITIVE;
8844         element->value_size = sprintf(element->value, "%u",
8845             numberObj->unsigned32BitValue()) + 1;
8846     } else if (typeID == OSTypeID(OSBoolean)) {
8847         OSBoolean * boolObj = OSDynamicCast(OSBoolean, value);
8848         element->value_type = MAC_DATA_TYPE_PRIMITIVE;
8849         if (boolObj->isTrue()) {
8850             strcpy(element->value, "true");
8851             element->value_size = 5;
8852         } else {
8853             strcpy(element->value, "false");
8854             element->value_size = 6;
8855         }
8856     } else if (typeID == OSTypeID(OSData)) {
8857         OSData * dataObj = OSDynamicCast(OSData, value);
8858         element->value_type = MAC_DATA_TYPE_PRIMITIVE;
8859         element->value_size = dataObj->getLength();
8860         DPRINTF(("osdict: data size %d\n", dataObj->getLength()));
8861         memcpy(element->value, dataObj->getBytesNoCopy(),
8862             element->value_size);
8863     }
8864     return;
8865 }
8866 
8867 /*********************************************************************
8868 * This function takes an OSDictionary and returns a struct mac_module_data
8869 * list.
8870 *********************************************************************/
8871 static struct mac_module_data *
8872 MACFEncodeOSDictionary(OSDictionary * dict)
8873 {
8874     struct mac_module_data         * result      = NULL;  // do not free
8875     const OSMetaClass              * typeID      = NULL;  // do not release
8876     OSString                       * key         = NULL;  // do not release
8877     OSCollectionIterator           * keyIterator = NULL;  // must release
8878     struct mac_module_data_element * element     = NULL;  // do not free
8879     unsigned int                     strtabsize  = 0;
8880     unsigned int                     listtabsize = 0;
8881     unsigned int                     dicttabsize = 0;
8882     unsigned int                     nkeys       = 0;
8883     unsigned int                     datalen     = 0;
8884     char                           * strtab      = NULL;  // do not free
8885     char                           * listtab     = NULL;  // do not free
8886     char                           * dicttab     = NULL;  // do not free
8887     vm_offset_t                      data_addr   = 0;
8888 
8889     keyIterator = OSCollectionIterator::withCollection(dict);
8890     if (!keyIterator) {
8891         goto finish;
8892     }
8893 
8894     /* Iterate over OSModuleData to figure out total size */
8895     while ( (key = OSDynamicCast(OSString, keyIterator->getNextObject())) ) {
8896 
8897         // Get the key's value and determine its type
8898         OSObject * value = dict->getObject(key);
8899         if (!value) {
8900             continue;
8901         }
8902 
8903         typeID = OSTypeIDInst(value);
8904         if (MACFObjectIsPrimitiveType(value)) {
8905             strtabsize += MACFLengthForObject(value);
8906         }
8907         else if (typeID == OSTypeID(OSArray)) {
8908             unsigned int k, cnt, nents;
8909             OSArray * arrayObj = OSDynamicCast(OSArray, value);
8910 
8911             nents = 0;
8912             cnt = arrayObj->getCount();
8913             for (k = 0; k < cnt; k++) {
8914                 value = arrayObj->getObject(k);
8915                 typeID = OSTypeIDInst(value);
8916                 if (MACFObjectIsPrimitiveType(value)) {
8917                     listtabsize += MACFLengthForObject(value);
8918                     nents++;
8919                 }
8920                 else if (typeID == OSTypeID(OSDictionary)) {
8921                     unsigned int           dents = 0;
8922                     OSDictionary         * dictObj      = NULL;  // do not release
8923                     OSString             * dictkey      = NULL;  // do not release
8924                     OSCollectionIterator * dictIterator = NULL;  // must release
8925 
8926                     dictObj = OSDynamicCast(OSDictionary, value);
8927                     dictIterator = OSCollectionIterator::withCollection(dictObj);
8928                     if (!dictIterator) {
8929                         goto finish;
8930                     }
8931                     while ((dictkey = OSDynamicCast(OSString,
8932                         dictIterator->getNextObject()))) {
8933 
8934                         OSObject * dictvalue = NULL;  // do not release
8935 
8936                         dictvalue = dictObj->getObject(dictkey);
8937                         if (!dictvalue) {
8938                             continue;
8939                         }
8940                         if (MACFObjectIsPrimitiveType(dictvalue)) {
8941                             strtabsize += MACFLengthForObject(dictvalue);
8942                         } else {
8943                             continue; /* Only handle primitive types here. */
8944                         }
8945                        /*
8946                         * Allow for the "arraynnn/" prefix in the key length.
8947                         */
8948                         strtabsize += dictkey->getLength() + 1;
8949                         dents++;
8950                     }
8951                     dictIterator->release();
8952                     if (dents-- > 0) {
8953                         dicttabsize += sizeof(struct mac_module_data_list) +
8954                         dents * sizeof(struct mac_module_data_element);
8955                         nents++;
8956                     }
8957                 }
8958                 else {
8959                     continue; /* Skip everything else. */
8960                 }
8961             }
8962             if (nents == 0) {
8963                 continue;
8964             }
8965             listtabsize += sizeof(struct mac_module_data_list) +
8966                 (nents - 1) * sizeof(struct mac_module_data_element);
8967         } else {
8968             continue; /* skip anything else */
8969         }
8970         strtabsize += key->getLength() + 1;
8971         nkeys++;
8972     }
8973     if (nkeys == 0) {
8974         goto finish;
8975     }
8976 
8977    /*
8978     * Allocate and fill in the module data structures.
8979     */
8980     datalen = sizeof(struct mac_module_data) +
8981         sizeof(mac_module_data_element) * (nkeys - 1) +
8982     strtabsize + listtabsize + dicttabsize;
8983     DPRINTF(("osdict: datalen %d strtabsize %d listtabsize %d dicttabsize %d\n",
8984         datalen, strtabsize, listtabsize, dicttabsize));
8985     if (kmem_alloc(kernel_map, &data_addr, datalen) != KERN_SUCCESS) {
8986         goto finish;
8987     }
8988     result = (mac_module_data *)data_addr;
8989     result->base_addr = data_addr;
8990     result->size = datalen;
8991     result->count = nkeys;
8992     strtab = (char *)&result->data[nkeys];
8993     listtab = strtab + strtabsize;
8994     dicttab = listtab + listtabsize;
8995     DPRINTF(("osdict: data_addr %p strtab %p listtab %p dicttab %p end %p\n",
8996         data_addr, strtab, listtab, dicttab, data_addr + datalen));
8997 
8998     keyIterator->reset();
8999     nkeys = 0;
9000     element = &result->data[0];
9001     DPRINTF(("osdict: element %p\n", element));
9002     while ( (key = OSDynamicCast(OSString, keyIterator->getNextObject())) ) {
9003 
9004         // Get the key's value and determine its type
9005         OSObject * value = dict->getObject(key);
9006         if (!value) {
9007             continue;
9008         }
9009 
9010         /* Store key */
9011         DPRINTF(("osdict: element @%p\n", element));
9012         element->key = strtab;
9013         element->key_size = key->getLength() + 1;
9014         DPRINTF(("osdict: key %s size %d @%p\n", key->getCStringNoCopy(),
9015             element->key_size, strtab));
9016         memcpy(element->key, key->getCStringNoCopy(), element->key_size);
9017 
9018         typeID = OSTypeIDInst(value);
9019         if (MACFObjectIsPrimitiveType(value)) {
9020             /* Store value */
9021             element->value = element->key + element->key_size;
9022             DPRINTF(("osdict: primitive element value %p\n", element->value));
9023             MACFInitElementFromObject(element, value);
9024             strtab += element->key_size + element->value_size;
9025             DPRINTF(("osdict: new strtab %p\n", strtab));
9026         } else if (typeID == OSTypeID(OSArray)) {
9027             unsigned int k, cnt, nents;
9028             char *astrtab;
9029             struct mac_module_data_list *arrayhd;
9030             struct mac_module_data_element *ele;
9031             OSArray *arrayObj = OSDynamicCast(OSArray, value);
9032 
9033             element->value = listtab;
9034             DPRINTF(("osdict: array element value %p\n", element->value));
9035             element->value_type = MAC_DATA_TYPE_ARRAY;
9036             arrayhd = (struct mac_module_data_list *)element->value;
9037             arrayhd->type = 0;
9038             DPRINTF(("osdict: arrayhd %p\n", arrayhd));
9039             nents = 0;
9040             astrtab = strtab + element->key_size;
9041             ele = &(arrayhd->list[0]);
9042             cnt = arrayObj->getCount();
9043             for (k = 0; k < cnt; k++) {
9044                 value = arrayObj->getObject(k);
9045                 DPRINTF(("osdict: array ele %d @%p\n", nents, ele));
9046                 ele->key = NULL;
9047                 ele->key_size = 0;
9048                 typeID = OSTypeIDInst(value);
9049                 if (MACFObjectIsPrimitiveType(value)) {
9050                     if (arrayhd->type != 0 &&
9051                         arrayhd->type != MAC_DATA_TYPE_PRIMITIVE) {
9052 
9053                         continue;
9054                     }
9055                     arrayhd->type = MAC_DATA_TYPE_PRIMITIVE;
9056                     ele->value = astrtab;
9057                     MACFInitElementFromObject(ele, value);
9058                     astrtab += ele->value_size;
9059                     DPRINTF(("osdict: array new astrtab %p\n", astrtab));
9060                 } else if (typeID == OSTypeID(OSDictionary)) {
9061                     unsigned int                     dents;
9062                     char                           * dstrtab      = NULL;  // do not free
9063                     OSDictionary                   * dictObj      = NULL;  // do not release
9064                     OSString                       * dictkey      = NULL;  // do not release
9065                     OSCollectionIterator           * dictIterator = NULL;  // must release
9066                     struct mac_module_data_list    * dicthd       = NULL;  // do not free
9067                     struct mac_module_data_element * dele         = NULL;  // do not free
9068 
9069                     if (arrayhd->type != 0 &&
9070                         arrayhd->type != MAC_DATA_TYPE_DICT) {
9071 
9072                         continue;
9073                     }
9074                     dictObj = OSDynamicCast(OSDictionary, value);
9075                     dictIterator = OSCollectionIterator::withCollection(dictObj);
9076                     if (!dictIterator) {
9077                         goto finish;
9078                     }
9079                     DPRINTF(("osdict: dict\n"));
9080                     ele->value = dicttab;
9081                     ele->value_type = MAC_DATA_TYPE_DICT;
9082                     dicthd = (struct mac_module_data_list *)ele->value;
9083                     DPRINTF(("osdict: dicthd %p\n", dicthd));
9084                     dstrtab = astrtab;
9085                     dents = 0;
9086                     while ((dictkey = OSDynamicCast(OSString,
9087                         dictIterator->getNextObject()))) {
9088 
9089                         OSObject * dictvalue = NULL;  // do not release
9090 
9091                         dictvalue = dictObj->getObject(dictkey);
9092                         if (!dictvalue) {
9093                             continue;
9094                         }
9095                         dele = &(dicthd->list[dents]);
9096                         DPRINTF(("osdict: dict ele %d @%p\n", dents, dele));
9097                         if (MACFObjectIsPrimitiveType(dictvalue)) {
9098                             dele->key = dstrtab;
9099                             dele->key_size = dictkey->getLength() + 1;
9100                             DPRINTF(("osdict: dictkey %s size %d @%p\n",
9101                                 dictkey->getCStringNoCopy(), dictkey->getLength(), dstrtab));
9102                             memcpy(dele->key, dictkey->getCStringNoCopy(),
9103                                 dele->key_size);
9104                             dele->value = dele->key + dele->key_size;
9105                             MACFInitElementFromObject(dele, dictvalue);
9106                             dstrtab += dele->key_size + dele->value_size;
9107                             DPRINTF(("osdict: dict new dstrtab %p\n", dstrtab));
9108                         } else {
9109                             continue;    /* Only handle primitive types here. */
9110                         }
9111                         dents++;
9112                     }
9113                     dictIterator->release();
9114                     if (dents == 0) {
9115                         continue;
9116                     }
9117                     arrayhd->type = MAC_DATA_TYPE_DICT;
9118                     ele->value_size = sizeof(struct mac_module_data_list) +
9119                         (dents - 1) * sizeof(struct mac_module_data_element);
9120                     DPRINTF(("osdict: dict ele size %d ents %d\n", ele->value_size, dents));
9121                     dicttab += ele->value_size;
9122                     DPRINTF(("osdict: new dicttab %p\n", dicttab));
9123                     dicthd->count = dents;
9124                     astrtab = dstrtab;
9125                 } else {
9126                     continue;        /* Skip everything else. */
9127                 }
9128                 nents++;
9129                 ele++;
9130             }
9131             if (nents == 0) {
9132                 continue;
9133             }
9134             element->value_size = sizeof(struct mac_module_data_list) +
9135                 (nents - 1) * sizeof(struct mac_module_data_element);
9136             listtab += element->value_size;
9137             DPRINTF(("osdict: new listtab %p\n", listtab));
9138             arrayhd->count = nents;
9139             strtab = astrtab;
9140             DPRINTF(("osdict: new strtab %p\n", strtab));
9141         } else {
9142             continue;        /* skip anything else */
9143         }
9144         element++;
9145     }
9146     DPRINTF(("result list @%p, key %p value %p\n",
9147         result, result->data[0].key, result->data[0].value));
9148 finish:
9149     if (keyIterator) keyIterator->release();
9150     return result;
9151 }
9152 
9153 /*********************************************************************
9154 * This function takes a plist and looks for an OSModuleData dictionary.
9155 * If it is found, an encoded copy is returned. The value must be
9156 * kmem_free()'d.
9157 *********************************************************************/
9158 static void *
9159 MACFCopyModuleDataForKext(
9160     OSKext                 * theKext,
9161     mach_msg_type_number_t * datalen)
9162 
9163 {
9164     struct mac_module_data * result         = NULL;
9165     OSDictionary           * kextModuleData = NULL;  // do not release
9166     vm_map_copy_t            copy           = 0;
9167 
9168     kextModuleData = OSDynamicCast(OSDictionary,
9169         theKext->getPropertyForHostArch("OSModuleData"));
9170     if (!kextModuleData) {
9171         goto finish;
9172     }
9173 
9174     result = MACFEncodeOSDictionary(kextModuleData);
9175     if (!result) {
9176         goto finish;
9177     }
9178     *datalen = module_data->size;
9179 
9180 finish:
9181     return (void *)result;
9182 }
9183 #endif /* CONFIG_MACF_KEXT */
9184