slcrep.cpp
1 /* 2 * Copyright (c) 2009,2011-2012 Apple 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 24 // 25 // slcrep - DiskRep representing the Mac OS Shared Library Cache 26 // 27 #include "slcrep.h" 28 29 30 namespace Security { 31 namespace CodeSigning { 32 33 using namespace UnixPlusPlus; 34 35 36 // 37 // Object management. 38 // We open the file lazily, so nothing much happens on constructions. 39 // We can construct directly from a file path, or from an architecture 40 // (represented by Context), which will find the file in its usual 41 // location on disk. 42 // 43 DYLDCacheRep::DYLDCacheRep(const char *path) 44 : SingleDiskRep(path), mCache(path) 45 { 46 this->setup(); 47 } 48 49 DYLDCacheRep::DYLDCacheRep(const Context *ctx) 50 : SingleDiskRep(DYLDCache::pathFor(((ctx && ctx->arch) ? ctx->arch : Architecture::local()))), 51 mCache(this->path()) 52 { 53 this->setup(); 54 } 55 56 void DYLDCacheRep::setup() 57 { 58 mSigningData = NULL; 59 if (mCache.totalSize() >= mCache.mapSize() + sizeof(BlobCore)) { 60 const EmbeddedSignatureBlob *blob = mCache.at<const EmbeddedSignatureBlob>((uint32_t)mCache.mapSize()); 61 if (mCache.totalSize() >= mCache.mapSize() + blob->length()) // entire blob fits in file 62 mSigningData = blob; 63 } 64 CODESIGN_DISKREP_CREATE_SLC(this, (char*)this->mainExecutablePath().c_str()); 65 } 66 67 68 // 69 // Sniffer function for "plausible shared library cache file". 70 // 71 bool DYLDCacheRep::candidate(FileDesc &fd) 72 { 73 return DYLDCache::validate(fd); 74 } 75 76 77 // 78 // Default to system page size for segmented (paged) signatures 79 // 80 size_t DYLDCacheRep::pageSize(const SigningContext &) 81 { 82 return segmentedPageSize; 83 } 84 85 86 // 87 // Signing limit is the start of the (trailing) signature 88 // 89 size_t DYLDCacheRep::signingLimit() 90 { 91 return mCache.mapSize(); 92 } 93 94 95 // 96 // Retrieve a component from the executable. 97 // Our mCache has mapped the entire file, so we just fish the contents out of 98 // the mapped area as needed. 99 // 100 CFDataRef DYLDCacheRep::component(CodeDirectory::SpecialSlot slot) 101 { 102 return mSigningData ? mSigningData->component(slot) : NULL; 103 } 104 105 106 // 107 // Provide a (vaguely) human readable characterization of this code 108 // 109 string DYLDCacheRep::format() 110 { 111 if (const char *name = mCache.architecture().name()) { 112 char result[100]; 113 snprintf(result, sizeof(result), "OS X Shared Library Cache (%s @ 0x%llx)", 114 name, mCache.baseAddress()); 115 return result; 116 } else 117 return "OS X Shared Library Cache (unknown type)"; 118 } 119 120 121 // 122 // DYLDCacheRep::Writers 123 // 124 DiskRep::Writer *DYLDCacheRep::writer() 125 { 126 return new Writer(this); 127 } 128 129 130 // 131 // Write a component. 132 // 133 void DYLDCacheRep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data) 134 { 135 EmbeddedSignatureBlob::Maker::component(slot, data); 136 } 137 138 139 // 140 // Append the superblob we built to the cache file. 141 // 142 void DYLDCacheRep::Writer::flush() 143 { 144 delete mSigningData; // ditch previous blob just in case 145 mSigningData = Maker::make(); // assemble new signature SuperBlob 146 fd().seek(rep->mCache.mapSize()); // end of impage proper 147 fd().writeAll(*mSigningData); 148 } 149 150 151 // 152 // The discretionary additions insert a Scatter vector describing the file's mapping table, 153 // and fills out the executable segment. 154 // 155 void DYLDCacheRep::Writer::addDiscretionary(CodeDirectory::Builder &builder) 156 { 157 bool execSegmentProcessed = false; 158 159 unsigned count = rep->mCache.mappingCount(); 160 builder.scatter(count); 161 for (unsigned n = 0; n < count; n++) { 162 const DYLDCache::Mapping dmap = rep->mCache.mapping(n); 163 CodeDirectory::Scatter *scatter = builder.scatter() + n; 164 scatter->targetOffset = dmap.address(); 165 scatter->base = (uint32_t)(dmap.offset() / segmentedPageSize); 166 assert(dmap.offset() % segmentedPageSize == 0); 167 scatter->count = (uint32_t)(dmap.size() / segmentedPageSize); 168 assert(dmap.size() % segmentedPageSize == 0); 169 170 if (dmap.maxProt() & VM_PROT_EXECUTE) { 171 if (execSegmentProcessed) { 172 CSError::throwMe(errSecMultipleExecSegments); 173 } 174 175 builder.execSeg(dmap.offset(), dmap.limit()-dmap.address(), 0); 176 } 177 } 178 } 179 180 181 } // end namespace CodeSigning 182 } // end namespace Security