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" 
  33 namespace CodeSigning 
{ 
  35 using namespace UnixPlusPlus
; 
  40 // We open the main executable lazily, so nothing much happens on construction. 
  41 // If the context specifies a file offset, we directly pick that Mach-O binary (only). 
  42 // if it specifies an architecture, we try to pick that. Otherwise, we deliver the whole 
  43 // Universal object (which will usually deliver the "native" architecture later). 
  45 MachORep::MachORep(const char *path
, const Context 
*ctx
) 
  46         : SingleDiskRep(path
), mSigningData(NULL
) 
  50                         mExecutable 
= new Universal(fd(), (size_t)ctx
->offset
, ctx
->size
); 
  52                         auto_ptr
<Universal
> full(new Universal(fd())); 
  53                         mExecutable 
= new Universal(fd(), full
->archOffset(ctx
->arch
), full
->archLength(ctx
->arch
)); 
  55                         mExecutable 
= new Universal(fd()); 
  57                 mExecutable 
= new Universal(fd()); 
  60         CODESIGN_DISKREP_CREATE_MACHO(this, (char*)path
, (void*)ctx
); 
  71 // Sniffer function for "plausible Mach-O binary" 
  73 bool MachORep::candidate(FileDesc 
&fd
) 
  75         switch (Universal::typeOf(fd
)) { 
  82                 return true;            // dynamic image; supported 
  84                 return false;           // maybe later... 
  86                 return false;           // not Mach-O (or too exotic) 
  93 // Nowadays, the main executable object is created upon construction. 
  95 Universal 
*MachORep::mainExecutableImage() 
 102 // Signing base is the start of the Mach-O architecture we're using 
 104 size_t MachORep::signingBase() 
 106         return mainExecutableImage()->archOffset(); 
 111 // We choose the binary identifier for a Mach-O binary as follows: 
 112 //      - If the Mach-O headers have a UUID command, use the UUID. 
 113 //      - Otherwise, use the SHA-1 hash of the (entire) load commands. 
 115 CFDataRef 
MachORep::identification() 
 117         std::auto_ptr
<MachO
> macho(mainExecutableImage()->architecture()); 
 118         return identificationFor(macho
.get()); 
 121 CFDataRef 
MachORep::identificationFor(MachO 
*macho
) 
 123         // if there is a LC_UUID load command, use the UUID contained therein 
 124         if (const load_command 
*cmd 
= macho
->findCommand(LC_UUID
)) { 
 125                 const uuid_command 
*uuidc 
= reinterpret_cast<const uuid_command 
*>(cmd
); 
 126                 // uuidc->cmdsize should be sizeof(uuid_command), so if it is not, 
 127                 // something is wrong. Fail out. 
 128                 if (macho
->flip(uuidc
->cmdsize
) != sizeof(uuid_command
)) 
 129                         MacOSError::throwMe(errSecCSSignatureInvalid
); 
 130                 char result
[4 + sizeof(uuidc
->uuid
)]; 
 131                 memcpy(result
, "UUID", 4); 
 132                 memcpy(result
+4, uuidc
->uuid
, sizeof(uuidc
->uuid
)); 
 133                 return makeCFData(result
, sizeof(result
)); 
 136         // otherwise, use the SHA-1 hash of the entire load command area (this is way, way obsolete) 
 138         hash(&macho
->header(), sizeof(mach_header
)); 
 139         hash(macho
->loadCommands(), macho
->commandLength()); 
 142         return makeCFData(digest
, sizeof(digest
)); 
 147 // Retrieve a component from the executable. 
 148 // This reads the entire signing SuperBlob when first called for an executable, 
 149 // and then caches it for further use. 
 150 // Note that we could read individual components directly off disk and only cache 
 151 // the SuperBlob Index directory. Our caller (usually SecStaticCode) is expected 
 152 // to cache the pieces anyway. 
 154 CFDataRef 
MachORep::component(CodeDirectory::SpecialSlot slot
) 
 160                 return embeddedComponent(slot
); 
 165 // Retrieve a component from the embedded signature SuperBlob (if present). 
 166 // This reads the entire signing SuperBlob when first called for an executable, 
 167 // and then caches it for further use. 
 168 // Note that we could read individual components directly off disk and only cache 
 169 // the SuperBlob Index directory. Our caller (usually SecStaticCode) is expected 
 170 // to cache the pieces anyway. But it's not clear that the resulting multiple I/O 
 171 // calls wouldn't be slower in the end. 
 173 CFDataRef 
MachORep::embeddedComponent(CodeDirectory::SpecialSlot slot
) 
 175         if (!mSigningData
) {            // fetch and cache 
 176                 auto_ptr
<MachO
> macho(mainExecutableImage()->architecture()); 
 178                         if (const linkedit_data_command 
*cs 
= macho
->findCodeSignature()) { 
 179                                 size_t offset 
= macho
->flip(cs
->dataoff
); 
 180                                 size_t length 
= macho
->flip(cs
->datasize
); 
 181                                 if ((mSigningData 
= EmbeddedSignatureBlob::readBlob(macho
->fd(), macho
->offset() + offset
, length
))) { 
 182                                         secdebug("machorep", "%zd signing bytes in %d blob(s) from %s(%s)", 
 183                                                 mSigningData
->length(), mSigningData
->count(), 
 184                                                 mainExecutablePath().c_str(), macho
->architecture().name()); 
 186                                         secdebug("machorep", "failed to read signing bytes from %s(%s)", 
 187                                                 mainExecutablePath().c_str(), macho
->architecture().name()); 
 188                                         MacOSError::throwMe(errSecCSSignatureInvalid
); 
 193                 return mSigningData
->component(slot
); 
 201 // Extract an embedded Info.plist from the file. 
 202 // Returns NULL if none is found. 
 204 CFDataRef 
MachORep::infoPlist() 
 206         CFRef
<CFDataRef
> info
; 
 208                 auto_ptr
<MachO
> macho(mainExecutableImage()->architecture()); 
 209                 if (const section 
*sect 
= macho
->findSection("__TEXT", "__info_plist")) { 
 211                                 const section_64 
*sect64 
= reinterpret_cast<const section_64 
*>(sect
); 
 212                                 info
.take(macho
->dataAt(macho
->flip(sect64
->offset
), (size_t)macho
->flip(sect64
->size
))); 
 214                                 info
.take(macho
->dataAt(macho
->flip(sect
->offset
), macho
->flip(sect
->size
))); 
 218                 secdebug("machorep", "exception reading embedded Info.plist"); 
 225 // Provide a (vaguely) human readable characterization of this code 
 227 string 
MachORep::format() 
 229         if (Universal 
*fat 
= mainExecutableImage()) { 
 230                 Universal::Architectures archs
; 
 231                 fat
->architectures(archs
); 
 232                 if (fat
->isUniversal()) { 
 233                         string s 
= "Mach-O universal ("; 
 234                         for (Universal::Architectures::const_iterator it 
= archs
.begin(); 
 235                                         it 
!= archs
.end(); ++it
) { 
 236                                 if (it 
!= archs
.begin()) 
 238                                 s 
+= it
->displayName(); 
 242                         assert(archs
.size() == 1); 
 243                         return string("Mach-O thin (") + archs
.begin()->displayName() + ")"; 
 246                 return "Mach-O (unrecognized format)"; 
 253 void MachORep::flush() 
 255         size_t offset 
= mExecutable
->offset(); 
 256         size_t length 
= mExecutable
->length(); 
 259         ::free(mSigningData
); 
 261         SingleDiskRep::flush(); 
 262         mExecutable 
= new Universal(fd(), offset
, length
); 
 267 // Return a recommended unique identifier. 
 268 // If our file has an embedded Info.plist, use the CFBundleIdentifier from that. 
 269 // Otherwise, use the default. 
 271 string 
MachORep::recommendedIdentifier(const SigningContext 
&ctx
) 
 273         if (CFDataRef info 
= infoPlist()) { 
 274                 if (CFRef
<CFDictionaryRef
> dict 
= makeCFDictionaryFrom(info
)) { 
 275                         CFStringRef code 
= CFStringRef(CFDictionaryGetValue(dict
, kCFBundleIdentifierKey
)); 
 276                         if (code 
&& CFGetTypeID(code
) != CFStringGetTypeID()) 
 277                                 MacOSError::throwMe(errSecCSBadDictionaryFormat
); 
 279                                 return cfString(code
); 
 281                         MacOSError::throwMe(errSecCSBadDictionaryFormat
); 
 284         // ah well. Use the default 
 285         return SingleDiskRep::recommendedIdentifier(ctx
); 
 290 // The default suggested requirements for Mach-O binaries are as follows: 
 291 // Library requirement: Composed from dynamic load commands. 
 293 const Requirements 
*MachORep::defaultRequirements(const Architecture 
*arch
, const SigningContext 
&ctx
) 
 295         assert(arch
);           // enforced by signing infrastructure 
 296         Requirements::Maker maker
; 
 298         // add library requirements from DYLIB commands (if any) 
 299         if (Requirement 
*libreq 
= libraryRequirements(arch
, ctx
)) 
 300                 maker
.add(kSecLibraryRequirementType
, libreq
);  // takes ownership 
 306 Requirement 
*MachORep::libraryRequirements(const Architecture 
*arch
, const SigningContext 
&ctx
) 
 308         auto_ptr
<MachO
> macho(mainExecutableImage()->architecture(*arch
)); 
 309         Requirement::Maker maker
; 
 310         Requirement::Maker::Chain 
chain(maker
, opOr
); 
 313                 if (const linkedit_data_command 
*ldep 
= macho
->findLibraryDependencies()) { 
 314                         size_t offset 
= macho
->flip(ldep
->dataoff
); 
 315                         size_t length 
= macho
->flip(ldep
->datasize
); 
 316                         if (LibraryDependencyBlob 
*deplist 
= LibraryDependencyBlob::readBlob(macho
->fd(), macho
->offset() + offset
, length
)) { 
 318                                         secdebug("machorep", "%zd library dependency bytes in %d blob(s) from %s(%s)", 
 319                                                 deplist
->length(), deplist
->count(), 
 320                                                 mainExecutablePath().c_str(), macho
->architecture().name()); 
 321                                         unsigned count 
= deplist
->count(); 
 322                                         // we could walk through DYLIB load commands in parallel. We just don't need anything from them so far 
 323                                         for (unsigned n 
= 0; n 
< count
; n
++) { 
 324                                                 const Requirement 
*req 
= NULL
; 
 325                                                 if (const BlobCore 
*dep 
= deplist
->blob(n
)) { 
 326                                                         if ((req 
= Requirement::specific(dep
))) { 
 327                                                                 // binary code requirement; good to go 
 328                                                         } else if (const BlobWrapper 
*wrap 
= BlobWrapper::specific(dep
)) { 
 329                                                                 // blob-wrapped text form - convert to binary requirement 
 330                                                                 std::string reqString 
= std::string((const char *)wrap
->data(), wrap
->length()); 
 331                                                                 CFRef
<SecRequirementRef
> areq
; 
 332                                                                 MacOSError::check(SecRequirementCreateWithString(CFTempString(reqString
), kSecCSDefaultFlags
, &areq
.aref())); 
 333                                                                 CFRef
<CFDataRef
> reqData
; 
 334                                                                 MacOSError::check(SecRequirementCopyData(areq
, kSecCSDefaultFlags
, &reqData
.aref())); 
 335                                                                 req 
= Requirement::specific((const BlobCore 
*)CFDataGetBytePtr(reqData
)); 
 337                                                                 secdebug("machorep", "unexpected blob type 0x%x in slot %d of binary dependencies", dep
->magic(), n
); 
 343                                                         secdebug("machorep", "missing DR info for library index %d", n
); 
 360 // Default to system page size for segmented (paged) signatures 
 362 size_t MachORep::pageSize(const SigningContext 
&) 
 364         return segmentedPageSize
; 
 371 void MachORep::strictValidate(const CodeDirectory
* cd
, const ToleratedErrors
& tolerated
) 
 373         // if the constructor found suspicious issues, fail a struct validation now 
 374         if (mExecutable
->isSuspicious() && tolerated
.find(errSecCSBadMainExecutable
) == tolerated
.end()) 
 375                 MacOSError::throwMe(errSecCSBadMainExecutable
); 
 377         // the signature's code extent must be what we would have picked (no funny hand editing) 
 379                 auto_ptr
<MachO
> macho(mExecutable
->architecture()); 
 380                 if (cd
->codeLimit 
!= macho
->signingExtent()) 
 381                         MacOSError::throwMe(errSecCSSignatureInvalid
); 
 387 // FileDiskRep::Writers 
 389 DiskRep::Writer 
*MachORep::writer() 
 391         return new Writer(this); 
 396 // Write a component. 
 397 // MachORep::Writers don't write to components directly; the signing code uses special 
 398 // knowledge of the Mach-O format to build embedded signatures and blasts them directly 
 399 // to disk. Thus this implementation will never be called (and, if called, will simply fail). 
 401 void MachORep::Writer::component(CodeDirectory::SpecialSlot slot
, CFDataRef data
) 
 404         MacOSError::throwMe(errSecCSInternalError
); 
 408 } // end namespace CodeSigning 
 409 } // end namespace Security