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