1/* 2 * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24// 25// cskernel - Kernel implementation of the Code Signing Host Interface. 26// 27// The kernel host currently supports only UNIX processes as guests. 28// It tracks then by their pid. Perhaps one day we'll get a more stable 29// means of tracking processes that doesn't involve reusing identifiers. 30// 31// The kernel host could represent non-process guests one day. One candidate 32// are Kernel Extensions. 33// 34#include "cskernel.h" 35#include "csprocess.h" 36#include "kerneldiskrep.h" 37#include "machorep.h" 38#include <libproc.h> 39#include <sys/codesign.h> 40#include <sys/param.h> // MAXPATHLEN 41 42namespace Security { 43namespace CodeSigning { 44 45 46// 47// The running-kernel singletons 48// 49ModuleNexus<KernelCode::Globals> KernelCode::globals; 50 51KernelCode::Globals::Globals() 52{ 53 code = new KernelCode; 54 staticCode = new KernelStaticCode; 55} 56 57KernelCode::KernelCode() 58 : SecCode(NULL) 59{ 60} 61 62KernelStaticCode::KernelStaticCode() 63 : SecStaticCode(new KernelDiskRep()) 64{ 65} 66 67 68// 69// Identify our guests (UNIX processes) by attribute. 70// The only supported lookup attribute is currently the pid. (We could support 71// task ports, but those can easily be mapped to pids.) 72// Note that we don't actually validate the pid here; if it's invalid, we'll notice 73// when we try to ask the kernel about it later. 74// 75SecCode *KernelCode::locateGuest(CFDictionaryRef attributes) 76{ 77 if (CFTypeRef attr = CFDictionaryGetValue(attributes, kSecGuestAttributePid)) { 78 RefPointer<PidDiskRep> diskRep = NULL; 79 80 if (CFGetTypeID(attr) != CFNumberGetTypeID()) 81 MacOSError::throwMe(errSecCSInvalidAttributeValues); 82 83 pid_t pid = cfNumber<pid_t>(CFNumberRef(attr)); 84 85 if (CFDictionaryGetValue(attributes, kSecGuestAttributeDynamicCode) != NULL) { 86 CFDataRef infoPlist = (CFDataRef)CFDictionaryGetValue(attributes, kSecGuestAttributeDynamicCodeInfoPlist); 87 if (infoPlist && CFGetTypeID(infoPlist) != CFDataGetTypeID()) 88 MacOSError::throwMe(errSecCSInvalidAttributeValues); 89 90 try { 91 diskRep = new PidDiskRep(pid, infoPlist); 92 } catch (...) { } 93 } 94 return (new ProcessCode(cfNumber<pid_t>(CFNumberRef(attr)), diskRep))->retain(); 95 } else 96 MacOSError::throwMe(errSecCSUnsupportedGuestAttributes); 97} 98 99 100// 101// We map guests to disk by calling a kernel service. 102// It is here that we verify that our user-space concept of the code identity 103// matches the kernel's idea (to defeat just-in-time switching attacks). 104// 105SecStaticCode *KernelCode::identifyGuest(SecCode *iguest, CFDataRef *cdhash) 106{ 107 if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest)) { 108 109 if (guest->pidBased()) { 110 111 SecPointer<SecStaticCode> code = new ProcessDynamicCode(guest); 112 113 SHA1::Digest kernelHash; 114 MacOSError::check(::csops(guest->pid(), CS_OPS_CDHASH, kernelHash, sizeof(kernelHash))); 115 *cdhash = makeCFData(kernelHash, sizeof(kernelHash)); 116 117 return code.yield(); 118 } 119 120 char path[2 * MAXPATHLEN]; // reasonable upper limit 121 if (::proc_pidpath(guest->pid(), path, sizeof(path))) { 122 off_t offset; 123 csops(guest, CS_OPS_PIDOFFSET, &offset, sizeof(offset)); 124 SecPointer<SecStaticCode> code = new ProcessStaticCode(DiskRep::bestGuess(path, (size_t)offset)); 125 CODESIGN_GUEST_IDENTIFY_PROCESS(guest, guest->pid(), code); 126 if (cdhash) { 127 SHA1::Digest kernelHash; 128 if (::csops(guest->pid(), CS_OPS_CDHASH, kernelHash, sizeof(kernelHash)) == -1) 129 switch (errno) { 130 case EBADEXEC: // means "no CodeDirectory hash for this program" 131 *cdhash = NULL; 132 break; 133 case ESRCH: 134 MacOSError::throwMe(errSecCSNoSuchCode); 135 default: 136 UnixError::throwMe(); 137 } 138 else // succeeded 139 *cdhash = makeCFData(kernelHash, sizeof(kernelHash)); 140 CODESIGN_GUEST_CDHASH_PROCESS(guest, kernelHash, sizeof(kernelHash)); 141 } 142 return code.yield(); 143 } else 144 UnixError::throwMe(); 145 } 146 MacOSError::throwMe(errSecCSNoSuchCode); 147} 148 149 150// 151// We obtain the guest's status by asking the kernel 152// 153SecCodeStatus KernelCode::getGuestStatus(SecCode *iguest) 154{ 155 if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest)) { 156 uint32_t pFlags; 157 csops(guest, CS_OPS_STATUS, &pFlags); 158 secdebug("kcode", "guest %p(%d) kernel status 0x%x", guest, guest->pid(), pFlags); 159 return pFlags; 160 } else 161 MacOSError::throwMe(errSecCSNoSuchCode); 162} 163 164 165// 166// We tell the kernel to make status changes 167// 168void KernelCode::changeGuestStatus(SecCode *iguest, SecCodeStatusOperation operation, CFDictionaryRef arguments) 169{ 170 if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest)) 171 switch (operation) { 172 case kSecCodeOperationNull: 173 break; 174 case kSecCodeOperationInvalidate: 175 csops(guest, CS_OPS_MARKINVALID); 176 break; 177 case kSecCodeOperationSetHard: 178 csops(guest, CS_OPS_MARKHARD); 179 break; 180 case kSecCodeOperationSetKill: 181 csops(guest, CS_OPS_MARKKILL); 182 break; 183 default: 184 MacOSError::throwMe(errSecCSUnimplemented); 185 } 186 else 187 MacOSError::throwMe(errSecCSNoSuchCode); 188} 189 190 191// 192// The StaticCode for the running kernel is explicit. 193// We can't ask our own host for it, naturally. 194// 195void KernelCode::identify() 196{ 197 mStaticCode.take(globals().staticCode->retain()); 198 // the kernel isn't currently signed, so we don't get a cdHash for it 199} 200 201 202// 203// Interface to kernel csops() system call. 204// 205void KernelCode::csops(ProcessCode *proc, unsigned int op, void *addr, size_t length) 206{ 207 if (::csops(proc->pid(), op, addr, length) == -1) { 208 switch (errno) { 209 case ESRCH: 210 MacOSError::throwMe(errSecCSNoSuchCode); 211 default: 212 UnixError::throwMe(); 213 } 214 } 215} 216 217 218} // CodeSigning 219} // Security 220