]> git.saurik.com Git - apple/security.git/blob - OSX/include/security_codesigning/cskernel.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / include / security_codesigning / cskernel.cpp
1 /*
2 * Copyright (c) 2006-2007,2011-2013 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
42 namespace Security {
43 namespace CodeSigning {
44
45
46 //
47 // The running-kernel singletons
48 //
49 ModuleNexus<KernelCode::Globals> KernelCode::globals;
50
51 KernelCode::Globals::Globals()
52 {
53 code = new KernelCode;
54 staticCode = new KernelStaticCode;
55 }
56
57 KernelCode::KernelCode()
58 : SecCode(NULL)
59 {
60 }
61
62 KernelStaticCode::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 //
75 SecCode *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 //
105 SecStaticCode *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 //
153 SecCodeStatus 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 //
168 void 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 //
195 void 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 //
205 void 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