+++ /dev/null
-/*
- * 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 <libproc.h>
-#include <sys/codesign.h>
-#include <sys/param.h> // MAXPATHLEN
-
-namespace Security {
-namespace CodeSigning {
-
-
-//
-// The running-kernel singletons
-//
-ModuleNexus<KernelCode::Globals> 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<PidDiskRep> diskRep = NULL;
-
- if (CFGetTypeID(attr) != CFNumberGetTypeID())
- MacOSError::throwMe(errSecCSInvalidAttributeValues);
-
- pid_t pid = cfNumber<pid_t>(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<pid_t>(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<ProcessCode *>(iguest)) {
-
- if (guest->pidBased()) {
-
- SecPointer<SecStaticCode> 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<SecStaticCode> 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<ProcessCode *>(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<ProcessCode *>(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