]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_cs.c
xnu-4570.31.3.tar.gz
[apple/xnu.git] / bsd / kern / kern_cs.c
CommitLineData
39236c6e
A
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>
fe8ab488 41#include <sys/file_internal.h>
39236c6e
A
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
39236c6e
A
67
68#include <kern/assert.h>
69
70#include <pexpert/pexpert.h>
71
15129b1c
A
72#include <mach/shared_region.h>
73
4bd07ac2
A
74#include <libkern/section_keywords.h>
75
39236c6e
A
76unsigned long cs_procs_killed = 0;
77unsigned long cs_procs_invalidated = 0;
78
79int cs_force_kill = 0;
80int cs_force_hard = 0;
81int cs_debug = 0;
82#if SECURE_KERNEL
3e170ce0
A
83const int cs_enforcement_enable = 1;
84const int cs_library_val_enable = 1;
85#else /* !SECURE_KERNEL */
86int cs_enforcement_panic=0;
5ba3f43e 87int cs_relax_platform_task_ports = 0;
3e170ce0 88
39236c6e 89#if CONFIG_ENFORCE_SIGNED_CODE
4bd07ac2 90#define DEFAULT_CS_ENFORCEMENT_ENABLE 1
39236c6e 91#else
4bd07ac2 92#define DEFAULT_CS_ENFORCEMENT_ENABLE 0
3e170ce0 93#endif
4bd07ac2 94SECURITY_READ_ONLY_LATE(int) cs_enforcement_enable = DEFAULT_CS_ENFORCEMENT_ENABLE;
fe8ab488
A
95
96#if CONFIG_ENFORCE_LIBRARY_VALIDATION
4bd07ac2 97#define DEFAULT_CS_LIBRARY_VA_ENABLE 1
fe8ab488 98#else
4bd07ac2 99#define DEFAULT_CS_LIBRARY_VA_ENABLE 0
3e170ce0 100#endif
4bd07ac2 101SECURITY_READ_ONLY_LATE(int) cs_library_val_enable = DEFAULT_CS_LIBRARY_VA_ENABLE;
fe8ab488 102
3e170ce0 103#endif /* !SECURE_KERNEL */
39236c6e
A
104int cs_all_vnodes = 0;
105
106static lck_grp_t *cs_lockgrp;
39236c6e
A
107
108SYSCTL_INT(_vm, OID_AUTO, cs_force_kill, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_force_kill, 0, "");
109SYSCTL_INT(_vm, OID_AUTO, cs_force_hard, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_force_hard, 0, "");
110SYSCTL_INT(_vm, OID_AUTO, cs_debug, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_debug, 0, "");
111
112SYSCTL_INT(_vm, OID_AUTO, cs_all_vnodes, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_all_vnodes, 0, "");
113
114#if !SECURE_KERNEL
115SYSCTL_INT(_vm, OID_AUTO, cs_enforcement, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_enforcement_enable, 0, "");
116SYSCTL_INT(_vm, OID_AUTO, cs_enforcement_panic, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_enforcement_panic, 0, "");
3e170ce0
A
117
118#if !CONFIG_ENFORCE_LIBRARY_VALIDATION
119SYSCTL_INT(_vm, OID_AUTO, cs_library_validation, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_library_val_enable, 0, "");
39236c6e 120#endif
3e170ce0 121#endif /* !SECURE_KERNEL */
39236c6e 122
15129b1c 123int panic_on_cs_killed = 0;
5ba3f43e 124
39236c6e
A
125void
126cs_init(void)
127{
fe8ab488 128#if MACH_ASSERT && __x86_64__
15129b1c 129 panic_on_cs_killed = 1;
fe8ab488 130#endif /* MACH_ASSERT && __x86_64__ */
15129b1c
A
131 PE_parse_boot_argn("panic_on_cs_killed", &panic_on_cs_killed,
132 sizeof (panic_on_cs_killed));
39236c6e
A
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
5ba3f43e
A
145 PE_parse_boot_argn("cs_relax_platform_task_ports",
146 &cs_relax_platform_task_ports,
147 sizeof(cs_relax_platform_task_ports));
148
39236c6e 149 PE_parse_boot_argn("cs_debug", &cs_debug, sizeof (cs_debug));
3e170ce0
A
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));
39236c6e 154#endif
3e170ce0
A
155#endif /* !SECURE_KERNEL */
156
39236c6e
A
157 lck_grp_attr_t *attr = lck_grp_attr_alloc_init();
158 cs_lockgrp = lck_grp_alloc_init("KERNCS", attr);
39037602 159 lck_grp_attr_free(attr);
39236c6e
A
160}
161
162int
163cs_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);
490019cf
A
185 if (p->p_csflags & CS_VALID)
186 {
187 p->p_csflags |= CS_DEBUGGED;
188 }
5ba3f43e 189
39236c6e 190 proc_unlock(p);
5ba3f43e 191
39236c6e
A
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
197int
39037602 198cs_invalid_page(addr64_t vaddr, boolean_t *cs_killed)
39236c6e
A
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
39236c6e
A
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
fe8ab488 239 if (verbose)
39236c6e 240 printf("CODE SIGNING: cs_invalid_page(0x%llx): "
15129b1c 241 "p=%d[%s] final status 0x%x, %s page%s\n",
39236c6e 242 vaddr, p->p_pid, p->p_comm, p->p_csflags,
15129b1c 243 retval ? "denying" : "allowing (remove VALID)",
39236c6e 244 send_kill ? " sending SIGKILL" : "");
39236c6e 245
39037602
A
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 }
39236c6e
A
255
256
257 return retval;
258}
259
260/*
261 * Assumes p (if passed in) is locked with proc_lock().
262 */
263
264int
265cs_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
39037602
A
280/*
281 * Returns whether a given process is still valid.
282 */
283int
284cs_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
fe8ab488
A
296/*
297 * Library validation functions
298 */
299int
300cs_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
39037602
A
315/*
316 * <rdar://problem/24634089> added to allow system level library
317 * validation check at mac_cred_label_update_execve time
318 */
319int
320cs_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 Mach-O binary
329 * for a given blob.
330*/
331
332off_t
333csblob_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
344vm_size_t
345csblob_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
356vm_address_t
357csblob_get_addr(struct cs_blob *blob)
358{
359 return blob->csb_mem_kaddr;
360}
361
fe8ab488 362/*
3e170ce0 363 * Function: csblob_get_platform_binary
fe8ab488 364 *
3e170ce0
A
365 * Description: This function returns true if the binary is
366 * in the trust cache.
fe8ab488 367*/
fe8ab488 368
3e170ce0
A
369int
370csblob_get_platform_binary(struct cs_blob *blob)
371{
372 if (blob && blob->csb_platform_binary)
373 return 1;
374 return 0;
375}
fe8ab488 376
3e170ce0
A
377/*
378 * Function: csblob_get_flags
379 *
380 * Description: This function returns the flags for a given blob
381*/
fe8ab488 382
3e170ce0
A
383unsigned int
384csblob_get_flags(struct cs_blob *blob)
385{
39037602 386 return blob->csb_flags;
fe8ab488
A
387}
388
5ba3f43e
A
389/*
390 * Function: csblob_get_hashtype
391 *
392 * Description: This function returns the hash type for a given blob
393*/
394
395uint8_t
396csblob_get_hashtype(struct cs_blob const * const blob)
397{
398 return blob->csb_hashtype != NULL ? cs_hash_type(blob->csb_hashtype) : 0;
399}
400
fe8ab488
A
401/*
402 * Function: csproc_get_blob
403 *
404 * Description: This function returns the cs_blob
405 * for the process p
406 */
3e170ce0 407struct cs_blob *
fe8ab488
A
408csproc_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 return ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff);
417}
418
3e170ce0
A
419/*
420 * Function: csproc_get_blob
421 *
422 * Description: This function returns the cs_blob
423 * for the vnode vp
424 */
425struct cs_blob *
426csvnode_get_blob(struct vnode *vp, off_t offset)
427{
428 return ubc_cs_blob_get(vp, -1, offset);
429}
430
431/*
432 * Function: csblob_get_teamid
433 *
434 * Description: This function returns a pointer to the
435 * team id of csblob
436*/
437const char *
438csblob_get_teamid(struct cs_blob *csblob)
439{
440 return csblob->csb_teamid;
441}
442
443/*
444 * Function: csblob_get_identity
445 *
446 * Description: This function returns a pointer to the
447 * identity string
448 */
449const char *
450csblob_get_identity(struct cs_blob *csblob)
451{
452 const CS_CodeDirectory *cd;
453
454 cd = (const CS_CodeDirectory *)csblob_find_blob(csblob, CSSLOT_CODEDIRECTORY, CSMAGIC_CODEDIRECTORY);
455 if (cd == NULL)
456 return NULL;
457
458 if (cd->identOffset == 0)
459 return NULL;
460
461 return ((const char *)cd) + ntohl(cd->identOffset);
462}
463
464/*
465 * Function: csblob_get_cdhash
466 *
467 * Description: This function returns a pointer to the
468 * cdhash of csblob (20 byte array)
469 */
470const uint8_t *
471csblob_get_cdhash(struct cs_blob *csblob)
472{
473 return csblob->csb_cdhash;
474}
475
5ba3f43e
A
476/*
477 * Function: csblob_get_signer_type
478 *
479 * Description: This function returns the signer type
480 * as an integer
481 */
482unsigned int
483csblob_get_signer_type(struct cs_blob *csblob)
484{
485 return csblob->csb_signer_type;
486}
487
39037602
A
488void *
489csblob_entitlements_dictionary_copy(struct cs_blob *csblob)
490{
491 if (!csblob->csb_entitlements) return NULL;
492 osobject_retain(csblob->csb_entitlements);
493 return csblob->csb_entitlements;
494}
495
496void
497csblob_entitlements_dictionary_set(struct cs_blob *csblob, void * entitlements)
498{
499 assert(csblob->csb_entitlements == NULL);
500 if (entitlements) osobject_retain(entitlements);
501 csblob->csb_entitlements = entitlements;
502}
503
fe8ab488
A
504/*
505 * Function: csproc_get_teamid
506 *
507 * Description: This function returns a pointer to the
508 * team id of the process p
509*/
510const char *
511csproc_get_teamid(struct proc *p)
512{
513 struct cs_blob *csblob;
514
515 csblob = csproc_get_blob(p);
3e170ce0
A
516 if (csblob == NULL)
517 return NULL;
fe8ab488 518
3e170ce0 519 return csblob_get_teamid(csblob);
fe8ab488
A
520}
521
5ba3f43e
A
522/*
523 * Function: csproc_get_signer_type
524 *
525 * Description: This function returns the signer type
526 * of the process p
527*/
528unsigned int
529csproc_get_signer_type(struct proc *p)
530{
531 struct cs_blob *csblob;
532
533 csblob = csproc_get_blob(p);
534 if (csblob == NULL)
535 return CS_SIGNER_TYPE_UNKNOWN;
536
537 return csblob_get_signer_type(csblob);
538}
539
fe8ab488
A
540/*
541 * Function: csvnode_get_teamid
542 *
543 * Description: This function returns a pointer to the
544 * team id of the binary at the given offset in vnode vp
545*/
546const char *
547csvnode_get_teamid(struct vnode *vp, off_t offset)
548{
549 struct cs_blob *csblob;
550
551 if (vp == NULL)
552 return NULL;
553
554 csblob = ubc_cs_blob_get(vp, -1, offset);
3e170ce0
A
555 if (csblob == NULL)
556 return NULL;
fe8ab488 557
3e170ce0 558 return csblob_get_teamid(csblob);
fe8ab488
A
559}
560
561/*
562 * Function: csproc_get_platform_binary
563 *
564 * Description: This function returns the value
565 * of the platform_binary field for proc p
566 */
567int
568csproc_get_platform_binary(struct proc *p)
569{
570 struct cs_blob *csblob;
571
572 csblob = csproc_get_blob(p);
573
574 /* If there is no csblob this returns 0 because
575 it is true that it is not a platform binary */
576 return (csblob == NULL) ? 0 : csblob->csb_platform_binary;
577}
578
3e170ce0
A
579int
580csproc_get_platform_path(struct proc *p)
581{
582 struct cs_blob *csblob = csproc_get_blob(p);
583
584 return (csblob == NULL) ? 0 : csblob->csb_platform_path;
585}
586
5ba3f43e
A
587#if DEVELOPMENT || DEBUG
588void
589csproc_clear_platform_binary(struct proc *p)
590{
591 struct cs_blob *csblob = csproc_get_blob(p);
592
593 if (csblob == NULL) {
594 return;
595 }
596
597 if (cs_debug) {
598 printf("clearing platform binary on proc/task: pid = %d\n", p->p_pid);
599 }
600
601 csblob->csb_platform_binary = 0;
602 csblob->csb_platform_path = 0;
603 task_set_platform_binary(proc_task(p), FALSE);
604}
605#endif
606
743345f9
A
607/*
608 * Function: csproc_get_prod_signed
609 *
610 * Description: Returns 1 if process is not signed with a developer identity.
611 * Note the inverted meaning from the cs_flag to make the error case safer.
612 * Will go away with rdar://problem/28322552.
613 */
614int
615csproc_get_prod_signed(struct proc *p)
616{
617 return ((p->p_csflags & CS_DEV_CODE) == 0);
618}
619
620
fe8ab488
A
621/*
622 * Function: csfg_get_platform_binary
623 *
624 * Description: This function returns the
625 * platform binary field for the
626 * fileglob fg
627 */
628int
629csfg_get_platform_binary(struct fileglob *fg)
630{
631 int platform_binary = 0;
632 struct ubc_info *uip;
633 vnode_t vp;
634
635 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
636 return 0;
637
638 vp = (struct vnode *)fg->fg_data;
639 if (vp == NULL)
640 return 0;
641
642 vnode_lock(vp);
643 if (!UBCINFOEXISTS(vp))
644 goto out;
645
646 uip = vp->v_ubcinfo;
647 if (uip == NULL)
648 goto out;
649
650 if (uip->cs_blobs == NULL)
651 goto out;
652
653 /* It is OK to extract the teamid from the first blob
654 because all blobs of a vnode must have the same teamid */
655 platform_binary = uip->cs_blobs->csb_platform_binary;
656out:
657 vnode_unlock(vp);
658
659 return platform_binary;
660}
661
3e170ce0
A
662uint8_t *
663csfg_get_cdhash(struct fileglob *fg, uint64_t offset, size_t *cdhash_size)
664{
665 vnode_t vp;
666
667 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
668 return NULL;
669
670 vp = (struct vnode *)fg->fg_data;
671 if (vp == NULL)
672 return NULL;
673
674 struct cs_blob *csblob = NULL;
675 if ((csblob = ubc_cs_blob_get(vp, -1, offset)) == NULL)
676 return NULL;
677
678 if (cdhash_size)
679 *cdhash_size = CS_CDHASH_LEN;
680
681 return csblob->csb_cdhash;
682}
683
5ba3f43e
A
684/*
685 * Function: csfg_get_signer_type
686 *
687 * Description: This returns the signer type
688 * for the fileglob fg
689 */
690unsigned int
691csfg_get_signer_type(struct fileglob *fg)
692{
693 struct ubc_info *uip;
694 unsigned int signer_type = CS_SIGNER_TYPE_UNKNOWN;
695 vnode_t vp;
696
697 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
698 return CS_SIGNER_TYPE_UNKNOWN;
699
700 vp = (struct vnode *)fg->fg_data;
701 if (vp == NULL)
702 return CS_SIGNER_TYPE_UNKNOWN;
703
704 vnode_lock(vp);
705 if (!UBCINFOEXISTS(vp))
706 goto out;
707
708 uip = vp->v_ubcinfo;
709 if (uip == NULL)
710 goto out;
711
712 if (uip->cs_blobs == NULL)
713 goto out;
714
715 /* It is OK to extract the signer type from the first blob,
716 because all blobs of a vnode must have the same signer type. */
717 signer_type = uip->cs_blobs->csb_signer_type;
718out:
719 vnode_unlock(vp);
720
721 return signer_type;
722}
723
fe8ab488
A
724/*
725 * Function: csfg_get_teamid
726 *
727 * Description: This returns a pointer to
728 * the teamid for the fileglob fg
729 */
730const char *
731csfg_get_teamid(struct fileglob *fg)
732{
733 struct ubc_info *uip;
734 const char *str = NULL;
735 vnode_t vp;
736
737 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
738 return NULL;
739
740 vp = (struct vnode *)fg->fg_data;
741 if (vp == NULL)
742 return NULL;
743
744 vnode_lock(vp);
745 if (!UBCINFOEXISTS(vp))
746 goto out;
747
748 uip = vp->v_ubcinfo;
749 if (uip == NULL)
750 goto out;
751
752 if (uip->cs_blobs == NULL)
753 goto out;
754
755 /* It is OK to extract the teamid from the first blob
756 because all blobs of a vnode must have the same teamid */
757 str = uip->cs_blobs->csb_teamid;
758out:
759 vnode_unlock(vp);
760
761 return str;
762}
763
743345f9
A
764/*
765 * Function: csfg_get_prod_signed
766 *
767 * Description: Returns 1 if code is not signed with a developer identity.
768 * Note the inverted meaning from the cs_flag to make the error case safer.
769 * Will go away with rdar://problem/28322552.
770 */
771int
772csfg_get_prod_signed(struct fileglob *fg)
773{
774 struct ubc_info *uip;
775 vnode_t vp;
776 int prod_signed = 0;
777
778 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
5ba3f43e 779 return 0;
743345f9
A
780
781 vp = (struct vnode *)fg->fg_data;
782 if (vp == NULL)
5ba3f43e 783 return 0;
743345f9
A
784
785 vnode_lock(vp);
786 if (!UBCINFOEXISTS(vp))
787 goto out;
788
789 uip = vp->v_ubcinfo;
790 if (uip == NULL)
791 goto out;
792
793 if (uip->cs_blobs == NULL)
794 goto out;
795
796 /* It is OK to extract the flag from the first blob
797 because all blobs of a vnode must have the same cs_flags */
798 prod_signed = (uip->cs_blobs->csb_flags & CS_DEV_CODE) == 0;
799out:
800 vnode_unlock(vp);
801
802 return prod_signed;
803}
804
805
fe8ab488
A
806uint32_t
807cs_entitlement_flags(struct proc *p)
808{
809 return (p->p_csflags & CS_ENTITLEMENT_FLAGS);
810}
811
3e170ce0
A
812int
813cs_restricted(struct proc *p)
814{
815 return (p->p_csflags & CS_RESTRICT) ? 1 : 0;
816}
817
fe8ab488
A
818/*
819 * Function: csfg_get_path
820 *
821 * Description: This populates the buffer passed in
822 * with the path of the vnode
823 * When calling this, the fileglob
824 * cannot go away. The caller must have a
825 * a reference on the fileglob or fileproc
826 */
827int
828csfg_get_path(struct fileglob *fg, char *path, int *len)
829{
830 vnode_t vp = NULL;
831
832 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
833 return -1;
834
835 vp = (struct vnode *)fg->fg_data;
836
837 /* vn_getpath returns 0 for success,
838 or an error code */
839 return vn_getpath(vp, path, len);
840}
3e170ce0
A
841
842/* Retrieve the entitlements blob for a process.
843 * Returns:
844 * EINVAL no text vnode associated with the process
845 * EBADEXEC invalid code signing data
846 * 0 no error occurred
847 *
848 * On success, out_start and out_length will point to the
849 * entitlements blob if found; or will be set to NULL/zero
850 * if there were no entitlements.
851 */
852
853int
854cs_entitlements_blob_get(proc_t p, void **out_start, size_t *out_length)
855{
856 struct cs_blob *csblob;
857
858 *out_start = NULL;
859 *out_length = 0;
860
861 if (NULL == p->p_textvp)
862 return EINVAL;
863
864 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL)
865 return 0;
866
867 return csblob_get_entitlements(csblob, out_start, out_length);
868}
869
870/* Retrieve the codesign identity for a process.
871 * Returns:
872 * NULL an error occured
873 * string the cs_identity
874 */
875
876const char *
877cs_identity_get(proc_t p)
878{
879 struct cs_blob *csblob;
880
881 if (NULL == p->p_textvp)
882 return NULL;
883
884 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL)
885 return NULL;
886
887 return csblob_get_identity(csblob);
888}
889
890
891/* Retrieve the codesign blob for a process.
892 * Returns:
893 * EINVAL no text vnode associated with the process
894 * 0 no error occurred
895 *
896 * On success, out_start and out_length will point to the
897 * cms blob if found; or will be set to NULL/zero
898 * if there were no blob.
899 */
900
901int
902cs_blob_get(proc_t p, void **out_start, size_t *out_length)
903{
904 struct cs_blob *csblob;
905
906 *out_start = NULL;
907 *out_length = 0;
908
909 if (NULL == p->p_textvp)
910 return EINVAL;
911
912 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL)
913 return 0;
914
915 *out_start = (void *)csblob->csb_mem_kaddr;
916 *out_length = csblob->csb_mem_size;
917
918 return 0;
919}
920
921/*
922 * return cshash of a process, cdhash is of size CS_CDHASH_LEN
923 */
924
925uint8_t *
926cs_get_cdhash(struct proc *p)
927{
928 struct cs_blob *csblob;
929
930 if (NULL == p->p_textvp)
931 return NULL;
932
933 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL)
934 return NULL;
935
936 return csblob->csb_cdhash;
937}