X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/72a12576750f52947eb043106ba5c12c0d07decf..b1ab9ed8d0e0f1c3b66d7daa8fd5564444c56195:/libsecurity_codesigning/lib/csgeneric.cpp diff --git a/libsecurity_codesigning/lib/csgeneric.cpp b/libsecurity_codesigning/lib/csgeneric.cpp new file mode 100644 index 00000000..c67d9467 --- /dev/null +++ b/libsecurity_codesigning/lib/csgeneric.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +// +// csgeneric - generic Code representative +// +#include "csgeneric.h" +#include "cs.h" +#include "StaticCode.h" +#include +#include + +namespace Security { +namespace CodeSigning { + +using MachPlusPlus::Port; + + +// +// Common call-out code for cshosting RPC service +// +#define CALL(host, name, args...) \ + OSStatus result; \ + if (cshosting_client_ ## name (host, mig_get_reply_port(), &result, args)) \ + MacOSError::throwMe(errSecCSNotAHost); \ + MacOSError::check(result); + + +// +// Construct a running process representation +// +GenericCode::GenericCode(SecCode *host, SecGuestRef guestRef) + : SecCode(host), mGuestRef(guestRef) +{ +} + + +// +// Identify a guest by attribute set, and return a new GenericCode representing it. +// This uses cshosting RPCs to ask the host (or its proxy). +// +SecCode *GenericCode::locateGuest(CFDictionaryRef attributes) +{ + if (Port host = hostingPort()) { + CFRef attrData; + void *attrPtr = NULL; size_t attrLength = 0; + if (attributes) { + attrData.take(CFPropertyListCreateXMLData(NULL, attributes)); + attrPtr = (void *)CFDataGetBytePtr(attrData); + attrLength = CFDataGetLength(attrData); + } + GuestChain guestPath; + mach_msg_type_number_t guestPathLength; + mach_port_t subport; + CALL(host, findGuest, guestRef(), attrPtr, attrLength, + &guestPath, &guestPathLength, &subport); + CODESIGN_GUEST_LOCATE_GENERIC(this, guestPath, guestPathLength, subport); + SecPointer code = this; + for (unsigned n = 0; n < guestPathLength; n++) + code = new GenericCode(code, guestPath[n]); + return code.yield(); + } else + return NULL; // not found, no error +} + + +// +// Identify a guest by returning its StaticCode and running CodeDirectory hash. +// This uses cshosting RPCs to ask the host (or its proxy). +// +SecStaticCode *GenericCode::identifyGuest(SecCode *guest, CFDataRef *cdhashOut) +{ + if (GenericCode *iguest = dynamic_cast(guest)) { + FilePathOut path; + CFRef cdhash; + CFDictionary attributes(errSecCSHostProtocolInvalidAttribute); + identifyGuest(iguest->guestRef(), path, cdhash.aref(), attributes.aref()); + DiskRep::Context ctx; + if (CFNumberRef architecture = attributes.get(kSecGuestAttributeArchitecture)) { + cpu_type_t cpu = cfNumber(architecture); + if (CFNumberRef subarchitecture = attributes.get(kSecGuestAttributeSubarchitecture)) + ctx.arch = Architecture(cpu, cfNumber(subarchitecture)); + else + ctx.arch = Architecture(cpu); + } + SecPointer code = new GenericStaticCode(DiskRep::bestGuess(path, &ctx)); + CODESIGN_GUEST_IDENTIFY_GENERIC(iguest, iguest->guestRef(), code); + if (cdhash) { + CODESIGN_GUEST_CDHASH_GENERIC(iguest, (void *)CFDataGetBytePtr(cdhash), CFDataGetLength(cdhash)); + *cdhashOut = cdhash.yield(); + } + return code.yield(); + } else + MacOSError::throwMe(errSecCSNotAHost); +} + +// helper to drive the identifyGuest hosting IPC and return results as CF objects +void GenericCode::identifyGuest(SecGuestRef guest, char *path, CFDataRef &cdhash, CFDictionaryRef &attributes) +{ + if (Port host = hostingPort()) { + HashDataOut hash; + uint32_t hashLength; + XMLBlobOut attr; + uint32_t attrLength; + CALL(host, identifyGuest, guest, path, hash, &hashLength, &attr, &attrLength); + if (hashLength) + cdhash = makeCFData(hash, hashLength); + if (attrLength) { + CFRef attrData = makeCFData(attr, attrLength); + attributes = makeCFDictionaryFrom(attrData); +#if ROSETTA_TEST_HACK + CFMutableDictionaryRef hattr = makeCFMutableDictionary(attributes); + CFDictionaryAddValue(hattr, kSecGuestAttributeArchitecture, CFTempNumber(CPU_TYPE_POWERPC)); + CFRelease(attributes); + attributes = hattr; +#endif + } + } else + MacOSError::throwMe(errSecCSNotAHost); +} + + +// +// Get the Code Signing Status Word for a Code. +// This uses cshosting RPCs to ask the host (or its proxy). +// +SecCodeStatus GenericCode::getGuestStatus(SecCode *guest) +{ + if (Port host = hostingPort()) { + uint32_t status; + CALL(host, guestStatus, safe_cast(guest)->guestRef(), &status); + return status; + } else + MacOSError::throwMe(errSecCSNotAHost); +} + + +// +// Status changes are transmitted through the cshosting RPCs. +// +void GenericCode::changeGuestStatus(SecCode *iguest, SecCodeStatusOperation operation, CFDictionaryRef arguments) +{ + if (/* GenericCode *guest = */dynamic_cast(iguest)) + switch (operation) { + case kSecCodeOperationNull: + break; + case kSecCodeOperationInvalidate: + case kSecCodeOperationSetHard: + case kSecCodeOperationSetKill: + MacOSError::throwMe(errSecCSUnimplemented); + break; + default: + MacOSError::throwMe(errSecCSUnimplemented); + } + else + MacOSError::throwMe(errSecCSNoSuchCode); +} + + +// +// Return the Hosting Port for this Code. +// May return MACH_PORT_NULL if the code is not a code host. +// Throws if we can't get the hosting port for some reason (and can't positively +// determine that there is none). +// +// Note that we do NOT cache negative outcomes. Being a host is a dynamic property, +// and this Code may not have commenced hosting operations yet. For non- (or not-yet-)hosts +// we simply return NULL. +// +Port GenericCode::hostingPort() +{ + if (!mHostingPort) { + if (staticCode()->codeDirectory()->flags & kSecCodeSignatureHost) { + mHostingPort = getHostingPort(); + CODESIGN_GUEST_HOSTINGPORT(this, mHostingPort); + } + } + return mHostingPort; +} + + +// +// A pure GenericHost has no idea where to get a hosting port from. +// This method must be overridden to get one. +// However, we do handle a contiguous chain of GenericCodes by deferring +// to our next-higher host for it. +// +mach_port_t GenericCode::getHostingPort() +{ + if (GenericCode *genericHost = dynamic_cast(host())) + return genericHost->getHostingPort(); + else + MacOSError::throwMe(errSecCSNotAHost); +} + + +} // CodeSigning +} // Security