X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_codesigning/lib/cskernel.cpp?ds=sidebyside diff --git a/Security/libsecurity_codesigning/lib/cskernel.cpp b/Security/libsecurity_codesigning/lib/cskernel.cpp new file mode 100644 index 00000000..530fa722 --- /dev/null +++ b/Security/libsecurity_codesigning/lib/cskernel.cpp @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2006-2007,2011-2013 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@ + */ + +// +// cskernel - Kernel implementation of the Code Signing Host Interface. +// +// The kernel host currently supports only UNIX processes as guests. +// It tracks then by their pid. Perhaps one day we'll get a more stable +// means of tracking processes that doesn't involve reusing identifiers. +// +// The kernel host could represent non-process guests one day. One candidate +// are Kernel Extensions. +// +#include "cskernel.h" +#include "csprocess.h" +#include "kerneldiskrep.h" +#include "machorep.h" +#include +#include +#include // MAXPATHLEN + +namespace Security { +namespace CodeSigning { + + +// +// The running-kernel singletons +// +ModuleNexus KernelCode::globals; + +KernelCode::Globals::Globals() +{ + code = new KernelCode; + staticCode = new KernelStaticCode; +} + +KernelCode::KernelCode() + : SecCode(NULL) +{ +} + +KernelStaticCode::KernelStaticCode() + : SecStaticCode(new KernelDiskRep()) +{ +} + + +// +// Identify our guests (UNIX processes) by attribute. +// The only supported lookup attribute is currently the pid. (We could support +// task ports, but those can easily be mapped to pids.) +// Note that we don't actually validate the pid here; if it's invalid, we'll notice +// when we try to ask the kernel about it later. +// +SecCode *KernelCode::locateGuest(CFDictionaryRef attributes) +{ + if (CFTypeRef attr = CFDictionaryGetValue(attributes, kSecGuestAttributePid)) { + RefPointer diskRep = NULL; + + if (CFGetTypeID(attr) != CFNumberGetTypeID()) + MacOSError::throwMe(errSecCSInvalidAttributeValues); + + pid_t pid = cfNumber(CFNumberRef(attr)); + + if (CFDictionaryGetValue(attributes, kSecGuestAttributeDynamicCode) != NULL) { + CFDataRef infoPlist = (CFDataRef)CFDictionaryGetValue(attributes, kSecGuestAttributeDynamicCodeInfoPlist); + if (infoPlist && CFGetTypeID(infoPlist) != CFDataGetTypeID()) + MacOSError::throwMe(errSecCSInvalidAttributeValues); + + try { + diskRep = new PidDiskRep(pid, infoPlist); + } catch (...) { } + } + return (new ProcessCode(cfNumber(CFNumberRef(attr)), diskRep))->retain(); + } else + MacOSError::throwMe(errSecCSUnsupportedGuestAttributes); +} + + +// +// We map guests to disk by calling a kernel service. +// It is here that we verify that our user-space concept of the code identity +// matches the kernel's idea (to defeat just-in-time switching attacks). +// +SecStaticCode *KernelCode::identifyGuest(SecCode *iguest, CFDataRef *cdhash) +{ + if (ProcessCode *guest = dynamic_cast(iguest)) { + + if (guest->pidBased()) { + + SecPointer code = new ProcessDynamicCode(guest); + + SHA1::Digest kernelHash; + MacOSError::check(::csops(guest->pid(), CS_OPS_CDHASH, kernelHash, sizeof(kernelHash))); + *cdhash = makeCFData(kernelHash, sizeof(kernelHash)); + + return code.yield(); + } + + char path[2 * MAXPATHLEN]; // reasonable upper limit + if (::proc_pidpath(guest->pid(), path, sizeof(path))) { + off_t offset; + csops(guest, CS_OPS_PIDOFFSET, &offset, sizeof(offset)); + SecPointer code = new ProcessStaticCode(DiskRep::bestGuess(path, (size_t)offset)); + CODESIGN_GUEST_IDENTIFY_PROCESS(guest, guest->pid(), code); + if (cdhash) { + SHA1::Digest kernelHash; + if (::csops(guest->pid(), CS_OPS_CDHASH, kernelHash, sizeof(kernelHash)) == -1) + switch (errno) { + case EBADEXEC: // means "no CodeDirectory hash for this program" + *cdhash = NULL; + break; + case ESRCH: + MacOSError::throwMe(errSecCSNoSuchCode); + default: + UnixError::throwMe(); + } + else // succeeded + *cdhash = makeCFData(kernelHash, sizeof(kernelHash)); + CODESIGN_GUEST_CDHASH_PROCESS(guest, kernelHash, sizeof(kernelHash)); + } + return code.yield(); + } else + UnixError::throwMe(); + } + MacOSError::throwMe(errSecCSNoSuchCode); +} + + +// +// We obtain the guest's status by asking the kernel +// +SecCodeStatus KernelCode::getGuestStatus(SecCode *iguest) +{ + if (ProcessCode *guest = dynamic_cast(iguest)) { + uint32_t pFlags; + csops(guest, CS_OPS_STATUS, &pFlags); + secdebug("kcode", "guest %p(%d) kernel status 0x%x", guest, guest->pid(), pFlags); + return pFlags; + } else + MacOSError::throwMe(errSecCSNoSuchCode); +} + + +// +// We tell the kernel to make status changes +// +void KernelCode::changeGuestStatus(SecCode *iguest, SecCodeStatusOperation operation, CFDictionaryRef arguments) +{ + if (ProcessCode *guest = dynamic_cast(iguest)) + switch (operation) { + case kSecCodeOperationNull: + break; + case kSecCodeOperationInvalidate: + csops(guest, CS_OPS_MARKINVALID); + break; + case kSecCodeOperationSetHard: + csops(guest, CS_OPS_MARKHARD); + break; + case kSecCodeOperationSetKill: + csops(guest, CS_OPS_MARKKILL); + break; + default: + MacOSError::throwMe(errSecCSUnimplemented); + } + else + MacOSError::throwMe(errSecCSNoSuchCode); +} + + +// +// The StaticCode for the running kernel is explicit. +// We can't ask our own host for it, naturally. +// +void KernelCode::identify() +{ + mStaticCode.take(globals().staticCode->retain()); + // the kernel isn't currently signed, so we don't get a cdHash for it +} + + +// +// Interface to kernel csops() system call. +// +void KernelCode::csops(ProcessCode *proc, unsigned int op, void *addr, size_t length) +{ + if (::csops(proc->pid(), op, addr, length) == -1) { + switch (errno) { + case ESRCH: + MacOSError::throwMe(errSecCSNoSuchCode); + default: + UnixError::throwMe(); + } + } +} + + +} // CodeSigning +} // Security