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