/ OSX / libsecurity_codesigning / lib / slcrep.cpp
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