2 * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <sys/types.h>
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/proc_internal.h>
34 #include <sys/sysctl.h>
35 #include <sys/signal.h>
36 #include <sys/signalvar.h>
37 #include <sys/codesign.h>
39 #include <sys/fcntl.h>
41 #include <sys/kauth.h>
42 #include <sys/mount.h>
45 #include <sys/socketvar.h>
46 #include <sys/vnode.h>
47 #include <sys/vnode_internal.h>
50 #include <sys/ubc_internal.h>
52 #include <security/mac.h>
53 #include <security/mac_policy.h>
54 #include <security/mac_framework.h>
56 #include <mach/mach_types.h>
57 #include <mach/vm_map.h>
58 #include <mach/mach_vm.h>
60 #include <kern/kern_types.h>
61 #include <kern/task.h>
63 #include <vm/vm_map.h>
64 #include <vm/vm_kern.h>
67 #include <sys/syslog.h>
69 #include <kern/assert.h>
71 #include <pexpert/pexpert.h>
73 #include <mach/shared_region.h>
75 unsigned long cs_procs_killed
= 0;
76 unsigned long cs_procs_invalidated
= 0;
78 int cs_force_kill
= 0;
79 int cs_force_hard
= 0;
82 const int cs_enforcement_enable
=1;
84 #if CONFIG_ENFORCE_SIGNED_CODE
85 int cs_enforcement_enable
=1;
87 int cs_enforcement_enable
=0;
89 int cs_enforcement_panic
=0;
91 int cs_all_vnodes
= 0;
93 static lck_grp_t
*cs_lockgrp
;
94 static lck_rw_t
* SigPUPLock
;
96 SYSCTL_INT(_vm
, OID_AUTO
, cs_force_kill
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &cs_force_kill
, 0, "");
97 SYSCTL_INT(_vm
, OID_AUTO
, cs_force_hard
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &cs_force_hard
, 0, "");
98 SYSCTL_INT(_vm
, OID_AUTO
, cs_debug
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &cs_debug
, 0, "");
100 SYSCTL_INT(_vm
, OID_AUTO
, cs_all_vnodes
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &cs_all_vnodes
, 0, "");
103 SYSCTL_INT(_vm
, OID_AUTO
, cs_enforcement
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &cs_enforcement_enable
, 0, "");
104 SYSCTL_INT(_vm
, OID_AUTO
, cs_enforcement_panic
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &cs_enforcement_panic
, 0, "");
107 int panic_on_cs_killed
= 0;
112 panic_on_cs_killed
= 1;
114 PE_parse_boot_argn("panic_on_cs_killed", &panic_on_cs_killed
,
115 sizeof (panic_on_cs_killed
));
117 int disable_cs_enforcement
= 0;
118 PE_parse_boot_argn("cs_enforcement_disable", &disable_cs_enforcement
,
119 sizeof (disable_cs_enforcement
));
120 if (disable_cs_enforcement
) {
121 cs_enforcement_enable
= 0;
124 PE_parse_boot_argn("cs_enforcement_panic", &panic
, sizeof(panic
));
125 cs_enforcement_panic
= (panic
!= 0);
128 PE_parse_boot_argn("cs_debug", &cs_debug
, sizeof (cs_debug
));
130 lck_grp_attr_t
*attr
= lck_grp_attr_alloc_init();
131 cs_lockgrp
= lck_grp_alloc_init("KERNCS", attr
);
132 SigPUPLock
= lck_rw_alloc_init(cs_lockgrp
, NULL
);
136 cs_allow_invalid(struct proc
*p
)
139 lck_mtx_assert(&p
->p_mlock
, LCK_MTX_ASSERT_NOTOWNED
);
141 #if CONFIG_MACF && CONFIG_ENFORCE_SIGNED_CODE
142 /* There needs to be a MAC policy to implement this hook, or else the
143 * kill bits will be cleared here every time. If we have
144 * CONFIG_ENFORCE_SIGNED_CODE, we can assume there is a policy
145 * implementing the hook.
147 if( 0 != mac_proc_check_run_cs_invalid(p
)) {
148 if(cs_debug
) printf("CODE SIGNING: cs_allow_invalid() "
149 "not allowed: pid %d\n",
153 if(cs_debug
) printf("CODE SIGNING: cs_allow_invalid() "
157 p
->p_csflags
&= ~(CS_KILL
| CS_HARD
);
159 vm_map_switch_protect(get_task_map(p
->task
), FALSE
);
161 return (p
->p_csflags
& (CS_KILL
| CS_HARD
)) == 0;
169 int send_kill
= 0, retval
= 0, verbose
= cs_debug
;
175 * XXX revisit locking when proc is no longer protected
176 * by the kernel funnel...
180 printf("CODE SIGNING: cs_invalid_page(0x%llx): p=%d[%s]\n",
181 vaddr
, p
->p_pid
, p
->p_comm
);
185 /* XXX for testing */
187 p
->p_csflags
|= CS_KILL
;
189 p
->p_csflags
|= CS_HARD
;
191 /* CS_KILL triggers a kill signal, and no you can't have the page. Nothing else. */
192 if (p
->p_csflags
& CS_KILL
) {
193 if (panic_on_cs_killed
&&
194 vaddr
>= SHARED_REGION_BASE
&&
195 vaddr
< SHARED_REGION_BASE
+ SHARED_REGION_SIZE
) {
196 panic("<rdar://14393620> cs_invalid_page(va=0x%llx): killing p=%p\n", (uint64_t) vaddr
, p
);
198 p
->p_csflags
|= CS_KILLED
;
205 if (panic_on_cs_killed
&&
206 vaddr
>= SHARED_REGION_BASE
&&
207 vaddr
< SHARED_REGION_BASE
+ SHARED_REGION_SIZE
) {
208 panic("<rdar://14393620> cs_invalid_page(va=0x%llx): cs error p=%p\n", (uint64_t) vaddr
, p
);
210 #endif /* __x86_64__ */
212 /* CS_HARD means fail the mapping operation so the process stays valid. */
213 if (p
->p_csflags
& CS_HARD
) {
216 if (p
->p_csflags
& CS_VALID
) {
217 p
->p_csflags
&= ~CS_VALID
;
218 cs_procs_invalidated
++;
222 csflags
= p
->p_csflags
;
227 snprintf(pid_str
, sizeof(pid_str
), "%d", p
->p_pid
);
228 kern_asl_msg(LOG_NOTICE
, "messagetracer",
230 "com.apple.message.domain", "com.apple.kernel.cs.invalidate",
231 "com.apple.message.signature", send_kill
? "kill" : retval
? "deny" : "invalidate",
232 "com.apple.message.signature4", pid_str
,
233 "com.apple.message.signature3", p
->p_comm
,
234 "com.apple.message.summarize", "YES",
237 printf("CODE SIGNING: cs_invalid_page(0x%llx): "
238 "p=%d[%s] final status 0x%x, %s page%s\n",
239 vaddr
, p
->p_pid
, p
->p_comm
, p
->p_csflags
,
240 retval
? "denying" : "allowing (remove VALID)",
241 send_kill
? " sending SIGKILL" : "");
245 threadsignal(current_thread(), SIGKILL
, EXC_BAD_ACCESS
);
252 * Assumes p (if passed in) is locked with proc_lock().
256 cs_enforcement(struct proc
*p
)
259 if (cs_enforcement_enable
)
265 if (p
!= NULL
&& (p
->p_csflags
& CS_ENFORCEMENT
))
272 struct cscsr_functions
*funcs
;
273 vm_map_offset_t csr_map_base
;
274 vm_map_size_t csr_map_size
;
279 SYSCTL_INT(_vm
, OID_AUTO
, sigpup_disable
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &csr_state
.disabled
, 0, "");
282 vnsize(vfs_context_t vfs
, vnode_t vp
, uint64_t *size
)
284 struct vnode_attr va
;
288 VATTR_WANTED(&va
, va_data_size
);
290 error
= vnode_getattr(vp
, &va
, vfs
);
293 *size
= va
.va_data_size
;
298 sigpup_install(user_addr_t argsp
)
300 struct sigpup_install_table args
;
301 memory_object_control_t control
;
302 kern_return_t result
;
303 vfs_context_t vfs
= NULL
;
304 struct vnode_attr va
;
311 if (!cs_enforcement_enable
|| csr_state
.funcs
== NULL
)
314 lck_rw_lock_exclusive(SigPUPLock
);
316 if (kauth_cred_issuser(kauth_cred_get()) == 0) {
322 printf("sigpup install\n");
324 if (csr_state
.csr_map_base
!= 0 || csr_state
.inuse
) {
329 if (USER_ADDR_NULL
== argsp
) {
333 if ((error
= copyin(argsp
, &args
, sizeof(args
))) != 0)
337 printf("sigpup install with args\n");
339 MALLOC(buf
, char *, MAXPATHLEN
, M_TEMP
, M_WAITOK
);
344 if ((error
= copyinstr((user_addr_t
)args
.path
, buf
, MAXPATHLEN
, &len
)) != 0)
347 if ((vfs
= vfs_context_create(NULL
)) == NULL
) {
352 if ((error
= vnode_lookup(buf
, VNODE_LOOKUP_NOFOLLOW
, &vp
, vfs
)) != 0)
356 printf("sigpup found file: %s\n", buf
);
358 /* make sure vnode is on the process's root volume */
359 if (rootvnode
->v_mount
!= vp
->v_mount
) {
360 if (cs_debug
) printf("sigpup csr no on root volume\n");
365 /* make sure vnode is owned by "root" */
367 VATTR_WANTED(&va
, va_uid
);
368 error
= vnode_getattr(vp
, &va
, vfs
);
372 if (va
.va_uid
!= 0) {
373 if (cs_debug
) printf("sigpup: csr file not owned by root\n");
378 error
= vnsize(vfs
, vp
, &size
);
382 control
= ubc_getobject(vp
, 0);
383 if (control
== MEMORY_OBJECT_CONTROL_NULL
) {
388 csr_state
.csr_map_size
= mach_vm_round_page(size
);
393 result
= vm_map_enter_mem_object_control(kernel_map
,
394 &csr_state
.csr_map_base
,
395 csr_state
.csr_map_size
,
396 0, VM_FLAGS_ANYWHERE
,
397 control
, 0 /* file offset */,
402 if (result
!= KERN_SUCCESS
) {
407 error
= csr_state
.funcs
->csr_validate_header((const uint8_t *)csr_state
.csr_map_base
,
408 csr_state
.csr_map_size
);
411 printf("sigpup header invalid, dropping mapping");
417 printf("table loaded %ld bytes\n", (long)csr_state
.csr_map_size
);
420 lck_rw_unlock_exclusive(SigPUPLock
);
427 (void)vfs_context_rele(vfs
);
430 printf("sigpup: load failed with error: %d\n", error
);
440 if (kauth_cred_issuser(kauth_cred_get()) == 0)
443 lck_rw_lock_exclusive(SigPUPLock
);
445 if (csr_state
.csr_map_base
== 0 || csr_state
.inuse
) {
446 printf("failed to unload the sigpup database\n");
447 lck_rw_unlock_exclusive(SigPUPLock
);
452 printf("sigpup: unloading\n");
454 (void)mach_vm_deallocate(kernel_map
,
455 csr_state
.csr_map_base
, csr_state
.csr_map_size
);
457 csr_state
.csr_map_base
= 0;
458 csr_state
.csr_map_size
= 0;
460 lck_rw_unlock_exclusive(SigPUPLock
);
465 void sigpup_attach_vnode(vnode_t
); /* XXX */
468 sigpup_attach_vnode(vnode_t vp
)
473 if (!cs_enforcement_enable
|| csr_state
.funcs
== NULL
|| csr_state
.csr_map_base
== 0 || csr_state
.disabled
)
476 /* if the file is not on the root volumes or already been check, skip */
477 if (vp
->v_mount
!= rootvnode
->v_mount
|| (vp
->v_flag
& VNOCS
))
480 csblob
= csr_state
.funcs
->csr_find_file_codedirectory(vp
, (const uint8_t *)csr_state
.csr_map_base
,
481 (size_t)csr_state
.csr_map_size
, &cslen
);
483 ubc_cs_sigpup_add(vp
, (vm_address_t
)csblob
, (vm_size_t
)cslen
);
490 cs_register_cscsr(struct cscsr_functions
*funcs
)
492 if (csr_state
.funcs
|| funcs
->csr_version
< CSCSR_VERSION
)
494 csr_state
.funcs
= funcs
;