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