X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/e3d460c9de4426da6c630c3ae3f46173a99f82d8..dd5fb164cf5b32c462296bc65e289e100f74b59a:/OSX/libsecurity_codesigning/lib/machorep.cpp?ds=sidebyside diff --git a/OSX/libsecurity_codesigning/lib/machorep.cpp b/OSX/libsecurity_codesigning/lib/machorep.cpp index de4b43a4..0959b559 100644 --- a/OSX/libsecurity_codesigning/lib/machorep.cpp +++ b/OSX/libsecurity_codesigning/lib/machorep.cpp @@ -27,6 +27,10 @@ #include "machorep.h" #include "StaticCode.h" #include "reqmaker.h" +#include +#include +#include + namespace Security { @@ -105,7 +109,8 @@ Universal *MachORep::mainExecutableImage() void MachORep::prepareForSigning(SigningContext &context) { if (context.digestAlgorithms().empty()) { - MachO *macho = mainExecutableImage()->architecture(); + auto_ptr macho(mainExecutableImage()->architecture()); + if (const version_min_command *version = macho->findMinVersion()) { uint32_t limit = 0; switch (macho->flip(version->cmd)) { @@ -149,6 +154,88 @@ size_t MachORep::signingBase() { return mainExecutableImage()->archOffset(); } + +size_t MachORep::signingLimit() +{ + auto_ptr macho(mExecutable->architecture()); + return macho->signingExtent(); +} + +bool MachORep::needsExecSeg(const MachO& macho) { + if (const version_min_command *version = macho.findMinVersion()) { + uint32_t min = UINT32_MAX; + + switch (macho.flip(version->cmd)) { + case LC_VERSION_MIN_IPHONEOS: + case LC_VERSION_MIN_TVOS: + min = (11 << 16 | 0 << 8); + break; + case LC_VERSION_MIN_WATCHOS: + min = (4 << 16 | 0 << 8); + break; + + default: + /* macOS currently does not get this. */ + return false; + } + + if (macho.flip(version->version) >= min) { + return true; + } + } + + return false; +} + +size_t MachORep::execSegBase(const Architecture *arch) +{ + auto_ptr macho(arch ? mExecutable->architecture(*arch) : mExecutable->architecture()); + + if (!needsExecSeg(*macho)) { + return 0; + } + + segment_command const * const text_cmd = macho->findSegment("__TEXT"); + + if (text_cmd == NULL) { + return 0; + } + + size_t off = 0; + + if (macho->is64()) { + off = int_cast(reinterpret_cast(text_cmd)->fileoff); + } else { + off = text_cmd->fileoff; + } + + return off; +} + +size_t MachORep::execSegLimit(const Architecture *arch) +{ + auto_ptr macho(arch ? mExecutable->architecture(*arch) : mExecutable->architecture()); + + if (!needsExecSeg(*macho)) { + return 0; + } + + segment_command const * const text_cmd = macho->findSegment("__TEXT"); + + if (text_cmd == NULL) { + return 0; + } + + size_t size = 0; + + if (macho->is64()) { + size = int_cast(reinterpret_cast(text_cmd)->filesize); + } else { + size = text_cmd->filesize; + } + + return size; +} // @@ -223,11 +310,11 @@ CFDataRef MachORep::embeddedComponent(CodeDirectory::SpecialSlot slot) size_t offset = macho->flip(cs->dataoff); size_t length = macho->flip(cs->datasize); if ((mSigningData = EmbeddedSignatureBlob::readBlob(macho->fd(), macho->offset() + offset, length))) { - secdebug("machorep", "%zd signing bytes in %d blob(s) from %s(%s)", + secinfo("machorep", "%zd signing bytes in %d blob(s) from %s(%s)", mSigningData->length(), mSigningData->count(), mainExecutablePath().c_str(), macho->architecture().name()); } else { - secdebug("machorep", "failed to read signing bytes from %s(%s)", + secinfo("machorep", "failed to read signing bytes from %s(%s)", mainExecutablePath().c_str(), macho->architecture().name()); MacOSError::throwMe(errSecCSSignatureInvalid); } @@ -259,7 +346,7 @@ CFDataRef MachORep::infoPlist() } } } catch (...) { - secdebug("machorep", "exception reading embedded Info.plist"); + secinfo("machorep", "exception reading embedded Info.plist"); } return info.yield(); } @@ -306,6 +393,30 @@ void MachORep::flush() mExecutable = new Universal(fd(), offset, length); } +CFDictionaryRef MachORep::diskRepInformation() +{ + auto_ptr macho (mainExecutableImage()->architecture()); + CFRef info; + + if (const version_min_command *version = macho->findMinVersion()) { + + info.take(cfmake("{%O = %d,%O = %d,%O = %d}", + kSecCodeInfoDiskRepOSPlatform, macho->flip(version->cmd), + kSecCodeInfoDiskRepOSVersionMin, macho->flip(version->version), + kSecCodeInfoDiskRepOSSDKVersion, macho->flip(version->sdk))); + + if (macho->flip(version->cmd) == LC_VERSION_MIN_MACOSX && + macho->flip(version->sdk) < (10 << 16 | 9 << 8)) + { + info.take(cfmake("{+%O, %O = 'OS X SDK version before 10.9 does not support Library Validation'}", + info.get(), + kSecCodeInfoDiskRepNoLibraryValidation)); + } + } + + return info.yield(); +} + // // Return a recommended unique identifier. @@ -359,7 +470,7 @@ Requirement *MachORep::libraryRequirements(const Architecture *arch, const Signi size_t length = macho->flip(ldep->datasize); if (LibraryDependencyBlob *deplist = LibraryDependencyBlob::readBlob(macho->fd(), macho->offset() + offset, length)) { try { - secdebug("machorep", "%zd library dependency bytes in %d blob(s) from %s(%s)", + secinfo("machorep", "%zd library dependency bytes in %d blob(s) from %s(%s)", deplist->length(), deplist->count(), mainExecutablePath().c_str(), macho->architecture().name()); unsigned count = deplist->count(); @@ -378,13 +489,13 @@ Requirement *MachORep::libraryRequirements(const Architecture *arch, const Signi MacOSError::check(SecRequirementCopyData(areq, kSecCSDefaultFlags, &reqData.aref())); req = Requirement::specific((const BlobCore *)CFDataGetBytePtr(reqData)); } else { - secdebug("machorep", "unexpected blob type 0x%x in slot %d of binary dependencies", dep->magic(), n); + secinfo("machorep", "unexpected blob type 0x%x in slot %d of binary dependencies", dep->magic(), n); continue; } chain.add(); maker.copy(req); } else - secdebug("machorep", "missing DR info for library index %d", n); + secinfo("machorep", "missing DR info for library index %d", n); } ::free(deplist); } catch (...) { @@ -414,18 +525,11 @@ size_t MachORep::pageSize(const SigningContext &) // void MachORep::strictValidate(const CodeDirectory* cd, const ToleratedErrors& tolerated, SecCSFlags flags) { - DiskRep::strictValidate(cd, tolerated, flags); + SingleDiskRep::strictValidate(cd, tolerated, flags); // if the constructor found suspicious issues, fail a struct validation now if (mExecutable->isSuspicious() && tolerated.find(errSecCSBadMainExecutable) == tolerated.end()) MacOSError::throwMe(errSecCSBadMainExecutable); - - // the signature's code extent must be what we would have picked (no funny hand editing) - if (cd) { - auto_ptr macho(mExecutable->architecture()); - if (cd->signingLimit() != macho->signingExtent()) - MacOSError::throwMe(errSecCSSignatureInvalid); - } } @@ -447,6 +551,7 @@ DiskRep::Writer *MachORep::writer() void MachORep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data) { assert(false); + Syslog::notice("code signing internal error: trying to write Mach-O component directly"); MacOSError::throwMe(errSecCSInternalError); }