2  * Copyright (c) 2006,2011-2012,2014 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   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 
  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. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  25 // machorep - DiskRep mix-in for handling Mach-O main executables 
  28 #include "StaticCode.h" 
  30 #include <security_utilities/logging.h> 
  31 #include <security_utilities/cfmunge.h> 
  32 #include <security_utilities/casts.h> 
  37 namespace CodeSigning 
{ 
  39 using namespace UnixPlusPlus
; 
  44 // We open the main executable lazily, so nothing much happens on construction. 
  45 // If the context specifies a file offset, we directly pick that Mach-O binary (only). 
  46 // if it specifies an architecture, we try to pick that. Otherwise, we deliver the whole 
  47 // Universal object (which will usually deliver the "native" architecture later). 
  49 MachORep::MachORep(const char *path
, const Context 
*ctx
) 
  50         : SingleDiskRep(path
), mSigningData(NULL
) 
  54                         mExecutable 
= new Universal(fd(), (size_t)ctx
->offset
, ctx
->size
); 
  56                         auto_ptr
<Universal
> full(new Universal(fd())); 
  57                         mExecutable 
= new Universal(fd(), full
->archOffset(ctx
->arch
), full
->archLength(ctx
->arch
)); 
  59                         mExecutable 
= new Universal(fd()); 
  61                 mExecutable 
= new Universal(fd()); 
  64         CODESIGN_DISKREP_CREATE_MACHO(this, (char*)path
, (void*)ctx
); 
  75 // Sniffer function for "plausible Mach-O binary" 
  77 bool MachORep::candidate(FileDesc 
&fd
) 
  79         switch (Universal::typeOf(fd
)) { 
  86                 return true;            // dynamic image; supported 
  88                 return false;           // maybe later... 
  90                 return false;           // not Mach-O (or too exotic) 
  97 // Nowadays, the main executable object is created upon construction. 
  99 Universal 
*MachORep::mainExecutableImage() 
 106 // Explicitly default to SHA256 (only) digests if the minimum deployment 
 107 // target is young enough. 
 109 void MachORep::prepareForSigning(SigningContext 
&context
) 
 111         if (context
.digestAlgorithms().empty()) { 
 112         auto_ptr
<MachO
> macho(mainExecutableImage()->architecture()); 
 115                 switch (macho
->platform()) { 
 117                                 // If we don't know the platform, we stay agile. 
 120                                 // 10.11.4 had first proper sha256 support. 
 121                                 limit 
= (10 << 16 | 11 << 8 | 4 << 0); 
 125                                 // iOS 11 and tvOS 11 had first proper sha256 support. 
 126                                 limit 
= (11 << 16 | 0 << 8 | 0 << 0); 
 128                         case PLATFORM_WATCHOS
: 
 129                                 // We stay agile on the watch right now. 
 132                                 // All other platforms are assumed to be new and support SHA256. 
 135                 if (macho
->minVersion() >= limit
) { 
 136                         // young enough not to need SHA-1 legacy support 
 137                         context
.setDigestAlgorithm(kSecCodeSignatureHashSHA256
); 
 144 // Signing base is the start of the Mach-O architecture we're using 
 146 size_t MachORep::signingBase() 
 148         return mainExecutableImage()->archOffset(); 
 151 size_t MachORep::signingLimit() 
 153         auto_ptr
<MachO
> macho(mExecutable
->architecture()); 
 154         return macho
->signingExtent(); 
 157 bool MachORep::needsExecSeg(const MachO
& macho
) { 
 158         uint32_t platform 
= macho
.platform(); 
 159         // Everything embedded gets an exec segment. 
 160         return platform 
!= 0 && platform 
!= PLATFORM_MACOS
; 
 163 size_t MachORep::execSegBase(const Architecture 
*arch
) 
 165         auto_ptr
<MachO
> macho(arch 
? mExecutable
->architecture(*arch
) : mExecutable
->architecture()); 
 167         if (!needsExecSeg(*macho
)) { 
 171         segment_command 
const * const text_cmd 
= macho
->findSegment("__TEXT"); 
 173         if (text_cmd 
== NULL
) { 
 180                 off 
= int_cast
<uint64_t,size_t>(reinterpret_cast<segment_command_64 
const * const>(text_cmd
)->fileoff
); 
 182                 off 
= text_cmd
->fileoff
; 
 188 size_t MachORep::execSegLimit(const Architecture 
*arch
) 
 190         auto_ptr
<MachO
> macho(arch 
? mExecutable
->architecture(*arch
) : mExecutable
->architecture()); 
 192         if (!needsExecSeg(*macho
)) { 
 196         segment_command 
const * const text_cmd 
= macho
->findSegment("__TEXT"); 
 198         if (text_cmd 
== NULL
) { 
 205                 size 
= int_cast
<uint64_t,size_t>(reinterpret_cast<segment_command_64 
const * const>(text_cmd
)->filesize
); 
 207                 size 
= text_cmd
->filesize
; 
 215 // We choose the binary identifier for a Mach-O binary as follows: 
 216 //      - If the Mach-O headers have a UUID command, use the UUID. 
 217 //      - Otherwise, use the SHA-1 hash of the (entire) load commands. 
 219 CFDataRef 
MachORep::identification() 
 221         std::auto_ptr
<MachO
> macho(mainExecutableImage()->architecture()); 
 222         return identificationFor(macho
.get()); 
 225 CFDataRef 
MachORep::identificationFor(MachO 
*macho
) 
 227         // if there is a LC_UUID load command, use the UUID contained therein 
 228         if (const load_command 
*cmd 
= macho
->findCommand(LC_UUID
)) { 
 229                 const uuid_command 
*uuidc 
= reinterpret_cast<const uuid_command 
*>(cmd
); 
 230                 // uuidc->cmdsize should be sizeof(uuid_command), so if it is not, 
 231                 // something is wrong. Fail out. 
 232                 if (macho
->flip(uuidc
->cmdsize
) != sizeof(uuid_command
)) 
 233                         MacOSError::throwMe(errSecCSSignatureInvalid
); 
 234                 char result
[4 + sizeof(uuidc
->uuid
)]; 
 235                 memcpy(result
, "UUID", 4); 
 236                 memcpy(result
+4, uuidc
->uuid
, sizeof(uuidc
->uuid
)); 
 237                 return makeCFData(result
, sizeof(result
)); 
 240         // otherwise, use the SHA-1 hash of the entire load command area (this is way, way obsolete) 
 242         hash(&macho
->header(), sizeof(mach_header
)); 
 243         hash(macho
->loadCommands(), macho
->commandLength()); 
 246         return makeCFData(digest
, sizeof(digest
)); 
 251 // Retrieve a component from the executable. 
 252 // This reads the entire signing SuperBlob when first called for an executable, 
 253 // and then caches it for further use. 
 254 // Note that we could read individual components directly off disk and only cache 
 255 // the SuperBlob Index directory. Our caller (usually SecStaticCode) is expected 
 256 // to cache the pieces anyway. 
 258 CFDataRef 
MachORep::component(CodeDirectory::SpecialSlot slot
) 
 264                 return embeddedComponent(slot
); 
 269 // Retrieve all components, used for signature editing. 
 271 EditableDiskRep::RawComponentMap 
MachORep::createRawComponents() 
 273         EditableDiskRep::RawComponentMap  blobMap
; 
 274         const EmbeddedSignatureBlob 
&blobs 
= *signingData(); 
 276         for (unsigned int i 
= 0; i 
< blobs
.count(); ++i
) { 
 277                 CodeDirectory::Slot slot 
= blobs
.type(i
); 
 278                 const BlobCore 
*blob 
= blobs
.blob(i
); 
 279                 blobMap
[slot
] = blobs
.blobData(slot
, blob
); 
 284 // Retrieve a component from the embedded signature SuperBlob (if present). 
 285 // This reads the entire signing SuperBlob when first called for an executable, 
 286 // and then caches it for further use. 
 287 // Note that we could read individual components directly off disk and only cache 
 288 // the SuperBlob Index directory. Our caller (usually SecStaticCode) is expected 
 289 // to cache the pieces anyway. But it's not clear that the resulting multiple I/O 
 290 // calls wouldn't be slower in the end. 
 292 CFDataRef 
MachORep::embeddedComponent(CodeDirectory::SpecialSlot slot
) 
 295                 return signingData()->component(slot
); 
 304 EmbeddedSignatureBlob 
*MachORep::signingData() 
 306         if (!mSigningData
) {            // fetch and cache 
 307                 auto_ptr
<MachO
> macho(mainExecutableImage()->architecture()); 
 309                         if (const linkedit_data_command 
*cs 
= macho
->findCodeSignature()) { 
 310                                 size_t offset 
= macho
->flip(cs
->dataoff
); 
 311                                 size_t length 
= macho
->flip(cs
->datasize
); 
 312                                 if ((mSigningData 
= EmbeddedSignatureBlob::readBlob(macho
->fd(), macho
->offset() + offset
, length
))) { 
 313                                         secinfo("machorep", "%zd signing bytes in %d blob(s) from %s(%s)", 
 314                                                         mSigningData
->length(), mSigningData
->count(), 
 315                                                         mainExecutablePath().c_str(), macho
->architecture().name()); 
 317                                         secinfo("machorep", "failed to read signing bytes from %s(%s)", 
 318                                                         mainExecutablePath().c_str(), macho
->architecture().name()); 
 319                                         MacOSError::throwMe(errSecCSSignatureInvalid
); 
 328 // Extract an embedded Info.plist from the file. 
 329 // Returns NULL if none is found. 
 331 CFDataRef 
MachORep::infoPlist() 
 333         CFRef
<CFDataRef
> info
; 
 335                 auto_ptr
<MachO
> macho(mainExecutableImage()->architecture()); 
 336                 if (const section 
*sect 
= macho
->findSection("__TEXT", "__info_plist")) { 
 338                                 const section_64 
*sect64 
= reinterpret_cast<const section_64 
*>(sect
); 
 339                                 info
.take(macho
->dataAt(macho
->flip(sect64
->offset
), (size_t)macho
->flip(sect64
->size
))); 
 341                                 info
.take(macho
->dataAt(macho
->flip(sect
->offset
), macho
->flip(sect
->size
))); 
 345                 secinfo("machorep", "exception reading embedded Info.plist"); 
 352 // Provide a (vaguely) human readable characterization of this code 
 354 string 
MachORep::format() 
 356         if (Universal 
*fat 
= mainExecutableImage()) { 
 357                 Universal::Architectures archs
; 
 358                 fat
->architectures(archs
); 
 359                 if (fat
->isUniversal()) { 
 360                         string s 
= "Mach-O universal ("; 
 361                         for (Universal::Architectures::const_iterator it 
= archs
.begin(); 
 362                                         it 
!= archs
.end(); ++it
) { 
 363                                 if (it 
!= archs
.begin()) 
 365                                 s 
+= it
->displayName(); 
 369                         assert(archs
.size() == 1); 
 370                         return string("Mach-O thin (") + archs
.begin()->displayName() + ")"; 
 373                 return "Mach-O (unrecognized format)"; 
 380 void MachORep::flush() 
 382         size_t offset 
= mExecutable
->offset(); 
 383         size_t length 
= mExecutable
->length(); 
 386         ::free(mSigningData
); 
 388         SingleDiskRep::flush(); 
 389         mExecutable 
= new Universal(fd(), offset
, length
); 
 392 CFDictionaryRef 
MachORep::diskRepInformation() 
 394     auto_ptr
<MachO
> macho (mainExecutableImage()->architecture()); 
 395     CFRef
<CFDictionaryRef
> info
; 
 397         uint32_t platform 
= 0; 
 398         uint32_t minVersion 
= 0; 
 399         uint32_t sdkVersion 
= 0; 
 401     if (macho
->version(&platform
, &minVersion
, &sdkVersion
)) { 
 403                 /* These keys replace the old kSecCodeInfoDiskRepOSPlatform, kSecCodeInfoDiskRepOSVersionMin 
 404                  * and kSecCodeInfoDiskRepOSSDKVersion. The keys were renamed because we changed what value 
 405                  * "platform" represents: For the old key, the actual load command (e.g. LC_VERSION_MIN_MACOSX) 
 406                  * was returned; for the new key, we return one of the PLATFORM_* values used by LC_BUILD_VERSION. 
 408                  * The keys are private and undocumented, and maintaining a translation table between the old and 
 409                  * new domain would provide little value at high cost, but we do remove the old keys to make 
 410                  * the change obvious. 
 413         info
.take(cfmake
<CFMutableDictionaryRef
>("{%O = %d,%O = %d,%O = %d}", 
 414                                               kSecCodeInfoDiskRepVersionPlatform
, platform
, 
 415                                               kSecCodeInfoDiskRepVersionMin
, minVersion
, 
 416                                               kSecCodeInfoDiskRepVersionSDK
, sdkVersion
)); 
 418         if (platform 
== PLATFORM_MACOS 
&& sdkVersion 
< (10 << 16 | 9 << 8)) 
 420             info
.take(cfmake
<CFMutableDictionaryRef
>("{+%O, %O = 'OS X SDK version before 10.9 does not support Library Validation'}", 
 422                                                   kSecCodeInfoDiskRepNoLibraryValidation
)); 
 431 // Return a recommended unique identifier. 
 432 // If our file has an embedded Info.plist, use the CFBundleIdentifier from that. 
 433 // Otherwise, use the default. 
 435 string 
MachORep::recommendedIdentifier(const SigningContext 
&ctx
) 
 437         if (CFDataRef info 
= infoPlist()) { 
 438                 if (CFRef
<CFDictionaryRef
> dict 
= makeCFDictionaryFrom(info
)) { 
 439                         CFStringRef code 
= CFStringRef(CFDictionaryGetValue(dict
, kCFBundleIdentifierKey
)); 
 440                         if (code 
&& CFGetTypeID(code
) != CFStringGetTypeID()) 
 441                                 MacOSError::throwMe(errSecCSBadDictionaryFormat
); 
 443                                 return cfString(code
); 
 445                         MacOSError::throwMe(errSecCSBadDictionaryFormat
); 
 448         // ah well. Use the default 
 449         return SingleDiskRep::recommendedIdentifier(ctx
); 
 454 // The default suggested requirements for Mach-O binaries are as follows: 
 455 // Library requirement: Composed from dynamic load commands. 
 457 const Requirements 
*MachORep::defaultRequirements(const Architecture 
*arch
, const SigningContext 
&ctx
) 
 459         assert(arch
);           // enforced by signing infrastructure 
 460         Requirements::Maker maker
; 
 462         // add library requirements from DYLIB commands (if any) 
 463         if (Requirement 
*libreq 
= libraryRequirements(arch
, ctx
)) 
 464                 maker
.add(kSecLibraryRequirementType
, libreq
);  // takes ownership 
 470 Requirement 
*MachORep::libraryRequirements(const Architecture 
*arch
, const SigningContext 
&ctx
) 
 472         auto_ptr
<MachO
> macho(mainExecutableImage()->architecture(*arch
)); 
 473         Requirement::Maker maker
; 
 474         Requirement::Maker::Chain 
chain(maker
, opOr
); 
 477                 if (const linkedit_data_command 
*ldep 
= macho
->findLibraryDependencies()) { 
 478                         size_t offset 
= macho
->flip(ldep
->dataoff
); 
 479                         size_t length 
= macho
->flip(ldep
->datasize
); 
 480                         if (LibraryDependencyBlob 
*deplist 
= LibraryDependencyBlob::readBlob(macho
->fd(), macho
->offset() + offset
, length
)) { 
 482                                         secinfo("machorep", "%zd library dependency bytes in %d blob(s) from %s(%s)", 
 483                                                 deplist
->length(), deplist
->count(), 
 484                                                 mainExecutablePath().c_str(), macho
->architecture().name()); 
 485                                         unsigned count 
= deplist
->count(); 
 486                                         // we could walk through DYLIB load commands in parallel. We just don't need anything from them so far 
 487                                         for (unsigned n 
= 0; n 
< count
; n
++) { 
 488                                                 const Requirement 
*req 
= NULL
; 
 489                                                 if (const BlobCore 
*dep 
= deplist
->blob(n
)) { 
 490                                                         if ((req 
= Requirement::specific(dep
))) { 
 491                                                                 // binary code requirement; good to go 
 492                                                         } else if (const BlobWrapper 
*wrap 
= BlobWrapper::specific(dep
)) { 
 493                                                                 // blob-wrapped text form - convert to binary requirement 
 494                                                                 std::string reqString 
= std::string((const char *)wrap
->data(), wrap
->length()); 
 495                                                                 CFRef
<SecRequirementRef
> areq
; 
 496                                                                 MacOSError::check(SecRequirementCreateWithString(CFTempString(reqString
), kSecCSDefaultFlags
, &areq
.aref())); 
 497                                                                 CFRef
<CFDataRef
> reqData
; 
 498                                                                 MacOSError::check(SecRequirementCopyData(areq
, kSecCSDefaultFlags
, &reqData
.aref())); 
 499                                                                 req 
= Requirement::specific((const BlobCore 
*)CFDataGetBytePtr(reqData
)); 
 501                                                                 secinfo("machorep", "unexpected blob type 0x%x in slot %d of binary dependencies", dep
->magic(), n
); 
 507                                                         secinfo("machorep", "missing DR info for library index %d", n
); 
 524 // Default to system page size for segmented (paged) signatures 
 526 size_t MachORep::pageSize(const SigningContext 
&) 
 528         return segmentedPageSize
; 
 535 void MachORep::strictValidate(const CodeDirectory
* cd
, const ToleratedErrors
& tolerated
, SecCSFlags flags
) 
 537         SingleDiskRep::strictValidate(cd
, tolerated
, flags
); 
 539         // if the constructor found suspicious issues, fail a struct validation now 
 540         if (mExecutable
->isSuspicious() && tolerated
.find(errSecCSBadMainExecutable
) == tolerated
.end()) 
 541                 MacOSError::throwMe(errSecCSBadMainExecutable
); 
 546 // FileDiskRep::Writers 
 548 DiskRep::Writer 
*MachORep::writer() 
 550         return new Writer(this); 
 555 // Write a component. 
 556 // MachORep::Writers don't write to components directly; the signing code uses special 
 557 // knowledge of the Mach-O format to build embedded signatures and blasts them directly 
 558 // to disk. Thus this implementation will never be called (and, if called, will simply fail). 
 560 void MachORep::Writer::component(CodeDirectory::SpecialSlot slot
, CFDataRef data
) 
 563     Syslog::notice("code signing internal error: trying to write Mach-O component directly"); 
 564         MacOSError::throwMe(errSecCSInternalError
); 
 568 } // end namespace CodeSigning 
 569 } // end namespace Security