X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/e3d460c9de4426da6c630c3ae3f46173a99f82d8..ee5f17c73ddf6cea151be3383378b7972c71f538:/OSX/libsecurity_codesigning/lib/cdbuilder.cpp diff --git a/OSX/libsecurity_codesigning/lib/cdbuilder.cpp b/OSX/libsecurity_codesigning/lib/cdbuilder.cpp index c4e75a2e..7fefc1c5 100644 --- a/OSX/libsecurity_codesigning/lib/cdbuilder.cpp +++ b/OSX/libsecurity_codesigning/lib/cdbuilder.cpp @@ -47,6 +47,11 @@ CodeDirectory::Builder::Builder(HashAlgorithm digestAlgorithm) mCodeSlots(0), mScatter(NULL), mScatterSize(0), + mExecSegOffset(0), + mExecSegLimit(0), + mExecSegFlags(0), + mGeneratePreEncryptHashes(false), + mRuntimeVersion(0), mDir(NULL) { mDigestLength = (uint32_t)MakeHash(this)->digestLength(); @@ -75,13 +80,18 @@ void CodeDirectory::Builder::executable(string path, void CodeDirectory::Builder::reopen(string path, size_t offset, size_t length) { - assert(mExec); // already called executable() + assert(opened()); // already called executable() mExec.close(); mExec.open(path); mExecOffset = offset; mExecLength = length; } +bool CodeDirectory::Builder::opened() +{ + return bool(mExec); +} + // // Set the source for one special slot @@ -115,9 +125,13 @@ CodeDirectory::Scatter *CodeDirectory::Builder::scatter(unsigned count) // the version chosen. We dynamically picked the least-needed version // to provide stability of virtual signatures. // -const size_t CodeDirectory::Builder::fixedSize(const uint32_t version) +size_t CodeDirectory::Builder::fixedSize(const uint32_t version) { size_t cdSize = sizeof(CodeDirectory); + if (version < supportsPreEncrypt) + cdSize -= sizeof(mDir->runtime) + sizeof(mDir->preEncryptOffset); + 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) @@ -152,6 +166,11 @@ size_t CodeDirectory::Builder::size(const uint32_t version) if (mTeamID.size()) offset += mTeamID.size() + 1; // size of teamID (with null byte) offset += (mCodeSlots + mSpecialSlots) * mDigestLength; // hash vector + + if (mGeneratePreEncryptHashes || !mPreservedPreEncryptHashMap.empty()) { + offset += mCodeSlots * mDigestLength; + } + if (offset <= offset0) UnixError::throwMe(ENOEXEC); @@ -182,8 +201,12 @@ CodeDirectory *CodeDirectory::Builder::build() size_t teamIDLength = mTeamID.size() + 1; // Determine the version - if (mExecLength > UINT32_MAX) { + if (mGeneratePreEncryptHashes || !mPreservedPreEncryptHashMap.empty() || mRuntimeVersion) { version = currentVersion; + } else if (mExecSegLimit > 0) { + version = supportsExecSegment; + } else if (mExecLength > UINT32_MAX) { + version = supportsCodeLimit64; } else if (mTeamID.size()) { version = supportsTeamID; } else { @@ -221,6 +244,11 @@ CodeDirectory *CodeDirectory::Builder::build() } else mDir->pageSize = 0; // means infinite page size + mDir->execSegBase = mExecSegOffset; + mDir->execSegLimit = mExecSegLimit; + mDir->execSegFlags = mExecSegFlags; + mDir->runtime = mRuntimeVersion; + // locate and fill flex fields size_t offset = fixedSize(mDir->version); @@ -239,16 +267,27 @@ CodeDirectory *CodeDirectory::Builder::build() memcpy(mDir->teamID(), mTeamID.c_str(), teamIDLength); offset += teamIDLength; } + // (add new flexibly-allocated fields here) + /* Pre-encrypt hashes come before normal hashes, so that the kernel can free + * the normal, potentially post-encrypt hashes away easily. */ + if (mGeneratePreEncryptHashes || !mPreservedPreEncryptHashMap.empty()) { + mDir->preEncryptOffset = (uint32_t)offset; + offset += mCodeSlots * mDigestLength; + } + 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); + memset(mDir->getSlotMutable((int)-mSpecialSlots, false), 0, mDigestLength * mSpecialSlots); for (size_t slot = 1; slot <= mSpecialSlots; ++slot) - memcpy((*mDir)[(int)-slot], specialSlot((SpecialSlot)slot), mDigestLength); + memcpy(mDir->getSlotMutable((int)-slot, false), specialSlot((SpecialSlot)slot), mDigestLength); // fill code slots mExec.seek(mExecOffset); @@ -258,10 +297,23 @@ CodeDirectory *CodeDirectory::Builder::build() if (mPageSize) thisPage = min(thisPage, mPageSize); MakeHash hasher(this); - generateHash(hasher, mExec, (*mDir)[slot], thisPage); + generateHash(hasher, mExec, mDir->getSlotMutable(slot, false), thisPage); + if (mGeneratePreEncryptHashes && mPreservedPreEncryptHashMap.empty()) { + memcpy(mDir->getSlotMutable(slot, true), mDir->getSlot(slot, false), + mDir->hashSize); + } remaining -= thisPage; } assert(remaining == 0); + + PreEncryptHashMap::iterator preEncrypt = + mPreservedPreEncryptHashMap.find(mHashType); + if (preEncrypt != mPreservedPreEncryptHashMap.end()) { + memcpy(mDir->getSlotMutable(0, true), + CFDataGetBytePtr(preEncrypt->second), + mCodeSlots * mDigestLength); + mPreservedPreEncryptHashMap.erase(preEncrypt->first); // Releases the CFData memory. + } // all done. Pass ownership to caller return mDir;