xref: /xnu-8020.140.41/bsd/kern/kern_cs.c (revision 27b03b360a988dfd3dfdf34262bb0042026747cc)
1 /*
2  * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_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. 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.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
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.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
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>
38 
39 #include <sys/fcntl.h>
40 #include <sys/file.h>
41 #include <sys/file_internal.h>
42 #include <sys/kauth.h>
43 #include <sys/mount.h>
44 #include <sys/msg.h>
45 #include <sys/proc.h>
46 #include <sys/socketvar.h>
47 #include <sys/vnode.h>
48 #include <sys/vnode_internal.h>
49 
50 #include <sys/ubc.h>
51 #include <sys/ubc_internal.h>
52 
53 #include <security/mac.h>
54 #include <security/mac_policy.h>
55 #include <security/mac_framework.h>
56 
57 #include <mach/mach_types.h>
58 #include <mach/vm_map.h>
59 #include <mach/mach_vm.h>
60 
61 #include <kern/kern_types.h>
62 #include <kern/startup.h>
63 #include <kern/task.h>
64 
65 #include <vm/vm_map.h>
66 #include <vm/pmap.h>
67 #include <vm/vm_kern.h>
68 
69 
70 #include <kern/assert.h>
71 
72 #include <pexpert/pexpert.h>
73 
74 #include <mach/shared_region.h>
75 
76 #include <libkern/section_keywords.h>
77 #include <libkern/amfi/amfi.h>
78 
79 
80 unsigned long cs_procs_killed = 0;
81 unsigned long cs_procs_invalidated = 0;
82 
83 int cs_force_kill = 0;
84 int cs_force_hard = 0;
85 int cs_debug = 0;
86 // If set, AMFI will error out early on unsigned code, before evaluation the normal policy.
87 int cs_debug_fail_on_unsigned_code = 0;
88 // If the previous mode is enabled, we count the resulting failures here.
89 unsigned int cs_debug_unsigned_exec_failures = 0;
90 unsigned int cs_debug_unsigned_mmap_failures = 0;
91 
92 #if CONFIG_ENFORCE_SIGNED_CODE
93 #define DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE 1
94 #define DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE 1
95 #else
96 #define DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE 1
97 #define DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE 0
98 #endif
99 
100 #if CONFIG_ENFORCE_LIBRARY_VALIDATION
101 #define DEFAULT_CS_LIBRARY_VA_ENABLE 1
102 #else
103 #define DEFAULT_CS_LIBRARY_VA_ENABLE 0
104 #endif
105 
106 #if SECURE_KERNEL
107 
108 /*
109  *  Here we split cs_enforcement_enable into cs_system_enforcement_enable and cs_process_enforcement_enable
110  *
111  *  cs_system_enforcement_enable governs whether or not system level code signing enforcement mechanisms
112  *  are applied on the system. Today, the only such mechanism is code signing enforcement of the dyld shared
113  *  cache.
114  *
115  *  cs_process_enforcement_enable governs whether code signing enforcement mechanisms are applied to all
116  *  processes or only those that opt into such enforcement.
117  *
118  *  (On iOS and related, both of these are set by default. On macOS, only cs_system_enforcement_enable
119  *  is set by default. Processes can then be opted into code signing enforcement on a case by case basis.)
120  */
121 SECURITY_READ_ONLY_EARLY(int) cs_system_enforcement_enable = DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE;
122 SECURITY_READ_ONLY_EARLY(int) cs_process_enforcement_enable = DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE;
123 SECURITY_READ_ONLY_EARLY(int) cs_library_val_enable = DEFAULT_CS_LIBRARY_VA_ENABLE;
124 
125 #else /* !SECURE_KERNEL */
126 int cs_enforcement_panic = 0;
127 int cs_relax_platform_task_ports = 0;
128 
129 SECURITY_READ_ONLY_LATE(int) cs_system_enforcement_enable = DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE;
130 SECURITY_READ_ONLY_LATE(int) cs_process_enforcement_enable = DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE;
131 
132 SECURITY_READ_ONLY_LATE(int) cs_library_val_enable = DEFAULT_CS_LIBRARY_VA_ENABLE;
133 
134 #endif /* !SECURE_KERNEL */
135 int cs_all_vnodes = 0;
136 
137 SYSCTL_INT(_vm, OID_AUTO, cs_force_kill, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_force_kill, 0, "");
138 SYSCTL_INT(_vm, OID_AUTO, cs_force_hard, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_force_hard, 0, "");
139 SYSCTL_INT(_vm, OID_AUTO, cs_debug, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_debug, 0, "");
140 SYSCTL_INT(_vm, OID_AUTO, cs_debug_fail_on_unsigned_code, CTLFLAG_RW | CTLFLAG_LOCKED,
141     &cs_debug_fail_on_unsigned_code, 0, "");
142 SYSCTL_UINT(_vm, OID_AUTO, cs_debug_unsigned_exec_failures, CTLFLAG_RD | CTLFLAG_LOCKED,
143     &cs_debug_unsigned_exec_failures, 0, "");
144 SYSCTL_UINT(_vm, OID_AUTO, cs_debug_unsigned_mmap_failures, CTLFLAG_RD | CTLFLAG_LOCKED,
145     &cs_debug_unsigned_mmap_failures, 0, "");
146 
147 SYSCTL_INT(_vm, OID_AUTO, cs_all_vnodes, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_all_vnodes, 0, "");
148 
149 #if !SECURE_KERNEL
150 SYSCTL_INT(_vm, OID_AUTO, cs_system_enforcement, CTLFLAG_RD | CTLFLAG_LOCKED, &cs_system_enforcement_enable, 0, "");
151 SYSCTL_INT(_vm, OID_AUTO, cs_process_enforcement, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_process_enforcement_enable, 0, "");
152 SYSCTL_INT(_vm, OID_AUTO, cs_enforcement_panic, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_enforcement_panic, 0, "");
153 
154 #if !CONFIG_ENFORCE_LIBRARY_VALIDATION
155 SYSCTL_INT(_vm, OID_AUTO, cs_library_validation, CTLFLAG_RD | CTLFLAG_LOCKED, &cs_library_val_enable, 0, "");
156 #endif
157 #endif /* !SECURE_KERNEL */
158 
159 __startup_func
160 static void
cs_init(void)161 cs_init(void)
162 {
163 #if !SECURE_KERNEL
164 	int disable_cs_enforcement = 0;
165 	PE_parse_boot_argn("cs_enforcement_disable", &disable_cs_enforcement,
166 	    sizeof(disable_cs_enforcement));
167 	if (disable_cs_enforcement && PE_i_can_has_debugger(NULL) != 0) {
168 		cs_system_enforcement_enable = 0;
169 		cs_process_enforcement_enable = 0;
170 	} else {
171 		int panic = 0;
172 		PE_parse_boot_argn("cs_enforcement_panic", &panic, sizeof(panic));
173 		cs_enforcement_panic = (panic != 0);
174 	}
175 
176 	PE_parse_boot_argn("cs_relax_platform_task_ports",
177 	    &cs_relax_platform_task_ports,
178 	    sizeof(cs_relax_platform_task_ports));
179 
180 	PE_parse_boot_argn("cs_debug", &cs_debug, sizeof(cs_debug));
181 
182 #if !CONFIG_ENFORCE_LIBRARY_VALIDATION
183 	PE_parse_boot_argn("cs_library_val_enable", &cs_library_val_enable,
184 	    sizeof(cs_library_val_enable));
185 #endif
186 #endif /* !SECURE_KERNEL */
187 }
188 STARTUP(CODESIGNING, STARTUP_RANK_FIRST, cs_init);
189 
190 int
cs_allow_invalid(struct proc * p)191 cs_allow_invalid(struct proc *p)
192 {
193 	uint64_t flags;
194 
195 #if MACH_ASSERT
196 	lck_mtx_assert(&p->p_mlock, LCK_MTX_ASSERT_NOTOWNED);
197 #endif
198 #if CONFIG_MACF
199 	/* There needs to be a MAC policy to implement this hook, or else the
200 	 * kill bits will be cleared here every time. If we have
201 	 * CONFIG_ENFORCE_SIGNED_CODE, we can assume there is a policy
202 	 * implementing the hook.
203 	 */
204 	if (0 != mac_proc_check_run_cs_invalid(p)) {
205 		if (cs_debug) {
206 			printf("CODE SIGNING: cs_allow_invalid() "
207 			    "not allowed: pid %d\n",
208 			    proc_getpid(p));
209 		}
210 		return 0;
211 	}
212 	if (cs_debug) {
213 		printf("CODE SIGNING: cs_allow_invalid() "
214 		    "allowed: pid %d\n",
215 		    proc_getpid(p));
216 	}
217 	proc_lock(p);
218 	flags = proc_getcsflags(p) & ~(CS_KILL | CS_HARD);
219 	if (flags & CS_VALID) {
220 		flags |= CS_DEBUGGED;
221 	}
222 	proc_csflags_update(p, flags);
223 #if PMAP_CS
224 	task_t procTask = proc_task(p);
225 	if (procTask) {
226 		vm_map_t proc_map = get_task_map_reference(procTask);
227 		if (proc_map) {
228 			if (vm_map_cs_wx_enable(proc_map) != KERN_SUCCESS) {
229 				printf("CODE SIGNING: cs_allow_invalid() not allowed by pmap: pid %d\n", proc_getpid(p));
230 			}
231 			vm_map_deallocate(proc_map);
232 		}
233 	}
234 #endif // MAP_CS
235 	proc_unlock(p);
236 
237 	/* allow a debugged process to hide some (debug-only!) memory */
238 	task_set_memory_ownership_transfer(p->task, TRUE);
239 
240 	vm_map_switch_protect(get_task_map(p->task), FALSE);
241 	vm_map_cs_debugged_set(get_task_map(p->task), TRUE);
242 #endif
243 	return (proc_getcsflags(p) & (CS_KILL | CS_HARD)) == 0;
244 }
245 
246 int
cs_invalid_page(addr64_t vaddr,boolean_t * cs_killed)247 cs_invalid_page(addr64_t vaddr, boolean_t *cs_killed)
248 {
249 	struct proc     *p;
250 	int             send_kill = 0, retval = 0, verbose = cs_debug;
251 	uint64_t flags;
252 
253 	p = current_proc();
254 
255 	if (verbose) {
256 		printf("CODE SIGNING: cs_invalid_page(0x%llx): p=%d[%s]\n",
257 		    vaddr, proc_getpid(p), p->p_comm);
258 	}
259 
260 	proc_lock(p);
261 
262 	flags = proc_getcsflags(p);
263 
264 	/* XXX for testing */
265 	if (cs_force_kill) {
266 		flags |= CS_KILL;
267 	}
268 	if (cs_force_hard) {
269 		flags |= CS_HARD;
270 	}
271 
272 	/* CS_KILL triggers a kill signal, and no you can't have the page. Nothing else. */
273 	if (flags & CS_KILL) {
274 		flags |= CS_KILLED;
275 		cs_procs_killed++;
276 		send_kill = 1;
277 		retval = 1;
278 	}
279 
280 	/* CS_HARD means fail the mapping operation so the process stays valid. */
281 	if (flags & CS_HARD) {
282 		retval = 1;
283 		proc_csflags_update(p, flags);
284 	} else {
285 		if (flags & CS_VALID) {
286 			flags &= ~CS_VALID;
287 			cs_procs_invalidated++;
288 			verbose = 1;
289 			proc_csflags_update(p, flags);
290 			cs_process_invalidated(NULL);
291 		} else {
292 			proc_csflags_update(p, flags);
293 		}
294 	}
295 	proc_unlock(p);
296 
297 	if (verbose) {
298 		printf("CODE SIGNING: cs_invalid_page(0x%llx): "
299 		    "p=%d[%s] final status 0x%x, %s page%s\n",
300 		    vaddr, proc_getpid(p), p->p_comm, (unsigned int)proc_getcsflags(p),
301 		    retval ? "denying" : "allowing (remove VALID)",
302 		    send_kill ? " sending SIGKILL" : "");
303 	}
304 
305 	if (send_kill) {
306 		/* We will set the exit reason for the thread later */
307 		threadsignal(current_thread(), SIGKILL, EXC_BAD_ACCESS, FALSE);
308 		if (cs_killed) {
309 			*cs_killed = TRUE;
310 		}
311 	} else if (cs_killed) {
312 		*cs_killed = FALSE;
313 	}
314 
315 	return retval;
316 }
317 
318 /*
319  * Called after a process got its CS_VALID bit removed, either by
320  * a previous call to cs_invalid_page, or through other means.
321  * Called from fault handler with vm object lock held.
322  * Called with proc lock held for current_proc or, if passed in, p,
323  * to ensure MACF hook can suspend the task before other threads
324  * can access the memory that is paged in after cs_invalid_page
325  * returns 0 due to missing CS_HARD|CS_KILL.
326  */
327 void
cs_process_invalidated(struct proc * __unused p)328 cs_process_invalidated(struct proc * __unused p)
329 {
330 #if CONFIG_MACF
331 	if (p == NULL) {
332 		p = current_proc();
333 	}
334 	mac_proc_notify_cs_invalidated(p);
335 #endif
336 }
337 
338 /*
339  * Assumes p (if passed in) is locked with proc_lock().
340  */
341 
342 int
cs_process_enforcement(struct proc * p)343 cs_process_enforcement(struct proc *p)
344 {
345 	if (cs_process_enforcement_enable) {
346 		return 1;
347 	}
348 
349 	if (p == NULL) {
350 		p = current_proc();
351 	}
352 
353 	if (p != NULL && (proc_getcsflags(p) & CS_ENFORCEMENT)) {
354 		return 1;
355 	}
356 
357 	return 0;
358 }
359 
360 int
cs_process_global_enforcement(void)361 cs_process_global_enforcement(void)
362 {
363 	return cs_process_enforcement_enable ? 1 : 0;
364 }
365 
366 int
cs_system_enforcement(void)367 cs_system_enforcement(void)
368 {
369 	return cs_system_enforcement_enable ? 1 : 0;
370 }
371 
372 int
cs_vm_supports_4k_translations(void)373 cs_vm_supports_4k_translations(void)
374 {
375 	return 0;
376 }
377 
378 
379 /*
380  * Returns whether a given process is still valid.
381  */
382 int
cs_valid(struct proc * p)383 cs_valid(struct proc *p)
384 {
385 	if (p == NULL) {
386 		p = current_proc();
387 	}
388 
389 	if (p != NULL && (proc_getcsflags(p) & CS_VALID)) {
390 		return 1;
391 	}
392 
393 	return 0;
394 }
395 
396 /*
397  * Library validation functions
398  */
399 int
cs_require_lv(struct proc * p)400 cs_require_lv(struct proc *p)
401 {
402 	if (cs_library_val_enable) {
403 		return 1;
404 	}
405 
406 	if (p == NULL) {
407 		p = current_proc();
408 	}
409 
410 	if (p != NULL && (proc_getcsflags(p) & CS_REQUIRE_LV)) {
411 		return 1;
412 	}
413 
414 	return 0;
415 }
416 
417 int
csproc_forced_lv(struct proc * p)418 csproc_forced_lv(struct proc* p)
419 {
420 	if (p == NULL) {
421 		p = current_proc();
422 	}
423 	if (p != NULL && (proc_getcsflags(p) & CS_FORCED_LV)) {
424 		return 1;
425 	}
426 	return 0;
427 }
428 
429 /*
430  * <rdar://problem/24634089> added to allow system level library
431  *  validation check at mac_cred_label_update_execve time
432  */
433 int
cs_system_require_lv(void)434 cs_system_require_lv(void)
435 {
436 	return cs_library_val_enable ? 1 : 0;
437 }
438 
439 /*
440  * Function: csblob_get_base_offset
441  *
442  * Description: This function returns the base offset into the (possibly universal) binary
443  *		for a given blob.
444  */
445 
446 off_t
csblob_get_base_offset(struct cs_blob * blob)447 csblob_get_base_offset(struct cs_blob *blob)
448 {
449 	return blob->csb_base_offset;
450 }
451 
452 /*
453  * Function: csblob_get_size
454  *
455  * Description: This function returns the size of a given blob.
456  */
457 
458 vm_size_t
csblob_get_size(struct cs_blob * blob)459 csblob_get_size(struct cs_blob *blob)
460 {
461 	return blob->csb_mem_size;
462 }
463 
464 /*
465  * Function: csblob_get_addr
466  *
467  * Description: This function returns the address of a given blob.
468  */
469 
470 vm_address_t
csblob_get_addr(struct cs_blob * blob)471 csblob_get_addr(struct cs_blob *blob)
472 {
473 	return (vm_address_t)blob->csb_mem_kaddr;
474 }
475 
476 /*
477  * Function: csblob_get_platform_binary
478  *
479  * Description: This function returns true if the binary is
480  *		in the trust cache.
481  */
482 
483 int
csblob_get_platform_binary(struct cs_blob * blob)484 csblob_get_platform_binary(struct cs_blob *blob)
485 {
486 	if (blob && blob->csb_platform_binary) {
487 		return 1;
488 	}
489 	return 0;
490 }
491 
492 /*
493  * Function: csblob_get_flags
494  *
495  * Description: This function returns the flags for a given blob
496  */
497 
498 unsigned int
csblob_get_flags(struct cs_blob * blob)499 csblob_get_flags(struct cs_blob *blob)
500 {
501 	return blob->csb_flags;
502 }
503 
504 /*
505  * Function: csblob_get_hashtype
506  *
507  * Description: This function returns the hash type for a given blob
508  */
509 
510 uint8_t
csblob_get_hashtype(struct cs_blob const * const blob)511 csblob_get_hashtype(struct cs_blob const * const blob)
512 {
513 	return blob->csb_hashtype != NULL ? cs_hash_type(blob->csb_hashtype) : 0;
514 }
515 
516 /*
517  * Function: csproc_get_blob
518  *
519  * Description: This function returns the cs_blob
520  *		for the process p
521  */
522 struct cs_blob *
csproc_get_blob(struct proc * p)523 csproc_get_blob(struct proc *p)
524 {
525 	if (NULL == p) {
526 		return NULL;
527 	}
528 
529 	if (NULL == p->p_textvp) {
530 		return NULL;
531 	}
532 
533 	if ((proc_getcsflags(p) & CS_SIGNED) == 0) {
534 		return NULL;
535 	}
536 
537 	return ubc_cs_blob_get(p->p_textvp, -1, -1, p->p_textoff);
538 }
539 
540 /*
541  * Function: csvnode_get_blob
542  *
543  * Description: This function returns the cs_blob
544  *		for the vnode vp
545  */
546 struct cs_blob *
csvnode_get_blob(struct vnode * vp,off_t offset)547 csvnode_get_blob(struct vnode *vp, off_t offset)
548 {
549 	return ubc_cs_blob_get(vp, -1, -1, offset);
550 }
551 
552 /*
553  * Function: csblob_get_teamid
554  *
555  * Description: This function returns a pointer to the
556  *		team id of csblob
557  */
558 const char *
csblob_get_teamid(struct cs_blob * csblob)559 csblob_get_teamid(struct cs_blob *csblob)
560 {
561 	return csblob->csb_teamid;
562 }
563 
564 /*
565  * Function: csblob_get_identity
566  *
567  * Description: This function returns a pointer to the
568  *		identity string
569  */
570 const char *
csblob_get_identity(struct cs_blob * csblob)571 csblob_get_identity(struct cs_blob *csblob)
572 {
573 	const CS_CodeDirectory *cd;
574 
575 	cd = (const CS_CodeDirectory *)csblob_find_blob(csblob, CSSLOT_CODEDIRECTORY, CSMAGIC_CODEDIRECTORY);
576 	if (cd == NULL) {
577 		return NULL;
578 	}
579 
580 	if (cd->identOffset == 0) {
581 		return NULL;
582 	}
583 
584 	return ((const char *)cd) + ntohl(cd->identOffset);
585 }
586 
587 /*
588  * Function: csblob_get_cdhash
589  *
590  * Description: This function returns a pointer to the
591  *		cdhash of csblob (20 byte array)
592  */
593 const uint8_t *
csblob_get_cdhash(struct cs_blob * csblob)594 csblob_get_cdhash(struct cs_blob *csblob)
595 {
596 	return csblob->csb_cdhash;
597 }
598 
599 /*
600  * Function: csblob_get_signer_type
601  *
602  * Description: This function returns the signer type
603  *		as an integer
604  */
605 unsigned int
csblob_get_signer_type(struct cs_blob * csblob)606 csblob_get_signer_type(struct cs_blob *csblob)
607 {
608 	return csblob->csb_signer_type;
609 }
610 
611 void *
csblob_entitlements_dictionary_copy(struct cs_blob * csblob)612 csblob_entitlements_dictionary_copy(struct cs_blob *csblob)
613 {
614 	if (!csblob->csb_entitlements) {
615 		return NULL;
616 	}
617 	if (!amfi) {
618 		panic("CoreEntitlements: missing AMFI bridge\n");
619 	}
620 	return amfi->OSEntitlements_asdict(csblob->csb_entitlements);
621 }
622 
623 OS_NORETURN
624 void
csblob_entitlements_dictionary_set(struct cs_blob __unused * csblob,void __unused * entitlements)625 csblob_entitlements_dictionary_set(struct cs_blob __unused *csblob, void  __unused *entitlements)
626 {
627 	panic("CoreEntitlements: This API is no longer supported\n");
628 }
629 
630 void
csblob_os_entitlements_set(struct cs_blob * csblob,void * entitlements)631 csblob_os_entitlements_set(struct cs_blob *csblob, void * entitlements)
632 {
633 	assert(csblob->csb_entitlements == NULL);
634 	if (entitlements) {
635 		osobject_retain(entitlements);
636 	}
637 	csblob->csb_entitlements = entitlements;
638 }
639 
640 void *
csblob_os_entitlements_copy(struct cs_blob * csblob)641 csblob_os_entitlements_copy(struct cs_blob *csblob)
642 {
643 	if (!csblob->csb_entitlements) {
644 		return NULL;
645 	}
646 	osobject_retain(csblob->csb_entitlements);
647 	return csblob->csb_entitlements;
648 }
649 
650 void *
csblob_os_entitlements_get(struct cs_blob * csblob)651 csblob_os_entitlements_get(struct cs_blob *csblob)
652 {
653 	if (!csblob->csb_entitlements) {
654 		return NULL;
655 	}
656 	return csblob->csb_entitlements;
657 }
658 
659 void *
csblob_get_storage_addr(struct cs_blob * csblob)660 csblob_get_storage_addr(struct cs_blob *csblob)
661 {
662 	void *addr = csblob->csb_ro_addr;
663 	cs_blob_require((struct cs_blob *)addr, NULL);
664 	return addr;
665 }
666 
667 /*
668  * Function: csproc_get_teamid
669  *
670  * Description: This function returns a pointer to the
671  *		team id of the process p
672  */
673 const char *
csproc_get_teamid(struct proc * p)674 csproc_get_teamid(struct proc *p)
675 {
676 	struct cs_blob *csblob;
677 
678 	csblob = csproc_get_blob(p);
679 	if (csblob == NULL) {
680 		return NULL;
681 	}
682 
683 	return csblob_get_teamid(csblob);
684 }
685 
686 const char *
csproc_get_identity(struct proc * p)687 csproc_get_identity(struct proc *p)
688 {
689 	struct cs_blob *csblob = NULL;
690 
691 	csblob = csproc_get_blob(p);
692 	if (csblob == NULL) {
693 		return NULL;
694 	}
695 
696 	return csblob_get_identity(csblob);
697 }
698 
699 /*
700  * Function: csproc_get_signer_type
701  *
702  * Description: This function returns the signer type
703  *		of the process p
704  */
705 unsigned int
csproc_get_signer_type(struct proc * p)706 csproc_get_signer_type(struct proc *p)
707 {
708 	struct cs_blob *csblob;
709 
710 	csblob = csproc_get_blob(p);
711 	if (csblob == NULL) {
712 		return CS_SIGNER_TYPE_UNKNOWN;
713 	}
714 
715 	return csblob_get_signer_type(csblob);
716 }
717 
718 /*
719  * Function: csvnode_get_teamid
720  *
721  * Description: This function returns a pointer to the
722  *		team id of the binary at the given offset in vnode vp
723  */
724 const char *
csvnode_get_teamid(struct vnode * vp,off_t offset)725 csvnode_get_teamid(struct vnode *vp, off_t offset)
726 {
727 	struct cs_blob *csblob;
728 
729 	if (vp == NULL) {
730 		return NULL;
731 	}
732 
733 	csblob = ubc_cs_blob_get(vp, -1, -1, offset);
734 	if (csblob == NULL) {
735 		return NULL;
736 	}
737 
738 	return csblob_get_teamid(csblob);
739 }
740 
741 /*
742  * Function: csproc_get_platform_binary
743  *
744  * Description: This function returns the value
745  *		of the platform_binary field for proc p
746  */
747 int
csproc_get_platform_binary(struct proc * p)748 csproc_get_platform_binary(struct proc *p)
749 {
750 	struct cs_blob *csblob;
751 
752 	csblob = csproc_get_blob(p);
753 
754 	/* If there is no csblob this returns 0 because
755 	 *  it is true that it is not a platform binary */
756 	return (csblob == NULL) ? 0 : csblob->csb_platform_binary;
757 }
758 
759 int
csproc_get_platform_path(struct proc * p)760 csproc_get_platform_path(struct proc *p)
761 {
762 	struct cs_blob *csblob;
763 
764 	csblob = csproc_get_blob(p);
765 
766 	return (csblob == NULL) ? 0 : csblob->csb_platform_path;
767 }
768 
769 #if DEVELOPMENT || DEBUG
770 void
csproc_clear_platform_binary(struct proc * p)771 csproc_clear_platform_binary(struct proc *p)
772 {
773 	struct cs_blob *csblob = csproc_get_blob(p);
774 	struct cs_blob_platform_flags platform_flags;
775 
776 	if (csblob == NULL) {
777 		return;
778 	}
779 
780 	if (cs_debug) {
781 		printf("clearing platform binary on proc/task: pid = %d\n", proc_getpid(p));
782 	}
783 
784 	platform_flags = csblob->csb_platform_flags;
785 	platform_flags.csb_platform_binary = 0;
786 	platform_flags.csb_platform_path = 0;
787 
788 	zalloc_ro_update_field(ZONE_ID_CS_BLOB, csblob, csb_platform_flags,
789 	    &platform_flags);
790 
791 	task_set_platform_binary(proc_task(p), FALSE);
792 }
793 #endif
794 
795 void
csproc_disable_enforcement(struct proc * __unused p)796 csproc_disable_enforcement(struct proc* __unused p)
797 {
798 #if !CONFIG_ENFORCE_SIGNED_CODE
799 	if (p != NULL) {
800 		proc_lock(p);
801 		proc_csflags_clear(p, CS_ENFORCEMENT);
802 		vm_map_cs_enforcement_set(get_task_map(p->task), FALSE);
803 		proc_unlock(p);
804 	}
805 #endif
806 }
807 
808 /* Function: csproc_mark_invalid_allowed
809  *
810  * Description: Mark the process as being allowed to go invalid. Called as part of
811  *		task_for_pid and ptrace policy. Note CS_INVALID_ALLOWED only matters for
812  *		processes that have been opted into CS_ENFORCEMENT.
813  */
814 void
csproc_mark_invalid_allowed(struct proc * __unused p)815 csproc_mark_invalid_allowed(struct proc* __unused p)
816 {
817 #if !CONFIG_ENFORCE_SIGNED_CODE
818 	if (p != NULL) {
819 		proc_lock(p);
820 		proc_csflags_set(p, CS_INVALID_ALLOWED);
821 		proc_unlock(p);
822 	}
823 #endif
824 }
825 
826 /*
827  * Function: csproc_check_invalid_allowed
828  *
829  * Description: Returns 1 if the process has been marked as allowed to go invalid
830  *		because it gave its task port to an allowed process.
831  */
832 int
csproc_check_invalid_allowed(struct proc * __unused p)833 csproc_check_invalid_allowed(struct proc* __unused p)
834 {
835 #if !CONFIG_ENFORCE_SIGNED_CODE
836 	if (p == NULL) {
837 		p = current_proc();
838 	}
839 
840 	if (p != NULL && (proc_getcsflags(p) & CS_INVALID_ALLOWED)) {
841 		return 1;
842 	}
843 #endif
844 	return 0;
845 }
846 
847 /*
848  * Function: csproc_get_prod_signed
849  *
850  * Description: Returns 1 if process is not signed with a developer identity.
851  *		Note the inverted meaning from the cs_flag to make the error case safer.
852  *		Will go away with rdar://problem/28322552.
853  */
854 int
csproc_get_prod_signed(struct proc * p)855 csproc_get_prod_signed(struct proc *p)
856 {
857 	return (proc_getcsflags(p) & CS_DEV_CODE) == 0;
858 }
859 
860 
861 /*
862  * Function: csfg_get_platform_binary
863  *
864  * Description: This function returns the
865  *		platform binary field for the
866  *              fileglob fg
867  */
868 int
csfg_get_platform_binary(struct fileglob * fg)869 csfg_get_platform_binary(struct fileglob *fg)
870 {
871 	int platform_binary = 0;
872 	struct ubc_info *uip;
873 	vnode_t vp;
874 
875 	if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
876 		return 0;
877 	}
878 
879 	vp = (struct vnode *)fg_get_data(fg);
880 	if (vp == NULL) {
881 		return 0;
882 	}
883 
884 	vnode_lock(vp);
885 	if (!UBCINFOEXISTS(vp)) {
886 		goto out;
887 	}
888 
889 	uip = vp->v_ubcinfo;
890 	if (uip == NULL) {
891 		goto out;
892 	}
893 
894 	if (uip->cs_blobs == NULL) {
895 		goto out;
896 	}
897 
898 	/* It is OK to extract the teamid from the first blob
899 	 *  because all blobs of a vnode must have the same teamid */
900 	platform_binary = uip->cs_blobs->csb_platform_binary;
901 out:
902 	vnode_unlock(vp);
903 
904 	return platform_binary;
905 }
906 
907 int
csfg_get_supplement_platform_binary(struct fileglob * fg __unused)908 csfg_get_supplement_platform_binary(struct fileglob *fg __unused)
909 {
910 #if CONFIG_SUPPLEMENTAL_SIGNATURES
911 	int platform_binary = 0;
912 	struct ubc_info *uip;
913 	vnode_t vp;
914 
915 	if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
916 		return 0;
917 	}
918 
919 	vp = (struct vnode *)fg_get_data(fg);
920 	if (vp == NULL) {
921 		return 0;
922 	}
923 
924 	vnode_lock(vp);
925 	if (!UBCINFOEXISTS(vp)) {
926 		goto out;
927 	}
928 
929 	uip = vp->v_ubcinfo;
930 	if (uip == NULL) {
931 		goto out;
932 	}
933 
934 	if (uip->cs_blob_supplement == NULL) {
935 		goto out;
936 	}
937 
938 	platform_binary = uip->cs_blob_supplement->csb_platform_binary;
939 out:
940 	vnode_unlock(vp);
941 
942 	return platform_binary;
943 #else
944 	// Supplemental signatures are only allowed in CONFIG_SUPPLEMENTAL_SIGNATURES
945 	// Return false if anyone asks about them
946 	return 0;
947 #endif
948 }
949 
950 uint8_t *
csfg_get_cdhash(struct fileglob * fg,uint64_t offset,size_t * cdhash_size)951 csfg_get_cdhash(struct fileglob *fg, uint64_t offset, size_t *cdhash_size)
952 {
953 	vnode_t vp;
954 
955 	if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
956 		return NULL;
957 	}
958 
959 	vp = (struct vnode *)fg_get_data(fg);
960 	if (vp == NULL) {
961 		return NULL;
962 	}
963 
964 	struct cs_blob *csblob = NULL;
965 	if ((csblob = ubc_cs_blob_get(vp, -1, -1, offset)) == NULL) {
966 		return NULL;
967 	}
968 
969 	if (cdhash_size) {
970 		*cdhash_size = CS_CDHASH_LEN;
971 	}
972 	return csblob->csb_cdhash;
973 }
974 
975 uint8_t *
csfg_get_supplement_cdhash(struct fileglob * fg __unused,uint64_t offset __unused,size_t * cdhash_size __unused)976 csfg_get_supplement_cdhash(struct fileglob *fg __unused, uint64_t offset __unused, size_t *cdhash_size __unused)
977 {
978 #if CONFIG_SUPPLEMENTAL_SIGNATURES
979 	vnode_t vp;
980 
981 	if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
982 		return NULL;
983 	}
984 
985 	vp = (struct vnode *)fg_get_data(fg);
986 	if (vp == NULL) {
987 		return NULL;
988 	}
989 
990 	struct cs_blob *csblob = NULL;
991 	if ((csblob = ubc_cs_blob_get_supplement(vp, offset)) == NULL) {
992 		return NULL;
993 	}
994 
995 	if (cdhash_size) {
996 		*cdhash_size = CS_CDHASH_LEN;
997 	}
998 	return csblob->csb_cdhash;
999 #else
1000 	// Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1001 	// return NULL if anyone asks about them
1002 	return NULL;
1003 #endif
1004 }
1005 
1006 const uint8_t *
csfg_get_supplement_linkage_cdhash(struct fileglob * fg __unused,uint64_t offset __unused,size_t * cdhash_size __unused)1007 csfg_get_supplement_linkage_cdhash(struct fileglob *fg __unused, uint64_t offset __unused, size_t *cdhash_size __unused)
1008 {
1009 #if CONFIG_SUPPLEMENTAL_SIGNATURES
1010 	vnode_t vp;
1011 
1012 	if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1013 		return NULL;
1014 	}
1015 
1016 	vp = (struct vnode *)fg_get_data(fg);
1017 	if (vp == NULL) {
1018 		return NULL;
1019 	}
1020 
1021 	struct cs_blob *csblob = NULL;
1022 	if ((csblob = ubc_cs_blob_get_supplement(vp, offset)) == NULL) {
1023 		return NULL;
1024 	}
1025 
1026 	if (cdhash_size) {
1027 		*cdhash_size = CS_CDHASH_LEN;
1028 	}
1029 
1030 	return csblob->csb_linkage;
1031 #else
1032 	// Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1033 	// return NULL if anyone asks about them
1034 	return NULL;
1035 #endif
1036 }
1037 
1038 /*
1039  * Function: csfg_get_signer_type
1040  *
1041  * Description: This returns the signer type
1042  *              for the fileglob fg
1043  */
1044 unsigned int
csfg_get_signer_type(struct fileglob * fg)1045 csfg_get_signer_type(struct fileglob *fg)
1046 {
1047 	struct ubc_info *uip;
1048 	unsigned int signer_type = CS_SIGNER_TYPE_UNKNOWN;
1049 	vnode_t vp;
1050 
1051 	if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1052 		return CS_SIGNER_TYPE_UNKNOWN;
1053 	}
1054 
1055 	vp = (struct vnode *)fg_get_data(fg);
1056 	if (vp == NULL) {
1057 		return CS_SIGNER_TYPE_UNKNOWN;
1058 	}
1059 
1060 	vnode_lock(vp);
1061 	if (!UBCINFOEXISTS(vp)) {
1062 		goto out;
1063 	}
1064 
1065 	uip = vp->v_ubcinfo;
1066 	if (uip == NULL) {
1067 		goto out;
1068 	}
1069 
1070 	if (uip->cs_blobs == NULL) {
1071 		goto out;
1072 	}
1073 
1074 	/* It is OK to extract the signer type from the first blob,
1075 	 *  because all blobs of a vnode must have the same signer type. */
1076 	signer_type = uip->cs_blobs->csb_signer_type;
1077 out:
1078 	vnode_unlock(vp);
1079 
1080 	return signer_type;
1081 }
1082 
1083 unsigned int
csfg_get_supplement_signer_type(struct fileglob * fg __unused)1084 csfg_get_supplement_signer_type(struct fileglob *fg __unused)
1085 {
1086 #if CONFIG_SUPPLEMENTAL_SIGNATURES
1087 	struct ubc_info *uip;
1088 	unsigned int signer_type = CS_SIGNER_TYPE_UNKNOWN;
1089 	vnode_t vp;
1090 
1091 	if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1092 		return CS_SIGNER_TYPE_UNKNOWN;
1093 	}
1094 
1095 	vp = (struct vnode *)fg_get_data(fg);
1096 	if (vp == NULL) {
1097 		return CS_SIGNER_TYPE_UNKNOWN;
1098 	}
1099 
1100 	vnode_lock(vp);
1101 	if (!UBCINFOEXISTS(vp)) {
1102 		goto out;
1103 	}
1104 
1105 	uip = vp->v_ubcinfo;
1106 	if (uip == NULL) {
1107 		goto out;
1108 	}
1109 
1110 	if (uip->cs_blob_supplement == NULL) {
1111 		goto out;
1112 	}
1113 
1114 	signer_type = uip->cs_blob_supplement->csb_signer_type;
1115 out:
1116 	vnode_unlock(vp);
1117 
1118 	return signer_type;
1119 #else
1120 	// Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1121 	// Return unknown if anyone asks
1122 	return CS_SIGNER_TYPE_UNKNOWN;
1123 #endif
1124 }
1125 
1126 /*
1127  * Function: csfg_get_teamid
1128  *
1129  * Description: This returns a pointer to
1130  *              the teamid for the fileglob fg
1131  */
1132 const char *
csfg_get_teamid(struct fileglob * fg)1133 csfg_get_teamid(struct fileglob *fg)
1134 {
1135 	struct ubc_info *uip;
1136 	const char *str = NULL;
1137 	vnode_t vp;
1138 
1139 	if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1140 		return NULL;
1141 	}
1142 
1143 	vp = (struct vnode *)fg_get_data(fg);
1144 	if (vp == NULL) {
1145 		return NULL;
1146 	}
1147 
1148 	vnode_lock(vp);
1149 	if (!UBCINFOEXISTS(vp)) {
1150 		goto out;
1151 	}
1152 
1153 	uip = vp->v_ubcinfo;
1154 	if (uip == NULL) {
1155 		goto out;
1156 	}
1157 
1158 	if (uip->cs_blobs == NULL) {
1159 		goto out;
1160 	}
1161 
1162 	/* It is OK to extract the teamid from the first blob
1163 	 *  because all blobs of a vnode must have the same teamid */
1164 	str = uip->cs_blobs->csb_teamid;
1165 out:
1166 	vnode_unlock(vp);
1167 
1168 	return str;
1169 }
1170 
1171 const char *
csfg_get_supplement_teamid(struct fileglob * fg __unused)1172 csfg_get_supplement_teamid(struct fileglob *fg __unused)
1173 {
1174 #if CONFIG_SUPPLEMENTAL_SIGNATURES
1175 	struct ubc_info *uip;
1176 	const char *str = NULL;
1177 	vnode_t vp;
1178 
1179 	if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1180 		return NULL;
1181 	}
1182 
1183 	vp = (struct vnode *)fg_get_data(fg);
1184 	if (vp == NULL) {
1185 		return NULL;
1186 	}
1187 
1188 	vnode_lock(vp);
1189 	if (!UBCINFOEXISTS(vp)) {
1190 		goto out;
1191 	}
1192 
1193 	uip = vp->v_ubcinfo;
1194 	if (uip == NULL) {
1195 		goto out;
1196 	}
1197 
1198 	if (uip->cs_blob_supplement == NULL) {
1199 		goto out;
1200 	}
1201 
1202 	str = uip->cs_blob_supplement->csb_supplement_teamid;
1203 out:
1204 	vnode_unlock(vp);
1205 
1206 	return str;
1207 #else
1208 	// Supplemental Signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1209 	// Return NULL if anyone asks
1210 	return NULL;
1211 #endif
1212 }
1213 
1214 /*
1215  * Function: csfg_get_prod_signed
1216  *
1217  * Description: Returns 1 if code is not signed with a developer identity.
1218  *		Note the inverted meaning from the cs_flag to make the error case safer.
1219  *		Will go away with rdar://problem/28322552.
1220  */
1221 int
csfg_get_prod_signed(struct fileglob * fg)1222 csfg_get_prod_signed(struct fileglob *fg)
1223 {
1224 	struct ubc_info *uip;
1225 	vnode_t vp;
1226 	int prod_signed = 0;
1227 
1228 	if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1229 		return 0;
1230 	}
1231 
1232 	vp = (struct vnode *)fg_get_data(fg);
1233 	if (vp == NULL) {
1234 		return 0;
1235 	}
1236 
1237 	vnode_lock(vp);
1238 	if (!UBCINFOEXISTS(vp)) {
1239 		goto out;
1240 	}
1241 
1242 	uip = vp->v_ubcinfo;
1243 	if (uip == NULL) {
1244 		goto out;
1245 	}
1246 
1247 	if (uip->cs_blobs == NULL) {
1248 		goto out;
1249 	}
1250 
1251 	/* It is OK to extract the flag from the first blob
1252 	 *  because all blobs of a vnode must have the same cs_flags */
1253 	prod_signed = (uip->cs_blobs->csb_flags & CS_DEV_CODE) == 0;
1254 out:
1255 	vnode_unlock(vp);
1256 
1257 	return prod_signed;
1258 }
1259 
1260 int
csfg_get_supplement_prod_signed(struct fileglob * fg __unused)1261 csfg_get_supplement_prod_signed(struct fileglob *fg __unused)
1262 {
1263 #if CONFIG_SUPPLEMENTAL_SIGNATURES
1264 	struct ubc_info *uip;
1265 	vnode_t vp;
1266 	int prod_signed = 0;
1267 
1268 	if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1269 		return 0;
1270 	}
1271 
1272 	vp = (struct vnode *)fg_get_data(fg);
1273 	if (vp == NULL) {
1274 		return 0;
1275 	}
1276 
1277 	vnode_lock(vp);
1278 	if (!UBCINFOEXISTS(vp)) {
1279 		goto out;
1280 	}
1281 
1282 	uip = vp->v_ubcinfo;
1283 	if (uip == NULL) {
1284 		goto out;
1285 	}
1286 
1287 	if (uip->cs_blob_supplement == NULL) {
1288 		goto out;
1289 	}
1290 
1291 	/* It is OK to extract the flag from the first blob
1292 	 *  because all blobs of a vnode must have the same cs_flags */
1293 	prod_signed = (uip->cs_blob_supplement->csb_flags & CS_DEV_CODE) == 0;
1294 out:
1295 	vnode_unlock(vp);
1296 
1297 	return prod_signed;
1298 #else
1299 	// Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1300 	// Indicate development signed if anyone tries to ask about one.
1301 	return 0;
1302 #endif
1303 }
1304 
1305 /*
1306  * Function: csfg_get_identity
1307  *
1308  * Description: This function returns the codesign identity
1309  *		for the fileglob
1310  */
1311 const char *
csfg_get_identity(struct fileglob * fg,off_t offset)1312 csfg_get_identity(struct fileglob *fg, off_t offset)
1313 {
1314 	vnode_t vp;
1315 	struct cs_blob *csblob = NULL;
1316 
1317 	if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1318 		return NULL;
1319 	}
1320 
1321 	vp = (struct vnode *)fg_get_data(fg);
1322 	if (vp == NULL) {
1323 		return NULL;
1324 	}
1325 
1326 	csblob = ubc_cs_blob_get(vp, -1, -1, offset);
1327 	if (csblob == NULL) {
1328 		return NULL;
1329 	}
1330 
1331 	return csblob_get_identity(csblob);
1332 }
1333 
1334 /*
1335  * Function: csfg_get_platform_identifier
1336  *
1337  * Description: This function returns the codesign platform
1338  *		identifier for the fileglob.  Assumes the fileproc
1339  *		is being held busy to keep the fileglob consistent.
1340  */
1341 uint8_t
csfg_get_platform_identifier(struct fileglob * fg,off_t offset)1342 csfg_get_platform_identifier(struct fileglob *fg, off_t offset)
1343 {
1344 	vnode_t vp;
1345 
1346 	if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1347 		return 0;
1348 	}
1349 
1350 	vp = (struct vnode *)fg_get_data(fg);
1351 	if (vp == NULL) {
1352 		return 0;
1353 	}
1354 
1355 	return csvnode_get_platform_identifier(vp, offset);
1356 }
1357 
1358 /*
1359  * Function: csvnode_get_platform_identifier
1360  *
1361  * Description: This function returns the codesign platform
1362  *		identifier for the vnode.  Assumes a vnode reference
1363  *		is held.
1364  */
1365 uint8_t
csvnode_get_platform_identifier(struct vnode * vp,off_t offset)1366 csvnode_get_platform_identifier(struct vnode *vp, off_t offset)
1367 {
1368 	struct cs_blob *csblob;
1369 	const CS_CodeDirectory *code_dir;
1370 
1371 	csblob = ubc_cs_blob_get(vp, -1, -1, offset);
1372 	if (csblob == NULL) {
1373 		return 0;
1374 	}
1375 
1376 	code_dir = csblob->csb_cd;
1377 	if (code_dir == NULL || ntohl(code_dir->length) < 8) {
1378 		return 0;
1379 	}
1380 
1381 	return code_dir->platform;
1382 }
1383 
1384 /*
1385  * Function: csproc_get_platform_identifier
1386  *
1387  * Description: This function returns the codesign platform
1388  *		identifier for the proc.  Assumes proc will remain
1389  *		valid through call.
1390  */
1391 uint8_t
csproc_get_platform_identifier(struct proc * p)1392 csproc_get_platform_identifier(struct proc *p)
1393 {
1394 	if (NULL == p->p_textvp) {
1395 		return 0;
1396 	}
1397 
1398 	return csvnode_get_platform_identifier(p->p_textvp, p->p_textoff);
1399 }
1400 
1401 uint32_t
cs_entitlement_flags(struct proc * p)1402 cs_entitlement_flags(struct proc *p)
1403 {
1404 	return proc_getcsflags(p) & CS_ENTITLEMENT_FLAGS;
1405 }
1406 
1407 int
cs_restricted(struct proc * p)1408 cs_restricted(struct proc *p)
1409 {
1410 	return (proc_getcsflags(p) & CS_RESTRICT) ? 1 : 0;
1411 }
1412 
1413 int
csproc_hardened_runtime(struct proc * p)1414 csproc_hardened_runtime(struct proc* p)
1415 {
1416 	return (proc_getcsflags(p) & CS_RUNTIME) ? 1 : 0;
1417 }
1418 
1419 /*
1420  * Function: csfg_get_path
1421  *
1422  * Description: This populates the buffer passed in
1423  *		with the path of the vnode
1424  *		When calling this, the fileglob
1425  *		cannot go away. The caller must have a
1426  *		a reference on the fileglob or fileproc
1427  */
1428 int
csfg_get_path(struct fileglob * fg,char * path,int * len)1429 csfg_get_path(struct fileglob *fg, char *path, int *len)
1430 {
1431 	vnode_t vp = NULL;
1432 
1433 	if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1434 		return -1;
1435 	}
1436 
1437 	vp = (struct vnode *)fg_get_data(fg);
1438 
1439 	/* vn_getpath returns 0 for success,
1440 	 *  or an error code */
1441 	return vn_getpath(vp, path, len);
1442 }
1443 
1444 /*
1445  * Retrieve the entitlements blob for a vnode
1446  * Returns:
1447  *   EINVAL	no text vnode associated with the process
1448  *   EBADEXEC   invalid code signing data
1449  *   0		no error occurred
1450  *
1451  * On success, out_start and out_length will point to the
1452  * entitlements blob if found; or will be set to NULL/zero
1453  * if there were no entitlements.
1454  */
1455 int
cs_entitlements_blob_get_vnode(vnode_t vnode,off_t offset,void ** out_start,size_t * out_length)1456 cs_entitlements_blob_get_vnode(vnode_t vnode, off_t offset, void **out_start, size_t *out_length)
1457 {
1458 	struct cs_blob *csblob;
1459 
1460 	*out_start = NULL;
1461 	*out_length = 0;
1462 
1463 	if (vnode == NULL) {
1464 		return EINVAL;
1465 	}
1466 
1467 	if ((csblob = ubc_cs_blob_get(vnode, -1, -1, offset)) == NULL) {
1468 		return 0;
1469 	}
1470 
1471 	return csblob_get_entitlements(csblob, out_start, out_length);
1472 }
1473 
1474 
1475 /* Retrieve the cached entitlements for a vnode
1476  * Returns:
1477  *   EINVAL	no vnode
1478  *   EBADEXEC   invalid code signing data
1479  *   0		no error occurred
1480  *
1481  * Note: the entitlements may be NULL if there is nothing cached.
1482  */
1483 
1484 int
cs_entitlements_dictionary_copy_vnode(vnode_t vnode,off_t offset,void ** entitlements)1485 cs_entitlements_dictionary_copy_vnode(vnode_t vnode, off_t offset, void **entitlements)
1486 {
1487 	struct cs_blob *csblob;
1488 
1489 	*entitlements = NULL;
1490 
1491 	if (vnode == NULL) {
1492 		return EINVAL;
1493 	}
1494 
1495 	if ((csblob = ubc_cs_blob_get(vnode, -1, -1, offset)) == NULL) {
1496 		return 0;
1497 	}
1498 
1499 	*entitlements = csblob_entitlements_dictionary_copy(csblob);
1500 	return 0;
1501 }
1502 
1503 /*
1504  * Retrieve the entitlements blob for a process.
1505  * Returns:
1506  *   EINVAL	no text vnode associated with the process
1507  *   EBADEXEC   invalid code signing data
1508  *   0		no error occurred
1509  *
1510  * On success, out_start and out_length will point to the
1511  * entitlements blob if found; or will be set to NULL/zero
1512  * if there were no entitlements.
1513  */
1514 int
cs_entitlements_blob_get(proc_t p,void ** out_start,size_t * out_length)1515 cs_entitlements_blob_get(proc_t p, void **out_start, size_t *out_length)
1516 {
1517 	if ((proc_getcsflags(p) & CS_SIGNED) == 0) {
1518 		return 0;
1519 	}
1520 
1521 	return cs_entitlements_blob_get_vnode(p->p_textvp, p->p_textoff, out_start, out_length);
1522 }
1523 
1524 
1525 /* Retrieve the cached entitlements for a process
1526  * Returns:
1527  *   EINVAL	no text vnode associated with the process
1528  *   EBADEXEC   invalid code signing data
1529  *   0		no error occurred
1530  *
1531  * Note: the entitlements may be NULL if there is nothing cached.
1532  */
1533 
1534 int
cs_entitlements_dictionary_copy(proc_t p,void ** entitlements)1535 cs_entitlements_dictionary_copy(proc_t p, void **entitlements)
1536 {
1537 	struct cs_blob *csblob;
1538 
1539 	*entitlements = NULL;
1540 
1541 	if ((proc_getcsflags(p) & CS_SIGNED) == 0) {
1542 		return 0;
1543 	}
1544 
1545 	if (NULL == p->p_textvp) {
1546 		return EINVAL;
1547 	}
1548 
1549 	if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, -1, p->p_textoff)) == NULL) {
1550 		return 0;
1551 	}
1552 
1553 	*entitlements = csblob_entitlements_dictionary_copy(csblob);
1554 	return 0;
1555 }
1556 
1557 /* Retrieve the codesign identity for a process.
1558  * Returns:
1559  *   NULL	an error occured
1560  *   string	the cs_identity
1561  */
1562 
1563 const char *
cs_identity_get(proc_t p)1564 cs_identity_get(proc_t p)
1565 {
1566 	struct cs_blob *csblob;
1567 
1568 	if ((proc_getcsflags(p) & CS_SIGNED) == 0) {
1569 		return NULL;
1570 	}
1571 
1572 	if (NULL == p->p_textvp) {
1573 		return NULL;
1574 	}
1575 
1576 	if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, -1, p->p_textoff)) == NULL) {
1577 		return NULL;
1578 	}
1579 
1580 	return csblob_get_identity(csblob);
1581 }
1582 
1583 /*
1584  * DO NOT USE THIS FUNCTION!
1585  * Use the properly guarded csproc_get_blob instead.
1586  *
1587  * This is currently here to allow detached signatures to work
1588  * properly. The only user of this function is also checking
1589  * for CS_VALID.
1590  */
1591 
1592 int
cs_blob_get(proc_t p,void ** out_start,size_t * out_length)1593 cs_blob_get(proc_t p, void **out_start, size_t *out_length)
1594 {
1595 	struct cs_blob *csblob;
1596 
1597 	*out_start = NULL;
1598 	*out_length = 0;
1599 
1600 	if (NULL == p->p_textvp) {
1601 		return EINVAL;
1602 	}
1603 
1604 	if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, -1, p->p_textoff)) == NULL) {
1605 		return 0;
1606 	}
1607 
1608 	*out_start = csblob->csb_mem_kaddr;
1609 	*out_length = csblob->csb_mem_size;
1610 
1611 	return 0;
1612 }
1613 
1614 /*
1615  * return cshash of a process, cdhash is of size CS_CDHASH_LEN
1616  */
1617 
1618 uint8_t *
cs_get_cdhash(struct proc * p)1619 cs_get_cdhash(struct proc *p)
1620 {
1621 	struct cs_blob *csblob;
1622 
1623 	if ((proc_getcsflags(p) & CS_SIGNED) == 0) {
1624 		return NULL;
1625 	}
1626 
1627 	if (NULL == p->p_textvp) {
1628 		return NULL;
1629 	}
1630 
1631 	if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, -1, p->p_textoff)) == NULL) {
1632 		return NULL;
1633 	}
1634 
1635 	return csblob->csb_cdhash;
1636 }
1637