X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/72a12576750f52947eb043106ba5c12c0d07decf..b1ab9ed8d0e0f1c3b66d7daa8fd5564444c56195:/libsecurity_codesigning/lib/cskernel.cpp diff --git a/libsecurity_codesigning/lib/cskernel.cpp b/libsecurity_codesigning/lib/cskernel.cpp new file mode 100644 index 00000000..9821465d --- /dev/null +++ b/libsecurity_codesigning/lib/cskernel.cpp @@ -0,0 +1,195 @@ +/* + * 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@ + */ + +// +// 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)) { + if (CFDictionaryGetCount(attributes) != 1) + MacOSError::throwMe(errSecCSUnsupportedGuestAttributes); // had more + if (CFGetTypeID(attr) == CFNumberGetTypeID()) + return (new ProcessCode(cfNumber(CFNumberRef(attr))))->retain(); + MacOSError::throwMe(errSecCSInvalidAttributeValues); + } 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)) { + 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, 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