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