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