]> git.saurik.com Git - apple/ld64.git/blame - src/ld/code-sign-blobs/superblob.h
ld64-302.3.tar.gz
[apple/ld64.git] / src / ld / code-sign-blobs / superblob.h
CommitLineData
ebf6f434
A
1//
2// SuperBlob - a typed bag of Blobs
3//
4#ifndef _H_SUPERBLOB
5#define _H_SUPERBLOB
6
7#include "blob.h"
8#include <assert.h>
9#include <utility>
10#include <map>
11
12using namespace std;
13
14namespace Security {
15
16
17//
18// A SuperBlob is a Blob that contains multiple sub-Blobs of varying type.
19// The SuperBlob is contiguous and contains a directory of its sub-blobs.
20// A Maker is included.
21//
22// SuperBlobCore lets you define your own SuperBlob type. To just use a generic
23// SuperBlob, use SuperBlob<> below.
24//
25template <class _BlobType, uint32_t _magic, class _Type>
26class SuperBlobCore: public Blob<_BlobType, _magic> {
27public:
28 class Maker; friend class Maker;
29
30 typedef _Type Type;
31
32 // echoes from parent BlobCore (the C++ type system is too restrictive here)
33 typedef BlobCore::Offset Offset;
34 template <class BlobType> BlobType *at(Offset offset) { return BlobCore::at<BlobType>(offset); }
35 template <class BlobType> const BlobType *at(Offset offset) const { return BlobCore::at<BlobType>(offset); }
36
37 void setup(size_t size, unsigned cnt)
38 { this->initialize(size); this->mCount = cnt; }
39
40 struct Index {
41 Endian<Type> type; // type of sub-Blob
42 Endian<Offset> offset; // starting offset
43 };
44
45 bool validateBlob(size_t maxSize = 0) const;
46
47 unsigned count() const { return mCount; }
48
49 // access by index number
50 Type type(unsigned n) const { assert(n < mCount); return mIndex[n].type; }
51 const BlobCore *blob(unsigned n) const { assert(n < mCount); Offset off=mIndex[n].offset; return off ? at<const BlobCore>(off) : NULL; }
52
53 template <class BlobType>
54 const BlobType *blob(unsigned n) const { return BlobType::specific(blob(n)); }
55
56 // access by index type (assumes unique types)
57 const BlobCore *find(Type type) const;
58 template <class BlobType>
59 const BlobType *find(Type t) const { return BlobType::specific(find(t)); }
60
61private:
62 Endian<uint32_t> mCount; // number of sub-Blobs following
63 Index mIndex[0]; // <count> IndexSlot structures
64 // followed by sub-Blobs, packed and ordered in an undefined way
65};
66
67
68template <class _BlobType, uint32_t _magic, class _Type>
69inline bool SuperBlobCore<_BlobType, _magic, _Type>::validateBlob(size_t maxSize /* = 0 */) const
70{
71 unsigned cnt = mCount;
72 size_t ixLimit = sizeof(SuperBlobCore) + cnt * sizeof(Index); // end of index vector
73 if (!BlobCore::validateBlob(_magic, ixLimit, maxSize))
74 return false;
75
76 for (const Index *ix = mIndex + cnt - 1; ix >= mIndex; ix--) {
77 Offset offset = ix->offset;
78 if ( offset == 0 )
79 continue; // offset==0 means unused entry
80 if (offset < ixLimit // offset not too small
81 || offset + sizeof(BlobCore) > this->length() // fits Blob header (including length field)
82 || offset + at<const BlobCore>(offset)->length() > this->length()) // fits entire blob
83 return false;
84 }
85 return true;
86}
87
88
89//
90// A generic SuperBlob ready for use. You still need to specify a magic number.
91//
92template <uint32_t _magic, class _Type = uint32_t>
93class SuperBlob : public SuperBlobCore<SuperBlob<_magic, _Type>, _magic, _Type> {
94};
95
96
97template <class _BlobType, uint32_t _magic, class _Type>
98const BlobCore *SuperBlobCore<_BlobType, _magic, _Type>::find(Type t) const
99{
100 for (unsigned slot = 0; slot < mCount; slot++) {
101 if (mIndex[slot].type == t) {
102 uint32_t off = mIndex[slot].offset;
103 if ( off == 0 )
104 return NULL;
105 else
106 return at<const BlobCore>(off);
107 }
108 }
109 return NULL; // not found
110}
111
112
113//
114// A SuperBlob::Maker simply assembles multiple Blobs into a single, indexed
115// super-blob. Just add() sub-Blobs by type and call build() to get
116// the result, malloc'ed. A Maker is not reusable.
117// Maker can repeatedly make SuperBlobs from the same (cached) inputs.
118// It can also tell you how big its output will be, given established contents
119// plus (optional) additional sizes of blobs yet to come.
120//
121template <class _BlobType, uint32_t _magic, class _Type>
122class SuperBlobCore<_BlobType, _magic, _Type>::Maker {
123public:
124 Maker() { }
125
126 Maker(const Maker &src)
127 {
128 for (typename BlobMap::iterator it = mPieces.begin(); it != mPieces.end(); ++it)
129 mPieces.insert(make_pair(it->first, it->second->clone()));
130 }
131
132 ~Maker()
133 {
134 for (typename BlobMap::iterator it = mPieces.begin(); it != mPieces.end(); ++it)
135 ::free(it->second);
136 }
137
138 void add(Type type, BlobCore *blob); // takes ownership of blob
139 void add(const _BlobType *blobs); // copies all blobs
140 void add(const Maker &maker); // ditto
141
142 size_t size(size_t size1 = 0, ...) const; // size with optional additional blob sizes
143 _BlobType *make() const; // create (malloc) and return SuperBlob
144 _BlobType *operator () () const { return make(); }
145
146private:
147 typedef std::map<Type, BlobCore *> BlobMap;
148 BlobMap mPieces;
149};
150
151
152//
153// Add a Blob to a SuperBlob::Maker.
154// This takes ownership of the blob, which must have been malloc'ed.
155// Any previous value set for this Type will be freed immediately.
156//
157template <class _BlobType, uint32_t _magic, class _Type>
158void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(Type type, BlobCore *blob)
159{
160 pair<typename BlobMap::iterator, bool> r = mPieces.insert(make_pair(type, blob));
161 if (!r.second) { // already there
162 //secdebug("superblob", "Maker %p replaces type=%d", this, type);
163 ::free(r.first->second);
164 r.first->second = blob;
165 }
166}
167
168template <class _BlobType, uint32_t _magic, class _Type>
169void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(const _BlobType *blobs)
170{
171 for (uint32_t ix = 0; ix < blobs->mCount; ix++)
172 this->add(blobs->mIndex[ix].type, blobs->blob(ix)->clone());
173}
174
175template <class _BlobType, uint32_t _magic, class _Type>
176void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(const Maker &maker)
177{
178 for (typename BlobMap::const_iterator it = maker.mPieces.begin(); it != maker.mPieces.end(); ++it)
179 this->add(it->first, it->second->clone());
180}
181
182
183//
184// Calculate the size the new SuperBlob would have, given the contents of the Maker
185// so far, plus additional blobs with the sizes given.
186//
187template <class _BlobType, uint32_t _magic, class _Type>
188size_t SuperBlobCore<_BlobType, _magic, _Type>::Maker::size(size_t size1, ...) const
189{
190 // count established blobs
191 unsigned count = mPieces.size();
192 size_t total = 0;
193 for (typename BlobMap::const_iterator it = mPieces.begin(); it != mPieces.end(); ++it) {
194 if ( it->second != NULL )
195 total += (it->second->length() + 3) & (-4); // 4-byte align each element
196 }
197
198 // add preview blob sizes to calculation (if any)
199 if (size1) {
200 va_list args;
201 va_start(args, size1);
202 do {
203 count++;
204 total += size1;
205 size1 = va_arg(args, size_t);
206 } while (size1);
207 va_end(args);
208 }
209
210 return sizeof(SuperBlobCore) + count * sizeof(Index) + total;
211}
212
213
214//
215// Finish SuperBlob construction and return the new, malloc'ed, SuperBlob.
216// This can be done repeatedly.
217//
218template <class _BlobType, uint32_t _magic, class _Type>
219_BlobType *SuperBlobCore<_BlobType, _magic, _Type>::Maker::make() const
220{
221 Offset pc = sizeof(SuperBlobCore) + mPieces.size() * sizeof(Index);
222 Offset total = size();
223 _BlobType *result = (_BlobType *)calloc(1, total);
224 if (!result)
225 throw ENOMEM;
226 result->setup(total, mPieces.size());
227 unsigned n = 0;
228 for (typename BlobMap::const_iterator it = mPieces.begin(); it != mPieces.end(); ++it) {
229 result->mIndex[n].type = it->first;
230 BlobCore* b = it->second;
231 if ( b != NULL ) {
232 result->mIndex[n].offset = pc;
233 memcpy(result->template at<unsigned char>(pc), b, b->length());
234 pc += ((b->length() + 3) & (-4)); // 4-byte align each element
235 }
236 else {
237 result->mIndex[n].offset = 0;
238 }
239 n++;
240 }
241 //secdebug("superblob", "Maker %p assembles %ld blob(s) into %p (size=%d)",
242 // this, mPieces.size(), result, total);
243 return result;
244}
245
246
247} // Security
248
249#endif //_H_SUPERBLOB