X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5c19dc3ae3bd8e40a9c028b0deddd50ff337692c..dd5fb164cf5b32c462296bc65e289e100f74b59a:/OSX/libsecurity_codesigning/lib/machorep.cpp?ds=inline diff --git a/OSX/libsecurity_codesigning/lib/machorep.cpp b/OSX/libsecurity_codesigning/lib/machorep.cpp index d362b5ab..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 { @@ -97,6 +101,51 @@ Universal *MachORep::mainExecutableImage() return mExecutable; } + +// +// Explicitly default to SHA256 (only) digests if the minimum deployment +// target is young enough. +// +void MachORep::prepareForSigning(SigningContext &context) +{ + if (context.digestAlgorithms().empty()) { + auto_ptr macho(mainExecutableImage()->architecture()); + + if (const version_min_command *version = macho->findMinVersion()) { + uint32_t limit = 0; + switch (macho->flip(version->cmd)) { + case LC_VERSION_MIN_MACOSX: + limit = (10 << 16 | 11 << 8 | 4 << 0); + break; +#if 0 /* need updated libMIS before we can do this switch */ + case LC_VERSION_MIN_IPHONEOS: + limit = (9 << 16 | 3 << 8); + break; + case LC_VERSION_MIN_WATCHOS: + limit = (2 << 16 | 2 << 8); + break; + case LC_VERSION_MIN_TVOS: + limit = (9 << 16 | 2 << 8); + break; + default: + break; +#else + case LC_VERSION_MIN_IPHONEOS: + case LC_VERSION_MIN_WATCHOS: + case LC_VERSION_MIN_TVOS: + return; + default: + break; +#endif + } + if (macho->flip(version->version) >= limit) { + // young enough not to need SHA-1 legacy support + context.setDigestAlgorithm(kSecCodeSignatureHashSHA256); + } + } + } +} + // // Signing base is the start of the Mach-O architecture we're using @@ -105,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; +} // @@ -179,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); } @@ -215,7 +346,7 @@ CFDataRef MachORep::infoPlist() } } } catch (...) { - secdebug("machorep", "exception reading embedded Info.plist"); + secinfo("machorep", "exception reading embedded Info.plist"); } return info.yield(); } @@ -262,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. @@ -315,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(); @@ -334,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 (...) { @@ -368,18 +523,13 @@ size_t MachORep::pageSize(const SigningContext &) // // Strict validation // -void MachORep::strictValidate(const CodeDirectory* cd, const ToleratedErrors& tolerated) +void MachORep::strictValidate(const CodeDirectory* cd, const ToleratedErrors& tolerated, SecCSFlags 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->codeLimit != macho->signingExtent()) - MacOSError::throwMe(errSecCSSignatureInvalid); - } } @@ -401,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); }