X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/ebf6f43431fe84b7b17822014a6d1f0169516e93..b1f7435d66a93f03b77932b3a9ad8a83ce5e1ebc:/ld64-134.9/src/ld/code-sign-blobs/superblob.h?ds=sidebyside diff --git a/ld64-134.9/src/ld/code-sign-blobs/superblob.h b/ld64-134.9/src/ld/code-sign-blobs/superblob.h new file mode 100644 index 0000000..7fea85e --- /dev/null +++ b/ld64-134.9/src/ld/code-sign-blobs/superblob.h @@ -0,0 +1,249 @@ +// +// SuperBlob - a typed bag of Blobs +// +#ifndef _H_SUPERBLOB +#define _H_SUPERBLOB + +#include "blob.h" +#include +#include +#include + +using namespace std; + +namespace Security { + + +// +// A SuperBlob is a Blob that contains multiple sub-Blobs of varying type. +// The SuperBlob is contiguous and contains a directory of its sub-blobs. +// A Maker is included. +// +// SuperBlobCore lets you define your own SuperBlob type. To just use a generic +// SuperBlob, use SuperBlob<> below. +// +template +class SuperBlobCore: public Blob<_BlobType, _magic> { +public: + class Maker; friend class Maker; + + typedef _Type Type; + + // echoes from parent BlobCore (the C++ type system is too restrictive here) + typedef BlobCore::Offset Offset; + template BlobType *at(Offset offset) { return BlobCore::at(offset); } + template const BlobType *at(Offset offset) const { return BlobCore::at(offset); } + + void setup(size_t size, unsigned cnt) + { this->initialize(size); this->mCount = cnt; } + + struct Index { + Endian type; // type of sub-Blob + Endian offset; // starting offset + }; + + bool validateBlob(size_t maxSize = 0) const; + + unsigned count() const { return mCount; } + + // access by index number + Type type(unsigned n) const { assert(n < mCount); return mIndex[n].type; } + const BlobCore *blob(unsigned n) const { assert(n < mCount); Offset off=mIndex[n].offset; return off ? at(off) : NULL; } + + template + const BlobType *blob(unsigned n) const { return BlobType::specific(blob(n)); } + + // access by index type (assumes unique types) + const BlobCore *find(Type type) const; + template + const BlobType *find(Type t) const { return BlobType::specific(find(t)); } + +private: + Endian mCount; // number of sub-Blobs following + Index mIndex[0]; // IndexSlot structures + // followed by sub-Blobs, packed and ordered in an undefined way +}; + + +template +inline bool SuperBlobCore<_BlobType, _magic, _Type>::validateBlob(size_t maxSize /* = 0 */) const +{ + unsigned cnt = mCount; + size_t ixLimit = sizeof(SuperBlobCore) + cnt * sizeof(Index); // end of index vector + if (!BlobCore::validateBlob(_magic, ixLimit, maxSize)) + return false; + + for (const Index *ix = mIndex + cnt - 1; ix >= mIndex; ix--) { + Offset offset = ix->offset; + if ( offset == 0 ) + continue; // offset==0 means unused entry + if (offset < ixLimit // offset not too small + || offset + sizeof(BlobCore) > this->length() // fits Blob header (including length field) + || offset + at(offset)->length() > this->length()) // fits entire blob + return false; + } + return true; +} + + +// +// A generic SuperBlob ready for use. You still need to specify a magic number. +// +template +class SuperBlob : public SuperBlobCore, _magic, _Type> { +}; + + +template +const BlobCore *SuperBlobCore<_BlobType, _magic, _Type>::find(Type t) const +{ + for (unsigned slot = 0; slot < mCount; slot++) { + if (mIndex[slot].type == t) { + uint32_t off = mIndex[slot].offset; + if ( off == 0 ) + return NULL; + else + return at(off); + } + } + return NULL; // not found +} + + +// +// A SuperBlob::Maker simply assembles multiple Blobs into a single, indexed +// super-blob. Just add() sub-Blobs by type and call build() to get +// the result, malloc'ed. A Maker is not reusable. +// Maker can repeatedly make SuperBlobs from the same (cached) inputs. +// It can also tell you how big its output will be, given established contents +// plus (optional) additional sizes of blobs yet to come. +// +template +class SuperBlobCore<_BlobType, _magic, _Type>::Maker { +public: + Maker() { } + + Maker(const Maker &src) + { + for (typename BlobMap::iterator it = mPieces.begin(); it != mPieces.end(); ++it) + mPieces.insert(make_pair(it->first, it->second->clone())); + } + + ~Maker() + { + for (typename BlobMap::iterator it = mPieces.begin(); it != mPieces.end(); ++it) + ::free(it->second); + } + + void add(Type type, BlobCore *blob); // takes ownership of blob + void add(const _BlobType *blobs); // copies all blobs + void add(const Maker &maker); // ditto + + size_t size(size_t size1 = 0, ...) const; // size with optional additional blob sizes + _BlobType *make() const; // create (malloc) and return SuperBlob + _BlobType *operator () () const { return make(); } + +private: + typedef std::map BlobMap; + BlobMap mPieces; +}; + + +// +// Add a Blob to a SuperBlob::Maker. +// This takes ownership of the blob, which must have been malloc'ed. +// Any previous value set for this Type will be freed immediately. +// +template +void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(Type type, BlobCore *blob) +{ + pair r = mPieces.insert(make_pair(type, blob)); + if (!r.second) { // already there + //secdebug("superblob", "Maker %p replaces type=%d", this, type); + ::free(r.first->second); + r.first->second = blob; + } +} + +template +void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(const _BlobType *blobs) +{ + for (uint32_t ix = 0; ix < blobs->mCount; ix++) + this->add(blobs->mIndex[ix].type, blobs->blob(ix)->clone()); +} + +template +void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(const Maker &maker) +{ + for (typename BlobMap::const_iterator it = maker.mPieces.begin(); it != maker.mPieces.end(); ++it) + this->add(it->first, it->second->clone()); +} + + +// +// Calculate the size the new SuperBlob would have, given the contents of the Maker +// so far, plus additional blobs with the sizes given. +// +template +size_t SuperBlobCore<_BlobType, _magic, _Type>::Maker::size(size_t size1, ...) const +{ + // count established blobs + unsigned count = mPieces.size(); + size_t total = 0; + for (typename BlobMap::const_iterator it = mPieces.begin(); it != mPieces.end(); ++it) { + if ( it->second != NULL ) + total += (it->second->length() + 3) & (-4); // 4-byte align each element + } + + // add preview blob sizes to calculation (if any) + if (size1) { + va_list args; + va_start(args, size1); + do { + count++; + total += size1; + size1 = va_arg(args, size_t); + } while (size1); + va_end(args); + } + + return sizeof(SuperBlobCore) + count * sizeof(Index) + total; +} + + +// +// Finish SuperBlob construction and return the new, malloc'ed, SuperBlob. +// This can be done repeatedly. +// +template +_BlobType *SuperBlobCore<_BlobType, _magic, _Type>::Maker::make() const +{ + Offset pc = sizeof(SuperBlobCore) + mPieces.size() * sizeof(Index); + Offset total = size(); + _BlobType *result = (_BlobType *)calloc(1, total); + if (!result) + throw ENOMEM; + result->setup(total, mPieces.size()); + unsigned n = 0; + for (typename BlobMap::const_iterator it = mPieces.begin(); it != mPieces.end(); ++it) { + result->mIndex[n].type = it->first; + BlobCore* b = it->second; + if ( b != NULL ) { + result->mIndex[n].offset = pc; + memcpy(result->template at(pc), b, b->length()); + pc += ((b->length() + 3) & (-4)); // 4-byte align each element + } + else { + result->mIndex[n].offset = 0; + } + n++; + } + //secdebug("superblob", "Maker %p assembles %ld blob(s) into %p (size=%d)", + // this, mPieces.size(), result, total); + return result; +} + + +} // Security + +#endif //_H_SUPERBLOB