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#include <sys/sysctl.h> 29#include <servers/bootstrap.h> 30#include <IOKit/kext/kextmanager_types.h> 31 32#include "security.h" 33#include "kext_tools_util.h" 34 35 36#define USE_OLD_EXCEPTION_LIST 1 37 38/******************************************************************************* 39 * Helper functions 40 *******************************************************************************/ 41static OSStatus checkRootCertificateIsApple(OSKextRef aKext); 42static CFStringRef copyCDHash(SecStaticCodeRef code); 43static CFStringRef copyIssuerCN(SecCertificateRef certificate); 44static void copySigningInfo(CFURLRef kextURL, 45 CFStringRef* cdhash, 46 CFStringRef* teamId, 47 CFStringRef* subjectCN, 48 CFStringRef* issuerCN); 49static CFArrayRef copySubjectCNArray(CFURLRef kextURL); 50static CFStringRef copyTeamID(SecCertificateRef certificate); 51static CFStringRef createArchitectureList(OSKextRef aKext, CFBooleanRef *isFat); 52static void getAdhocSignatureHash(CFURLRef kextURL, char ** signatureBuffer); 53static void filterKextLoadForMT(OSKextRef aKext, CFMutableArrayRef *kextList); 54static Boolean hashIsInExceptionList(CFURLRef theKextURL, CFDictionaryRef theDict); 55#if USE_OLD_EXCEPTION_LIST 56static Boolean bundleIdIsInExceptionList(OSKextRef theKext, CFDictionaryRef theDict); 57#endif 58 59/******************************************************************************* 60 * messageTraceExcludedKext() - log MessageTracer message for kexts in 61 * exclude list. 62 * <rdar://problem/12994418> MessageTrace when we block the load of something 63 * on the kext exclude list 64 *******************************************************************************/ 65 66void messageTraceExcludedKext(OSKextRef theKext) 67{ 68 CFStringRef versionString; 69 CFStringRef bundleIDString; 70 CFURLRef kextURL = NULL; // must release 71 CFStringRef filename = NULL; // must release 72 aslmsg amsg = NULL; // must free 73 char *versionCString = NULL; // must free 74 char *bundleIDCString = NULL; // must free 75 char *filenameCString = NULL; // must free 76 77 kextURL = CFURLCopyAbsoluteURL(OSKextGetURL(theKext)); 78 if (!kextURL) { 79 OSKextLogMemError(); 80 goto finish; 81 } 82 versionString = OSKextGetValueForInfoDictionaryKey(theKext, 83 kCFBundleVersionKey); 84 if (versionString) { 85 versionCString = createUTF8CStringForCFString(versionString); 86 } 87 bundleIDString = OSKextGetValueForInfoDictionaryKey(theKext, 88 kCFBundleIdentifierKey); 89 if (bundleIDString) { 90 bundleIDCString = createUTF8CStringForCFString(bundleIDString); 91 } 92 93 filename = CFURLCopyLastPathComponent(kextURL); 94 if (filename) { 95 filenameCString = createUTF8CStringForCFString(filename); 96 } 97 SAFE_RELEASE(filename); 98 99 /* log the message tracer data 100 */ 101 amsg = asl_new(ASL_TYPE_MSG); 102 if (!amsg) { 103 OSKextLogMemError(); 104 goto finish; 105 } 106 107 asl_set(amsg, kMessageTracerDomainKey, kMTKextBlockedDomain); 108 asl_set(amsg, kMessageTracerBundleIDKey, 109 bundleIDCString ? bundleIDCString : ""); 110 asl_set(amsg, kMessageTracerVersionKey, 111 versionCString ? versionCString : ""); 112 asl_set(amsg, kMessageTracerKextNameKey, 113 filenameCString ? filenameCString : ""); 114 115 asl_log(NULL, amsg, ASL_LEVEL_NOTICE, ""); 116 117finish: 118 SAFE_FREE(versionCString); 119 SAFE_FREE(bundleIDCString); 120 SAFE_FREE(filenameCString); 121 122 SAFE_RELEASE(kextURL); 123 124 if (amsg) { 125 asl_free(amsg); 126 } 127 return; 128} 129 130/******************************************************************************* 131 * checkRootCertificateIsApple() - check if the root certificate of the kext 132 * is issued by Apple 133 * <rdar://problem/12435992> 134 *******************************************************************************/ 135static OSStatus checkRootCertificateIsApple(OSKextRef aKext) 136{ 137 OSStatus result = -1; 138 CFURLRef kextURL = NULL; // must release 139 SecStaticCodeRef staticCodeRef = NULL; // must release 140 SecRequirementRef requirementRef = NULL; // must release 141 CFStringRef myCFString; 142 CFStringRef requirementsString; 143 144 if (aKext == NULL) { 145 return result; 146 } 147 148 kextURL = CFURLCopyAbsoluteURL(OSKextGetURL(aKext)); 149 if (!kextURL) { 150 OSKextLogMemError(); 151 goto finish; 152 } 153 154 if (SecStaticCodeCreateWithPath(kextURL, 155 kSecCSDefaultFlags, 156 &staticCodeRef) != errSecSuccess || 157 (staticCodeRef == NULL)) { 158 OSKextLogMemError(); 159 goto finish; 160 } 161 162 /* set up correct requirement string */ 163 myCFString = OSKextGetIdentifier(aKext); 164 if (CFStringHasPrefix(myCFString, __kOSKextApplePrefix)) { 165 requirementsString = CFSTR("anchor apple"); 166 } 167 else { 168 requirementsString = CFSTR("anchor apple generic"); 169 } 170 171 if (SecRequirementCreateWithString(requirementsString, 172 kSecCSDefaultFlags, 173 &requirementRef) != errSecSuccess || 174 (requirementRef == NULL)) { 175 OSKextLogMemError(); 176 goto finish; 177 } 178 179 // errSecCSUnsigned == -67062 180 result = SecStaticCodeCheckValidity(staticCodeRef, 181 kSecCSDefaultFlags, 182 requirementRef); 183 if (result != 0) { 184 OSKextLogCFString(NULL, 185 kOSKextLogErrorLevel | kOSKextLogLoadFlag, 186 CFSTR("Invalid signature %ld for kext %@"), 187 (long)result, aKext); 188 } 189 190finish: 191 SAFE_RELEASE(kextURL); 192 SAFE_RELEASE(staticCodeRef); 193 SAFE_RELEASE(requirementRef); 194 195 return result; 196} 197 198 199/******************************************************************************* 200 * getAdhocSignatureHash() - create a hash signature for an unsigned kext 201 *******************************************************************************/ 202 203static void getAdhocSignatureHash(CFURLRef kextURL, char ** signatureBuffer) 204{ 205 CFMutableDictionaryRef signdict = NULL; // must release 206 SecCodeSignerRef signerRef = NULL; // must release 207 SecStaticCodeRef staticCodeRef = NULL; // must release 208 CFDataRef signature = NULL; // must release 209 CFDictionaryRef signingDict = NULL; // must release 210 CFDataRef cdhash = NULL; // must release 211 CFMutableDictionaryRef resourceRules = NULL; // must release 212 CFMutableDictionaryRef rules = NULL; // must release 213 CFMutableDictionaryRef rules2 = NULL; // must release 214 CFMutableDictionaryRef omitPlugins = NULL; // must release 215 CFMutableDictionaryRef frameworksDict = NULL; // must release 216 CFMutableDictionaryRef topDict = NULL; // must release 217 char * tempBufPtr = NULL; // do not free 218 CFNumberRef myNumValue = NULL; // must release 219 CFNumberRef myRealValue = NULL; // must release 220 221 /* Ad-hoc sign the code temporarily so we can get its hash */ 222 if (SecStaticCodeCreateWithPath(kextURL, 223 kSecCSDefaultFlags, 224 &staticCodeRef) != 0 || 225 (staticCodeRef == NULL)) { 226 OSKextLogMemError(); 227 goto finish; 228 } 229 230 signature = CFDataCreateMutable(NULL, 0); 231 if (signature == NULL) { 232 OSKextLogMemError(); 233 goto finish; 234 } 235 236 signdict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 237 &kCFTypeDictionaryKeyCallBacks, 238 &kCFTypeDictionaryValueCallBacks); 239 if (signdict == NULL) { 240 OSKextLogMemError(); 241 goto finish; 242 } 243 244 CFDictionarySetValue(signdict, kSecCodeSignerIdentity, kCFNull); 245 CFDictionarySetValue(signdict, kSecCodeSignerDetached, signature); 246 247 resourceRules = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 248 &kCFTypeDictionaryKeyCallBacks, 249 &kCFTypeDictionaryValueCallBacks); 250 if (resourceRules == NULL) { 251 OSKextLogMemError(); 252 goto finish; 253 } 254 255 rules = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 256 &kCFTypeDictionaryKeyCallBacks, 257 &kCFTypeDictionaryValueCallBacks); 258 if (rules == NULL) { 259 OSKextLogMemError(); 260 goto finish; 261 } 262 263 rules2 = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 264 &kCFTypeDictionaryKeyCallBacks, 265 &kCFTypeDictionaryValueCallBacks); 266 if (rules2 == NULL) { 267 OSKextLogMemError(); 268 goto finish; 269 } 270 271 omitPlugins = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 272 &kCFTypeDictionaryKeyCallBacks, 273 &kCFTypeDictionaryValueCallBacks); 274 if (omitPlugins == NULL) { 275 OSKextLogMemError(); 276 goto finish; 277 } 278 279 frameworksDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 280 &kCFTypeDictionaryKeyCallBacks, 281 &kCFTypeDictionaryValueCallBacks); 282 if (frameworksDict == NULL) { 283 OSKextLogMemError(); 284 goto finish; 285 } 286 287 topDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 288 &kCFTypeDictionaryKeyCallBacks, 289 &kCFTypeDictionaryValueCallBacks); 290 if (topDict == NULL) { 291 OSKextLogMemError(); 292 goto finish; 293 } 294 295 /* exclude PlugIns directory (old style, see 16411212) 296 */ 297 int myNum = 100; 298 myNumValue = CFNumberCreate(kCFAllocatorDefault, 299 kCFNumberIntType, &myNum); 300 if (myNumValue == NULL) { 301 OSKextLogMemError(); 302 goto finish; 303 } 304 305 CFDictionarySetValue(omitPlugins, CFSTR("omit"), kCFBooleanTrue); 306 CFDictionarySetValue(omitPlugins, CFSTR("weight"), myNumValue); 307 308 CFDictionarySetValue(rules, CFSTR("^.*"), kCFBooleanTrue); 309 CFDictionarySetValue(rules, CFSTR("^PlugIns/"), omitPlugins); 310 CFDictionarySetValue(resourceRules, CFSTR("rules"), rules); 311 312 /* exclude PlugIns directory (new style, see 16411212) 313 */ 314 float myRealNum = 0.0; 315 myRealValue = CFNumberCreate(kCFAllocatorDefault, 316 kCFNumberFloatType, &myRealNum); 317 if (myRealValue == NULL) { 318 OSKextLogMemError(); 319 goto finish; 320 } 321 322 CFDictionarySetValue(frameworksDict, CFSTR("nested"), kCFBooleanTrue); 323 CFDictionarySetValue(frameworksDict, CFSTR("weight"), myRealValue); 324 CFDictionarySetValue(rules2, 325 CFSTR("^(Frameworks|SharedFrameworks|Plugins|Plug-ins|XPCServices|Helpers|MacOS)/"), 326 frameworksDict); 327 328 CFDictionarySetValue(rules2, CFSTR("^.*"), kCFBooleanTrue); 329 CFDictionarySetValue(rules2, CFSTR("^PlugIns/"), omitPlugins); 330 331 CFDictionarySetValue(topDict, CFSTR("top"), kCFBooleanTrue); 332 CFDictionarySetValue(topDict, CFSTR("weight"), myRealValue); 333 CFDictionarySetValue(rules2, 334 CFSTR("^[^/]+$"), 335 topDict); 336 CFDictionarySetValue(resourceRules, CFSTR("rules2"), rules2); 337 338 // add both rules to signdict 339 CFDictionarySetValue(signdict, kSecCodeSignerResourceRules, resourceRules); 340 341 if (SecCodeSignerCreate(signdict, kSecCSDefaultFlags, &signerRef) != 0) { 342 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogGeneralFlag, 343 "%s - SecCodeSignerCreate failed", __func__); 344 goto finish; 345 } 346 if (SecCodeSignerAddSignature(signerRef, staticCodeRef, kSecCSDefaultFlags) != 0) { 347 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogGeneralFlag, 348 "%s - SecCodeSignerAddSignature failed", __func__); 349 goto finish; 350 } 351 if (SecCodeSetDetachedSignature(staticCodeRef, signature, kSecCSDefaultFlags) != 0) { 352 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogGeneralFlag, 353 "%s - SecCodeSetDetachedSignature failed", __func__); 354 goto finish; 355 } 356 357 /* get the hash info 358 */ 359 if (SecCodeCopySigningInformation(staticCodeRef, kSecCSDefaultFlags, &signingDict) != 0) { 360 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogGeneralFlag, 361 "%s - SecCodeCopySigningInformation failed", __func__); 362 goto finish; 363 } 364 365 cdhash = CFRetain(CFDictionaryGetValue(signingDict, kSecCodeInfoUnique)); 366 if (cdhash) { 367 const UInt8 * hashDataPtr = NULL; // don't free 368 CFIndex hashDataLen = 0; 369 370 hashDataPtr = CFDataGetBytePtr(cdhash); 371 hashDataLen = CFDataGetLength(cdhash); 372 tempBufPtr = (char *) malloc((hashDataLen + 1) * 2); 373 if (tempBufPtr == NULL) { 374 OSKextLogMemError(); 375 goto finish; 376 } 377#if 0 378 OSKextLogCFString(/* kext */ NULL, 379 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 380 CFSTR("%s - kextURL %@"), 381 __func__, 382 kextURL); 383 OSKextLogCFString(/* kext */ NULL, 384 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 385 CFSTR("%s - cdhash %@"), 386 __func__, 387 cdhash); 388#endif 389 390 bzero(tempBufPtr, ((hashDataLen + 1) * 2)); 391 for (int i = 0; i < hashDataLen; i++) { 392 sprintf(tempBufPtr + (i * 2), "%02.2x", *(hashDataPtr + i)); 393 } 394 } 395 396finish: 397 SAFE_RELEASE(signdict); 398 SAFE_RELEASE(signerRef); 399 SAFE_RELEASE(staticCodeRef); 400 SAFE_RELEASE(signature); 401 SAFE_RELEASE(signingDict); 402 SAFE_RELEASE(cdhash); 403 SAFE_RELEASE(resourceRules); 404 SAFE_RELEASE(rules); 405 SAFE_RELEASE(rules2); 406 SAFE_RELEASE(omitPlugins); 407 SAFE_RELEASE(frameworksDict); 408 SAFE_RELEASE(topDict); 409 SAFE_RELEASE(myNumValue); 410 SAFE_RELEASE(myRealValue); 411 412 *signatureBuffer = tempBufPtr; 413} 414 415/******************************************************************************* 416 * createArchitectureList() - create the list of architectures for the kext 417 * <rdar://13529984> 418 * Note: the caller must release the created CFStringRef 419 *******************************************************************************/ 420static CFStringRef createArchitectureList(OSKextRef aKext, CFBooleanRef *isFat) 421{ 422 if (aKext == NULL || isFat == NULL) { 423 return NULL; 424 } 425 426 *isFat = kCFBooleanFalse; 427 428 const NXArchInfo ** archList = NULL; // must free 429 CFMutableArrayRef archNamesList = NULL; // must release 430 CFStringRef archNames = NULL; // do not release 431 const char * archNameCString = NULL; // do not free 432 int index = 0; 433 434 archList = OSKextCopyArchitectures(aKext); 435 if (!archList) { 436 goto finish; 437 } 438 439 archNamesList = CFArrayCreateMutable(kCFAllocatorDefault, 440 0, 441 &kCFTypeArrayCallBacks); 442 if (!archNamesList) { 443 goto finish; 444 } 445 446 for (index=0; archList[index]; index++) { 447 archNameCString = archList[index]->name; 448 if (archNameCString) { 449 CFStringRef archName = NULL; 450 archName = CFStringCreateWithCString(kCFAllocatorDefault, 451 archNameCString, 452 kCFStringEncodingUTF8); 453 if (archName) { 454 CFArrayAppendValue(archNamesList, archName); 455 SAFE_RELEASE_NULL(archName); 456 } 457 } 458 } 459 460 if (index>1) { 461 *isFat = kCFBooleanTrue; 462 } 463 archNames = CFStringCreateByCombiningStrings(kCFAllocatorDefault, 464 archNamesList, 465 CFSTR(" ")); 466 if (!archNames) { 467 goto finish; 468 } 469 470finish: 471 SAFE_RELEASE(archNamesList); 472 SAFE_FREE(archList); 473 474 return archNames; 475} 476 477/******************************************************************************* 478 * copyTeamID() - copy the team id field from the given certificate 479 * <rdar://13646260> 480 * Note: the caller must release the created CFStringRef 481 *******************************************************************************/ 482static CFStringRef copyTeamID(SecCertificateRef certificate) 483{ 484 if (!certificate || 485 CFGetTypeID(certificate) !=SecCertificateGetTypeID()) { 486 return NULL; 487 } 488 489 CFDictionaryRef subjectDict = NULL; // do not release 490 CFArrayRef subjectArray = NULL; // do not release 491 CFDictionaryRef subjectInfo = NULL; // do not release 492 CFStringRef teamID = NULL; // do not release 493 CFErrorRef error = NULL; // do not release 494 495 CFMutableArrayRef certificateKeys = NULL; // must release 496 CFDictionaryRef certificateDict = NULL; // must release 497 498 certificateKeys = CFArrayCreateMutable(kCFAllocatorDefault, 499 1, 500 &kCFTypeArrayCallBacks); 501 if (!certificateKeys) { 502 goto finish; 503 } 504 505 CFArrayAppendValue(certificateKeys, kSecOIDX509V1SubjectName); 506 507 certificateDict = SecCertificateCopyValues(certificate, 508 certificateKeys, 509 &error); 510 if (error != errSecSuccess || 511 !certificateDict || 512 CFGetTypeID(certificateDict) != CFDictionaryGetTypeID()) { 513 goto finish; 514 } 515 516 subjectDict = (CFDictionaryRef) CFDictionaryGetValue(certificateDict, 517 kSecOIDX509V1SubjectName); 518 if (!subjectDict || 519 CFGetTypeID(subjectDict) != CFDictionaryGetTypeID()) { 520 goto finish; 521 } 522 523 subjectArray = (CFArrayRef) CFDictionaryGetValue(subjectDict, 524 kSecPropertyKeyValue); 525 if (!subjectArray || 526 CFGetTypeID(subjectArray) != CFArrayGetTypeID()) { 527 goto finish; 528 } 529 530 // Try to look for UserID field ("0.9.2342.19200300.100.1.1") 531 for (int index=0; index<CFArrayGetCount(subjectArray); index++) { 532 subjectInfo = (CFDictionaryRef) CFArrayGetValueAtIndex(subjectArray, 533 index); 534 if (!subjectInfo || 535 CFGetTypeID(subjectInfo) != CFDictionaryGetTypeID()) { 536 continue; 537 } 538 539 CFStringRef label = NULL; // do not release 540 label = CFDictionaryGetValue(subjectInfo, 541 kSecPropertyKeyLabel); 542 if (kCFCompareEqualTo == CFStringCompare(label, 543 CFSTR("0.9.2342.19200300.100.1.1"), 544 0)) { 545 teamID = CFDictionaryGetValue(subjectInfo, 546 kSecPropertyKeyValue); 547 if (teamID && 548 CFGetTypeID(teamID) == CFStringGetTypeID()) { 549 CFRetain(teamID); 550 goto finish; 551 } 552 else { 553 teamID = NULL; 554 } 555 } 556 } 557 558 // In case of failure, look for OU field ("2.5.4.11") 559 if (!teamID) { 560 for (int index=0; index<CFArrayGetCount(subjectArray); index++) { 561 subjectInfo = (CFDictionaryRef) CFArrayGetValueAtIndex(subjectArray, 562 index); 563 if (!subjectInfo || 564 CFGetTypeID(subjectInfo) != CFDictionaryGetTypeID()) { 565 continue; 566 } 567 568 CFStringRef label = NULL; // do not release 569 label = CFDictionaryGetValue(subjectInfo, 570 kSecPropertyKeyLabel); 571 if (kCFCompareEqualTo == CFStringCompare(label, 572 CFSTR("2.5.4.11"), 573 0)) { 574 teamID = CFDictionaryGetValue(subjectInfo, 575 kSecPropertyKeyValue); 576 if (teamID && 577 CFGetTypeID(teamID) == CFStringGetTypeID()) { 578 CFRetain(teamID); 579 goto finish; 580 } 581 else { 582 teamID = NULL; 583 } 584 } 585 } 586 } 587 588finish: 589 if (!teamID && subjectArray) { 590 CFShow(subjectArray); 591 } 592 SAFE_RELEASE(certificateKeys); 593 SAFE_RELEASE(certificateDict); 594 return teamID; 595} 596 597/******************************************************************************* 598 * copyIssuerCN() - copy the issuer CN field from the given certificate 599 * <rdar://13646260> 600 * Note: the caller must release the created CFStringRef 601 *******************************************************************************/ 602static CFStringRef copyIssuerCN(SecCertificateRef certificate) 603{ 604 if (!certificate || 605 CFGetTypeID(certificate) !=SecCertificateGetTypeID()) { 606 return NULL; 607 } 608 609 CFStringRef issuerCN = NULL; // do not release 610 CFDictionaryRef issuerDict = NULL; // do not release 611 CFArrayRef issuerArray = NULL; // do not release 612 CFDictionaryRef issuerInfo = NULL; // do not release 613 CFErrorRef error = NULL; // do not release 614 615 CFMutableArrayRef certificateKeys = NULL; // must release 616 CFDictionaryRef certificateDict = NULL; // must release 617 618 certificateKeys = CFArrayCreateMutable(kCFAllocatorDefault, 619 1, 620 &kCFTypeArrayCallBacks); 621 if (!certificateKeys) { 622 goto finish; 623 } 624 625 CFArrayAppendValue(certificateKeys, kSecOIDX509V1IssuerName); 626 627 certificateDict = SecCertificateCopyValues(certificate, 628 certificateKeys, 629 &error); 630 631 if (error != errSecSuccess || 632 !certificateDict || 633 CFGetTypeID(certificateDict) != CFDictionaryGetTypeID()) { 634 goto finish; 635 } 636 637 issuerDict = (CFDictionaryRef) CFDictionaryGetValue(certificateDict, 638 kSecOIDX509V1IssuerName); 639 if (!issuerDict || 640 CFGetTypeID(issuerDict) != CFDictionaryGetTypeID()) { 641 goto finish; 642 } 643 644 issuerArray = (CFArrayRef) CFDictionaryGetValue(issuerDict, 645 kSecPropertyKeyValue); 646 if (!issuerArray || 647 CFGetTypeID(issuerArray) != CFArrayGetTypeID()) { 648 goto finish; 649 } 650 651 for (int index=0; index<CFArrayGetCount(issuerArray); index++) { 652 issuerInfo = (CFDictionaryRef) CFArrayGetValueAtIndex(issuerArray, 653 index); 654 if (!issuerInfo || 655 CFGetTypeID(issuerInfo) != CFDictionaryGetTypeID()) { 656 continue; 657 } 658 659 CFStringRef label = NULL; // do not release 660 label = CFDictionaryGetValue(issuerInfo, 661 kSecPropertyKeyLabel); 662 if (kCFCompareEqualTo == CFStringCompare(label, 663 CFSTR("2.5.4.3"), 664 0)) { 665 issuerCN = CFDictionaryGetValue(issuerInfo, 666 kSecPropertyKeyValue); 667 if (issuerCN && 668 CFGetTypeID(issuerCN) == CFStringGetTypeID()) { 669 CFRetain(issuerCN); 670 goto finish; 671 } 672 else { 673 issuerCN = NULL; 674 } 675 } 676 } 677 678finish: 679 SAFE_RELEASE(certificateDict); 680 SAFE_RELEASE(certificateKeys); 681 return issuerCN; 682} 683 684/******************************************************************************* 685 * copyCDHash() - copy the SHA-1 hash of the code 686 * <rdar://13646260> 687 * Note: the caller must release the created CFStringRef 688 *******************************************************************************/ 689static CFStringRef copyCDHash(SecStaticCodeRef code) 690{ 691 CFDictionaryRef signingInfo = NULL; // must release 692 char * tempBufPtr = NULL; // free 693 const UInt8 * hashDataPtr = NULL; // do not free 694 CFDataRef cdhash = NULL; // do not release 695 CFStringRef hash = NULL; // do not release 696 CFIndex hashDataLen = 0; 697 698 SecCodeCopySigningInformation(code, 699 kSecCSDefaultFlags, 700 &signingInfo); 701 if (!signingInfo) { 702 goto finish; 703 } 704 705 cdhash = CFDictionaryGetValue(signingInfo, kSecCodeInfoUnique); 706 if (!cdhash || 707 CFGetTypeID(cdhash) != CFDataGetTypeID()) { 708 goto finish; 709 } 710 711 hashDataPtr = CFDataGetBytePtr(cdhash); 712 hashDataLen = CFDataGetLength(cdhash); 713 tempBufPtr = (char *) malloc((hashDataLen + 1) * 2); 714 if (tempBufPtr == NULL) { 715 OSKextLogMemError(); 716 goto finish; 717 } 718 719 bzero(tempBufPtr, ((hashDataLen + 1) * 2)); 720 for (int i = 0; i < hashDataLen; i++) { 721 sprintf(tempBufPtr + (i * 2), "%02.2x", *(hashDataPtr + i)); 722 } 723 724 if (tempBufPtr) { 725 hash = CFStringCreateWithCString(kCFAllocatorDefault, 726 tempBufPtr, 727 kCFStringEncodingUTF8); 728 } 729 730finish: 731 SAFE_FREE(tempBufPtr); 732 SAFE_RELEASE(signingInfo); 733 return hash; 734} 735 736/******************************************************************************* 737 * copySigningInfo() - copy a set of signing information for the given kext 738 * cdhash: the SHA-1 hash 739 * teamid: the team id of the leaf certificate 740 * subjectCN: the subject common name of the leaf certificate 741 * issuerCN: the issuer common name of the leaf certificate 742 * <rdar://13646260> 743 * Note: the caller must release the created CFStringRefs 744 *******************************************************************************/ 745static void copySigningInfo(CFURLRef kextURL, 746 CFStringRef* cdhash, 747 CFStringRef* teamId, 748 CFStringRef* subjectCN, 749 CFStringRef* issuerCN) 750{ 751 if (!kextURL) { 752 return; 753 } 754 755 SecStaticCodeRef code = NULL; // must release 756 CFDictionaryRef information = NULL; // must release 757 758 SecCertificateRef issuerCertificate = NULL; // do not release 759 CFArrayRef certificateChain = NULL; // do not release 760 OSStatus status; 761 CFIndex count; 762 763 if (SecStaticCodeCreateWithPath(kextURL, 764 kSecCSDefaultFlags, 765 &code) != 0 766 || (code == NULL)) { 767 OSKextLogMemError(); 768 goto finish; 769 } 770 771 if (cdhash) { 772 *cdhash = copyCDHash(code); 773 } 774 775 status = SecCodeCopySigningInformation(code, 776 kSecCSSigningInformation, 777 &information); 778 if (status != noErr) { 779 goto finish; 780 } 781 782 // a CFArrayRef array of SecCertificateRef objects 783 certificateChain = (CFArrayRef) CFDictionaryGetValue(information, kSecCodeInfoCertificates); 784 if (!certificateChain || 785 CFGetTypeID(certificateChain) != CFArrayGetTypeID()) { 786 goto finish; 787 } 788 789 count = CFArrayGetCount(certificateChain); 790 if (count < 1) { 791 goto finish; 792 } 793 794 issuerCertificate = (SecCertificateRef) CFArrayGetValueAtIndex(certificateChain, 0); 795 if (!issuerCertificate) { 796 goto finish; 797 } 798 799 if (subjectCN) { 800 SecCertificateCopyCommonName(issuerCertificate, subjectCN); 801 } 802 803 if (teamId) { 804 *teamId = copyTeamID(issuerCertificate); 805 } 806 807 if (issuerCN) { 808 *issuerCN = copyIssuerCN(issuerCertificate); 809 } 810 811finish: 812 SAFE_RELEASE(code); 813 SAFE_RELEASE(information); 814 815 return; 816} 817 818/******************************************************************************* 819 * copySubjectCNArray() - copy the subject CN from every certificate in the kext's 820 * certificate chain. 821 * <rdar://13646260> 822 * Note: the caller must release the created CFArrayRef 823 *******************************************************************************/ 824static CFArrayRef copySubjectCNArray(CFURLRef kextURL) 825{ 826 if (!kextURL) { 827 return NULL; 828 } 829 830 CFMutableArrayRef subjectCNArray = NULL; // do not release 831 CFArrayRef certificateChain = NULL; // do not release 832 SecCertificateRef certificate = NULL; // do not release 833 834 SecStaticCodeRef code = NULL; // must release 835 CFDictionaryRef information = NULL; // must release 836 837 OSStatus status; 838 CFIndex count; 839 840 subjectCNArray = CFArrayCreateMutable(kCFAllocatorDefault, 841 0, 842 &kCFTypeArrayCallBacks); 843 if (!subjectCNArray) { 844 goto finish; 845 } 846 847 if (SecStaticCodeCreateWithPath(kextURL, 848 kSecCSDefaultFlags, 849 &code) != 0 850 || (code == NULL)) { 851 OSKextLogMemError(); 852 goto finish; 853 } 854 855 status = SecCodeCopySigningInformation(code, 856 kSecCSSigningInformation, 857 &information); 858 if (status != noErr) { 859 goto finish; 860 } 861 862 certificateChain = (CFArrayRef) CFDictionaryGetValue(information, kSecCodeInfoCertificates); 863 if (!certificateChain || 864 CFGetTypeID(certificateChain) != CFArrayGetTypeID()) { 865 goto finish; 866 } 867 868 count = CFArrayGetCount(certificateChain); 869 if (count < 1) { 870 goto finish; 871 } 872 873 for (CFIndex i=0; i<count; i++) { 874 certificate = (SecCertificateRef) CFArrayGetValueAtIndex(certificateChain, i); 875 CFStringRef subjectCN = NULL; // must release 876 SecCertificateCopyCommonName(certificate, &subjectCN); 877 if (subjectCN) { 878 CFArrayAppendValue(subjectCNArray, subjectCN); 879 SAFE_RELEASE(subjectCN); 880 } 881 } 882 883finish: 884 SAFE_RELEASE(code); 885 SAFE_RELEASE(information); 886 887 return subjectCNArray; 888} 889 890/******************************************************************************* 891 * filterKextLoadForMT() - check that the kext is of interest, and place kext 892 * information in the kext list 893 * <rdar://problem/12435992> 894 *******************************************************************************/ 895 896static void filterKextLoadForMT(OSKextRef aKext, CFMutableArrayRef *kextList) 897{ 898 if (aKext == NULL || kextList == NULL) 899 return; 900 901 CFStringRef versionString; // do not release 902 CFStringRef bundleIDString; // do not release 903 CFStringRef kextSigningCategory = NULL; // do not release 904 CFBooleanRef isFat = kCFBooleanFalse; // do not release 905 CFBooleanRef isSigned = kCFBooleanFalse; // do not release 906 907 CFURLRef kextURL = NULL; // must release 908 CFStringRef kextPath = NULL; // must release 909 CFStringRef filename = NULL; // must release 910 CFStringRef hashString = NULL; // must release 911 CFStringRef archString = NULL; // must release 912 CFStringRef teamId = NULL; // must release 913 CFStringRef subjectCN = NULL; // must release 914 CFStringRef issuerCN = NULL; // must release 915 916 SecStaticCodeRef code = NULL; // must release 917 CFDictionaryRef information = NULL; // must release 918 CFMutableDictionaryRef kextDict = NULL; // must release 919 920 char * hashCString = NULL; // must free 921 922 OSStatus status = noErr; 923 924 /* do not message trace this if boot-args has debug set */ 925 if (isDebugSetInBootargs()) { 926 return; 927 } 928 929 kextURL = CFURLCopyAbsoluteURL(OSKextGetURL(aKext)); 930 if (!kextURL) { 931 OSKextLogMemError(); 932 goto finish; 933 } 934 kextPath = CFURLCopyFileSystemPath(kextURL, kCFURLPOSIXPathStyle); 935 if (!kextPath) { 936 OSKextLogMemError(); 937 goto finish; 938 } 939 940 versionString = OSKextGetValueForInfoDictionaryKey(aKext, 941 kCFBundleVersionKey); 942 bundleIDString = OSKextGetValueForInfoDictionaryKey(aKext, 943 kCFBundleIdentifierKey); 944 filename = CFURLCopyLastPathComponent(kextURL); 945 946 archString = createArchitectureList(aKext, &isFat); 947 948 if (SecStaticCodeCreateWithPath(kextURL, 949 kSecCSDefaultFlags, 950 &code) != 0 951 || (code == NULL)) { 952 OSKextLogMemError(); 953 goto finish; 954 } 955 status = SecCodeCopySigningInformation(code, 956 kSecCSSigningInformation, 957 &information); 958 if (status != noErr) { 959 goto finish; 960 } 961 962 isSigned = CFDictionaryContainsKey(information, kSecCodeInfoIdentifier); 963 if (!isSigned) { 964 /* The kext is unsigned, so there is little information we can retrieve. 965 * A hash of the kext is generated for data collection. */ 966 kextSigningCategory = CFSTR(kUnsignedKext); 967 968 getAdhocSignatureHash(kextURL, &hashCString); 969 if (hashCString) { 970 hashString = CFStringCreateWithCString(kCFAllocatorDefault, 971 hashCString, 972 kCFStringEncodingUTF8); 973 } 974 } 975 else { 976 CFStringRef myCFString = NULL; // do not release 977 myCFString = OSKextGetIdentifier(aKext); 978 status = checkKextSignature(aKext, true, false); 979 if (CFStringHasPrefix(myCFString, __kOSKextApplePrefix)) { 980 if (status == noErr) { 981 /* This is a signed Apple kext, with an Apple root certificate. 982 * There is no need to retrieve additional signing information */ 983 kextSigningCategory = CFSTR(kAppleKextWithAppleRoot); 984 copySigningInfo(kextURL, 985 &hashString, 986 NULL, 987 NULL, 988 NULL); 989 } 990 else { 991 /* This is a signed Apple kext, but the root certificate is not Apple. 992 * This should not happen, so it is better to flag it as unsigned for 993 * collection purpose. */ 994 kextSigningCategory = CFSTR(kUnsignedKext); 995 copySigningInfo(kextURL, 996 &hashString, 997 &teamId, 998 NULL, 999 &issuerCN); 1000 CFArrayRef subjectCNArray = NULL; // must release 1001 subjectCNArray = copySubjectCNArray(kextURL); 1002 if (subjectCNArray) { 1003 subjectCN = CFStringCreateByCombiningStrings(kCFAllocatorDefault, 1004 subjectCNArray, 1005 CFSTR(";")); 1006 SAFE_RELEASE(subjectCNArray); 1007 } 1008 } 1009 } 1010 else { 1011 if (status == noErr) { 1012 /* This 3rd-party kext is signed with a devid+ kext certificate */ 1013 kextSigningCategory = CFSTR(k3rdPartyKextWithDevIdPlus); 1014 copySigningInfo(kextURL, 1015 &hashString, 1016 &teamId, 1017 &subjectCN, 1018 &issuerCN); 1019 } 1020 else if (status == CSSMERR_TP_CERT_REVOKED) { 1021 /* This 3rd-party kext is signed with a revoked devid+ kext certificate */ 1022 kextSigningCategory = CFSTR(k3rdPartyKextWithRevokedDevIdPlus); 1023 copySigningInfo(kextURL, 1024 &hashString, 1025 &teamId, 1026 &subjectCN, 1027 &issuerCN); 1028 } 1029 else { 1030 status = checkRootCertificateIsApple(aKext); 1031 if (status == noErr) { 1032 /* This 3rd-party kext is not signed with a devid+ certificate, 1033 * but uses an Apple root certificate. */ 1034 kextSigningCategory = CFSTR(k3rdPartyKextWithAppleRoot); 1035 /* The certificates may not have the expected format. 1036 * Attempt to get the information if present, and also 1037 * retrieve the subject cn of every certificate in the chain. */ 1038 copySigningInfo(kextURL, 1039 &hashString, 1040 &teamId, 1041 NULL, 1042 &issuerCN); 1043 CFArrayRef subjectCNArray = NULL; // must release 1044 subjectCNArray = copySubjectCNArray(kextURL); 1045 if (subjectCNArray) { 1046 subjectCN = CFStringCreateByCombiningStrings(kCFAllocatorDefault, 1047 subjectCNArray, 1048 CFSTR(";")); 1049 SAFE_RELEASE(subjectCNArray); 1050 } 1051 } 1052 else { 1053 /* This 3rd-party kext is not signed with a devid+ certificate, 1054 * and does not use an Apple root certificate. */ 1055 kextSigningCategory = CFSTR(k3rdPartyKextWithoutAppleRoot); 1056 /* The certificates may not have the expected format. 1057 * The subjectcn, issuercn and teamid must not be logged. */ 1058 copySigningInfo(kextURL, 1059 &hashString, 1060 NULL, 1061 NULL, 1062 NULL); 1063 } 1064 } 1065 } 1066 } 1067 1068 kextDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 1069 0, 1070 &kCFTypeDictionaryKeyCallBacks, 1071 &kCFTypeDictionaryValueCallBacks); 1072 if (!kextDict) { 1073 OSKextLogMemError(); 1074 goto finish; 1075 } 1076 1077 if (bundleIDString) { 1078 CFDictionaryAddValue(kextDict, 1079 CFSTR(kMessageTracerBundleIDKey), 1080 bundleIDString); 1081 } 1082 if (versionString) { 1083 CFDictionaryAddValue(kextDict, 1084 CFSTR(kMessageTracerVersionKey), 1085 versionString); 1086 } 1087 if (filename) { 1088 CFDictionaryAddValue(kextDict, 1089 CFSTR(kMessageTracerKextNameKey), 1090 filename); 1091 } 1092 if (isFat != NULL) { 1093 CFDictionaryAddValue(kextDict, 1094 CFSTR(kMessageTracerFatKey), 1095 isFat); 1096 } 1097 if (archString) { 1098 CFDictionaryAddValue(kextDict, 1099 CFSTR(kMessageTracerArchKey), 1100 archString); 1101 } 1102 1103 if (kextSigningCategory) { 1104 CFDictionaryAddValue(kextDict, 1105 CFSTR(kMessageTracerSignatureTypeKey), 1106 kextSigningCategory); 1107 } 1108 1109 if (hashString) { 1110 CFDictionaryAddValue(kextDict, 1111 CFSTR(kMessageTracerHashKey), 1112 hashString); 1113 } 1114 1115 if (teamId) { 1116 CFDictionaryAddValue(kextDict, 1117 CFSTR(kMessageTracerTeamIdKey), 1118 teamId); 1119 } 1120 if (subjectCN) { 1121 CFDictionaryAddValue(kextDict, 1122 CFSTR(kMessageTracerSubjectCNKey), 1123 subjectCN); 1124 } 1125 if (issuerCN) { 1126 CFDictionaryAddValue(kextDict, 1127 CFSTR(kMessageTracerIssuerCNKey), 1128 issuerCN); 1129 } 1130 1131 if (kextPath) { 1132 CFDictionaryAddValue(kextDict, 1133 CFSTR(kMessageTracerPathKey), 1134 kextPath); 1135 } 1136 1137 1138 CFArrayAppendValue(*kextList, kextDict); 1139 1140finish: 1141 SAFE_FREE(hashCString); 1142 SAFE_RELEASE(kextURL); 1143 SAFE_RELEASE(kextPath); 1144 SAFE_RELEASE(filename); 1145 SAFE_RELEASE(hashString); 1146 SAFE_RELEASE(kextDict); 1147 SAFE_RELEASE(archString); 1148 SAFE_RELEASE(teamId); 1149 SAFE_RELEASE(subjectCN); 1150 SAFE_RELEASE(issuerCN); 1151 SAFE_RELEASE(code); 1152 SAFE_RELEASE(information); 1153 return; 1154} 1155 1156/******************************************************************************* 1157 * recordKextLoadListForMT() - record the list of loaded kexts 1158 * <rdar://problem/12435992> 1159 *******************************************************************************/ 1160void 1161recordKextLoadListForMT(CFArrayRef kextList) 1162{ 1163 CFIndex count, i; 1164 CFMutableArrayRef kextsToMessageTrace = NULL; //must release 1165 OSKextRef aKext; //do not release 1166 1167 if (kextList && (count = CFArrayGetCount(kextList))) { 1168 kextsToMessageTrace = CFArrayCreateMutable(kCFAllocatorDefault, 1169 CFArrayGetCount(kextList), 1170 &kCFTypeArrayCallBacks); 1171 if (kextsToMessageTrace) { 1172 for (i = 0; i < count; i ++) { 1173 aKext = (OSKextRef)CFArrayGetValueAtIndex(kextList, i); 1174 filterKextLoadForMT(aKext, &kextsToMessageTrace); 1175 } 1176 if (CFArrayGetCount(kextsToMessageTrace)) { 1177 postNoteAboutKextLoadsMT(CFSTR("Loaded Kext Notification"), 1178 kextsToMessageTrace); 1179 } 1180 SAFE_RELEASE(kextsToMessageTrace); 1181 } 1182 } 1183} 1184 1185/******************************************************************************* 1186 * recordKextLoadForMT() - record the loaded kext 1187 * <rdar://problem/12435992> 1188 *******************************************************************************/ 1189void recordKextLoadForMT(OSKextRef aKext) 1190{ 1191 CFMutableArrayRef myArray = NULL; // must release 1192 1193 if (!aKext) 1194 return; 1195 1196 myArray = CFArrayCreateMutable(kCFAllocatorDefault, 1197 1, 1198 &kCFTypeArrayCallBacks); 1199 if (myArray) { 1200 CFArrayAppendValue(myArray, aKext); 1201 recordKextLoadListForMT(myArray); 1202 SAFE_RELEASE(myArray); 1203 } 1204} 1205 1206/******************************************************************************* 1207 * checkKextSignature() - check the signature for given kext. 1208 *******************************************************************************/ 1209OSStatus checkKextSignature(OSKextRef aKext, 1210 Boolean checkExceptionList, 1211 Boolean earlyBoot) 1212{ 1213 OSStatus result = errSecCSSignatureFailed; 1214 CFURLRef kextURL = NULL; // must release 1215 SecStaticCodeRef staticCodeRef = NULL; // must release 1216 SecRequirementRef requirementRef = NULL; // must release 1217 CFStringRef myCFString; 1218 CFStringRef requirementsString; 1219 1220 if (aKext == NULL) { 1221 return result; 1222 } 1223 1224 kextURL = CFURLCopyAbsoluteURL(OSKextGetURL(aKext)); 1225 if (!kextURL) { 1226 OSKextLogMemError(); 1227 goto finish; 1228 } 1229 1230 if (SecStaticCodeCreateWithPath(kextURL, 1231 kSecCSDefaultFlags, 1232 &staticCodeRef) != errSecSuccess || 1233 (staticCodeRef == NULL)) { 1234 OSKextLogMemError(); 1235 goto finish; 1236 } 1237 1238 /* set up correct requirement string. Apple kexts are signed by B&I while 1239 * 3rd party kexts are signed through a special developer kext devid 1240 * program 1241 */ 1242 myCFString = OSKextGetIdentifier(aKext); 1243 if (CFStringHasPrefix(myCFString, __kOSKextApplePrefix)) { 1244 requirementsString = CFSTR("anchor apple"); 1245 } 1246 else { 1247 /* DevID for kexts cert 1248 */ 1249 requirementsString = 1250 CFSTR("anchor apple generic " 1251 "and certificate 1[field.1.2.840.113635.100.6.2.6] " 1252 "and certificate leaf[field.1.2.840.113635.100.6.1.13] " 1253 "and certificate leaf[field.1.2.840.113635.100.6.1.18]" ); 1254 } 1255 1256 if (SecRequirementCreateWithString(requirementsString, 1257 kSecCSDefaultFlags, 1258 &requirementRef) != errSecSuccess || 1259 (requirementRef == NULL)) { 1260 OSKextLogMemError(); 1261 goto finish; 1262 } 1263 1264 // errSecCSUnsigned == -67062 1265 if (earlyBoot) { 1266 result = SecStaticCodeCheckValidity(staticCodeRef, 1267 kSecCSNoNetworkAccess, 1268 requirementRef); 1269 } 1270 else { 1271 result = SecStaticCodeCheckValidity(staticCodeRef, 1272 kSecCSEnforceRevocationChecks, 1273 requirementRef); 1274 } 1275 if ( result != 0 && 1276 checkExceptionList && 1277 isInExceptionList(aKext, kextURL, true) ) { 1278 result = 0; 1279 } 1280 1281finish: 1282 SAFE_RELEASE(kextURL); 1283 SAFE_RELEASE(staticCodeRef); 1284 SAFE_RELEASE(requirementRef); 1285 1286 return result; 1287} 1288 1289#define GET_CSTRING_PTR(the_cfstring, the_ptr, the_buffer, the_size) \ 1290do { \ 1291the_ptr = CFStringGetCStringPtr(the_cfstring, kCFStringEncodingUTF8); \ 1292if (the_ptr == NULL) { \ 1293the_buffer[0] = 0x00; \ 1294the_ptr = the_buffer; \ 1295CFStringGetCString(the_cfstring, the_buffer, the_size, kCFStringEncodingUTF8); \ 1296} \ 1297} while(0) 1298 1299/********************************************************************* 1300 * isInExceptionList checks to see if the given kext is in the 1301 * kext signing exception list (in com.apple.driver.KextExcludeList). 1302 * If useCache is TRUE, we will use the cached copy of the exception list. 1303 * If useCache is FALSE, we will refresh the cache from disk. 1304 * 1305 * The kext signing exception list rarely changes but to insure you have the 1306 * most recent copy in the cache pass FALSE for the first call and TRUE for 1307 * subsequent calls (when dealing with a large list of kexts). 1308 * theKext can be NULL if you just want the invalidate the cache. 1309 *********************************************************************/ 1310Boolean isInExceptionList(OSKextRef theKext, 1311 CFURLRef theKextURL, 1312 Boolean useCache) 1313{ 1314 Boolean result = false; 1315 CFURLRef kextURL = NULL; // must release 1316 CFStringRef kextID = NULL; // must release 1317 OSKextRef excludelistKext = NULL; // must release 1318 CFDictionaryRef tempDict = NULL; // do NOT release 1319#if USE_OLD_EXCEPTION_LIST 1320 static CFDictionaryRef sExceptionListDict = NULL; // do NOT release 1321#endif 1322 static CFDictionaryRef sExceptionHashListDict = NULL; // do NOT release 1323 1324 /* invalidate the exception list "by hash" cache or create if not 1325 * present 1326 */ 1327 if (useCache == false || sExceptionHashListDict == NULL) { 1328 if (sExceptionHashListDict) { 1329 SAFE_RELEASE_NULL(sExceptionHashListDict); 1330 } 1331 kextID = CFStringCreateWithCString(kCFAllocatorDefault, 1332 "com.apple.driver.KextExcludeList", 1333 kCFStringEncodingUTF8); 1334 if (kextID == NULL) { 1335 OSKextLogStringError(/* kext */ NULL); 1336 goto finish; 1337 } 1338 1339 excludelistKext = OSKextCreateWithIdentifier(kCFAllocatorDefault, 1340 kextID); 1341 if (excludelistKext == NULL) { 1342 goto finish; 1343 } 1344 1345 /* can we trust AppleKextExcludeList.kext */ 1346 if (isDevMode() == false) { 1347 if (checkKextSignature(excludelistKext, false, false) != 0) { 1348 char kextPath[PATH_MAX]; 1349 1350 if (!CFURLGetFileSystemRepresentation(OSKextGetURL(excludelistKext), 1351 false, 1352 (UInt8 *)kextPath, 1353 sizeof(kextPath))) { 1354 strlcpy(kextPath, "(unknown)", sizeof(kextPath)); 1355 } 1356 OSKextLog(/* kext */ NULL, 1357 kOSKextLogErrorLevel | kOSKextLogArchiveFlag | 1358 kOSKextLogAuthenticationFlag | kOSKextLogGeneralFlag, 1359 "%s has invalid signature; Trust cache is disabled.", 1360 kextPath); 1361 goto finish; 1362 } 1363 } 1364 1365 tempDict = OSKextGetValueForInfoDictionaryKey( 1366 excludelistKext, 1367 CFSTR("OSKextSigExceptionHashList") ); 1368 if (tempDict) { 1369 if ((unsigned int)CFDictionaryGetCount(tempDict) > 0) { 1370 sExceptionHashListDict = CFDictionaryCreateCopy(NULL, tempDict); 1371 if (sExceptionHashListDict == NULL) { 1372 OSKextLogMemError(); 1373 } 1374 } 1375 } 1376 } 1377 1378 /* invalidate the exception list "by bundle ID" cache or create if not 1379 * present 1380 */ 1381#if USE_OLD_EXCEPTION_LIST 1382 if (useCache == false || sExceptionListDict == NULL) { 1383 if (sExceptionListDict) { 1384 SAFE_RELEASE_NULL(sExceptionListDict); 1385 } 1386 1387 if (kextID == NULL) { 1388 kextID = CFStringCreateWithCString(kCFAllocatorDefault, 1389 "com.apple.driver.KextExcludeList", 1390 kCFStringEncodingUTF8); 1391 if (kextID == NULL) { 1392 OSKextLogStringError(/* kext */ NULL); 1393 goto finish; 1394 } 1395 } 1396 1397 if (excludelistKext == NULL) { 1398 excludelistKext = OSKextCreateWithIdentifier(kCFAllocatorDefault, 1399 kextID); 1400 if (excludelistKext == NULL) { 1401 goto finish; 1402 } 1403 } 1404 1405 /* can we trust AppleKextExcludeList.kext */ 1406 if (isDevMode() == false) { 1407 if (checkKextSignature(excludelistKext, false, false) != 0) { 1408 char kextPath[PATH_MAX]; 1409 1410 if (!CFURLGetFileSystemRepresentation(OSKextGetURL(excludelistKext), 1411 false, 1412 (UInt8 *)kextPath, 1413 sizeof(kextPath))) { 1414 strlcpy(kextPath, "(unknown)", sizeof(kextPath)); 1415 } 1416 OSKextLog(/* kext */ NULL, 1417 kOSKextLogErrorLevel | kOSKextLogArchiveFlag | 1418 kOSKextLogAuthenticationFlag | kOSKextLogGeneralFlag, 1419 "%s has invalid signature; Trust cache is disabled.", 1420 kextPath); 1421 goto finish; 1422 } 1423 } 1424 1425 tempDict = OSKextGetValueForInfoDictionaryKey( 1426 excludelistKext, 1427 CFSTR("OSKextSigExceptionList")); 1428 if (tempDict) { 1429 if ((unsigned int)CFDictionaryGetCount(tempDict) > 0) { 1430 sExceptionListDict = CFDictionaryCreateCopy(NULL, tempDict); 1431 if (sExceptionListDict == NULL) { 1432 OSKextLogMemError(); 1433 } 1434 } 1435 } 1436 } 1437#endif 1438 1439 if (theKext == NULL) { 1440 goto finish; 1441 } 1442 1443 if (sExceptionHashListDict) { 1444 if (theKextURL == NULL) { 1445 kextURL = CFURLCopyAbsoluteURL(OSKextGetURL(theKext)); 1446 if (kextURL == NULL) { 1447 OSKextLogMemError(); 1448 goto finish; 1449 } 1450 theKextURL = kextURL; 1451 } 1452 if (hashIsInExceptionList(theKextURL, sExceptionHashListDict)) { 1453 result = true; 1454 goto finish; 1455 } 1456 } 1457 1458#if USE_OLD_EXCEPTION_LIST 1459 if (sExceptionListDict) { 1460 if (bundleIdIsInExceptionList(theKext, sExceptionListDict)) { 1461 result = true; 1462 goto finish; 1463 } 1464 } 1465#endif 1466 1467finish: 1468 SAFE_RELEASE(kextURL); 1469 SAFE_RELEASE(kextID); 1470 SAFE_RELEASE(excludelistKext); 1471 return result; 1472} 1473 1474#if USE_OLD_EXCEPTION_LIST 1475/********************************************************************* 1476 * theDict is a dictionary with keys / values of: 1477 * key = bundleID string of kext we will allow to load inspite of signing 1478 * failure. 1479 * value = version string of kext to allow to load. 1480 * The value is used to check equal or less than a kext with a matching 1481 * version string. For example if an entry in the list has key: 1482 * com.foocompany.fookext 1483 * and value: 1484 * 4.2.10 1485 * Then any kext with bundle ID of com.foocompany.fookext and a version 1486 * string of 4.2.10 or less will be allowed to load even if there is a 1487 * a kext signing validation failure. 1488 * 1489 * NOTE - Kext versions use an extended Mac OS 'vers' format with double 1490 * the number of digits before the build stage: ####.##.##s{1-255} where 's' 1491 * is a build stage 'd', 'a', 'b', 'f' or 'fc'. We parse this with 1492 * OSKextParseVersionString 1493 *********************************************************************/ 1494 1495static Boolean bundleIdIsInExceptionList(OSKextRef theKext, 1496 CFDictionaryRef theDict) 1497{ 1498 Boolean result = false; 1499 CFStringRef bundleID = NULL; // do NOT release 1500 CFStringRef exceptionKextVersString = NULL; // do NOT release 1501 OSKextVersion kextVers = -1; 1502 const char * versCString = NULL; // do not free 1503 OSKextVersion exceptionKextVers; 1504 char versBuffer[256]; 1505 1506 bundleID = OSKextGetIdentifier(theKext); 1507 if (!bundleID) { 1508 OSKextLog(/* kext */ NULL, 1509 kOSKextLogDebugLevel | kOSKextLogGeneralFlag, 1510 "%s could not get bundleID", 1511 __FUNCTION__); 1512 goto finish; 1513 } 1514 1515 kextVers = OSKextGetVersion(theKext); 1516 if (!kextVers) { 1517 OSKextLog(/* kext */ NULL, 1518 kOSKextLogDebugLevel | kOSKextLogGeneralFlag, 1519 "%s could not get kextVers", 1520 __FUNCTION__); 1521 goto finish; 1522 } 1523 1524 exceptionKextVersString = CFDictionaryGetValue(theDict, bundleID); 1525 if (!exceptionKextVersString) { 1526 goto finish; 1527 } 1528 1529 /* parse version strings */ 1530 GET_CSTRING_PTR(exceptionKextVersString, 1531 versCString, 1532 versBuffer, 1533 sizeof(versBuffer)); 1534 if (strlen(versCString) < 1) { 1535 goto finish; 1536 } 1537 1538 exceptionKextVers = OSKextParseVersionString(versCString); 1539 if (kextVers <= exceptionKextVers) { 1540 OSKextLogCFString(NULL, 1541 kOSKextLogGeneralFlag | kOSKextLogErrorLevel, 1542 CFSTR("kext %@ %lld is in exception list, allowing to load"), 1543 bundleID, kextVers); 1544 result = true; 1545 } 1546 1547finish: 1548 1549 return result; 1550} 1551#endif 1552 1553/********************************************************************* 1554 * theDict is a dictionary with keys / values of: 1555 * key = message tracing hash of kext 1556 * value = dictionary containing the bundle ID and version of the kext 1557 * the hash key represents 1558 * 1559 * Example OSKextSigExceptionHashList from AppleKextExcludeList.kext Info.plist: 1560 * 1561 * <key>OSKextSigExceptionHashList</key> 1562 * <dict> 1563 * <key>3205773049fb43b4a54cafc8493aa19217fbae7a</key> 1564 * <dict> 1565 * <key>CFBundleIdentifier</key> 1566 * <string>com.apple.driver.AppleMobileDevice</string> 1567 * <key>CFBundleVersion</key> 1568 * <string>3.3.0</string> 1569 * </dict> 1570 * </dict> 1571 *********************************************************************/ 1572 1573static Boolean hashIsInExceptionList(CFURLRef theKextURL, 1574 CFDictionaryRef theDict) 1575{ 1576 Boolean result = false; 1577 char * hashCString = NULL; // must free 1578 CFStringRef hashString = NULL; // must release 1579 CFStringRef kextInfoString = NULL; // do NOT release 1580 1581 if (theKextURL == NULL) { 1582 goto finish; 1583 } 1584 1585 /* generate the hash for unsigned kext to look up in exception list 1586 */ 1587 getAdhocSignatureHash(theKextURL, &hashCString); 1588 if (hashCString == NULL) { 1589 goto finish; 1590 } 1591 hashString = CFStringCreateWithCString(kCFAllocatorDefault, 1592 hashCString, 1593 kCFStringEncodingUTF8); 1594 if (hashString == NULL) { 1595 OSKextLogMemError(); 1596 goto finish; 1597 } 1598 1599 kextInfoString = CFDictionaryGetValue(theDict, hashString); 1600 if (kextInfoString == NULL || 1601 CFGetTypeID(kextInfoString) != CFStringGetTypeID()) { 1602 goto finish; 1603 } 1604 1605 OSKextLogCFString(NULL, 1606 kOSKextLogGeneralFlag | kOSKextLogErrorLevel, 1607 CFSTR("kext %@ is in hash exception list, allowing to load"), 1608 theKextURL); 1609 result = true; 1610 1611finish: 1612 SAFE_RELEASE(hashString); 1613 SAFE_FREE(hashCString); 1614 1615 return result; 1616} 1617 1618/******************************************************************************* 1619 * isDevMode() - check to see if this machine is in "kext developer mode" 1620 *******************************************************************************/ 1621#define KEXT_DEV_MODE_STRING "kext-dev-mode=" 1622 1623Boolean isDevMode(void) 1624{ 1625 Boolean result = false; 1626 uint64_t kext_dev_mode; 1627 size_t bufsize; 1628 char bootargs_buffer[1024], *dev_mode_ptr; 1629 1630 1631 bufsize = sizeof(bootargs_buffer); 1632 if (sysctlbyname("kern.bootargs", bootargs_buffer, &bufsize, NULL, 0) < 0) { 1633 return(false); 1634 } 1635 1636 /* looking for "kext-dev-mode=1", no prefix allowed and we currently only 1637 * support a value of '1' all else are ignored. 1638 */ 1639 dev_mode_ptr = strnstr(bootargs_buffer, 1640 KEXT_DEV_MODE_STRING, 1641 sizeof(bootargs_buffer)); 1642 if (dev_mode_ptr && 1643 (dev_mode_ptr == &bootargs_buffer[0] || *(dev_mode_ptr - 1) == ' ')) { 1644 kext_dev_mode = strtoul(dev_mode_ptr + strlen(KEXT_DEV_MODE_STRING), 1645 NULL, 10); 1646 if (kext_dev_mode == 1) { 1647 result = true; 1648 } 1649 } 1650 1651 return(result); 1652} 1653 1654/********************************************************************* 1655 *********************************************************************/ 1656Boolean isInLibraryExtensionsFolder(OSKextRef theKext) 1657{ 1658 CFStringRef myKextPath = NULL; // must release 1659 Boolean myResult = false; 1660 1661 myKextPath = copyKextPath(theKext); 1662 if ( myKextPath ) { 1663 if ( CFStringHasPrefix(myKextPath, 1664 CFSTR(_kOSKextLibraryExtensionsFolder)) ) { 1665 myResult = true; 1666 } 1667 } 1668 SAFE_RELEASE(myKextPath); 1669 return(myResult); 1670} 1671 1672/********************************************************************* 1673 *********************************************************************/ 1674Boolean isInSystemLibraryExtensionsFolder(OSKextRef theKext) 1675{ 1676 CFStringRef myKextPath = NULL; // must release 1677 Boolean myResult = false; 1678 1679 myKextPath = copyKextPath(theKext); 1680 if ( myKextPath ) { 1681 if ( CFStringHasPrefix(myKextPath, 1682 CFSTR(_kOSKextSystemLibraryExtensionsFolder)) ) { 1683 myResult = true; 1684 } 1685 } 1686 SAFE_RELEASE(myKextPath); 1687 return(myResult); 1688} 1689 1690/******************************************************************************* 1691 * isInvalidSignatureAllowed() - check if kext with invalid signature is 1692 * allowed to load. Currently we check to see if we are running with boot-args 1693 * including "kext-dev-mode". In the future this is likely be removed or 1694 * changed to use other methods to set up machines in "developer mode". 1695 *******************************************************************************/ 1696Boolean isInvalidSignatureAllowed(void) 1697{ 1698 Boolean result = false; // default to not allowed 1699 1700 if (isDevMode()) { 1701 result = true; 1702 } 1703 1704 return(result); 1705} 1706#include <Security/SecKeychainPriv.h> 1707 1708/* If kextd isn't running, assume it's early boot and that securityd 1709 * isn't running either. Configure Security to avoid securityd. 1710 * SecKeychainMDSInstall needs to be called once before any kext signatures 1711 * are checked. 1712 */ 1713int callSecKeychainMDSInstall( void ) 1714{ 1715 static int calledOnce = 0; 1716 static int result = 0; 1717 1718 if (calledOnce) return(result); 1719 1720 calledOnce++; 1721 if (isKextdRunning() == FALSE) { 1722 OSStatus err; 1723 1724 err = SecKeychainMDSInstall(); 1725 if (err != errSecSuccess) { 1726 OSKextLog(/* kext */ NULL, 1727 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 1728 "Error in security framework, error %d.", (int) err); 1729 result = err; 1730 //result = EX_SOFTWARE; 1731 } 1732 } 1733 return(result); 1734} 1735 1736/******************************************************************************* 1737 * isKextdRunning() - we use this to tell if we're running before kextd is up. 1738 *******************************************************************************/ 1739Boolean isKextdRunning(void) 1740{ 1741 mach_port_t kextd_port = MACH_PORT_NULL; 1742 kern_return_t kern_result = 0; 1743 1744 kern_result = bootstrap_look_up(bootstrap_port, 1745 (char *)KEXTD_SERVER_NAME, 1746 &kextd_port); 1747 if (kern_result == kOSReturnSuccess && kextd_port != MACH_PORT_NULL) { 1748 return( TRUE ); 1749 } 1750 1751 return( FALSE ); 1752} 1753