X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5c19dc3ae3bd8e40a9c028b0deddd50ff337692c..dd5fb164cf5b32c462296bc65e289e100f74b59a:/OSX/libsecurity_codesigning/lib/cdbuilder.cpp diff --git a/OSX/libsecurity_codesigning/lib/cdbuilder.cpp b/OSX/libsecurity_codesigning/lib/cdbuilder.cpp index 719a01b3..babfe29c 100644 --- a/OSX/libsecurity_codesigning/lib/cdbuilder.cpp +++ b/OSX/libsecurity_codesigning/lib/cdbuilder.cpp @@ -47,6 +47,9 @@ CodeDirectory::Builder::Builder(HashAlgorithm digestAlgorithm) mCodeSlots(0), mScatter(NULL), mScatterSize(0), + mExecSegOffset(0), + mExecSegLimit(0), + mExecSegFlags(0), mDir(NULL) { mDigestLength = (uint32_t)MakeHash(this)->digestLength(); @@ -92,6 +95,7 @@ void CodeDirectory::Builder::specialSlot(SpecialSlot slot, CFDataRef data) MakeHash hash(this); hash->update(CFDataGetBytePtr(data), CFDataGetLength(data)); hash->finish(specialSlot(slot)); + mFilledSpecialSlots.insert(slot); if (slot >= mSpecialSlots) mSpecialSlots = slot; } @@ -109,14 +113,18 @@ CodeDirectory::Scatter *CodeDirectory::Builder::scatter(unsigned count) return mScatter; } -// This calculates the fixed size of the code directory -// Because of , if the team ID -// field is not used, we leave out the team ID offset -// as well, to keep cd hashes consistent between -// versions. -const size_t CodeDirectory::Builder::fixedSize(const uint32_t version) +// +// Keep the allocated size of the (static) CodeDirectory consistent with +// the version chosen. We dynamically picked the least-needed version +// to provide stability of virtual signatures. +// +size_t CodeDirectory::Builder::fixedSize(const uint32_t version) { size_t cdSize = sizeof(CodeDirectory); + if (version < supportsExecSegment) + cdSize -= sizeof(mDir->execSegBase) + sizeof(mDir->execSegLimit) + sizeof(mDir->execSegFlags); + if (version < supportsCodeLimit64) + cdSize -= sizeof(mDir->spare3) + sizeof(mDir->codeLimit64); if (version < supportsTeamID) cdSize -= sizeof(mDir->teamIDOffset); @@ -179,26 +187,35 @@ CodeDirectory *CodeDirectory::Builder::build() size_t teamIDLength = mTeamID.size() + 1; // Determine the version - if (mTeamID.size()) { + if (mExecSegLimit > 0) { version = currentVersion; + } else if (mExecLength > UINT32_MAX) { + version = supportsCodeLimit64; + } else if (mTeamID.size()) { + version = supportsTeamID; } else { version = supportsScatter; } + if (mCodeSlots > UINT32_MAX) // (still limited to 32 bits) + MacOSError::throwMe(errSecCSTooBig); + size_t total = size(version); if (!(mDir = (CodeDirectory *)calloc(1, total))) // initialize to zero UnixError::throwMe(ENOMEM); - - if (mExecLength > UINT32_MAX) - MacOSError::throwMe(errSecCSTooBig); - + // fill header mDir->initialize(total); mDir->version = version; mDir->flags = mFlags; mDir->nSpecialSlots = (uint32_t)mSpecialSlots; mDir->nCodeSlots = (uint32_t)mCodeSlots; - mDir->codeLimit = (uint32_t)mExecLength; + if (mExecLength > UINT32_MAX) { + mDir->codeLimit = UINT32_MAX; + mDir->codeLimit64 = mExecLength; + } else { + mDir->codeLimit = uint32_t(mExecLength); + } mDir->hashType = mHashType; mDir->platform = mPlatform; mDir->hashSize = mDigestLength; @@ -211,6 +228,10 @@ CodeDirectory *CodeDirectory::Builder::build() } else mDir->pageSize = 0; // means infinite page size + mDir->execSegBase = mExecSegOffset; + mDir->execSegLimit = mExecSegLimit; + mDir->execSegFlags = mExecSegFlags; + // locate and fill flex fields size_t offset = fixedSize(mDir->version); @@ -234,6 +255,8 @@ CodeDirectory *CodeDirectory::Builder::build() mDir->hashOffset = (uint32_t)(offset + mSpecialSlots * mDigestLength); offset += (mSpecialSlots + mCodeSlots) * mDigestLength; assert(offset == total); // matches allocated size + + (void)offset; // fill special slots memset((*mDir)[(int)-mSpecialSlots], 0, mDigestLength * mSpecialSlots); @@ -244,11 +267,14 @@ CodeDirectory *CodeDirectory::Builder::build() mExec.seek(mExecOffset); size_t remaining = mExecLength; for (unsigned int slot = 0; slot < mCodeSlots; ++slot) { - size_t thisPage = min(mPageSize, remaining); + size_t thisPage = remaining; + if (mPageSize) + thisPage = min(thisPage, mPageSize); MakeHash hasher(this); generateHash(hasher, mExec, (*mDir)[slot], thisPage); remaining -= thisPage; } + assert(remaining == 0); // all done. Pass ownership to caller return mDir;