]> git.saurik.com Git - apple/security.git/blame - OSX/libsecurity_codesigning/lib/cskernel.cpp
Security-58286.41.2.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / cskernel.cpp
CommitLineData
b1ab9ed8 1/*
d8f41ccd 2 * Copyright (c) 2006-2007,2011-2013 Apple Inc. All Rights Reserved.
b1ab9ed8
A
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>
fa7225c8
A
40#include <bsm/libbsm.h>
41#include <security_utilities/cfmunge.h>
b1ab9ed8
A
42#include <sys/param.h> // MAXPATHLEN
43
44namespace Security {
45namespace CodeSigning {
46
47
48//
49// The running-kernel singletons
50//
51ModuleNexus<KernelCode::Globals> KernelCode::globals;
52
53KernelCode::Globals::Globals()
54{
55 code = new KernelCode;
56 staticCode = new KernelStaticCode;
57}
58
59KernelCode::KernelCode()
60 : SecCode(NULL)
61{
62}
63
64KernelStaticCode::KernelStaticCode()
65 : SecStaticCode(new KernelDiskRep())
66{
67}
68
69
70//
71// Identify our guests (UNIX processes) by attribute.
fa7225c8
A
72// We support either pid or audit token (which contains the pid). If we get both,
73// we record them both and let the kernel sort them out.
b1ab9ed8
A
74// Note that we don't actually validate the pid here; if it's invalid, we'll notice
75// when we try to ask the kernel about it later.
76//
77SecCode *KernelCode::locateGuest(CFDictionaryRef attributes)
78{
866f8763 79#if TARGET_OS_OSX
fa7225c8
A
80 CFNumberRef pidNumber = NULL;
81 CFDataRef auditData = NULL;
82 cfscan(attributes, "{%O=%NO}", kSecGuestAttributePid, &pidNumber);
83 cfscan(attributes, "{%O=%XO}", kSecGuestAttributeAudit, &auditData);
84 if (pidNumber == NULL && auditData == NULL)
b1ab9ed8 85 MacOSError::throwMe(errSecCSUnsupportedGuestAttributes);
fa7225c8
A
86
87 // Extract information from pid and audit token as presented. We need at least one.
88 // If both are specified, we pass them both to the kernel, which will fail if they
89 // don't agree.
90 if (auditData && CFDataGetLength(auditData) != sizeof(audit_token_t))
91 MacOSError::throwMe(errSecCSInvalidAttributeValues);
92 pid_t pid = 0;
93 audit_token_t* audit = NULL;
94 if (pidNumber)
95 pid = cfNumber<pid_t>(pidNumber);
96 if (auditData)
97 audit = (audit_token_t*)CFDataGetBytePtr(auditData);
98 if (audit && pid == 0)
99 pid = audit_token_to_pid(*audit);
100
101 // handle requests for server-based validation
102 RefPointer<PidDiskRep> diskRep = NULL;
103 if (CFDictionaryGetValue(attributes, kSecGuestAttributeDynamicCode) != NULL) {
104 CFDataRef infoPlist = (CFDataRef)CFDictionaryGetValue(attributes, kSecGuestAttributeDynamicCodeInfoPlist);
105 if (infoPlist && CFGetTypeID(infoPlist) != CFDataGetTypeID())
106 MacOSError::throwMe(errSecCSInvalidAttributeValues);
107
108 try {
109 diskRep = new PidDiskRep(pid, infoPlist);
110 } catch (...) { }
111 }
112
113 return (new ProcessCode(pid, audit, diskRep))->retain();
866f8763
A
114#else
115 MacOSError::throwMe(errSecCSUnimplemented);
116#endif
b1ab9ed8
A
117}
118
119
120//
121// We map guests to disk by calling a kernel service.
122// It is here that we verify that our user-space concept of the code identity
123// matches the kernel's idea (to defeat just-in-time switching attacks).
124//
125SecStaticCode *KernelCode::identifyGuest(SecCode *iguest, CFDataRef *cdhash)
126{
127 if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest)) {
427c49bc
A
128
129 if (guest->pidBased()) {
130
131 SecPointer<SecStaticCode> code = new ProcessDynamicCode(guest);
fa7225c8 132 guest->pidBased()->setCredentials(code->codeDirectory());
427c49bc
A
133
134 SHA1::Digest kernelHash;
fa7225c8 135 MacOSError::check(guest->csops(CS_OPS_CDHASH, kernelHash, sizeof(kernelHash)));
427c49bc
A
136 *cdhash = makeCFData(kernelHash, sizeof(kernelHash));
137
138 return code.yield();
139 }
140
b1ab9ed8
A
141 char path[2 * MAXPATHLEN]; // reasonable upper limit
142 if (::proc_pidpath(guest->pid(), path, sizeof(path))) {
143 off_t offset;
144 csops(guest, CS_OPS_PIDOFFSET, &offset, sizeof(offset));
427c49bc 145 SecPointer<SecStaticCode> code = new ProcessStaticCode(DiskRep::bestGuess(path, (size_t)offset));
b1ab9ed8
A
146 CODESIGN_GUEST_IDENTIFY_PROCESS(guest, guest->pid(), code);
147 if (cdhash) {
148 SHA1::Digest kernelHash;
fa7225c8 149 if (guest->csops(CS_OPS_CDHASH, kernelHash, sizeof(kernelHash)) == -1)
b1ab9ed8
A
150 switch (errno) {
151 case EBADEXEC: // means "no CodeDirectory hash for this program"
152 *cdhash = NULL;
153 break;
154 case ESRCH:
155 MacOSError::throwMe(errSecCSNoSuchCode);
156 default:
157 UnixError::throwMe();
158 }
159 else // succeeded
160 *cdhash = makeCFData(kernelHash, sizeof(kernelHash));
161 CODESIGN_GUEST_CDHASH_PROCESS(guest, kernelHash, sizeof(kernelHash));
162 }
163 return code.yield();
164 } else
165 UnixError::throwMe();
166 }
167 MacOSError::throwMe(errSecCSNoSuchCode);
168}
169
170
171//
172// We obtain the guest's status by asking the kernel
173//
174SecCodeStatus KernelCode::getGuestStatus(SecCode *iguest)
175{
176 if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest)) {
177 uint32_t pFlags;
178 csops(guest, CS_OPS_STATUS, &pFlags);
fa7225c8 179 secinfo("kcode", "guest %p(%d) kernel status 0x%x", guest, guest->pid(), pFlags);
b1ab9ed8
A
180 return pFlags;
181 } else
182 MacOSError::throwMe(errSecCSNoSuchCode);
183}
184
185
186//
187// We tell the kernel to make status changes
188//
189void KernelCode::changeGuestStatus(SecCode *iguest, SecCodeStatusOperation operation, CFDictionaryRef arguments)
190{
191 if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest))
192 switch (operation) {
193 case kSecCodeOperationNull:
194 break;
195 case kSecCodeOperationInvalidate:
196 csops(guest, CS_OPS_MARKINVALID);
197 break;
198 case kSecCodeOperationSetHard:
199 csops(guest, CS_OPS_MARKHARD);
200 break;
201 case kSecCodeOperationSetKill:
202 csops(guest, CS_OPS_MARKKILL);
203 break;
204 default:
205 MacOSError::throwMe(errSecCSUnimplemented);
206 }
207 else
208 MacOSError::throwMe(errSecCSNoSuchCode);
209}
210
211
212//
213// The StaticCode for the running kernel is explicit.
214// We can't ask our own host for it, naturally.
215//
216void KernelCode::identify()
217{
218 mStaticCode.take(globals().staticCode->retain());
219 // the kernel isn't currently signed, so we don't get a cdHash for it
220}
221
222
223//
224// Interface to kernel csops() system call.
225//
226void KernelCode::csops(ProcessCode *proc, unsigned int op, void *addr, size_t length)
227{
fa7225c8 228 if (proc->csops(op, addr, length) == -1) {
b1ab9ed8
A
229 switch (errno) {
230 case ESRCH:
231 MacOSError::throwMe(errSecCSNoSuchCode);
232 default:
233 UnixError::throwMe();
234 }
235 }
236}
237
238
239} // CodeSigning
240} // Security