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
30namespace Security {
31namespace CodeSigning {
32
33using 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//
43DYLDCacheRep::DYLDCacheRep(const char *path)
44	: SingleDiskRep(path), mCache(path)
45{
46	this->setup();
47}
48
49DYLDCacheRep::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
56void 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//
71bool 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//
80size_t DYLDCacheRep::pageSize(const SigningContext &)
81{
82	return segmentedPageSize;
83}
84
85
86//
87// Signing limit is the start of the (trailing) signature
88//
89size_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//
100CFDataRef 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//
109string 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//
124DiskRep::Writer *DYLDCacheRep::writer()
125{
126	return new Writer(this);
127}
128
129
130//
131// Write a component.
132//
133void 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//
142void 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//
154void DYLDCacheRep::Writer::addDiscretionary(CodeDirectory::Builder &builder)
155{
156	unsigned count = rep->mCache.mappingCount();
157	builder.scatter(count);
158	for (unsigned n = 0; n < count; n++) {
159		const DYLDCache::Mapping dmap = rep->mCache.mapping(n);
160		CodeDirectory::Scatter *scatter = builder.scatter() + n;
161		scatter->targetOffset = dmap.address();
162		scatter->base = (uint32_t)(dmap.offset() / segmentedPageSize);
163		assert(dmap.offset() % segmentedPageSize == 0);
164		scatter->count = (uint32_t)(dmap.size() / segmentedPageSize);
165		assert(dmap.size() % segmentedPageSize == 0);
166	}
167}
168
169
170} // end namespace CodeSigning
171} // end namespace Security
172