]> git.saurik.com Git - apple/security.git/blob - libsecurity_codesigning/lib/cskernel.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_codesigning / lib / cskernel.cpp
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
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 if (CFDictionaryGetCount(attributes) != 1)
79 MacOSError::throwMe(errSecCSUnsupportedGuestAttributes); // had more
80 if (CFGetTypeID(attr) == CFNumberGetTypeID())
81 return (new ProcessCode(cfNumber<pid_t>(CFNumberRef(attr))))->retain();
82 MacOSError::throwMe(errSecCSInvalidAttributeValues);
83 } else
84 MacOSError::throwMe(errSecCSUnsupportedGuestAttributes);
85 }
86
87
88 //
89 // We map guests to disk by calling a kernel service.
90 // It is here that we verify that our user-space concept of the code identity
91 // matches the kernel's idea (to defeat just-in-time switching attacks).
92 //
93 SecStaticCode *KernelCode::identifyGuest(SecCode *iguest, CFDataRef *cdhash)
94 {
95 if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest)) {
96 char path[2 * MAXPATHLEN]; // reasonable upper limit
97 if (::proc_pidpath(guest->pid(), path, sizeof(path))) {
98 off_t offset;
99 csops(guest, CS_OPS_PIDOFFSET, &offset, sizeof(offset));
100 SecPointer<SecStaticCode> code = new ProcessStaticCode(DiskRep::bestGuess(path, offset));
101 CODESIGN_GUEST_IDENTIFY_PROCESS(guest, guest->pid(), code);
102 if (cdhash) {
103 SHA1::Digest kernelHash;
104 if (::csops(guest->pid(), CS_OPS_CDHASH, kernelHash, sizeof(kernelHash)) == -1)
105 switch (errno) {
106 case EBADEXEC: // means "no CodeDirectory hash for this program"
107 *cdhash = NULL;
108 break;
109 case ESRCH:
110 MacOSError::throwMe(errSecCSNoSuchCode);
111 default:
112 UnixError::throwMe();
113 }
114 else // succeeded
115 *cdhash = makeCFData(kernelHash, sizeof(kernelHash));
116 CODESIGN_GUEST_CDHASH_PROCESS(guest, kernelHash, sizeof(kernelHash));
117 }
118 return code.yield();
119 } else
120 UnixError::throwMe();
121 }
122 MacOSError::throwMe(errSecCSNoSuchCode);
123 }
124
125
126 //
127 // We obtain the guest's status by asking the kernel
128 //
129 SecCodeStatus KernelCode::getGuestStatus(SecCode *iguest)
130 {
131 if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest)) {
132 uint32_t pFlags;
133 csops(guest, CS_OPS_STATUS, &pFlags);
134 secdebug("kcode", "guest %p(%d) kernel status 0x%x", guest, guest->pid(), pFlags);
135 return pFlags;
136 } else
137 MacOSError::throwMe(errSecCSNoSuchCode);
138 }
139
140
141 //
142 // We tell the kernel to make status changes
143 //
144 void KernelCode::changeGuestStatus(SecCode *iguest, SecCodeStatusOperation operation, CFDictionaryRef arguments)
145 {
146 if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest))
147 switch (operation) {
148 case kSecCodeOperationNull:
149 break;
150 case kSecCodeOperationInvalidate:
151 csops(guest, CS_OPS_MARKINVALID);
152 break;
153 case kSecCodeOperationSetHard:
154 csops(guest, CS_OPS_MARKHARD);
155 break;
156 case kSecCodeOperationSetKill:
157 csops(guest, CS_OPS_MARKKILL);
158 break;
159 default:
160 MacOSError::throwMe(errSecCSUnimplemented);
161 }
162 else
163 MacOSError::throwMe(errSecCSNoSuchCode);
164 }
165
166
167 //
168 // The StaticCode for the running kernel is explicit.
169 // We can't ask our own host for it, naturally.
170 //
171 void KernelCode::identify()
172 {
173 mStaticCode.take(globals().staticCode->retain());
174 // the kernel isn't currently signed, so we don't get a cdHash for it
175 }
176
177
178 //
179 // Interface to kernel csops() system call.
180 //
181 void KernelCode::csops(ProcessCode *proc, unsigned int op, void *addr, size_t length)
182 {
183 if (::csops(proc->pid(), op, addr, length) == -1) {
184 switch (errno) {
185 case ESRCH:
186 MacOSError::throwMe(errSecCSNoSuchCode);
187 default:
188 UnixError::throwMe();
189 }
190 }
191 }
192
193
194 } // CodeSigning
195 } // Security