]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_codesigning/lib/cdbuilder.cpp
Security-58286.20.16.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / cdbuilder.cpp
index 719a01b3364cdd72f1924266f7440195c8342119..babfe29c1603f114eee3a3fa5765f36601a360ac 100644 (file)
@@ -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<Builder>(this)->digestLength();
@@ -92,6 +95,7 @@ void CodeDirectory::Builder::specialSlot(SpecialSlot slot, CFDataRef data)
        MakeHash<Builder> 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 <rdar://problem/16102695>, 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<Builder> hasher(this);
                generateHash(hasher, mExec, (*mDir)[slot], thisPage);
                remaining -= thisPage;
        }
+       assert(remaining == 0);
        
        // all done. Pass ownership to caller
        return mDir;