#include "machorep.h"
namespace Security {
namespace CodeSigning {
using namespace UnixPlusPlus;
MachORep::MachORep(const char *path)
: SingleDiskRep(path), mSigningData(NULL)
{
mExecutable = new Universal(fd());
}
MachORep::~MachORep()
{
delete mExecutable;
::free(mSigningData);
}
bool MachORep::candidiate(FileDesc &fd)
{
switch (Universal::typeOf(fd)) {
case MH_EXECUTE:
case MH_DYLIB:
case MH_DYLINKER:
case MH_BUNDLE:
case MH_PRELOAD:
return true; case MH_OBJECT:
return false; default:
return false; }
}
static const uint8_t ppc_ireqs[] = { 0xfa, 0xde, 0x0c, 0x01, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x14, 0xfa, 0xde, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13,
0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c,
0x61, 0x74, 0x65, 0x00,
};
const Requirements *MachORep::defaultRequirements(const Architecture *arch)
{
assert(arch); if (arch->cpuType() == CPU_TYPE_POWERPC)
return ((const Requirements *)ppc_ireqs)->clone(); else
return NULL;
}
Universal *MachORep::mainExecutableImage()
{
if (!mExecutable)
mExecutable = new Universal(fd());
return mExecutable;
}
size_t MachORep::pageSize()
{
return segmentedPageSize;
}
size_t MachORep::signingBase()
{
return mainExecutableImage()->archOffset();
}
CFDataRef MachORep::component(CodeDirectory::SpecialSlot slot)
{
switch (slot) {
case cdInfoSlot:
return infoPlist();
default:
return embeddedComponent(slot);
}
}
CFDataRef MachORep::embeddedComponent(CodeDirectory::SpecialSlot slot)
{
if (!mSigningData) try {
auto_ptr<MachO> macho(mainExecutableImage()->architecture());
if (macho.get())
if (size_t offset = macho->signingOffset()) {
macho->seek(offset);
mSigningData = EmbeddedSignatureBlob::readBlob(macho->fd());
if (mSigningData)
secdebug("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)",
mainExecutablePath().c_str(), macho->architecture().name());
}
} catch (...) {
secdebug("machorep", "exception reading Mach-O from universal");
}
if (mSigningData)
return mSigningData->component(slot);
return NULL;
}
CFDataRef MachORep::infoPlist()
{
CFRef<CFDataRef> info;
try {
auto_ptr<MachO> macho(mainExecutableImage()->architecture());
if (const section *sect = macho->findSection("__TEXT", "__info_plist")) {
if (macho->is64()) {
const section_64 *sect64 = reinterpret_cast<const section_64 *>(sect);
info = macho->dataAt(macho->flip(sect64->offset), macho->flip(sect64->size));
} else {
info = macho->dataAt(macho->flip(sect->offset), macho->flip(sect->size));
}
}
} catch (...) {
secdebug("machorep", "exception reading embedded Info.plist");
}
return info.yield();
}
string MachORep::recommendedIdentifier()
{
if (CFDataRef info = infoPlist()) {
if (CFDictionaryRef dict = makeCFDictionaryFrom(info)) {
CFStringRef code = CFStringRef(CFDictionaryGetValue(dict, kCFBundleIdentifierKey));
if (code && CFGetTypeID(code) != CFStringGetTypeID())
MacOSError::throwMe(errSecCSBadDictionaryFormat);
if (code)
return cfString(code);
} else
MacOSError::throwMe(errSecCSBadDictionaryFormat);
}
return SingleDiskRep::recommendedIdentifier();
}
string MachORep::format()
{
if (Universal *fat = mainExecutableImage()) {
Universal::Architectures archs;
fat->architectures(archs);
if (fat->isUniversal()) {
string s = "Mach-O universal (";
for (Universal::Architectures::const_iterator it = archs.begin();
it != archs.end(); ++it) {
if (it != archs.begin())
s += " ";
s += it->name();
}
return s + ")";
} else {
assert(archs.size() == 1);
return string("Mach-O thin (") + archs.begin()->name() + ")";
}
} else
return "not Mach-O"; }
void MachORep::flush()
{
delete mExecutable;
mExecutable = NULL;
::free(mSigningData);
mSigningData = NULL;
SingleDiskRep::flush();
}
DiskRep::Writer *MachORep::writer()
{
return new Writer(this);
}
void MachORep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
{
MacOSError::throwMe(errSecCSInternalError);
}
} }