]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_cs.c
92d1c43bea64332a043e658fc485a67aeddff5ae
[apple/xnu.git] / bsd / kern / kern_cs.c
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/task.h>
63
64 #include <vm/vm_map.h>
65 #include <vm/vm_kern.h>
66
67
68 #include <kern/assert.h>
69
70 #include <pexpert/pexpert.h>
71
72 #include <mach/shared_region.h>
73
74 #include <libkern/section_keywords.h>
75
76 unsigned long cs_procs_killed = 0;
77 unsigned long cs_procs_invalidated = 0;
78
79 int cs_force_kill = 0;
80 int cs_force_hard = 0;
81 int cs_debug = 0;
82 #if SECURE_KERNEL
83 const int cs_enforcement_enable = 1;
84 const int cs_library_val_enable = 1;
85 #else /* !SECURE_KERNEL */
86 int cs_enforcement_panic=0;
87 int cs_relax_platform_task_ports = 0;
88
89 #if CONFIG_ENFORCE_SIGNED_CODE
90 #define DEFAULT_CS_ENFORCEMENT_ENABLE 1
91 #else
92 #define DEFAULT_CS_ENFORCEMENT_ENABLE 0
93 #endif
94 SECURITY_READ_ONLY_LATE(int) cs_enforcement_enable = DEFAULT_CS_ENFORCEMENT_ENABLE;
95
96 #if CONFIG_ENFORCE_LIBRARY_VALIDATION
97 #define DEFAULT_CS_LIBRARY_VA_ENABLE 1
98 #else
99 #define DEFAULT_CS_LIBRARY_VA_ENABLE 0
100 #endif
101 SECURITY_READ_ONLY_LATE(int) cs_library_val_enable = DEFAULT_CS_LIBRARY_VA_ENABLE;
102
103 #endif /* !SECURE_KERNEL */
104 int cs_all_vnodes = 0;
105
106 static lck_grp_t *cs_lockgrp;
107
108 SYSCTL_INT(_vm, OID_AUTO, cs_force_kill, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_force_kill, 0, "");
109 SYSCTL_INT(_vm, OID_AUTO, cs_force_hard, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_force_hard, 0, "");
110 SYSCTL_INT(_vm, OID_AUTO, cs_debug, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_debug, 0, "");
111
112 SYSCTL_INT(_vm, OID_AUTO, cs_all_vnodes, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_all_vnodes, 0, "");
113
114 #if !SECURE_KERNEL
115 SYSCTL_INT(_vm, OID_AUTO, cs_enforcement, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_enforcement_enable, 0, "");
116 SYSCTL_INT(_vm, OID_AUTO, cs_enforcement_panic, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_enforcement_panic, 0, "");
117
118 #if !CONFIG_ENFORCE_LIBRARY_VALIDATION
119 SYSCTL_INT(_vm, OID_AUTO, cs_library_validation, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_library_val_enable, 0, "");
120 #endif
121 #endif /* !SECURE_KERNEL */
122
123 int panic_on_cs_killed = 0;
124
125 void
126 cs_init(void)
127 {
128 #if MACH_ASSERT && __x86_64__
129 panic_on_cs_killed = 1;
130 #endif /* MACH_ASSERT && __x86_64__ */
131 PE_parse_boot_argn("panic_on_cs_killed", &panic_on_cs_killed,
132 sizeof (panic_on_cs_killed));
133 #if !SECURE_KERNEL
134 int disable_cs_enforcement = 0;
135 PE_parse_boot_argn("cs_enforcement_disable", &disable_cs_enforcement,
136 sizeof (disable_cs_enforcement));
137 if (disable_cs_enforcement) {
138 cs_enforcement_enable = 0;
139 } else {
140 int panic = 0;
141 PE_parse_boot_argn("cs_enforcement_panic", &panic, sizeof(panic));
142 cs_enforcement_panic = (panic != 0);
143 }
144
145 PE_parse_boot_argn("cs_relax_platform_task_ports",
146 &cs_relax_platform_task_ports,
147 sizeof(cs_relax_platform_task_ports));
148
149 PE_parse_boot_argn("cs_debug", &cs_debug, sizeof (cs_debug));
150
151 #if !CONFIG_ENFORCE_LIBRARY_VALIDATION
152 PE_parse_boot_argn("cs_library_val_enable", &cs_library_val_enable,
153 sizeof (cs_library_val_enable));
154 #endif
155 #endif /* !SECURE_KERNEL */
156
157 lck_grp_attr_t *attr = lck_grp_attr_alloc_init();
158 cs_lockgrp = lck_grp_alloc_init("KERNCS", attr);
159 lck_grp_attr_free(attr);
160 }
161
162 int
163 cs_allow_invalid(struct proc *p)
164 {
165 #if MACH_ASSERT
166 lck_mtx_assert(&p->p_mlock, LCK_MTX_ASSERT_NOTOWNED);
167 #endif
168 #if CONFIG_MACF && CONFIG_ENFORCE_SIGNED_CODE
169 /* There needs to be a MAC policy to implement this hook, or else the
170 * kill bits will be cleared here every time. If we have
171 * CONFIG_ENFORCE_SIGNED_CODE, we can assume there is a policy
172 * implementing the hook.
173 */
174 if( 0 != mac_proc_check_run_cs_invalid(p)) {
175 if(cs_debug) printf("CODE SIGNING: cs_allow_invalid() "
176 "not allowed: pid %d\n",
177 p->p_pid);
178 return 0;
179 }
180 if(cs_debug) printf("CODE SIGNING: cs_allow_invalid() "
181 "allowed: pid %d\n",
182 p->p_pid);
183 proc_lock(p);
184 p->p_csflags &= ~(CS_KILL | CS_HARD);
185 if (p->p_csflags & CS_VALID)
186 {
187 p->p_csflags |= CS_DEBUGGED;
188 }
189
190 proc_unlock(p);
191
192 vm_map_switch_protect(get_task_map(p->task), FALSE);
193 #endif
194 return (p->p_csflags & (CS_KILL | CS_HARD)) == 0;
195 }
196
197 int
198 cs_invalid_page(addr64_t vaddr, boolean_t *cs_killed)
199 {
200 struct proc *p;
201 int send_kill = 0, retval = 0, verbose = cs_debug;
202 uint32_t csflags;
203
204 p = current_proc();
205
206 if (verbose)
207 printf("CODE SIGNING: cs_invalid_page(0x%llx): p=%d[%s]\n",
208 vaddr, p->p_pid, p->p_comm);
209
210 proc_lock(p);
211
212 /* XXX for testing */
213 if (cs_force_kill)
214 p->p_csflags |= CS_KILL;
215 if (cs_force_hard)
216 p->p_csflags |= CS_HARD;
217
218 /* CS_KILL triggers a kill signal, and no you can't have the page. Nothing else. */
219 if (p->p_csflags & CS_KILL) {
220 p->p_csflags |= CS_KILLED;
221 cs_procs_killed++;
222 send_kill = 1;
223 retval = 1;
224 }
225
226 /* CS_HARD means fail the mapping operation so the process stays valid. */
227 if (p->p_csflags & CS_HARD) {
228 retval = 1;
229 } else {
230 if (p->p_csflags & CS_VALID) {
231 p->p_csflags &= ~CS_VALID;
232 cs_procs_invalidated++;
233 verbose = 1;
234 }
235 }
236 csflags = p->p_csflags;
237 proc_unlock(p);
238
239 if (verbose)
240 printf("CODE SIGNING: cs_invalid_page(0x%llx): "
241 "p=%d[%s] final status 0x%x, %s page%s\n",
242 vaddr, p->p_pid, p->p_comm, p->p_csflags,
243 retval ? "denying" : "allowing (remove VALID)",
244 send_kill ? " sending SIGKILL" : "");
245
246 if (send_kill) {
247 /* We will set the exit reason for the thread later */
248 threadsignal(current_thread(), SIGKILL, EXC_BAD_ACCESS, FALSE);
249 if (cs_killed) {
250 *cs_killed = TRUE;
251 }
252 } else if (cs_killed) {
253 *cs_killed = FALSE;
254 }
255
256
257 return retval;
258 }
259
260 /*
261 * Assumes p (if passed in) is locked with proc_lock().
262 */
263
264 int
265 cs_enforcement(struct proc *p)
266 {
267
268 if (cs_enforcement_enable)
269 return 1;
270
271 if (p == NULL)
272 p = current_proc();
273
274 if (p != NULL && (p->p_csflags & CS_ENFORCEMENT))
275 return 1;
276
277 return 0;
278 }
279
280 /*
281 * Returns whether a given process is still valid.
282 */
283 int
284 cs_valid(struct proc *p)
285 {
286
287 if (p == NULL)
288 p = current_proc();
289
290 if (p != NULL && (p->p_csflags & CS_VALID))
291 return 1;
292
293 return 0;
294 }
295
296 /*
297 * Library validation functions
298 */
299 int
300 cs_require_lv(struct proc *p)
301 {
302
303 if (cs_library_val_enable)
304 return 1;
305
306 if (p == NULL)
307 p = current_proc();
308
309 if (p != NULL && (p->p_csflags & CS_REQUIRE_LV))
310 return 1;
311
312 return 0;
313 }
314
315 /*
316 * <rdar://problem/24634089> added to allow system level library
317 * validation check at mac_cred_label_update_execve time
318 */
319 int
320 cs_system_require_lv(void)
321 {
322 return cs_library_val_enable ? 1 : 0;
323 }
324
325 /*
326 * Function: csblob_get_base_offset
327 *
328 * Description: This function returns the base offset into the (possibly universal) binary
329 * for a given blob.
330 */
331
332 off_t
333 csblob_get_base_offset(struct cs_blob *blob)
334 {
335 return blob->csb_base_offset;
336 }
337
338 /*
339 * Function: csblob_get_size
340 *
341 * Description: This function returns the size of a given blob.
342 */
343
344 vm_size_t
345 csblob_get_size(struct cs_blob *blob)
346 {
347 return blob->csb_mem_size;
348 }
349
350 /*
351 * Function: csblob_get_addr
352 *
353 * Description: This function returns the address of a given blob.
354 */
355
356 vm_address_t
357 csblob_get_addr(struct cs_blob *blob)
358 {
359 return blob->csb_mem_kaddr;
360 }
361
362 /*
363 * Function: csblob_get_platform_binary
364 *
365 * Description: This function returns true if the binary is
366 * in the trust cache.
367 */
368
369 int
370 csblob_get_platform_binary(struct cs_blob *blob)
371 {
372 if (blob && blob->csb_platform_binary)
373 return 1;
374 return 0;
375 }
376
377 /*
378 * Function: csblob_get_flags
379 *
380 * Description: This function returns the flags for a given blob
381 */
382
383 unsigned int
384 csblob_get_flags(struct cs_blob *blob)
385 {
386 return blob->csb_flags;
387 }
388
389 /*
390 * Function: csblob_get_hashtype
391 *
392 * Description: This function returns the hash type for a given blob
393 */
394
395 uint8_t
396 csblob_get_hashtype(struct cs_blob const * const blob)
397 {
398 return blob->csb_hashtype != NULL ? cs_hash_type(blob->csb_hashtype) : 0;
399 }
400
401 /*
402 * Function: csproc_get_blob
403 *
404 * Description: This function returns the cs_blob
405 * for the process p
406 */
407 struct cs_blob *
408 csproc_get_blob(struct proc *p)
409 {
410 if (NULL == p)
411 return NULL;
412
413 if (NULL == p->p_textvp)
414 return NULL;
415
416 if ((p->p_csflags & CS_SIGNED) == 0) {
417 return NULL;
418 }
419
420 return ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff);
421 }
422
423 /*
424 * Function: csvnode_get_blob
425 *
426 * Description: This function returns the cs_blob
427 * for the vnode vp
428 */
429 struct cs_blob *
430 csvnode_get_blob(struct vnode *vp, off_t offset)
431 {
432 return ubc_cs_blob_get(vp, -1, offset);
433 }
434
435 /*
436 * Function: csblob_get_teamid
437 *
438 * Description: This function returns a pointer to the
439 * team id of csblob
440 */
441 const char *
442 csblob_get_teamid(struct cs_blob *csblob)
443 {
444 return csblob->csb_teamid;
445 }
446
447 /*
448 * Function: csblob_get_identity
449 *
450 * Description: This function returns a pointer to the
451 * identity string
452 */
453 const char *
454 csblob_get_identity(struct cs_blob *csblob)
455 {
456 const CS_CodeDirectory *cd;
457
458 cd = (const CS_CodeDirectory *)csblob_find_blob(csblob, CSSLOT_CODEDIRECTORY, CSMAGIC_CODEDIRECTORY);
459 if (cd == NULL)
460 return NULL;
461
462 if (cd->identOffset == 0)
463 return NULL;
464
465 return ((const char *)cd) + ntohl(cd->identOffset);
466 }
467
468 /*
469 * Function: csblob_get_cdhash
470 *
471 * Description: This function returns a pointer to the
472 * cdhash of csblob (20 byte array)
473 */
474 const uint8_t *
475 csblob_get_cdhash(struct cs_blob *csblob)
476 {
477 return csblob->csb_cdhash;
478 }
479
480 /*
481 * Function: csblob_get_signer_type
482 *
483 * Description: This function returns the signer type
484 * as an integer
485 */
486 unsigned int
487 csblob_get_signer_type(struct cs_blob *csblob)
488 {
489 return csblob->csb_signer_type;
490 }
491
492 void *
493 csblob_entitlements_dictionary_copy(struct cs_blob *csblob)
494 {
495 if (!csblob->csb_entitlements) return NULL;
496 osobject_retain(csblob->csb_entitlements);
497 return csblob->csb_entitlements;
498 }
499
500 void
501 csblob_entitlements_dictionary_set(struct cs_blob *csblob, void * entitlements)
502 {
503 assert(csblob->csb_entitlements == NULL);
504 if (entitlements) osobject_retain(entitlements);
505 csblob->csb_entitlements = entitlements;
506 }
507
508 /*
509 * Function: csproc_get_teamid
510 *
511 * Description: This function returns a pointer to the
512 * team id of the process p
513 */
514 const char *
515 csproc_get_teamid(struct proc *p)
516 {
517 struct cs_blob *csblob;
518
519 csblob = csproc_get_blob(p);
520 if (csblob == NULL)
521 return NULL;
522
523 return csblob_get_teamid(csblob);
524 }
525
526 /*
527 * Function: csproc_get_signer_type
528 *
529 * Description: This function returns the signer type
530 * of the process p
531 */
532 unsigned int
533 csproc_get_signer_type(struct proc *p)
534 {
535 struct cs_blob *csblob;
536
537 csblob = csproc_get_blob(p);
538 if (csblob == NULL)
539 return CS_SIGNER_TYPE_UNKNOWN;
540
541 return csblob_get_signer_type(csblob);
542 }
543
544 /*
545 * Function: csvnode_get_teamid
546 *
547 * Description: This function returns a pointer to the
548 * team id of the binary at the given offset in vnode vp
549 */
550 const char *
551 csvnode_get_teamid(struct vnode *vp, off_t offset)
552 {
553 struct cs_blob *csblob;
554
555 if (vp == NULL)
556 return NULL;
557
558 csblob = ubc_cs_blob_get(vp, -1, offset);
559 if (csblob == NULL)
560 return NULL;
561
562 return csblob_get_teamid(csblob);
563 }
564
565 /*
566 * Function: csproc_get_platform_binary
567 *
568 * Description: This function returns the value
569 * of the platform_binary field for proc p
570 */
571 int
572 csproc_get_platform_binary(struct proc *p)
573 {
574 struct cs_blob *csblob;
575
576 csblob = csproc_get_blob(p);
577
578 /* If there is no csblob this returns 0 because
579 it is true that it is not a platform binary */
580 return (csblob == NULL) ? 0 : csblob->csb_platform_binary;
581 }
582
583 int
584 csproc_get_platform_path(struct proc *p)
585 {
586 struct cs_blob *csblob;
587
588 csblob = csproc_get_blob(p);
589
590 return (csblob == NULL) ? 0 : csblob->csb_platform_path;
591 }
592
593 #if DEVELOPMENT || DEBUG
594 void
595 csproc_clear_platform_binary(struct proc *p)
596 {
597 struct cs_blob *csblob = csproc_get_blob(p);
598
599 if (csblob == NULL) {
600 return;
601 }
602
603 if (cs_debug) {
604 printf("clearing platform binary on proc/task: pid = %d\n", p->p_pid);
605 }
606
607 csblob->csb_platform_binary = 0;
608 csblob->csb_platform_path = 0;
609 task_set_platform_binary(proc_task(p), FALSE);
610 }
611 #endif
612
613 /*
614 * Function: csproc_get_prod_signed
615 *
616 * Description: Returns 1 if process is not signed with a developer identity.
617 * Note the inverted meaning from the cs_flag to make the error case safer.
618 * Will go away with rdar://problem/28322552.
619 */
620 int
621 csproc_get_prod_signed(struct proc *p)
622 {
623 return ((p->p_csflags & CS_DEV_CODE) == 0);
624 }
625
626
627 /*
628 * Function: csfg_get_platform_binary
629 *
630 * Description: This function returns the
631 * platform binary field for the
632 * fileglob fg
633 */
634 int
635 csfg_get_platform_binary(struct fileglob *fg)
636 {
637 int platform_binary = 0;
638 struct ubc_info *uip;
639 vnode_t vp;
640
641 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
642 return 0;
643
644 vp = (struct vnode *)fg->fg_data;
645 if (vp == NULL)
646 return 0;
647
648 vnode_lock(vp);
649 if (!UBCINFOEXISTS(vp))
650 goto out;
651
652 uip = vp->v_ubcinfo;
653 if (uip == NULL)
654 goto out;
655
656 if (uip->cs_blobs == NULL)
657 goto out;
658
659 /* It is OK to extract the teamid from the first blob
660 because all blobs of a vnode must have the same teamid */
661 platform_binary = uip->cs_blobs->csb_platform_binary;
662 out:
663 vnode_unlock(vp);
664
665 return platform_binary;
666 }
667
668 uint8_t *
669 csfg_get_cdhash(struct fileglob *fg, uint64_t offset, size_t *cdhash_size)
670 {
671 vnode_t vp;
672
673 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
674 return NULL;
675
676 vp = (struct vnode *)fg->fg_data;
677 if (vp == NULL)
678 return NULL;
679
680 struct cs_blob *csblob = NULL;
681 if ((csblob = ubc_cs_blob_get(vp, -1, offset)) == NULL)
682 return NULL;
683
684 if (cdhash_size)
685 *cdhash_size = CS_CDHASH_LEN;
686
687 return csblob->csb_cdhash;
688 }
689
690 /*
691 * Function: csfg_get_signer_type
692 *
693 * Description: This returns the signer type
694 * for the fileglob fg
695 */
696 unsigned int
697 csfg_get_signer_type(struct fileglob *fg)
698 {
699 struct ubc_info *uip;
700 unsigned int signer_type = CS_SIGNER_TYPE_UNKNOWN;
701 vnode_t vp;
702
703 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
704 return CS_SIGNER_TYPE_UNKNOWN;
705
706 vp = (struct vnode *)fg->fg_data;
707 if (vp == NULL)
708 return CS_SIGNER_TYPE_UNKNOWN;
709
710 vnode_lock(vp);
711 if (!UBCINFOEXISTS(vp))
712 goto out;
713
714 uip = vp->v_ubcinfo;
715 if (uip == NULL)
716 goto out;
717
718 if (uip->cs_blobs == NULL)
719 goto out;
720
721 /* It is OK to extract the signer type from the first blob,
722 because all blobs of a vnode must have the same signer type. */
723 signer_type = uip->cs_blobs->csb_signer_type;
724 out:
725 vnode_unlock(vp);
726
727 return signer_type;
728 }
729
730 /*
731 * Function: csfg_get_teamid
732 *
733 * Description: This returns a pointer to
734 * the teamid for the fileglob fg
735 */
736 const char *
737 csfg_get_teamid(struct fileglob *fg)
738 {
739 struct ubc_info *uip;
740 const char *str = NULL;
741 vnode_t vp;
742
743 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
744 return NULL;
745
746 vp = (struct vnode *)fg->fg_data;
747 if (vp == NULL)
748 return NULL;
749
750 vnode_lock(vp);
751 if (!UBCINFOEXISTS(vp))
752 goto out;
753
754 uip = vp->v_ubcinfo;
755 if (uip == NULL)
756 goto out;
757
758 if (uip->cs_blobs == NULL)
759 goto out;
760
761 /* It is OK to extract the teamid from the first blob
762 because all blobs of a vnode must have the same teamid */
763 str = uip->cs_blobs->csb_teamid;
764 out:
765 vnode_unlock(vp);
766
767 return str;
768 }
769
770 /*
771 * Function: csfg_get_prod_signed
772 *
773 * Description: Returns 1 if code is not signed with a developer identity.
774 * Note the inverted meaning from the cs_flag to make the error case safer.
775 * Will go away with rdar://problem/28322552.
776 */
777 int
778 csfg_get_prod_signed(struct fileglob *fg)
779 {
780 struct ubc_info *uip;
781 vnode_t vp;
782 int prod_signed = 0;
783
784 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
785 return 0;
786
787 vp = (struct vnode *)fg->fg_data;
788 if (vp == NULL)
789 return 0;
790
791 vnode_lock(vp);
792 if (!UBCINFOEXISTS(vp))
793 goto out;
794
795 uip = vp->v_ubcinfo;
796 if (uip == NULL)
797 goto out;
798
799 if (uip->cs_blobs == NULL)
800 goto out;
801
802 /* It is OK to extract the flag from the first blob
803 because all blobs of a vnode must have the same cs_flags */
804 prod_signed = (uip->cs_blobs->csb_flags & CS_DEV_CODE) == 0;
805 out:
806 vnode_unlock(vp);
807
808 return prod_signed;
809 }
810
811 /*
812 * Function: csfg_get_identity
813 *
814 * Description: This function returns the codesign identity
815 * for the fileglob
816 */
817 const char *
818 csfg_get_identity(struct fileglob *fg, off_t offset)
819 {
820 vnode_t vp;
821 struct cs_blob *csblob = NULL;
822
823 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
824 return NULL;
825
826 vp = (struct vnode *)fg->fg_data;
827 if (vp == NULL)
828 return NULL;
829
830 csblob = ubc_cs_blob_get(vp, -1, offset);
831 if (csblob == NULL)
832 return NULL;
833
834 return csblob_get_identity(csblob);
835 }
836
837 /*
838 * Function: csfg_get_platform_identifier
839 *
840 * Description: This function returns the codesign platform
841 * identifier for the fileglob. Assumes the fileproc
842 * is being held busy to keep the fileglob consistent.
843 */
844 uint8_t
845 csfg_get_platform_identifier(struct fileglob *fg, off_t offset)
846 {
847 vnode_t vp;
848
849 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
850 return 0;
851
852 vp = (struct vnode *)fg->fg_data;
853 if (vp == NULL)
854 return 0;
855
856 return csvnode_get_platform_identifier(vp, offset);
857 }
858
859 /*
860 * Function: csvnode_get_platform_identifier
861 *
862 * Description: This function returns the codesign platform
863 * identifier for the vnode. Assumes a vnode reference
864 * is held.
865 */
866 uint8_t
867 csvnode_get_platform_identifier(struct vnode *vp, off_t offset)
868 {
869 struct cs_blob *csblob;
870 const CS_CodeDirectory *code_dir;
871
872 csblob = ubc_cs_blob_get(vp, -1, offset);
873 if (csblob == NULL)
874 return 0;
875
876 code_dir = csblob->csb_cd;
877 if (code_dir == NULL || ntohl(code_dir->length) < 8)
878 return 0;
879
880 return code_dir->platform;
881 }
882
883 /*
884 * Function: csproc_get_platform_identifier
885 *
886 * Description: This function returns the codesign platform
887 * identifier for the proc. Assumes proc will remain
888 * valid through call.
889 */
890 uint8_t
891 csproc_get_platform_identifier(struct proc *p)
892 {
893 if (NULL == p->p_textvp)
894 return 0;
895
896 return csvnode_get_platform_identifier(p->p_textvp, p->p_textoff);
897 }
898
899 uint32_t
900 cs_entitlement_flags(struct proc *p)
901 {
902 return (p->p_csflags & CS_ENTITLEMENT_FLAGS);
903 }
904
905 int
906 cs_restricted(struct proc *p)
907 {
908 return (p->p_csflags & CS_RESTRICT) ? 1 : 0;
909 }
910
911 /*
912 * Function: csfg_get_path
913 *
914 * Description: This populates the buffer passed in
915 * with the path of the vnode
916 * When calling this, the fileglob
917 * cannot go away. The caller must have a
918 * a reference on the fileglob or fileproc
919 */
920 int
921 csfg_get_path(struct fileglob *fg, char *path, int *len)
922 {
923 vnode_t vp = NULL;
924
925 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
926 return -1;
927
928 vp = (struct vnode *)fg->fg_data;
929
930 /* vn_getpath returns 0 for success,
931 or an error code */
932 return vn_getpath(vp, path, len);
933 }
934
935 /* Retrieve the entitlements blob for a process.
936 * Returns:
937 * EINVAL no text vnode associated with the process
938 * EBADEXEC invalid code signing data
939 * 0 no error occurred
940 *
941 * On success, out_start and out_length will point to the
942 * entitlements blob if found; or will be set to NULL/zero
943 * if there were no entitlements.
944 */
945
946 int
947 cs_entitlements_blob_get(proc_t p, void **out_start, size_t *out_length)
948 {
949 struct cs_blob *csblob;
950
951 *out_start = NULL;
952 *out_length = 0;
953
954 if ((p->p_csflags & CS_SIGNED) == 0) {
955 return 0;
956 }
957
958 if (NULL == p->p_textvp)
959 return EINVAL;
960
961 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL)
962 return 0;
963
964 return csblob_get_entitlements(csblob, out_start, out_length);
965 }
966
967 /* Retrieve the codesign identity for a process.
968 * Returns:
969 * NULL an error occured
970 * string the cs_identity
971 */
972
973 const char *
974 cs_identity_get(proc_t p)
975 {
976 struct cs_blob *csblob;
977
978 if ((p->p_csflags & CS_SIGNED) == 0) {
979 return NULL;
980 }
981
982 if (NULL == p->p_textvp)
983 return NULL;
984
985 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL)
986 return NULL;
987
988 return csblob_get_identity(csblob);
989 }
990
991 /*
992 * DO NOT USE THIS FUNCTION!
993 * Use the properly guarded csproc_get_blob instead.
994 *
995 * This is currently here to allow detached signatures to work
996 * properly. The only user of this function is also checking
997 * for CS_VALID.
998 */
999
1000 int
1001 cs_blob_get(proc_t p, void **out_start, size_t *out_length)
1002 {
1003 struct cs_blob *csblob;
1004
1005 *out_start = NULL;
1006 *out_length = 0;
1007
1008 if (NULL == p->p_textvp)
1009 return EINVAL;
1010
1011 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL)
1012 return 0;
1013
1014 *out_start = (void *)csblob->csb_mem_kaddr;
1015 *out_length = csblob->csb_mem_size;
1016
1017 return 0;
1018 }
1019
1020 /*
1021 * return cshash of a process, cdhash is of size CS_CDHASH_LEN
1022 */
1023
1024 uint8_t *
1025 cs_get_cdhash(struct proc *p)
1026 {
1027 struct cs_blob *csblob;
1028
1029 if ((p->p_csflags & CS_SIGNED) == 0) {
1030 return NULL;
1031 }
1032
1033 if (NULL == p->p_textvp)
1034 return NULL;
1035
1036 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL)
1037 return NULL;
1038
1039 return csblob->csb_cdhash;
1040 }