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