]> git.saurik.com Git - apple/security.git/blame - libsecurity_codesigning/lib/cskernel.cpp
Security-55178.0.1.tar.gz
[apple/security.git] / libsecurity_codesigning / lib / cskernel.cpp
CommitLineData
b1ab9ed8
A
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 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//
93SecStaticCode *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//
129SecCodeStatus 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//
144void 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//
171void 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//
181void 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