1/*
2 * Copyright (c) 2012 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23#include <asl.h>
24#include <IOKit/kext/OSKext.h>
25#include <IOKit/kext/OSKextPrivate.h>
26#include <IOKit/IOKitLib.h>
27#include <Security/Security.h>
28
29#include "security.h"
30#include "kext_tools_util.h"
31
32/*******************************************************************************
33 * Helper functions
34 *******************************************************************************/
35static OSStatus     checkRootCertificateIsApple(OSKextRef aKext);
36static CFStringRef  copyCDHash(SecStaticCodeRef code);
37static CFStringRef  copyIssuerCN(SecCertificateRef certificate);
38static void         copySigningInfo(CFURLRef kextURL,
39                                    CFStringRef* cdhash,
40                                    CFStringRef* teamId,
41                                    CFStringRef* subjectCN,
42                                    CFStringRef* issuerCN);
43static CFArrayRef   copySubjectCNArray(CFURLRef kextURL);
44static CFStringRef  copyTeamID(SecCertificateRef certificate);
45static CFStringRef  createArchitectureList(OSKextRef aKext, CFBooleanRef *isFat);
46static void         createHashForMT(CFURLRef kextURL, char ** signatureBuffer);
47static void         filterKextLoadForMT(OSKextRef aKext, CFMutableArrayRef *kextList);
48
49/*******************************************************************************
50 * messageTraceExcludedKext() - log MessageTracer message for kexts in
51 * exclude list.
52 *  <rdar://problem/12994418> MessageTrace when we block the load of something
53 *                            on the kext exclude list
54 *******************************************************************************/
55
56void messageTraceExcludedKext(OSKextRef theKext)
57{
58    CFStringRef     versionString;
59    CFStringRef     bundleIDString;
60    CFURLRef        kextURL             = NULL;   // must release
61    CFStringRef     filename            = NULL;   // must release
62    aslmsg          amsg                = NULL;   // must free
63    char            *versionCString     = NULL;   // must free
64    char            *bundleIDCString    = NULL;   // must free
65    char            *filenameCString    = NULL;   // must free
66
67    kextURL = CFURLCopyAbsoluteURL(OSKextGetURL(theKext));
68    if (!kextURL) {
69        OSKextLogMemError();
70        goto finish;
71    }
72    versionString = OSKextGetValueForInfoDictionaryKey(theKext,
73                                                       kCFBundleVersionKey);
74    if (versionString) {
75        versionCString = createUTF8CStringForCFString(versionString);
76    }
77    bundleIDString = OSKextGetValueForInfoDictionaryKey(theKext,
78                                                        kCFBundleIdentifierKey);
79    if (bundleIDString) {
80        bundleIDCString = createUTF8CStringForCFString(bundleIDString);
81    }
82
83    filename = CFURLCopyLastPathComponent(kextURL);
84    if (filename) {
85        filenameCString = createUTF8CStringForCFString(filename);
86    }
87    SAFE_RELEASE(filename);
88
89    /* log the message tracer data
90     */
91    amsg = asl_new(ASL_TYPE_MSG);
92    if (!amsg) {
93        OSKextLogMemError();
94        goto finish;
95    }
96
97    asl_set(amsg, kMessageTracerDomainKey, kMTKextBlockedDomain);
98    asl_set(amsg, kMessageTracerBundleIDKey,
99            bundleIDCString ? bundleIDCString : "");
100    asl_set(amsg, kMessageTracerVersionKey,
101            versionCString ? versionCString : "");
102    asl_set(amsg, kMessageTracerKextNameKey,
103            filenameCString ? filenameCString : "");
104
105    asl_log(NULL, amsg, ASL_LEVEL_NOTICE, "");
106
107finish:
108    SAFE_FREE(versionCString);
109    SAFE_FREE(bundleIDCString);
110    SAFE_FREE(filenameCString);
111
112    SAFE_RELEASE(kextURL);
113
114    if (amsg) {
115        asl_free(amsg);
116    }
117    return;
118}
119
120/*******************************************************************************
121 * checkRootCertificateIsApple() - check if the root certificate of the kext
122 *  is issued by Apple
123 *  <rdar://problem/12435992>
124 *******************************************************************************/
125static OSStatus checkRootCertificateIsApple(OSKextRef aKext)
126{
127    OSStatus                result          = -1;
128    CFURLRef                kextURL         = NULL;   // must release
129    SecStaticCodeRef        staticCodeRef   = NULL;   // must release
130    SecRequirementRef       requirementRef  = NULL;   // must release
131    CFStringRef             myCFString;
132    CFStringRef             requirementsString;
133
134    if (aKext == NULL) {
135        return result;
136    }
137
138    kextURL = CFURLCopyAbsoluteURL(OSKextGetURL(aKext));
139    if (!kextURL) {
140        OSKextLogMemError();
141        goto finish;
142    }
143
144    if (SecStaticCodeCreateWithPath(kextURL,
145                                    kSecCSDefaultFlags,
146                                    &staticCodeRef) != errSecSuccess ||
147        (staticCodeRef == NULL)) {
148        OSKextLogMemError();
149        goto finish;
150    }
151
152    /* set up correct requirement string */
153    myCFString = OSKextGetIdentifier(aKext);
154    if (CFStringHasPrefix(myCFString, __kOSKextApplePrefix)) {
155        requirementsString = CFSTR("anchor apple");
156    }
157    else {
158        requirementsString = CFSTR("anchor apple generic");
159    }
160
161    if (SecRequirementCreateWithString(requirementsString,
162                                       kSecCSDefaultFlags,
163                                       &requirementRef) != errSecSuccess ||
164        (requirementRef == NULL)) {
165        OSKextLogMemError();
166        goto finish;
167    }
168
169    // errSecCSUnsigned == -67062
170    result = SecStaticCodeCheckValidity(staticCodeRef,
171                                        kSecCSDefaultFlags,
172                                        requirementRef);
173    if (result != 0) {
174        OSKextLogCFString(NULL,
175                          kOSKextLogErrorLevel | kOSKextLogLoadFlag,
176                          CFSTR("Invalid signature %ld for kext %@"),
177                          (long)result, aKext);
178    }
179
180finish:
181    SAFE_RELEASE(kextURL);
182    SAFE_RELEASE(staticCodeRef);
183    SAFE_RELEASE(requirementRef);
184
185    return result;
186}
187
188/*******************************************************************************
189 * createHashForMT() - create a hash signature for the kext
190 *  <rdar://problem/12435992>
191 *******************************************************************************/
192
193static void createHashForMT(CFURLRef kextURL, char ** signatureBuffer)
194{
195    CFMutableDictionaryRef signdict     = NULL;   // must release
196    SecCodeSignerRef    signerRef       = NULL;   // must release
197    SecStaticCodeRef    staticCodeRef   = NULL;   // must release
198    CFDataRef           signature       = NULL;   // must release
199    CFDictionaryRef     signingDict     = NULL;   // must release
200    CFDataRef           cdhash          = NULL;   // must release
201    CFMutableDictionaryRef resourceRules = NULL;  // must release
202    CFMutableDictionaryRef rules        = NULL;   // must release
203    CFMutableDictionaryRef omitPlugins  = NULL;   // must release
204    char *              tempBufPtr      = NULL;   // do not free
205
206    if (!kextURL || !signatureBuffer) {
207        return;
208    }
209
210    /* Ad-hoc sign the code temporarily so we can get its hash */
211    if (SecStaticCodeCreateWithPath(kextURL,
212                                    kSecCSDefaultFlags,
213                                    &staticCodeRef) != 0 ||
214        (staticCodeRef == NULL)) {
215        OSKextLogMemError();
216        goto finish;
217    }
218
219    signature = CFDataCreateMutable(NULL, 0);
220    if (signature == NULL) {
221        OSKextLogMemError();
222        goto finish;
223    }
224
225    signdict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
226                                         &kCFTypeDictionaryKeyCallBacks,
227                                         &kCFTypeDictionaryValueCallBacks);
228    if (signdict == NULL) {
229        OSKextLogMemError();
230        goto finish;
231    }
232
233    CFDictionarySetValue(signdict, kSecCodeSignerIdentity, kCFNull);
234    CFDictionarySetValue(signdict, kSecCodeSignerDetached, signature);
235
236    resourceRules = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
237                                              &kCFTypeDictionaryKeyCallBacks,
238                                              &kCFTypeDictionaryValueCallBacks);
239    if (resourceRules == NULL) {
240        OSKextLogMemError();
241        goto finish;
242    }
243
244    rules = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
245                                      &kCFTypeDictionaryKeyCallBacks,
246                                      &kCFTypeDictionaryValueCallBacks);
247    if (rules == NULL) {
248        OSKextLogMemError();
249        goto finish;
250    }
251
252    omitPlugins = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
253                                            &kCFTypeDictionaryKeyCallBacks,
254                                            &kCFTypeDictionaryValueCallBacks);
255    if (omitPlugins == NULL) {
256        OSKextLogMemError();
257        goto finish;
258    }
259
260    /* exclude PlugIns directory
261     */
262    CFNumberRef myNumValue;
263    int myNum = 100;
264    myNumValue = CFNumberCreate(kCFAllocatorDefault,
265                                kCFNumberIntType, &myNum);
266    if (myNumValue == NULL) {
267        OSKextLogMemError();
268        goto finish;
269    }
270
271    CFDictionarySetValue(omitPlugins, CFSTR("omit"), kCFBooleanTrue);
272    CFDictionarySetValue(omitPlugins, CFSTR("weight"), myNumValue);
273    CFRelease( myNumValue );
274
275    CFDictionarySetValue(rules, CFSTR("^.*"), kCFBooleanTrue);
276    CFDictionarySetValue(rules, CFSTR("^PlugIns/"), omitPlugins);
277    CFDictionarySetValue(resourceRules, CFSTR("rules"), rules);
278    CFDictionarySetValue(signdict, kSecCodeSignerResourceRules, resourceRules);
279
280    if (SecCodeSignerCreate(signdict, kSecCSDefaultFlags, &signerRef) != 0) {
281        OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogGeneralFlag,
282                  "%s - SecCodeSignerCreate failed", __func__);
283        goto finish;
284    }
285    if (SecCodeSignerAddSignature(signerRef, staticCodeRef, kSecCSDefaultFlags) != 0) {
286        OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogGeneralFlag,
287                  "%s - SecCodeSignerAddSignature failed", __func__);
288        goto finish;
289    }
290    if (SecCodeSetDetachedSignature(staticCodeRef, signature, kSecCSDefaultFlags) != 0) {
291        OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogGeneralFlag,
292                  "%s - SecCodeSetDetachedSignature failed", __func__);
293        goto finish;
294    }
295
296    /* get the hash info
297     */
298    if (SecCodeCopySigningInformation(staticCodeRef, kSecCSDefaultFlags, &signingDict) != 0) {
299        OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogGeneralFlag,
300                  "%s - SecCodeCopySigningInformation failed", __func__);
301        goto finish;
302    }
303
304    cdhash = CFRetain(CFDictionaryGetValue(signingDict, kSecCodeInfoUnique));
305    if (cdhash) {
306        const UInt8 *   hashDataPtr     = NULL;  // don't free
307        CFIndex         hashDataLen     = 0;
308
309        hashDataPtr = CFDataGetBytePtr(cdhash);
310        hashDataLen = CFDataGetLength(cdhash);
311        tempBufPtr = (char *) malloc((hashDataLen + 1) * 2);
312        if (tempBufPtr == NULL) {
313            OSKextLogMemError();
314            goto finish;
315        }
316#if 0
317        OSKextLogCFString(/* kext */ NULL,
318                          kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
319                          CFSTR("%s - cdhash %@"),
320                          __func__,
321                          cdhash);
322#endif
323
324        bzero(tempBufPtr, ((hashDataLen + 1) * 2));
325        for (int i = 0; i < hashDataLen; i++) {
326            sprintf(tempBufPtr + (i * 2), "%02.2x", *(hashDataPtr + i));
327        }
328    }
329
330finish:
331    SAFE_RELEASE(signdict);
332    SAFE_RELEASE(signerRef);
333    SAFE_RELEASE(staticCodeRef);
334    SAFE_RELEASE(signature);
335    SAFE_RELEASE(signingDict);
336    SAFE_RELEASE(cdhash);
337    SAFE_RELEASE(resourceRules);
338    SAFE_RELEASE(rules);
339    SAFE_RELEASE(omitPlugins);
340
341    *signatureBuffer = tempBufPtr;
342}
343
344/*******************************************************************************
345 * createArchitectureList() - create the list of architectures for the kext
346 *  <rdar://13529984>
347 *  Note: the caller must release the created CFStringRef
348 *******************************************************************************/
349static CFStringRef createArchitectureList(OSKextRef aKext, CFBooleanRef *isFat)
350{
351    if (aKext == NULL || isFat == NULL) {
352        return NULL;
353    }
354
355    *isFat = kCFBooleanFalse;
356
357    const NXArchInfo **         archList            = NULL; // must free
358    CFMutableArrayRef           archNamesList       = NULL; // must release
359    CFStringRef                 archNames           = NULL; // do not release
360    const char *                archNameCString     = NULL; // do not free
361    int                         index               = 0;
362
363    archList = OSKextCopyArchitectures(aKext);
364    if (!archList) {
365        goto finish;
366    }
367
368    archNamesList = CFArrayCreateMutable(kCFAllocatorDefault,
369                                         0,
370                                         &kCFTypeArrayCallBacks);
371    if (!archNamesList) {
372        goto finish;
373    }
374
375    for (index=0; archList[index]; index++) {
376        archNameCString = archList[index]->name;
377        if (archNameCString) {
378            CFStringRef archName = NULL;
379            archName = CFStringCreateWithCString(kCFAllocatorDefault,
380                                                 archNameCString,
381                                                 kCFStringEncodingUTF8);
382            if (archName) {
383                CFArrayAppendValue(archNamesList, archName);
384                SAFE_RELEASE_NULL(archName);
385            }
386        }
387    }
388
389    if (index>1) {
390        *isFat = kCFBooleanTrue;
391    }
392    archNames = CFStringCreateByCombiningStrings(kCFAllocatorDefault,
393                                                 archNamesList,
394                                                 CFSTR(" "));
395    if (!archNames) {
396        goto finish;
397    }
398
399finish:
400    SAFE_RELEASE(archNamesList);
401    SAFE_FREE(archList);
402
403    return archNames;
404}
405
406/*******************************************************************************
407 * copyTeamID() - copy the team id field from the given certificate
408 *  <rdar://13646260>
409 *  Note: the caller must release the created CFStringRef
410 *******************************************************************************/
411static CFStringRef copyTeamID(SecCertificateRef certificate)
412{
413    if (!certificate ||
414        CFGetTypeID(certificate) !=SecCertificateGetTypeID()) {
415        return NULL;
416    }
417
418    CFDictionaryRef     subjectDict     = NULL; // do not release
419    CFArrayRef          subjectArray    = NULL; // do not release
420    CFDictionaryRef     subjectInfo     = NULL; // do not release
421    CFStringRef         teamID          = NULL; // do not release
422    CFErrorRef          error           = NULL; // do not release
423
424    CFMutableArrayRef   certificateKeys = NULL; // must release
425    CFDictionaryRef     certificateDict = NULL; // must release
426
427    certificateKeys = CFArrayCreateMutable(kCFAllocatorDefault,
428                                           1,
429                                           &kCFTypeArrayCallBacks);
430    if (!certificateKeys) {
431        goto finish;
432    }
433
434    CFArrayAppendValue(certificateKeys, kSecOIDX509V1SubjectName);
435
436    certificateDict = SecCertificateCopyValues(certificate,
437                                               certificateKeys,
438                                               &error);
439    if (error != errSecSuccess ||
440        !certificateDict ||
441        CFGetTypeID(certificateDict) != CFDictionaryGetTypeID()) {
442        goto finish;
443    }
444
445    subjectDict = (CFDictionaryRef) CFDictionaryGetValue(certificateDict,
446                                                         kSecOIDX509V1SubjectName);
447    if (!subjectDict ||
448        CFGetTypeID(subjectDict) != CFDictionaryGetTypeID()) {
449        goto finish;
450    }
451
452    subjectArray = (CFArrayRef) CFDictionaryGetValue(subjectDict,
453                                                     kSecPropertyKeyValue);
454    if (!subjectArray ||
455        CFGetTypeID(subjectArray) != CFArrayGetTypeID()) {
456        goto finish;
457    }
458
459    // Try to look for UserID field ("0.9.2342.19200300.100.1.1")
460    for (int index=0; index<CFArrayGetCount(subjectArray); index++) {
461        subjectInfo = (CFDictionaryRef) CFArrayGetValueAtIndex(subjectArray,
462                                                               index);
463        if (!subjectInfo ||
464            CFGetTypeID(subjectInfo) != CFDictionaryGetTypeID()) {
465            continue;
466        }
467
468        CFStringRef label = NULL; // do not release
469        label = CFDictionaryGetValue(subjectInfo,
470                                     kSecPropertyKeyLabel);
471        if (kCFCompareEqualTo == CFStringCompare(label,
472                                                 CFSTR("0.9.2342.19200300.100.1.1"),
473                                                 0)) {
474            teamID = CFDictionaryGetValue(subjectInfo,
475                                          kSecPropertyKeyValue);
476            if (teamID &&
477                CFGetTypeID(teamID) == CFStringGetTypeID()) {
478                CFRetain(teamID);
479                goto finish;
480            }
481            else {
482                teamID = NULL;
483            }
484        }
485    }
486
487    // In case of failure, look for OU field ("2.5.4.11")
488    if (!teamID) {
489        for (int index=0; index<CFArrayGetCount(subjectArray); index++) {
490            subjectInfo = (CFDictionaryRef) CFArrayGetValueAtIndex(subjectArray,
491                                                                   index);
492            if (!subjectInfo ||
493                CFGetTypeID(subjectInfo) != CFDictionaryGetTypeID()) {
494                continue;
495            }
496
497            CFStringRef label = NULL; // do not release
498            label = CFDictionaryGetValue(subjectInfo,
499                                         kSecPropertyKeyLabel);
500            if (kCFCompareEqualTo == CFStringCompare(label,
501                                                     CFSTR("2.5.4.11"),
502                                                     0)) {
503                teamID = CFDictionaryGetValue(subjectInfo,
504                                              kSecPropertyKeyValue);
505                if (teamID &&
506                    CFGetTypeID(teamID) == CFStringGetTypeID()) {
507                    CFRetain(teamID);
508                    goto finish;
509                }
510                else {
511                    teamID = NULL;
512                }
513            }
514        }
515    }
516
517finish:
518    if (!teamID && subjectArray) {
519        CFShow(subjectArray);
520    }
521    SAFE_RELEASE(certificateKeys);
522    SAFE_RELEASE(certificateDict);
523    return teamID;
524}
525
526/*******************************************************************************
527 * copyIssuerCN() - copy the issuer CN field from the given certificate
528 *  <rdar://13646260>
529 *  Note: the caller must release the created CFStringRef
530 *******************************************************************************/
531static CFStringRef copyIssuerCN(SecCertificateRef certificate)
532{
533    if (!certificate ||
534        CFGetTypeID(certificate) !=SecCertificateGetTypeID()) {
535        return NULL;
536    }
537
538    CFStringRef         issuerCN        = NULL; // do not release
539    CFDictionaryRef     issuerDict      = NULL; // do not release
540    CFArrayRef          issuerArray     = NULL; // do not release
541    CFDictionaryRef     issuerInfo      = NULL; // do not release
542    CFErrorRef          error           = NULL; // do not release
543
544    CFMutableArrayRef   certificateKeys = NULL; // must release
545    CFDictionaryRef     certificateDict = NULL; // must release
546
547    certificateKeys = CFArrayCreateMutable(kCFAllocatorDefault,
548                                           1,
549                                           &kCFTypeArrayCallBacks);
550    if (!certificateKeys) {
551        goto finish;
552    }
553
554    CFArrayAppendValue(certificateKeys, kSecOIDX509V1IssuerName);
555
556    certificateDict = SecCertificateCopyValues(certificate,
557                                               certificateKeys,
558                                               &error);
559
560    if (error != errSecSuccess ||
561        !certificateDict ||
562        CFGetTypeID(certificateDict) != CFDictionaryGetTypeID()) {
563        goto finish;
564    }
565
566    issuerDict = (CFDictionaryRef) CFDictionaryGetValue(certificateDict,
567                                                        kSecOIDX509V1IssuerName);
568    if (!issuerDict ||
569        CFGetTypeID(issuerDict) != CFDictionaryGetTypeID()) {
570        goto finish;
571    }
572
573    issuerArray = (CFArrayRef) CFDictionaryGetValue(issuerDict,
574                                                    kSecPropertyKeyValue);
575    if (!issuerArray ||
576        CFGetTypeID(issuerArray) != CFArrayGetTypeID()) {
577        goto finish;
578    }
579
580    for (int index=0; index<CFArrayGetCount(issuerArray); index++) {
581        issuerInfo = (CFDictionaryRef) CFArrayGetValueAtIndex(issuerArray,
582                                                              index);
583        if (!issuerInfo ||
584            CFGetTypeID(issuerInfo) != CFDictionaryGetTypeID()) {
585            continue;
586        }
587
588        CFStringRef label = NULL; // do not release
589        label = CFDictionaryGetValue(issuerInfo,
590                                     kSecPropertyKeyLabel);
591        if (kCFCompareEqualTo == CFStringCompare(label,
592                                                 CFSTR("2.5.4.3"),
593                                                 0)) {
594            issuerCN = CFDictionaryGetValue(issuerInfo,
595                                            kSecPropertyKeyValue);
596            if (issuerCN &&
597                CFGetTypeID(issuerCN) == CFStringGetTypeID()) {
598                CFRetain(issuerCN);
599                goto finish;
600            }
601            else {
602                issuerCN = NULL;
603            }
604        }
605    }
606
607finish:
608    SAFE_RELEASE(certificateDict);
609    SAFE_RELEASE(certificateKeys);
610    return issuerCN;
611}
612
613/*******************************************************************************
614 * copyCDHash() - copy the SHA-1 hash of the code
615 *  <rdar://13646260>
616 *  Note: the caller must release the created CFStringRef
617 *******************************************************************************/
618static CFStringRef copyCDHash(SecStaticCodeRef code)
619{
620    CFDictionaryRef signingInfo     = NULL; // must release
621    char *          tempBufPtr      = NULL; // free
622    const UInt8 *   hashDataPtr     = NULL; // do not free
623    CFDataRef       cdhash          = NULL; // do not release
624    CFStringRef     hash            = NULL; // do not release
625    CFIndex         hashDataLen     = 0;
626
627    SecCodeCopySigningInformation(code,
628                                  kSecCSDefaultFlags,
629                                  &signingInfo);
630    if (!signingInfo) {
631        goto finish;
632    }
633
634    cdhash = CFDictionaryGetValue(signingInfo, kSecCodeInfoUnique);
635    if (!cdhash ||
636        CFGetTypeID(cdhash) != CFDataGetTypeID()) {
637        goto finish;
638    }
639
640    hashDataPtr = CFDataGetBytePtr(cdhash);
641    hashDataLen = CFDataGetLength(cdhash);
642    tempBufPtr = (char *) malloc((hashDataLen + 1) * 2);
643    if (tempBufPtr == NULL) {
644        OSKextLogMemError();
645        goto finish;
646    }
647
648    bzero(tempBufPtr, ((hashDataLen + 1) * 2));
649    for (int i = 0; i < hashDataLen; i++) {
650        sprintf(tempBufPtr + (i * 2), "%02.2x", *(hashDataPtr + i));
651    }
652
653    if (tempBufPtr) {
654        hash = CFStringCreateWithCString(kCFAllocatorDefault,
655                                         tempBufPtr,
656                                         kCFStringEncodingUTF8);
657    }
658
659finish:
660    SAFE_FREE(tempBufPtr);
661    SAFE_RELEASE(signingInfo);
662    return hash;
663}
664
665/*******************************************************************************
666 * copySigningInfo() - copy a set of signing information for the given kext
667 *  cdhash:     the SHA-1 hash
668 *  teamid:     the team id of the leaf certificate
669 *  subjectCN:  the subject common name of the leaf certificate
670 *  issuerCN:   the issuer common name of the leaf certificate
671 *  <rdar://13646260>
672 *  Note: the caller must release the created CFStringRefs
673 *******************************************************************************/
674static void copySigningInfo(CFURLRef kextURL,
675                            CFStringRef* cdhash,
676                            CFStringRef* teamId,
677                            CFStringRef* subjectCN,
678                            CFStringRef* issuerCN)
679{
680    if (!kextURL) {
681        return;
682    }
683
684    SecStaticCodeRef    code                = NULL; // must release
685    CFDictionaryRef     information         = NULL; // must release
686
687    SecCertificateRef   issuerCertificate   = NULL; // do not release
688    CFArrayRef          certificateChain    = NULL; // do not release
689    OSStatus            status;
690    CFIndex             count;
691
692    if (SecStaticCodeCreateWithPath(kextURL,
693                                    kSecCSDefaultFlags,
694                                    &code) != 0
695        || (code == NULL)) {
696        OSKextLogMemError();
697        goto finish;
698    }
699
700    if (cdhash) {
701        *cdhash = copyCDHash(code);
702    }
703
704    status = SecCodeCopySigningInformation(code,
705                                           kSecCSSigningInformation,
706                                           &information);
707    if (status != noErr) {
708        goto finish;
709    }
710
711    // a CFArrayRef array of SecCertificateRef objects
712    certificateChain = (CFArrayRef) CFDictionaryGetValue(information, kSecCodeInfoCertificates);
713    if (!certificateChain ||
714        CFGetTypeID(certificateChain) != CFArrayGetTypeID()) {
715        goto finish;
716    }
717
718    count = CFArrayGetCount(certificateChain);
719    if (count < 1) {
720        goto finish;
721    }
722
723    issuerCertificate = (SecCertificateRef) CFArrayGetValueAtIndex(certificateChain, 0);
724    if (!issuerCertificate) {
725        goto finish;
726    }
727
728    if (subjectCN) {
729        SecCertificateCopyCommonName(issuerCertificate, subjectCN);
730    }
731
732    if (teamId) {
733        *teamId = copyTeamID(issuerCertificate);
734    }
735
736    if (issuerCN) {
737        *issuerCN = copyIssuerCN(issuerCertificate);
738    }
739
740finish:
741    SAFE_RELEASE(code);
742    SAFE_RELEASE(information);
743
744    return;
745}
746
747/*******************************************************************************
748 * copySubjectCNArray() - copy the subject CN from every certificate in the kext's
749 *  certificate chain.
750 *  <rdar://13646260>
751 *  Note: the caller must release the created CFArrayRef
752 *******************************************************************************/
753static CFArrayRef copySubjectCNArray(CFURLRef kextURL)
754{
755    if (!kextURL) {
756        return NULL;
757    }
758
759    CFMutableArrayRef   subjectCNArray      = NULL; // do not release
760    CFArrayRef          certificateChain    = NULL; // do not release
761    SecCertificateRef   certificate         = NULL; // do not release
762
763    SecStaticCodeRef    code                = NULL; // must release
764    CFDictionaryRef     information         = NULL; // must release
765
766    OSStatus            status;
767    CFIndex             count;
768
769    subjectCNArray = CFArrayCreateMutable(kCFAllocatorDefault,
770                                          0,
771                                          &kCFTypeArrayCallBacks);
772    if (!subjectCNArray) {
773        goto finish;
774    }
775
776    if (SecStaticCodeCreateWithPath(kextURL,
777                                    kSecCSDefaultFlags,
778                                    &code) != 0
779        || (code == NULL)) {
780        OSKextLogMemError();
781        goto finish;
782    }
783
784    status = SecCodeCopySigningInformation(code,
785                                           kSecCSSigningInformation,
786                                           &information);
787    if (status != noErr) {
788        goto finish;
789    }
790
791    certificateChain = (CFArrayRef) CFDictionaryGetValue(information, kSecCodeInfoCertificates);
792    if (!certificateChain ||
793        CFGetTypeID(certificateChain) != CFArrayGetTypeID()) {
794        goto finish;
795    }
796
797    count = CFArrayGetCount(certificateChain);
798    if (count < 1) {
799        goto finish;
800    }
801
802    for (CFIndex i=0; i<count; i++) {
803        certificate = (SecCertificateRef) CFArrayGetValueAtIndex(certificateChain, i);
804        CFStringRef subjectCN = NULL; // must release
805        SecCertificateCopyCommonName(certificate, &subjectCN);
806        if (subjectCN) {
807            CFArrayAppendValue(subjectCNArray, subjectCN);
808            SAFE_RELEASE(subjectCN);
809        }
810    }
811
812finish:
813    SAFE_RELEASE(code);
814    SAFE_RELEASE(information);
815
816    return subjectCNArray;
817}
818
819/*******************************************************************************
820 * filterKextLoadForMT() - check that the kext is of interest, and place kext
821 * information in the kext list
822 *  <rdar://problem/12435992>
823 *******************************************************************************/
824
825static void filterKextLoadForMT(OSKextRef aKext, CFMutableArrayRef *kextList)
826{
827    if (aKext == NULL || kextList == NULL)
828        return;
829
830    CFStringRef     versionString;                // do not release
831    CFStringRef     bundleIDString;               // do not release
832    CFStringRef     kextSigningCategory = NULL;   // do not release
833    CFBooleanRef    isFat               = kCFBooleanFalse; // do not release
834    CFBooleanRef    isSigned            = kCFBooleanFalse; // do not release
835
836    CFURLRef        kextURL             = NULL;   // must release
837    CFStringRef     kextPath            = NULL;   // must release
838    CFStringRef     filename            = NULL;   // must release
839    CFStringRef     hashString          = NULL;   // must release
840    CFStringRef     archString          = NULL;   // must release
841    CFStringRef     teamId              = NULL;   // must release
842    CFStringRef     subjectCN           = NULL;   // must release
843    CFStringRef     issuerCN            = NULL;   // must release
844
845    SecStaticCodeRef        code        = NULL;   // must release
846    CFDictionaryRef         information = NULL;   // must release
847    CFMutableDictionaryRef  kextDict    = NULL;   // must release
848
849    char *          hashCString         = NULL;   // must free
850
851    OSStatus status = noErr;
852
853    /* do not message trace this if boot-args has debug set */
854    if (isDebugSetInBootargs()) {
855        return;
856    }
857
858    kextURL = CFURLCopyAbsoluteURL(OSKextGetURL(aKext));
859    if (!kextURL) {
860        OSKextLogMemError();
861        goto finish;
862    }
863    kextPath = CFURLCopyFileSystemPath(kextURL, kCFURLPOSIXPathStyle);
864    if (!kextPath) {
865        OSKextLogMemError();
866        goto finish;
867    }
868
869    versionString   = OSKextGetValueForInfoDictionaryKey(aKext,
870                                                         kCFBundleVersionKey);
871    bundleIDString  = OSKextGetValueForInfoDictionaryKey(aKext,
872                                                         kCFBundleIdentifierKey);
873    filename = CFURLCopyLastPathComponent(kextURL);
874
875    archString = createArchitectureList(aKext, &isFat);
876
877    if (SecStaticCodeCreateWithPath(kextURL,
878                                    kSecCSDefaultFlags,
879                                    &code) != 0
880        || (code == NULL)) {
881        OSKextLogMemError();
882        goto finish;
883    }
884    status = SecCodeCopySigningInformation(code,
885                                           kSecCSSigningInformation,
886                                           &information);
887    if (status != noErr) {
888        goto finish;
889    }
890
891    isSigned = CFDictionaryContainsKey(information, kSecCodeInfoIdentifier);
892    if (!isSigned) {
893        /* The kext is unsigned, so there is little information we can retrieve.
894         * A hash of the kext is generated for data collection. */
895        kextSigningCategory = CFSTR(kUnsignedKext);
896
897        createHashForMT(kextURL, &hashCString);
898        if (hashCString) {
899            hashString = CFStringCreateWithCString(kCFAllocatorDefault,
900                                                   hashCString,
901                                                   kCFStringEncodingUTF8);
902        }
903    }
904    else {
905        CFStringRef myCFString = NULL; // do not release
906        myCFString = OSKextGetIdentifier(aKext);
907        status = checkKextSignature(aKext, true);
908        if (CFStringHasPrefix(myCFString, __kOSKextApplePrefix)) {
909            if (status == noErr) {
910                /* This is a signed Apple kext, with an Apple root certificate.
911                 * There is no need to retrieve additional signing information */
912                kextSigningCategory = CFSTR(kAppleKextWithAppleRoot);
913                copySigningInfo(kextURL,
914                                &hashString,
915                                NULL,
916                                NULL,
917                                NULL);
918            }
919            else {
920                /* This is a signed Apple kext, but the root certificate is not Apple.
921                 * This should not happen, so it is better to flag it as unsigned for
922                 * collection purpose. */
923                kextSigningCategory = CFSTR(kUnsignedKext);
924                copySigningInfo(kextURL,
925                                &hashString,
926                                &teamId,
927                                NULL,
928                                &issuerCN);
929                CFArrayRef subjectCNArray = NULL; // must release
930                subjectCNArray = copySubjectCNArray(kextURL);
931                if (subjectCNArray) {
932                    subjectCN = CFStringCreateByCombiningStrings(kCFAllocatorDefault,
933                                                                 subjectCNArray,
934                                                                 CFSTR(";"));
935                    SAFE_RELEASE(subjectCNArray);
936                }
937            }
938        }
939        else {
940            if (status == noErr) {
941                /* This 3rd-party kext is signed with a devid+ kext certificate */
942                kextSigningCategory = CFSTR(k3rdPartyKextWithDevIdPlus);
943                copySigningInfo(kextURL,
944                                &hashString,
945                                &teamId,
946                                &subjectCN,
947                                &issuerCN);
948            }
949            else if (status == CSSMERR_TP_CERT_REVOKED) {
950                /* This 3rd-party kext is signed with a revoked devid+ kext certificate */
951                kextSigningCategory = CFSTR(k3rdPartyKextWithRevokedDevIdPlus);
952                copySigningInfo(kextURL,
953                                &hashString,
954                                &teamId,
955                                &subjectCN,
956                                &issuerCN);
957            }
958            else {
959                status = checkRootCertificateIsApple(aKext);
960                if (status == noErr) {
961                    /* This 3rd-party kext is not signed with a devid+ certificate,
962                     * but uses an Apple root certificate. */
963                    kextSigningCategory = CFSTR(k3rdPartyKextWithAppleRoot);
964                    /* The certificates may not have the expected format.
965                     * Attempt to get the information if present, and also
966                     * retrieve the subject cn of every certificate in the chain. */
967                    copySigningInfo(kextURL,
968                                    &hashString,
969                                    &teamId,
970                                    NULL,
971                                    &issuerCN);
972                    CFArrayRef subjectCNArray = NULL; // must release
973                    subjectCNArray = copySubjectCNArray(kextURL);
974                    if (subjectCNArray) {
975                        subjectCN = CFStringCreateByCombiningStrings(kCFAllocatorDefault,
976                                                                     subjectCNArray,
977                                                                     CFSTR(";"));
978                        SAFE_RELEASE(subjectCNArray);
979                    }
980                }
981                else {
982                    /* This 3rd-party kext is not signed with a devid+ certificate,
983                     * and does not use an Apple root certificate. */
984                    kextSigningCategory = CFSTR(k3rdPartyKextWithoutAppleRoot);
985                    /* The certificates may not have the expected format.
986                     * The subjectcn, issuercn and teamid must not be logged. */
987                    copySigningInfo(kextURL,
988                                    &hashString,
989                                    NULL,
990                                    NULL,
991                                    NULL);
992                }
993            }
994        }
995    }
996
997    kextDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
998                                         0,
999                                         &kCFTypeDictionaryKeyCallBacks,
1000                                         &kCFTypeDictionaryValueCallBacks);
1001    if (!kextDict) {
1002        OSKextLogMemError();
1003        goto finish;
1004    }
1005
1006    if (bundleIDString) {
1007        CFDictionaryAddValue(kextDict,
1008                             CFSTR(kMessageTracerBundleIDKey),
1009                             bundleIDString);
1010    }
1011    if (versionString) {
1012        CFDictionaryAddValue(kextDict,
1013                             CFSTR(kMessageTracerVersionKey),
1014                             versionString);
1015    }
1016    if (filename) {
1017        CFDictionaryAddValue(kextDict,
1018                             CFSTR(kMessageTracerKextNameKey),
1019                             filename);
1020    }
1021    if (isFat != NULL) {
1022        CFDictionaryAddValue(kextDict,
1023                             CFSTR(kMessageTracerFatKey),
1024                             isFat);
1025    }
1026    if (archString) {
1027        CFDictionaryAddValue(kextDict,
1028                             CFSTR(kMessageTracerArchKey),
1029                             archString);
1030    }
1031
1032    if (kextSigningCategory) {
1033        CFDictionaryAddValue(kextDict,
1034                             CFSTR(kMessageTracerSignatureTypeKey),
1035                             kextSigningCategory);
1036    }
1037
1038    if (hashString) {
1039        CFDictionaryAddValue(kextDict,
1040                             CFSTR(kMessageTracerHashKey),
1041                             hashString);
1042    }
1043
1044    if (teamId) {
1045        CFDictionaryAddValue(kextDict,
1046                             CFSTR(kMessageTracerTeamIdKey),
1047                             teamId);
1048    }
1049    if (subjectCN) {
1050        CFDictionaryAddValue(kextDict,
1051                             CFSTR(kMessageTracerSubjectCNKey),
1052                             subjectCN);
1053    }
1054    if (issuerCN) {
1055        CFDictionaryAddValue(kextDict,
1056                             CFSTR(kMessageTracerIssuerCNKey),
1057                             issuerCN);
1058    }
1059
1060    if (kextPath) {
1061        CFDictionaryAddValue(kextDict,
1062                             CFSTR(kMessageTracerPathKey),
1063                             kextPath);
1064    }
1065
1066
1067    CFArrayAppendValue(*kextList, kextDict);
1068
1069finish:
1070    SAFE_FREE(hashCString);
1071    SAFE_RELEASE(kextURL);
1072    SAFE_RELEASE(kextPath);
1073    SAFE_RELEASE(filename);
1074    SAFE_RELEASE(hashString);
1075    SAFE_RELEASE(kextDict);
1076    SAFE_RELEASE(archString);
1077    SAFE_RELEASE(teamId);
1078    SAFE_RELEASE(subjectCN);
1079    SAFE_RELEASE(issuerCN);
1080    SAFE_RELEASE(code);
1081    SAFE_RELEASE(information);
1082    return;
1083}
1084
1085/*******************************************************************************
1086 * recordKextLoadListForMT() - record the list of loaded kexts
1087 *  <rdar://problem/12435992>
1088 *******************************************************************************/
1089void
1090recordKextLoadListForMT(CFArrayRef kextList)
1091{
1092    CFIndex             count, i;
1093    CFMutableArrayRef   kextsToMessageTrace = NULL; //must release
1094    OSKextRef           aKext;                      //do not release
1095
1096    if (kextList && (count = CFArrayGetCount(kextList))) {
1097        kextsToMessageTrace = CFArrayCreateMutable(kCFAllocatorDefault,
1098                                                  CFArrayGetCount(kextList),
1099                                                  &kCFTypeArrayCallBacks);
1100        if (kextsToMessageTrace) {
1101            for (i = 0; i < count; i ++) {
1102                aKext = (OSKextRef)CFArrayGetValueAtIndex(kextList, i);
1103                filterKextLoadForMT(aKext, &kextsToMessageTrace);
1104            }
1105            if (CFArrayGetCount(kextsToMessageTrace)) {
1106                postNoteAboutKextLoadsMT(CFSTR("Loaded Kext Notification"),
1107                                         kextsToMessageTrace);
1108            }
1109            SAFE_RELEASE(kextsToMessageTrace);
1110        }
1111    }
1112}
1113
1114/*******************************************************************************
1115 * recordKextLoadForMT() - record the loaded kext
1116 *  <rdar://problem/12435992>
1117 *******************************************************************************/
1118void recordKextLoadForMT(OSKextRef aKext)
1119{
1120    CFMutableArrayRef myArray = NULL; // must release
1121
1122    if (!aKext)
1123        return;
1124
1125    myArray = CFArrayCreateMutable(kCFAllocatorDefault,
1126                                   1,
1127                                   &kCFTypeArrayCallBacks);
1128    if (myArray) {
1129        CFArrayAppendValue(myArray, aKext);
1130        recordKextLoadListForMT(myArray);
1131        SAFE_RELEASE(myArray);
1132    }
1133}
1134
1135/*******************************************************************************
1136 * checkKextSignature() - check the signature for given kext.
1137 *******************************************************************************/
1138OSStatus checkKextSignature(OSKextRef aKext, Boolean checkExceptionList)
1139{
1140    OSStatus                result          = -1;
1141    CFURLRef                kextURL         = NULL;   // must release
1142    SecStaticCodeRef        staticCodeRef   = NULL;   // must release
1143    SecRequirementRef       requirementRef  = NULL;   // must release
1144    CFStringRef             myCFString;
1145    CFStringRef             requirementsString;
1146
1147    if (aKext == NULL) {
1148        return result;
1149    }
1150
1151    kextURL = CFURLCopyAbsoluteURL(OSKextGetURL(aKext));
1152    if (!kextURL) {
1153        OSKextLogMemError();
1154        goto finish;
1155    }
1156
1157    if (SecStaticCodeCreateWithPath(kextURL,
1158                                    kSecCSDefaultFlags,
1159                                    &staticCodeRef) != errSecSuccess ||
1160        (staticCodeRef == NULL)) {
1161        OSKextLogMemError();
1162        goto finish;
1163    }
1164
1165    /* set up correct requirement string.  Apple kexts are signed by B&I while
1166     * 3rd party kexts are signed through a special developer kext devid
1167     * program
1168     */
1169    myCFString = OSKextGetIdentifier(aKext);
1170    if (CFStringHasPrefix(myCFString, __kOSKextApplePrefix)) {
1171        requirementsString = CFSTR("anchor apple");
1172    }
1173    else {
1174        /* DevID for kexts cert
1175         */
1176        requirementsString =
1177            CFSTR("anchor apple generic "
1178                  "and certificate 1[field.1.2.840.113635.100.6.2.6] "
1179                  "and certificate leaf[field.1.2.840.113635.100.6.1.13] "
1180                  "and certificate leaf[field.1.2.840.113635.100.6.1.18]" );
1181    }
1182
1183    if (SecRequirementCreateWithString(requirementsString,
1184                                       kSecCSDefaultFlags,
1185                                       &requirementRef) != errSecSuccess ||
1186        (requirementRef == NULL)) {
1187        OSKextLogMemError();
1188        goto finish;
1189    }
1190
1191    // errSecCSUnsigned == -67062
1192    result = SecStaticCodeCheckValidity(staticCodeRef,
1193                                        kSecCSEnforceRevocationChecks,
1194                                        requirementRef);
1195    if ( result != 0 &&
1196         checkExceptionList &&
1197         isInExceptionList(aKext, true) ) {
1198        result = 0;
1199    }
1200
1201finish:
1202    SAFE_RELEASE(kextURL);
1203    SAFE_RELEASE(staticCodeRef);
1204    SAFE_RELEASE(requirementRef);
1205
1206    return result;
1207}
1208
1209#define GET_CSTRING_PTR(the_cfstring, the_ptr, the_buffer, the_size) \
1210do { \
1211the_ptr = CFStringGetCStringPtr(the_cfstring, kCFStringEncodingUTF8); \
1212if (the_ptr == NULL) { \
1213the_buffer[0] = 0x00; \
1214the_ptr = the_buffer;  \
1215CFStringGetCString(the_cfstring, the_buffer, the_size, kCFStringEncodingUTF8); \
1216} \
1217} while(0)
1218
1219/*********************************************************************
1220 * isInExceptionList checks to see if the given kext is in the
1221 * kext signing exception list (in com.apple.driver.KextExcludeList).
1222 * If useCache is TRUE, we will use the cached copy of the exception list.
1223 * If useCache is FALSE, we will refresh the cache from disk.
1224 *
1225 * The kext signing exception list rarely changes but to insure you have the
1226 * most recent copy in the cache pass FALSE for the first call and TRUE for
1227 * subsequent calls (when dealing with a large list of kexts).
1228 * theKext can be NULL if you just want the invalidate the cache.
1229 *********************************************************************/
1230Boolean isInExceptionList(OSKextRef theKext, Boolean useCache)
1231{
1232    Boolean             result              = false;
1233    CFStringRef         kextID              = NULL;  // must release
1234    OSKextRef           excludelistKext     = NULL;  // must release
1235    CFDictionaryRef     exceptionlistDict   = NULL;  // do NOT release
1236    static CFDictionaryRef myDictionary     = NULL;  // do NOT release
1237
1238    /* invalidate the cache or create it if not present */
1239    if (useCache == false || myDictionary == NULL) {
1240        if (myDictionary != NULL) {
1241            SAFE_RELEASE_NULL(myDictionary);
1242        }
1243        kextID = CFStringCreateWithCString(kCFAllocatorDefault,
1244                                           "com.apple.driver.KextExcludeList",
1245                                           kCFStringEncodingUTF8);
1246        if (!kextID) {
1247            OSKextLogStringError(/* kext */ NULL);
1248            goto finish;
1249        }
1250
1251        excludelistKext = OSKextCreateWithIdentifier(kCFAllocatorDefault,
1252                                                     kextID);
1253        if (!excludelistKext) {
1254            OSKextLog(/* kext */ NULL,
1255                      kOSKextLogDebugLevel | kOSKextLogGeneralFlag,
1256                      "Warning: %s could not find com.apple.driver.KextExcludeList",
1257                      __FUNCTION__);
1258            goto finish;
1259        }
1260
1261        exceptionlistDict = OSKextGetValueForInfoDictionaryKey(
1262                                            excludelistKext,
1263                                            CFSTR("OSKextSigExceptionList"));
1264        if (!exceptionlistDict) {
1265            goto finish;
1266        }
1267
1268        if ((unsigned int)CFDictionaryGetCount(exceptionlistDict) > 0) {
1269            myDictionary = CFDictionaryCreateCopy(NULL, exceptionlistDict);
1270        }
1271        if (myDictionary == NULL) {
1272            OSKextLogMemError();
1273            goto finish;
1274        }
1275    }
1276    if (theKext == NULL) {
1277        goto finish;
1278    }
1279
1280    /*********************************************************************
1281     * myDictionary is a dictionary with keys / values of:
1282     *  key = bundleID string of kext we will allow to load inspite of signing
1283     *      failure.
1284     *  value = version string of kext to allow to load.
1285     *      The value is used to check equal or less than a kext with a matching
1286     *      version string.  For example if an entry in the list has key:
1287     *      com.foocompany.fookext
1288     *      and value:
1289     *      4.2.10
1290     *      Then any kext with bundle ID of com.foocompany.fookext and a version
1291     *      string of 4.2.10 or less will be allowed to load even if there is a
1292     *      a kext signing validation failure.
1293     *
1294     * NOTE - Kext versions use an extended Mac OS 'vers' format with double
1295     * the number of digits before the build stage: ####.##.##s{1-255} where 's'
1296     * is a build stage 'd', 'a', 'b', 'f' or 'fc'.  We parse this with
1297     * OSKextParseVersionString
1298     *********************************************************************/
1299    CFStringRef     bundleID                = NULL;  // do NOT release
1300    CFStringRef     exceptionKextVersString = NULL;  // do NOT release
1301    OSKextVersion   kextVers                = -1;
1302    const char *    versCString             = NULL;  // do not free
1303    OSKextVersion   exceptionKextVers;
1304    char            versBuffer[256];
1305
1306    bundleID = OSKextGetIdentifier(theKext);
1307    if (!bundleID) {
1308        OSKextLog(/* kext */ NULL,
1309                  kOSKextLogDebugLevel | kOSKextLogGeneralFlag,
1310                  "%s could not get bundleID",
1311                  __FUNCTION__);
1312        goto finish;
1313    }
1314
1315    kextVers = OSKextGetVersion(theKext);
1316    if (!kextVers) {
1317        OSKextLog(/* kext */ NULL,
1318                  kOSKextLogDebugLevel | kOSKextLogGeneralFlag,
1319                  "%s could not get kextVers",
1320                  __FUNCTION__);
1321        goto finish;
1322    }
1323
1324    exceptionKextVersString = CFDictionaryGetValue(myDictionary, bundleID);
1325    if (!exceptionKextVersString) {
1326        goto finish;
1327    }
1328
1329    /* parse version strings */
1330    GET_CSTRING_PTR(exceptionKextVersString,
1331                    versCString,
1332                    versBuffer,
1333                    sizeof(versBuffer));
1334    if (strlen(versCString) < 1) {
1335        goto finish;
1336    }
1337
1338    exceptionKextVers = OSKextParseVersionString(versCString);
1339    if (kextVers <= exceptionKextVers) {
1340        OSKextLogCFString(NULL,
1341                          kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
1342                          CFSTR("kext %@  %lld is in exception list, allowing to load"),
1343                          bundleID, kextVers);
1344        result = true;
1345    }
1346
1347finish:
1348    SAFE_RELEASE(kextID);
1349    SAFE_RELEASE(excludelistKext);
1350    return result;
1351}
1352
1353/*******************************************************************************
1354 * isDebugSetInBootargs() - check to see if boot-args has debug set.  We cache
1355 * the result since boot-args / debug will not change until reboot.
1356 *******************************************************************************/
1357Boolean isDebugSetInBootargs(void)
1358{
1359    static int          didOnce         = 0;
1360    static Boolean      result          = false;
1361    io_registry_entry_t optionsNode     = MACH_PORT_NULL;   // must release
1362    CFStringRef         bootargsEntry   = NULL;             // must release
1363
1364    if (didOnce) {
1365        return(result);
1366    }
1367    optionsNode = IORegistryEntryFromPath(kIOMasterPortDefault,
1368                                          "IODeviceTree:/options");
1369    if (optionsNode) {
1370        bootargsEntry = (CFStringRef)
1371        IORegistryEntryCreateCFProperty(optionsNode,
1372                                        CFSTR("boot-args"),
1373                                        kCFAllocatorDefault, 0);
1374        if (bootargsEntry &&
1375            (CFGetTypeID(bootargsEntry) == CFStringGetTypeID())) {
1376            CFRange     findRange;
1377            findRange = CFStringFind(bootargsEntry, CFSTR("debug"), 0);
1378
1379            if (findRange.length != 0) {
1380                result = true;
1381            }
1382        }
1383    }
1384    didOnce++;
1385    if (optionsNode)  IOObjectRelease(optionsNode);
1386    SAFE_RELEASE(bootargsEntry);
1387
1388    return(result);
1389}
1390
1391
1392/*********************************************************************
1393 *********************************************************************/
1394Boolean isInLibraryExtensionsFolder(OSKextRef theKext)
1395{
1396    CFStringRef     myKextPath = NULL; // must release
1397    Boolean         myResult = false;
1398
1399    myKextPath = copyKextPath(theKext);
1400    if ( myKextPath ) {
1401        if ( CFStringHasPrefix(myKextPath,
1402                               CFSTR(_kOSKextLibraryExtensionsFolder)) ) {
1403            myResult = true;
1404        }
1405    }
1406    SAFE_RELEASE(myKextPath);
1407    return(myResult);
1408}
1409
1410
1411
1412