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.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_get_code_directory
723 *
724 * Description: This function returns the best code directory
725 * as chosen by the system
726 */
727 const CS_CodeDirectory*
csblob_get_code_directory(struct cs_blob * csblob)728 csblob_get_code_directory(struct cs_blob *csblob)
729 {
730 return csblob->csb_cd;
731 }
732
733 void *
csblob_entitlements_dictionary_copy(struct cs_blob * csblob)734 csblob_entitlements_dictionary_copy(struct cs_blob *csblob)
735 {
736 if (!csblob->csb_entitlements) {
737 return NULL;
738 }
739 if (!amfi) {
740 panic("CoreEntitlements: missing AMFI bridge\n");
741 }
742 return amfi->OSEntitlements_asdict(csblob->csb_entitlements);
743 }
744
745 OS_NORETURN
746 void
csblob_entitlements_dictionary_set(struct cs_blob __unused * csblob,void __unused * entitlements)747 csblob_entitlements_dictionary_set(struct cs_blob __unused *csblob, void __unused *entitlements)
748 {
749 panic("CoreEntitlements: This API is no longer supported\n");
750 }
751
752 void
csblob_os_entitlements_set(struct cs_blob * csblob,void * entitlements)753 csblob_os_entitlements_set(struct cs_blob *csblob, void * entitlements)
754 {
755 assert(csblob->csb_entitlements == NULL);
756 if (entitlements) {
757 osobject_retain(entitlements);
758 }
759 csblob->csb_entitlements = entitlements;
760 }
761
762 void *
csblob_os_entitlements_copy(struct cs_blob * csblob)763 csblob_os_entitlements_copy(struct cs_blob *csblob)
764 {
765 if (!csblob->csb_entitlements) {
766 return NULL;
767 }
768 osobject_retain(csblob->csb_entitlements);
769 return csblob->csb_entitlements;
770 }
771
772 void *
csblob_os_entitlements_get(struct cs_blob * csblob)773 csblob_os_entitlements_get(struct cs_blob *csblob)
774 {
775 if (!csblob->csb_entitlements) {
776 return NULL;
777 }
778 return csblob->csb_entitlements;
779 }
780
781 void *
csblob_get_storage_addr(struct cs_blob * csblob)782 csblob_get_storage_addr(struct cs_blob *csblob)
783 {
784 void *addr = csblob->csb_ro_addr;
785 cs_blob_require((struct cs_blob *)addr, NULL);
786 return addr;
787 }
788
789 /*
790 * Function: csproc_get_teamid
791 *
792 * Description: This function returns a pointer to the
793 * team id of the process p
794 */
795 const char *
csproc_get_teamid(struct proc * p)796 csproc_get_teamid(struct proc *p)
797 {
798 struct cs_blob *csblob;
799
800 csblob = csproc_get_blob(p);
801 if (csblob == NULL) {
802 return NULL;
803 }
804
805 return csblob_get_teamid(csblob);
806 }
807
808 const char *
csproc_get_identity(struct proc * p)809 csproc_get_identity(struct proc *p)
810 {
811 struct cs_blob *csblob = NULL;
812
813 csblob = csproc_get_blob(p);
814 if (csblob == NULL) {
815 return NULL;
816 }
817
818 return csblob_get_identity(csblob);
819 }
820
821 /*
822 * Function: csproc_get_signer_type
823 *
824 * Description: This function returns the signer type
825 * of the process p
826 */
827 unsigned int
csproc_get_signer_type(struct proc * p)828 csproc_get_signer_type(struct proc *p)
829 {
830 struct cs_blob *csblob;
831
832 csblob = csproc_get_blob(p);
833 if (csblob == NULL) {
834 return CS_SIGNER_TYPE_UNKNOWN;
835 }
836
837 return csblob_get_signer_type(csblob);
838 }
839
840 /*
841 * Function: csvnode_get_teamid
842 *
843 * Description: This function returns a pointer to the
844 * team id of the binary at the given offset in vnode vp
845 */
846 const char *
csvnode_get_teamid(struct vnode * vp,off_t offset)847 csvnode_get_teamid(struct vnode *vp, off_t offset)
848 {
849 struct cs_blob *csblob;
850
851 if (vp == NULL) {
852 return NULL;
853 }
854
855 csblob = ubc_cs_blob_get(vp, -1, -1, offset);
856 if (csblob == NULL) {
857 return NULL;
858 }
859
860 return csblob_get_teamid(csblob);
861 }
862
863 /*
864 * Function: csproc_get_platform_binary
865 *
866 * Description: This function returns the value
867 * of the platform_binary field for proc p
868 */
869 int
csproc_get_platform_binary(struct proc * p)870 csproc_get_platform_binary(struct proc *p)
871 {
872 struct cs_blob *csblob;
873
874 csblob = csproc_get_blob(p);
875
876 /* If there is no csblob this returns 0 because
877 * it is true that it is not a platform binary */
878 return (csblob == NULL) ? 0 : csblob->csb_platform_binary;
879 }
880
881 int
csproc_get_platform_path(struct proc * p)882 csproc_get_platform_path(struct proc *p)
883 {
884 struct cs_blob *csblob;
885
886 csblob = csproc_get_blob(p);
887
888 return (csblob == NULL) ? 0 : csblob->csb_platform_path;
889 }
890
891 #if DEVELOPMENT || DEBUG
892 void
csproc_clear_platform_binary(struct proc * p)893 csproc_clear_platform_binary(struct proc *p)
894 {
895 struct cs_blob *csblob = csproc_get_blob(p);
896 struct cs_blob_platform_flags platform_flags;
897
898 if (csblob == NULL) {
899 return;
900 }
901
902 if (cs_debug) {
903 printf("clearing platform binary on proc/task: pid = %d\n", proc_getpid(p));
904 }
905
906 platform_flags = csblob->csb_platform_flags;
907 platform_flags.csb_platform_binary = 0;
908 platform_flags.csb_platform_path = 0;
909
910 zalloc_ro_update_field(ZONE_ID_CS_BLOB, csblob, csb_platform_flags,
911 &platform_flags);
912
913 task_set_platform_binary(proc_task(p), FALSE);
914 }
915 #endif
916
917 void
csproc_disable_enforcement(struct proc * __unused p)918 csproc_disable_enforcement(struct proc* __unused p)
919 {
920 #if !CONFIG_ENFORCE_SIGNED_CODE
921 if (p != NULL) {
922 proc_lock(p);
923 proc_csflags_clear(p, CS_ENFORCEMENT);
924 vm_map_cs_enforcement_set(get_task_map(proc_task(p)), FALSE);
925 proc_unlock(p);
926 }
927 #endif
928 }
929
930 /* Function: csproc_mark_invalid_allowed
931 *
932 * Description: Mark the process as being allowed to go invalid. Called as part of
933 * task_for_pid and ptrace policy. Note CS_INVALID_ALLOWED only matters for
934 * processes that have been opted into CS_ENFORCEMENT.
935 */
936 void
csproc_mark_invalid_allowed(struct proc * __unused p)937 csproc_mark_invalid_allowed(struct proc* __unused p)
938 {
939 #if !CONFIG_ENFORCE_SIGNED_CODE
940 if (p != NULL) {
941 proc_lock(p);
942 proc_csflags_set(p, CS_INVALID_ALLOWED);
943 proc_unlock(p);
944 }
945 #endif
946 }
947
948 /*
949 * Function: csproc_check_invalid_allowed
950 *
951 * Description: Returns 1 if the process has been marked as allowed to go invalid
952 * because it gave its task port to an allowed process.
953 */
954 int
csproc_check_invalid_allowed(struct proc * __unused p)955 csproc_check_invalid_allowed(struct proc* __unused p)
956 {
957 #if !CONFIG_ENFORCE_SIGNED_CODE
958 if (p == NULL) {
959 p = current_proc();
960 }
961
962 if (p != NULL && (proc_getcsflags(p) & CS_INVALID_ALLOWED)) {
963 return 1;
964 }
965 #endif
966 return 0;
967 }
968
969 /*
970 * Function: csproc_get_prod_signed
971 *
972 * Description: Returns 1 if process is not signed with a developer identity.
973 * Note the inverted meaning from the cs_flag to make the error case safer.
974 * Will go away with rdar://problem/28322552.
975 */
976 int
csproc_get_prod_signed(struct proc * p)977 csproc_get_prod_signed(struct proc *p)
978 {
979 return (proc_getcsflags(p) & CS_DEV_CODE) == 0;
980 }
981
982 int
csproc_get_validation_category(struct proc * pt,unsigned int * out_validation_category)983 csproc_get_validation_category(struct proc *pt, unsigned int *out_validation_category)
984 {
985 struct cs_blob* blob = NULL;
986 unsigned int validation_category = CS_VALIDATION_CATEGORY_INVALID;
987 int error;
988
989 proc_lock(pt);
990 if ((proc_getcsflags(pt) & (CS_VALID | CS_DEBUGGED)) == 0) {
991 proc_unlock(pt);
992 error = EINVAL;
993 goto out;
994 }
995 blob = csproc_get_blob(pt);
996 proc_unlock(pt);
997
998 if (!blob) {
999 error = EBADEXEC;
1000 goto out;
1001 }
1002
1003 validation_category = csblob_get_validation_category(blob);
1004 if (out_validation_category) {
1005 *out_validation_category = validation_category;
1006 }
1007 error = KERN_SUCCESS;
1008 out:
1009 return error;
1010 }
1011
1012
1013 /*
1014 * Function: csfg_get_platform_binary
1015 *
1016 * Description: This function returns the
1017 * platform binary field for the
1018 * fileglob fg
1019 */
1020 int
csfg_get_platform_binary(struct fileglob * fg)1021 csfg_get_platform_binary(struct fileglob *fg)
1022 {
1023 int platform_binary = 0;
1024 struct ubc_info *uip;
1025 vnode_t vp;
1026
1027 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1028 return 0;
1029 }
1030
1031 vp = (struct vnode *)fg_get_data(fg);
1032 if (vp == NULL) {
1033 return 0;
1034 }
1035
1036 vnode_lock(vp);
1037 if (!UBCINFOEXISTS(vp)) {
1038 goto out;
1039 }
1040
1041 uip = vp->v_ubcinfo;
1042 if (uip == NULL) {
1043 goto out;
1044 }
1045
1046 if (uip->cs_blobs == NULL) {
1047 goto out;
1048 }
1049
1050 /* It is OK to extract the teamid from the first blob
1051 * because all blobs of a vnode must have the same teamid */
1052 platform_binary = uip->cs_blobs->csb_platform_binary;
1053 out:
1054 vnode_unlock(vp);
1055
1056 return platform_binary;
1057 }
1058
1059 int
csfg_get_supplement_platform_binary(struct fileglob * fg __unused)1060 csfg_get_supplement_platform_binary(struct fileglob *fg __unused)
1061 {
1062 #if CONFIG_SUPPLEMENTAL_SIGNATURES
1063 int platform_binary = 0;
1064 struct ubc_info *uip;
1065 vnode_t vp;
1066
1067 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1068 return 0;
1069 }
1070
1071 vp = (struct vnode *)fg_get_data(fg);
1072 if (vp == NULL) {
1073 return 0;
1074 }
1075
1076 vnode_lock(vp);
1077 if (!UBCINFOEXISTS(vp)) {
1078 goto out;
1079 }
1080
1081 uip = vp->v_ubcinfo;
1082 if (uip == NULL) {
1083 goto out;
1084 }
1085
1086 if (uip->cs_blob_supplement == NULL) {
1087 goto out;
1088 }
1089
1090 platform_binary = uip->cs_blob_supplement->csb_platform_binary;
1091 out:
1092 vnode_unlock(vp);
1093
1094 return platform_binary;
1095 #else
1096 // Supplemental signatures are only allowed in CONFIG_SUPPLEMENTAL_SIGNATURES
1097 // Return false if anyone asks about them
1098 return 0;
1099 #endif
1100 }
1101
1102 uint8_t *
csfg_get_cdhash(struct fileglob * fg,uint64_t offset,size_t * cdhash_size)1103 csfg_get_cdhash(struct fileglob *fg, uint64_t offset, size_t *cdhash_size)
1104 {
1105 vnode_t vp;
1106
1107 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1108 return NULL;
1109 }
1110
1111 vp = (struct vnode *)fg_get_data(fg);
1112 if (vp == NULL) {
1113 return NULL;
1114 }
1115
1116 struct cs_blob *csblob = NULL;
1117 if ((csblob = ubc_cs_blob_get(vp, -1, -1, offset)) == NULL) {
1118 return NULL;
1119 }
1120
1121 if (cdhash_size) {
1122 *cdhash_size = CS_CDHASH_LEN;
1123 }
1124 return csblob->csb_cdhash;
1125 }
1126
1127 uint8_t *
csfg_get_supplement_cdhash(struct fileglob * fg __unused,uint64_t offset __unused,size_t * cdhash_size __unused)1128 csfg_get_supplement_cdhash(struct fileglob *fg __unused, uint64_t offset __unused, size_t *cdhash_size __unused)
1129 {
1130 #if CONFIG_SUPPLEMENTAL_SIGNATURES
1131 vnode_t vp;
1132
1133 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1134 return NULL;
1135 }
1136
1137 vp = (struct vnode *)fg_get_data(fg);
1138 if (vp == NULL) {
1139 return NULL;
1140 }
1141
1142 struct cs_blob *csblob = NULL;
1143 if ((csblob = ubc_cs_blob_get_supplement(vp, offset)) == NULL) {
1144 return NULL;
1145 }
1146
1147 if (cdhash_size) {
1148 *cdhash_size = CS_CDHASH_LEN;
1149 }
1150 return csblob->csb_cdhash;
1151 #else
1152 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1153 // return NULL if anyone asks about them
1154 return NULL;
1155 #endif
1156 }
1157
1158 const uint8_t *
csfg_get_supplement_linkage_cdhash(struct fileglob * fg __unused,uint64_t offset __unused,size_t * cdhash_size __unused)1159 csfg_get_supplement_linkage_cdhash(struct fileglob *fg __unused, uint64_t offset __unused, size_t *cdhash_size __unused)
1160 {
1161 #if CONFIG_SUPPLEMENTAL_SIGNATURES
1162 vnode_t vp;
1163
1164 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1165 return NULL;
1166 }
1167
1168 vp = (struct vnode *)fg_get_data(fg);
1169 if (vp == NULL) {
1170 return NULL;
1171 }
1172
1173 struct cs_blob *csblob = NULL;
1174 if ((csblob = ubc_cs_blob_get_supplement(vp, offset)) == NULL) {
1175 return NULL;
1176 }
1177
1178 if (cdhash_size) {
1179 *cdhash_size = CS_CDHASH_LEN;
1180 }
1181
1182 return csblob->csb_linkage;
1183 #else
1184 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1185 // return NULL if anyone asks about them
1186 return NULL;
1187 #endif
1188 }
1189
1190 /*
1191 * Function: csfg_get_signer_type
1192 *
1193 * Description: This returns the signer type
1194 * for the fileglob fg
1195 */
1196 unsigned int
csfg_get_signer_type(struct fileglob * fg)1197 csfg_get_signer_type(struct fileglob *fg)
1198 {
1199 struct ubc_info *uip;
1200 unsigned int signer_type = CS_SIGNER_TYPE_UNKNOWN;
1201 vnode_t vp;
1202
1203 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1204 return CS_SIGNER_TYPE_UNKNOWN;
1205 }
1206
1207 vp = (struct vnode *)fg_get_data(fg);
1208 if (vp == NULL) {
1209 return CS_SIGNER_TYPE_UNKNOWN;
1210 }
1211
1212 vnode_lock(vp);
1213 if (!UBCINFOEXISTS(vp)) {
1214 goto out;
1215 }
1216
1217 uip = vp->v_ubcinfo;
1218 if (uip == NULL) {
1219 goto out;
1220 }
1221
1222 if (uip->cs_blobs == NULL) {
1223 goto out;
1224 }
1225
1226 /* It is OK to extract the signer type from the first blob,
1227 * because all blobs of a vnode must have the same signer type. */
1228 signer_type = uip->cs_blobs->csb_signer_type;
1229 out:
1230 vnode_unlock(vp);
1231
1232 return signer_type;
1233 }
1234
1235 unsigned int
csfg_get_supplement_signer_type(struct fileglob * fg __unused)1236 csfg_get_supplement_signer_type(struct fileglob *fg __unused)
1237 {
1238 #if CONFIG_SUPPLEMENTAL_SIGNATURES
1239 struct ubc_info *uip;
1240 unsigned int signer_type = CS_SIGNER_TYPE_UNKNOWN;
1241 vnode_t vp;
1242
1243 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1244 return CS_SIGNER_TYPE_UNKNOWN;
1245 }
1246
1247 vp = (struct vnode *)fg_get_data(fg);
1248 if (vp == NULL) {
1249 return CS_SIGNER_TYPE_UNKNOWN;
1250 }
1251
1252 vnode_lock(vp);
1253 if (!UBCINFOEXISTS(vp)) {
1254 goto out;
1255 }
1256
1257 uip = vp->v_ubcinfo;
1258 if (uip == NULL) {
1259 goto out;
1260 }
1261
1262 if (uip->cs_blob_supplement == NULL) {
1263 goto out;
1264 }
1265
1266 signer_type = uip->cs_blob_supplement->csb_signer_type;
1267 out:
1268 vnode_unlock(vp);
1269
1270 return signer_type;
1271 #else
1272 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1273 // Return unknown if anyone asks
1274 return CS_SIGNER_TYPE_UNKNOWN;
1275 #endif
1276 }
1277
1278 /*
1279 * Function: csfg_get_teamid
1280 *
1281 * Description: This returns a pointer to
1282 * the teamid for the fileglob fg
1283 */
1284 const char *
csfg_get_teamid(struct fileglob * fg)1285 csfg_get_teamid(struct fileglob *fg)
1286 {
1287 struct ubc_info *uip;
1288 const char *str = NULL;
1289 vnode_t vp;
1290
1291 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1292 return NULL;
1293 }
1294
1295 vp = (struct vnode *)fg_get_data(fg);
1296 if (vp == NULL) {
1297 return NULL;
1298 }
1299
1300 vnode_lock(vp);
1301 if (!UBCINFOEXISTS(vp)) {
1302 goto out;
1303 }
1304
1305 uip = vp->v_ubcinfo;
1306 if (uip == NULL) {
1307 goto out;
1308 }
1309
1310 if (uip->cs_blobs == NULL) {
1311 goto out;
1312 }
1313
1314 /* It is OK to extract the teamid from the first blob
1315 * because all blobs of a vnode must have the same teamid */
1316 str = uip->cs_blobs->csb_teamid;
1317 out:
1318 vnode_unlock(vp);
1319
1320 return str;
1321 }
1322
1323 const char *
csfg_get_supplement_teamid(struct fileglob * fg __unused)1324 csfg_get_supplement_teamid(struct fileglob *fg __unused)
1325 {
1326 #if CONFIG_SUPPLEMENTAL_SIGNATURES
1327 struct ubc_info *uip;
1328 const char *str = NULL;
1329 vnode_t vp;
1330
1331 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1332 return NULL;
1333 }
1334
1335 vp = (struct vnode *)fg_get_data(fg);
1336 if (vp == NULL) {
1337 return NULL;
1338 }
1339
1340 vnode_lock(vp);
1341 if (!UBCINFOEXISTS(vp)) {
1342 goto out;
1343 }
1344
1345 uip = vp->v_ubcinfo;
1346 if (uip == NULL) {
1347 goto out;
1348 }
1349
1350 if (uip->cs_blob_supplement == NULL) {
1351 goto out;
1352 }
1353
1354 str = uip->cs_blob_supplement->csb_supplement_teamid;
1355 out:
1356 vnode_unlock(vp);
1357
1358 return str;
1359 #else
1360 // Supplemental Signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1361 // Return NULL if anyone asks
1362 return NULL;
1363 #endif
1364 }
1365
1366 /*
1367 * Function: csfg_get_csblob
1368 *
1369 * Description: This returns a pointer to
1370 * the csblob for the fileglob fg
1371 */
1372 struct cs_blob*
csfg_get_csblob(struct fileglob * fg,uint64_t offset)1373 csfg_get_csblob(struct fileglob *fg, uint64_t offset)
1374 {
1375 vnode_t vp;
1376
1377 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1378 return NULL;
1379 }
1380
1381 vp = (struct vnode *)fg_get_data(fg);
1382 if (vp == NULL) {
1383 return NULL;
1384 }
1385
1386 struct cs_blob *csblob = NULL;
1387 if ((csblob = ubc_cs_blob_get(vp, -1, -1, offset)) == NULL) {
1388 return NULL;
1389 }
1390
1391 return csblob;
1392 }
1393
1394 struct cs_blob*
csfg_get_supplement_csblob(__unused struct fileglob * fg,__unused uint64_t offset)1395 csfg_get_supplement_csblob(__unused struct fileglob *fg, __unused uint64_t offset)
1396 {
1397 #if CONFIG_SUPPLEMENTAL_SIGNATURES
1398 vnode_t vp;
1399
1400 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1401 return NULL;
1402 }
1403
1404 vp = (struct vnode *)fg_get_data(fg);
1405 if (vp == NULL) {
1406 return NULL;
1407 }
1408
1409 struct cs_blob *csblob = NULL;
1410 if ((csblob = ubc_cs_blob_get_supplement(vp, offset)) == NULL) {
1411 return NULL;
1412 }
1413
1414 return csblob;
1415 #else
1416 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1417 // return NULL if anyone asks about them
1418 return NULL;
1419 #endif
1420 }
1421
1422 /*
1423 * Function: csfg_get_prod_signed
1424 *
1425 * Description: Returns 1 if code is not signed with a developer identity.
1426 * Note the inverted meaning from the cs_flag to make the error case safer.
1427 * Will go away with rdar://problem/28322552.
1428 */
1429 int
csfg_get_prod_signed(struct fileglob * fg)1430 csfg_get_prod_signed(struct fileglob *fg)
1431 {
1432 struct ubc_info *uip;
1433 vnode_t vp;
1434 int prod_signed = 0;
1435
1436 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1437 return 0;
1438 }
1439
1440 vp = (struct vnode *)fg_get_data(fg);
1441 if (vp == NULL) {
1442 return 0;
1443 }
1444
1445 vnode_lock(vp);
1446 if (!UBCINFOEXISTS(vp)) {
1447 goto out;
1448 }
1449
1450 uip = vp->v_ubcinfo;
1451 if (uip == NULL) {
1452 goto out;
1453 }
1454
1455 if (uip->cs_blobs == NULL) {
1456 goto out;
1457 }
1458
1459 /* It is OK to extract the flag from the first blob
1460 * because all blobs of a vnode must have the same cs_flags */
1461 prod_signed = (uip->cs_blobs->csb_flags & CS_DEV_CODE) == 0;
1462 out:
1463 vnode_unlock(vp);
1464
1465 return prod_signed;
1466 }
1467
1468 int
csfg_get_supplement_prod_signed(struct fileglob * fg __unused)1469 csfg_get_supplement_prod_signed(struct fileglob *fg __unused)
1470 {
1471 #if CONFIG_SUPPLEMENTAL_SIGNATURES
1472 struct ubc_info *uip;
1473 vnode_t vp;
1474 int prod_signed = 0;
1475
1476 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1477 return 0;
1478 }
1479
1480 vp = (struct vnode *)fg_get_data(fg);
1481 if (vp == NULL) {
1482 return 0;
1483 }
1484
1485 vnode_lock(vp);
1486 if (!UBCINFOEXISTS(vp)) {
1487 goto out;
1488 }
1489
1490 uip = vp->v_ubcinfo;
1491 if (uip == NULL) {
1492 goto out;
1493 }
1494
1495 if (uip->cs_blob_supplement == NULL) {
1496 goto out;
1497 }
1498
1499 /* It is OK to extract the flag from the first blob
1500 * because all blobs of a vnode must have the same cs_flags */
1501 prod_signed = (uip->cs_blob_supplement->csb_flags & CS_DEV_CODE) == 0;
1502 out:
1503 vnode_unlock(vp);
1504
1505 return prod_signed;
1506 #else
1507 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1508 // Indicate development signed if anyone tries to ask about one.
1509 return 0;
1510 #endif
1511 }
1512
1513 /*
1514 * Function: csfg_get_identity
1515 *
1516 * Description: This function returns the codesign identity
1517 * for the fileglob
1518 */
1519 const char *
csfg_get_identity(struct fileglob * fg,off_t offset)1520 csfg_get_identity(struct fileglob *fg, off_t offset)
1521 {
1522 vnode_t vp;
1523 struct cs_blob *csblob = NULL;
1524
1525 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1526 return NULL;
1527 }
1528
1529 vp = (struct vnode *)fg_get_data(fg);
1530 if (vp == NULL) {
1531 return NULL;
1532 }
1533
1534 csblob = ubc_cs_blob_get(vp, -1, -1, offset);
1535 if (csblob == NULL) {
1536 return NULL;
1537 }
1538
1539 return csblob_get_identity(csblob);
1540 }
1541
1542 /*
1543 * Function: csfg_get_platform_identifier
1544 *
1545 * Description: This function returns the codesign platform
1546 * identifier for the fileglob. Assumes the fileproc
1547 * is being held busy to keep the fileglob consistent.
1548 */
1549 uint8_t
csfg_get_platform_identifier(struct fileglob * fg,off_t offset)1550 csfg_get_platform_identifier(struct fileglob *fg, off_t offset)
1551 {
1552 vnode_t vp;
1553
1554 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1555 return 0;
1556 }
1557
1558 vp = (struct vnode *)fg_get_data(fg);
1559 if (vp == NULL) {
1560 return 0;
1561 }
1562
1563 return csvnode_get_platform_identifier(vp, offset);
1564 }
1565
1566 /*
1567 * Function: csvnode_get_platform_identifier
1568 *
1569 * Description: This function returns the codesign platform
1570 * identifier for the vnode. Assumes a vnode reference
1571 * is held.
1572 */
1573 uint8_t
csvnode_get_platform_identifier(struct vnode * vp,off_t offset)1574 csvnode_get_platform_identifier(struct vnode *vp, off_t offset)
1575 {
1576 struct cs_blob *csblob;
1577 const CS_CodeDirectory *code_dir;
1578
1579 csblob = ubc_cs_blob_get(vp, -1, -1, offset);
1580 if (csblob == NULL) {
1581 return 0;
1582 }
1583
1584 code_dir = csblob->csb_cd;
1585 if (code_dir == NULL || ntohl(code_dir->length) < 8) {
1586 return 0;
1587 }
1588
1589 return code_dir->platform;
1590 }
1591
1592 /*
1593 * Function: csproc_get_platform_identifier
1594 *
1595 * Description: This function returns the codesign platform
1596 * identifier for the proc. Assumes proc will remain
1597 * valid through call.
1598 */
1599 uint8_t
csproc_get_platform_identifier(struct proc * p)1600 csproc_get_platform_identifier(struct proc *p)
1601 {
1602 if (NULL == p->p_textvp) {
1603 return 0;
1604 }
1605
1606 return csvnode_get_platform_identifier(p->p_textvp, p->p_textoff);
1607 }
1608
1609 uint32_t
cs_entitlement_flags(struct proc * p)1610 cs_entitlement_flags(struct proc *p)
1611 {
1612 return proc_getcsflags(p) & CS_ENTITLEMENT_FLAGS;
1613 }
1614
1615 int
cs_restricted(struct proc * p)1616 cs_restricted(struct proc *p)
1617 {
1618 return (proc_getcsflags(p) & CS_RESTRICT) ? 1 : 0;
1619 }
1620
1621 int
csproc_hardened_runtime(struct proc * p)1622 csproc_hardened_runtime(struct proc* p)
1623 {
1624 return (proc_getcsflags(p) & CS_RUNTIME) ? 1 : 0;
1625 }
1626
1627 /*
1628 * Function: csfg_get_path
1629 *
1630 * Description: This populates the buffer passed in
1631 * with the path of the vnode
1632 * When calling this, the fileglob
1633 * cannot go away. The caller must have a
1634 * a reference on the fileglob or fileproc
1635 */
1636 int
csfg_get_path(struct fileglob * fg,char * path,int * len)1637 csfg_get_path(struct fileglob *fg, char *path, int *len)
1638 {
1639 vnode_t vp = NULL;
1640
1641 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1642 return -1;
1643 }
1644
1645 vp = (struct vnode *)fg_get_data(fg);
1646
1647 /* vn_getpath returns 0 for success,
1648 * or an error code */
1649 return vn_getpath(vp, path, len);
1650 }
1651
1652 /*
1653 * Retrieve the entitlements blob for a vnode
1654 * Returns:
1655 * EINVAL no text vnode associated with the process
1656 * EBADEXEC invalid code signing data
1657 * 0 no error occurred
1658 *
1659 * On success, out_start and out_length will point to the
1660 * entitlements blob if found; or will be set to NULL/zero
1661 * if there were no entitlements.
1662 */
1663 int
cs_entitlements_blob_get_vnode(vnode_t vnode,off_t offset,void ** out_start,size_t * out_length)1664 cs_entitlements_blob_get_vnode(vnode_t vnode, off_t offset, void **out_start, size_t *out_length)
1665 {
1666 struct cs_blob *csblob;
1667
1668 *out_start = NULL;
1669 *out_length = 0;
1670
1671 if (vnode == NULL) {
1672 return EINVAL;
1673 }
1674
1675 if ((csblob = ubc_cs_blob_get(vnode, -1, -1, offset)) == NULL) {
1676 return 0;
1677 }
1678
1679 return csblob_get_entitlements(csblob, out_start, out_length);
1680 }
1681
1682
1683 /* Retrieve the cached entitlements for a vnode
1684 * Returns:
1685 * EINVAL no vnode
1686 * EBADEXEC invalid code signing data
1687 * 0 no error occurred
1688 *
1689 * Note: the entitlements may be NULL if there is nothing cached.
1690 */
1691
1692 int
cs_entitlements_dictionary_copy_vnode(vnode_t vnode,off_t offset,void ** entitlements)1693 cs_entitlements_dictionary_copy_vnode(vnode_t vnode, off_t offset, void **entitlements)
1694 {
1695 struct cs_blob *csblob;
1696
1697 *entitlements = NULL;
1698
1699 if (vnode == NULL) {
1700 return EINVAL;
1701 }
1702
1703 if ((csblob = ubc_cs_blob_get(vnode, -1, -1, offset)) == NULL) {
1704 return 0;
1705 }
1706
1707 *entitlements = csblob_entitlements_dictionary_copy(csblob);
1708 return 0;
1709 }
1710
1711 /*
1712 * Retrieve the entitlements blob for a process.
1713 * Returns:
1714 * EINVAL no text vnode associated with the process
1715 * EBADEXEC invalid code signing data
1716 * 0 no error occurred
1717 *
1718 * On success, out_start and out_length will point to the
1719 * entitlements blob if found; or will be set to NULL/zero
1720 * if there were no entitlements.
1721 */
1722 int
cs_entitlements_blob_get(proc_t p,void ** out_start,size_t * out_length)1723 cs_entitlements_blob_get(proc_t p, void **out_start, size_t *out_length)
1724 {
1725 if ((proc_getcsflags(p) & CS_SIGNED) == 0) {
1726 return 0;
1727 }
1728
1729 return cs_entitlements_blob_get_vnode(p->p_textvp, p->p_textoff, out_start, out_length);
1730 }
1731
1732
1733 /* Retrieve the cached entitlements for a process
1734 * Returns:
1735 * EINVAL no text vnode associated with the process
1736 * EBADEXEC invalid code signing data
1737 * 0 no error occurred
1738 *
1739 * Note: the entitlements may be NULL if there is nothing cached.
1740 */
1741
1742 int
cs_entitlements_dictionary_copy(proc_t p,void ** entitlements)1743 cs_entitlements_dictionary_copy(proc_t p, void **entitlements)
1744 {
1745 struct cs_blob *csblob;
1746
1747 *entitlements = NULL;
1748
1749 if ((proc_getcsflags(p) & CS_SIGNED) == 0) {
1750 return 0;
1751 }
1752
1753 if (NULL == p->p_textvp) {
1754 return EINVAL;
1755 }
1756
1757 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, -1, p->p_textoff)) == NULL) {
1758 return 0;
1759 }
1760
1761 *entitlements = csblob_entitlements_dictionary_copy(csblob);
1762 return 0;
1763 }
1764
1765 /* Retrieve the codesign identity for a process.
1766 * Returns:
1767 * NULL an error occured
1768 * string the cs_identity
1769 */
1770
1771 const char *
cs_identity_get(proc_t p)1772 cs_identity_get(proc_t p)
1773 {
1774 struct cs_blob *csblob;
1775
1776 if ((proc_getcsflags(p) & CS_SIGNED) == 0) {
1777 return NULL;
1778 }
1779
1780 if (NULL == p->p_textvp) {
1781 return NULL;
1782 }
1783
1784 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, -1, p->p_textoff)) == NULL) {
1785 return NULL;
1786 }
1787
1788 return csblob_get_identity(csblob);
1789 }
1790
1791 /*
1792 * DO NOT USE THIS FUNCTION!
1793 * Use the properly guarded csproc_get_blob instead.
1794 *
1795 * This is currently here to allow detached signatures to work
1796 * properly. The only user of this function is also checking
1797 * for CS_VALID.
1798 */
1799
1800 int
cs_blob_get(proc_t p,void ** out_start,size_t * out_length)1801 cs_blob_get(proc_t p, void **out_start, size_t *out_length)
1802 {
1803 struct cs_blob *csblob;
1804
1805 *out_start = NULL;
1806 *out_length = 0;
1807
1808 if (NULL == p->p_textvp) {
1809 return EINVAL;
1810 }
1811
1812 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, -1, p->p_textoff)) == NULL) {
1813 return 0;
1814 }
1815
1816 *out_start = csblob->csb_mem_kaddr;
1817 *out_length = csblob->csb_mem_size;
1818
1819 return 0;
1820 }
1821
1822 /*
1823 * return cshash of a process, cdhash is of size CS_CDHASH_LEN
1824 */
1825
1826 uint8_t *
cs_get_cdhash(struct proc * p)1827 cs_get_cdhash(struct proc *p)
1828 {
1829 struct cs_blob *csblob;
1830
1831 if ((proc_getcsflags(p) & CS_SIGNED) == 0) {
1832 return NULL;
1833 }
1834
1835 if (NULL == p->p_textvp) {
1836 return NULL;
1837 }
1838
1839 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, -1, p->p_textoff)) == NULL) {
1840 return NULL;
1841 }
1842
1843 return csblob->csb_cdhash;
1844 }
1845
1846 /*
1847 * return launch type of a process being created.
1848 */
1849 cs_launch_type_t
launch_constraint_data_get_launch_type(launch_constraint_data_t lcd)1850 launch_constraint_data_get_launch_type(launch_constraint_data_t lcd)
1851 {
1852 return lcd->launch_type;
1853 }
1854