2 * Copyright (c) 2006-2007,2011-2013 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 // cskernel - Kernel implementation of the Code Signing Host Interface.
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.
31 // The kernel host could represent non-process guests one day. One candidate
32 // are Kernel Extensions.
35 #include "csprocess.h"
36 #include "kerneldiskrep.h"
39 #include <sys/codesign.h>
40 #include <bsm/libbsm.h>
41 #include <security_utilities/cfmunge.h>
42 #include <sys/param.h> // MAXPATHLEN
45 namespace CodeSigning
{
49 // The running-kernel singletons
51 ModuleNexus
<KernelCode::Globals
> KernelCode::globals
;
53 KernelCode::Globals::Globals()
55 code
= new KernelCode
;
56 staticCode
= new KernelStaticCode
;
59 KernelCode::KernelCode()
64 KernelStaticCode::KernelStaticCode()
65 : SecStaticCode(new KernelDiskRep())
71 // Identify our guests (UNIX processes) by attribute.
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.
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.
77 SecCode
*KernelCode::locateGuest(CFDictionaryRef attributes
)
79 CFNumberRef pidNumber
= NULL
;
80 CFDataRef auditData
= NULL
;
81 cfscan(attributes
, "{%O=%NO}", kSecGuestAttributePid
, &pidNumber
);
82 cfscan(attributes
, "{%O=%XO}", kSecGuestAttributeAudit
, &auditData
);
83 if (pidNumber
== NULL
&& auditData
== NULL
)
84 MacOSError::throwMe(errSecCSUnsupportedGuestAttributes
);
86 // Extract information from pid and audit token as presented. We need at least one.
87 // If both are specified, we pass them both to the kernel, which will fail if they
89 if (auditData
&& CFDataGetLength(auditData
) != sizeof(audit_token_t
))
90 MacOSError::throwMe(errSecCSInvalidAttributeValues
);
92 audit_token_t
* audit
= NULL
;
94 pid
= cfNumber
<pid_t
>(pidNumber
);
96 audit
= (audit_token_t
*)CFDataGetBytePtr(auditData
);
97 if (audit
&& pid
== 0)
98 pid
= audit_token_to_pid(*audit
);
100 // handle requests for server-based validation
101 RefPointer
<PidDiskRep
> diskRep
= NULL
;
102 if (CFDictionaryGetValue(attributes
, kSecGuestAttributeDynamicCode
) != NULL
) {
103 CFDataRef infoPlist
= (CFDataRef
)CFDictionaryGetValue(attributes
, kSecGuestAttributeDynamicCodeInfoPlist
);
104 if (infoPlist
&& CFGetTypeID(infoPlist
) != CFDataGetTypeID())
105 MacOSError::throwMe(errSecCSInvalidAttributeValues
);
108 diskRep
= new PidDiskRep(pid
, infoPlist
);
112 return (new ProcessCode(pid
, audit
, diskRep
))->retain();
117 // We map guests to disk by calling a kernel service.
118 // It is here that we verify that our user-space concept of the code identity
119 // matches the kernel's idea (to defeat just-in-time switching attacks).
121 SecStaticCode
*KernelCode::identifyGuest(SecCode
*iguest
, CFDataRef
*cdhash
)
123 if (ProcessCode
*guest
= dynamic_cast<ProcessCode
*>(iguest
)) {
125 if (guest
->pidBased()) {
127 SecPointer
<SecStaticCode
> code
= new ProcessDynamicCode(guest
);
128 guest
->pidBased()->setCredentials(code
->codeDirectory());
130 SHA1::Digest kernelHash
;
131 MacOSError::check(guest
->csops(CS_OPS_CDHASH
, kernelHash
, sizeof(kernelHash
)));
132 *cdhash
= makeCFData(kernelHash
, sizeof(kernelHash
));
137 char path
[2 * MAXPATHLEN
]; // reasonable upper limit
138 if (::proc_pidpath(guest
->pid(), path
, sizeof(path
))) {
140 csops(guest
, CS_OPS_PIDOFFSET
, &offset
, sizeof(offset
));
141 SecPointer
<SecStaticCode
> code
= new ProcessStaticCode(DiskRep::bestGuess(path
, (size_t)offset
));
142 CODESIGN_GUEST_IDENTIFY_PROCESS(guest
, guest
->pid(), code
);
144 SHA1::Digest kernelHash
;
145 if (guest
->csops(CS_OPS_CDHASH
, kernelHash
, sizeof(kernelHash
)) == -1)
147 case EBADEXEC
: // means "no CodeDirectory hash for this program"
151 MacOSError::throwMe(errSecCSNoSuchCode
);
153 UnixError::throwMe();
156 *cdhash
= makeCFData(kernelHash
, sizeof(kernelHash
));
157 CODESIGN_GUEST_CDHASH_PROCESS(guest
, kernelHash
, sizeof(kernelHash
));
161 UnixError::throwMe();
163 MacOSError::throwMe(errSecCSNoSuchCode
);
168 // We obtain the guest's status by asking the kernel
170 SecCodeStatus
KernelCode::getGuestStatus(SecCode
*iguest
)
172 if (ProcessCode
*guest
= dynamic_cast<ProcessCode
*>(iguest
)) {
174 csops(guest
, CS_OPS_STATUS
, &pFlags
);
175 secinfo("kcode", "guest %p(%d) kernel status 0x%x", guest
, guest
->pid(), pFlags
);
178 MacOSError::throwMe(errSecCSNoSuchCode
);
183 // We tell the kernel to make status changes
185 void KernelCode::changeGuestStatus(SecCode
*iguest
, SecCodeStatusOperation operation
, CFDictionaryRef arguments
)
187 if (ProcessCode
*guest
= dynamic_cast<ProcessCode
*>(iguest
))
189 case kSecCodeOperationNull
:
191 case kSecCodeOperationInvalidate
:
192 csops(guest
, CS_OPS_MARKINVALID
);
194 case kSecCodeOperationSetHard
:
195 csops(guest
, CS_OPS_MARKHARD
);
197 case kSecCodeOperationSetKill
:
198 csops(guest
, CS_OPS_MARKKILL
);
201 MacOSError::throwMe(errSecCSUnimplemented
);
204 MacOSError::throwMe(errSecCSNoSuchCode
);
209 // The StaticCode for the running kernel is explicit.
210 // We can't ask our own host for it, naturally.
212 void KernelCode::identify()
214 mStaticCode
.take(globals().staticCode
->retain());
215 // the kernel isn't currently signed, so we don't get a cdHash for it
220 // Interface to kernel csops() system call.
222 void KernelCode::csops(ProcessCode
*proc
, unsigned int op
, void *addr
, size_t length
)
224 if (proc
->csops(op
, addr
, length
) == -1) {
227 MacOSError::throwMe(errSecCSNoSuchCode
);
229 UnixError::throwMe();