]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_cs.c
xnu-3789.31.2.tar.gz
[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
88 #if CONFIG_ENFORCE_SIGNED_CODE
89 #define DEFAULT_CS_ENFORCEMENT_ENABLE 1
90 #else
91 #define DEFAULT_CS_ENFORCEMENT_ENABLE 0
92 #endif
93 SECURITY_READ_ONLY_LATE(int) cs_enforcement_enable = DEFAULT_CS_ENFORCEMENT_ENABLE;
94
95 #if CONFIG_ENFORCE_LIBRARY_VALIDATION
96 #define DEFAULT_CS_LIBRARY_VA_ENABLE 1
97 #else
98 #define DEFAULT_CS_LIBRARY_VA_ENABLE 0
99 #endif
100 SECURITY_READ_ONLY_LATE(int) cs_library_val_enable = DEFAULT_CS_LIBRARY_VA_ENABLE;
101
102 #endif /* !SECURE_KERNEL */
103 int cs_all_vnodes = 0;
104
105 static lck_grp_t *cs_lockgrp;
106
107 SYSCTL_INT(_vm, OID_AUTO, cs_force_kill, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_force_kill, 0, "");
108 SYSCTL_INT(_vm, OID_AUTO, cs_force_hard, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_force_hard, 0, "");
109 SYSCTL_INT(_vm, OID_AUTO, cs_debug, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_debug, 0, "");
110
111 SYSCTL_INT(_vm, OID_AUTO, cs_all_vnodes, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_all_vnodes, 0, "");
112
113 #if !SECURE_KERNEL
114 SYSCTL_INT(_vm, OID_AUTO, cs_enforcement, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_enforcement_enable, 0, "");
115 SYSCTL_INT(_vm, OID_AUTO, cs_enforcement_panic, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_enforcement_panic, 0, "");
116
117 #if !CONFIG_ENFORCE_LIBRARY_VALIDATION
118 SYSCTL_INT(_vm, OID_AUTO, cs_library_validation, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_library_val_enable, 0, "");
119 #endif
120 #endif /* !SECURE_KERNEL */
121
122 int panic_on_cs_killed = 0;
123 void
124 cs_init(void)
125 {
126 #if MACH_ASSERT && __x86_64__
127 panic_on_cs_killed = 1;
128 #endif /* MACH_ASSERT && __x86_64__ */
129 PE_parse_boot_argn("panic_on_cs_killed", &panic_on_cs_killed,
130 sizeof (panic_on_cs_killed));
131 #if !SECURE_KERNEL
132 int disable_cs_enforcement = 0;
133 PE_parse_boot_argn("cs_enforcement_disable", &disable_cs_enforcement,
134 sizeof (disable_cs_enforcement));
135 if (disable_cs_enforcement) {
136 cs_enforcement_enable = 0;
137 } else {
138 int panic = 0;
139 PE_parse_boot_argn("cs_enforcement_panic", &panic, sizeof(panic));
140 cs_enforcement_panic = (panic != 0);
141 }
142
143 PE_parse_boot_argn("cs_debug", &cs_debug, sizeof (cs_debug));
144
145 #if !CONFIG_ENFORCE_LIBRARY_VALIDATION
146 PE_parse_boot_argn("cs_library_val_enable", &cs_library_val_enable,
147 sizeof (cs_library_val_enable));
148 #endif
149 #endif /* !SECURE_KERNEL */
150
151 lck_grp_attr_t *attr = lck_grp_attr_alloc_init();
152 cs_lockgrp = lck_grp_alloc_init("KERNCS", attr);
153 lck_grp_attr_free(attr);
154 }
155
156 int
157 cs_allow_invalid(struct proc *p)
158 {
159 #if MACH_ASSERT
160 lck_mtx_assert(&p->p_mlock, LCK_MTX_ASSERT_NOTOWNED);
161 #endif
162 #if CONFIG_MACF && CONFIG_ENFORCE_SIGNED_CODE
163 /* There needs to be a MAC policy to implement this hook, or else the
164 * kill bits will be cleared here every time. If we have
165 * CONFIG_ENFORCE_SIGNED_CODE, we can assume there is a policy
166 * implementing the hook.
167 */
168 if( 0 != mac_proc_check_run_cs_invalid(p)) {
169 if(cs_debug) printf("CODE SIGNING: cs_allow_invalid() "
170 "not allowed: pid %d\n",
171 p->p_pid);
172 return 0;
173 }
174 if(cs_debug) printf("CODE SIGNING: cs_allow_invalid() "
175 "allowed: pid %d\n",
176 p->p_pid);
177 proc_lock(p);
178 p->p_csflags &= ~(CS_KILL | CS_HARD);
179 if (p->p_csflags & CS_VALID)
180 {
181 p->p_csflags |= CS_DEBUGGED;
182 }
183 proc_unlock(p);
184 vm_map_switch_protect(get_task_map(p->task), FALSE);
185 #endif
186 return (p->p_csflags & (CS_KILL | CS_HARD)) == 0;
187 }
188
189 int
190 cs_invalid_page(addr64_t vaddr, boolean_t *cs_killed)
191 {
192 struct proc *p;
193 int send_kill = 0, retval = 0, verbose = cs_debug;
194 uint32_t csflags;
195
196 p = current_proc();
197
198 if (verbose)
199 printf("CODE SIGNING: cs_invalid_page(0x%llx): p=%d[%s]\n",
200 vaddr, p->p_pid, p->p_comm);
201
202 proc_lock(p);
203
204 /* XXX for testing */
205 if (cs_force_kill)
206 p->p_csflags |= CS_KILL;
207 if (cs_force_hard)
208 p->p_csflags |= CS_HARD;
209
210 /* CS_KILL triggers a kill signal, and no you can't have the page. Nothing else. */
211 if (p->p_csflags & CS_KILL) {
212 p->p_csflags |= CS_KILLED;
213 cs_procs_killed++;
214 send_kill = 1;
215 retval = 1;
216 }
217
218 /* CS_HARD means fail the mapping operation so the process stays valid. */
219 if (p->p_csflags & CS_HARD) {
220 retval = 1;
221 } else {
222 if (p->p_csflags & CS_VALID) {
223 p->p_csflags &= ~CS_VALID;
224 cs_procs_invalidated++;
225 verbose = 1;
226 }
227 }
228 csflags = p->p_csflags;
229 proc_unlock(p);
230
231 if (verbose)
232 printf("CODE SIGNING: cs_invalid_page(0x%llx): "
233 "p=%d[%s] final status 0x%x, %s page%s\n",
234 vaddr, p->p_pid, p->p_comm, p->p_csflags,
235 retval ? "denying" : "allowing (remove VALID)",
236 send_kill ? " sending SIGKILL" : "");
237
238 if (send_kill) {
239 /* We will set the exit reason for the thread later */
240 threadsignal(current_thread(), SIGKILL, EXC_BAD_ACCESS, FALSE);
241 if (cs_killed) {
242 *cs_killed = TRUE;
243 }
244 } else if (cs_killed) {
245 *cs_killed = FALSE;
246 }
247
248
249 return retval;
250 }
251
252 /*
253 * Assumes p (if passed in) is locked with proc_lock().
254 */
255
256 int
257 cs_enforcement(struct proc *p)
258 {
259
260 if (cs_enforcement_enable)
261 return 1;
262
263 if (p == NULL)
264 p = current_proc();
265
266 if (p != NULL && (p->p_csflags & CS_ENFORCEMENT))
267 return 1;
268
269 return 0;
270 }
271
272 /*
273 * Returns whether a given process is still valid.
274 */
275 int
276 cs_valid(struct proc *p)
277 {
278
279 if (p == NULL)
280 p = current_proc();
281
282 if (p != NULL && (p->p_csflags & CS_VALID))
283 return 1;
284
285 return 0;
286 }
287
288 /*
289 * Library validation functions
290 */
291 int
292 cs_require_lv(struct proc *p)
293 {
294
295 if (cs_library_val_enable)
296 return 1;
297
298 if (p == NULL)
299 p = current_proc();
300
301 if (p != NULL && (p->p_csflags & CS_REQUIRE_LV))
302 return 1;
303
304 return 0;
305 }
306
307 /*
308 * <rdar://problem/24634089> added to allow system level library
309 * validation check at mac_cred_label_update_execve time
310 */
311 int
312 cs_system_require_lv(void)
313 {
314 return cs_library_val_enable ? 1 : 0;
315 }
316
317 /*
318 * Function: csblob_get_base_offset
319 *
320 * Description: This function returns the base offset into the Mach-O binary
321 * for a given blob.
322 */
323
324 off_t
325 csblob_get_base_offset(struct cs_blob *blob)
326 {
327 return blob->csb_base_offset;
328 }
329
330 /*
331 * Function: csblob_get_size
332 *
333 * Description: This function returns the size of a given blob.
334 */
335
336 vm_size_t
337 csblob_get_size(struct cs_blob *blob)
338 {
339 return blob->csb_mem_size;
340 }
341
342 /*
343 * Function: csblob_get_addr
344 *
345 * Description: This function returns the address of a given blob.
346 */
347
348 vm_address_t
349 csblob_get_addr(struct cs_blob *blob)
350 {
351 return blob->csb_mem_kaddr;
352 }
353
354 /*
355 * Function: csblob_get_platform_binary
356 *
357 * Description: This function returns true if the binary is
358 * in the trust cache.
359 */
360
361 int
362 csblob_get_platform_binary(struct cs_blob *blob)
363 {
364 if (blob && blob->csb_platform_binary)
365 return 1;
366 return 0;
367 }
368
369 /*
370 * Function: csblob_get_flags
371 *
372 * Description: This function returns the flags for a given blob
373 */
374
375 unsigned int
376 csblob_get_flags(struct cs_blob *blob)
377 {
378 return blob->csb_flags;
379 }
380
381 /*
382 * Function: csproc_get_blob
383 *
384 * Description: This function returns the cs_blob
385 * for the process p
386 */
387 struct cs_blob *
388 csproc_get_blob(struct proc *p)
389 {
390 if (NULL == p)
391 return NULL;
392
393 if (NULL == p->p_textvp)
394 return NULL;
395
396 return ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff);
397 }
398
399 /*
400 * Function: csproc_get_blob
401 *
402 * Description: This function returns the cs_blob
403 * for the vnode vp
404 */
405 struct cs_blob *
406 csvnode_get_blob(struct vnode *vp, off_t offset)
407 {
408 return ubc_cs_blob_get(vp, -1, offset);
409 }
410
411 /*
412 * Function: csblob_get_teamid
413 *
414 * Description: This function returns a pointer to the
415 * team id of csblob
416 */
417 const char *
418 csblob_get_teamid(struct cs_blob *csblob)
419 {
420 return csblob->csb_teamid;
421 }
422
423 /*
424 * Function: csblob_get_identity
425 *
426 * Description: This function returns a pointer to the
427 * identity string
428 */
429 const char *
430 csblob_get_identity(struct cs_blob *csblob)
431 {
432 const CS_CodeDirectory *cd;
433
434 cd = (const CS_CodeDirectory *)csblob_find_blob(csblob, CSSLOT_CODEDIRECTORY, CSMAGIC_CODEDIRECTORY);
435 if (cd == NULL)
436 return NULL;
437
438 if (cd->identOffset == 0)
439 return NULL;
440
441 return ((const char *)cd) + ntohl(cd->identOffset);
442 }
443
444 /*
445 * Function: csblob_get_cdhash
446 *
447 * Description: This function returns a pointer to the
448 * cdhash of csblob (20 byte array)
449 */
450 const uint8_t *
451 csblob_get_cdhash(struct cs_blob *csblob)
452 {
453 return csblob->csb_cdhash;
454 }
455
456 void *
457 csblob_entitlements_dictionary_copy(struct cs_blob *csblob)
458 {
459 if (!csblob->csb_entitlements) return NULL;
460 osobject_retain(csblob->csb_entitlements);
461 return csblob->csb_entitlements;
462 }
463
464 void
465 csblob_entitlements_dictionary_set(struct cs_blob *csblob, void * entitlements)
466 {
467 assert(csblob->csb_entitlements == NULL);
468 if (entitlements) osobject_retain(entitlements);
469 csblob->csb_entitlements = entitlements;
470 }
471
472 /*
473 * Function: csproc_get_teamid
474 *
475 * Description: This function returns a pointer to the
476 * team id of the process p
477 */
478 const char *
479 csproc_get_teamid(struct proc *p)
480 {
481 struct cs_blob *csblob;
482
483 csblob = csproc_get_blob(p);
484 if (csblob == NULL)
485 return NULL;
486
487 return csblob_get_teamid(csblob);
488 }
489
490 /*
491 * Function: csvnode_get_teamid
492 *
493 * Description: This function returns a pointer to the
494 * team id of the binary at the given offset in vnode vp
495 */
496 const char *
497 csvnode_get_teamid(struct vnode *vp, off_t offset)
498 {
499 struct cs_blob *csblob;
500
501 if (vp == NULL)
502 return NULL;
503
504 csblob = ubc_cs_blob_get(vp, -1, offset);
505 if (csblob == NULL)
506 return NULL;
507
508 return csblob_get_teamid(csblob);
509 }
510
511 /*
512 * Function: csproc_get_platform_binary
513 *
514 * Description: This function returns the value
515 * of the platform_binary field for proc p
516 */
517 int
518 csproc_get_platform_binary(struct proc *p)
519 {
520 struct cs_blob *csblob;
521
522 csblob = csproc_get_blob(p);
523
524 /* If there is no csblob this returns 0 because
525 it is true that it is not a platform binary */
526 return (csblob == NULL) ? 0 : csblob->csb_platform_binary;
527 }
528
529 int
530 csproc_get_platform_path(struct proc *p)
531 {
532 struct cs_blob *csblob = csproc_get_blob(p);
533
534 return (csblob == NULL) ? 0 : csblob->csb_platform_path;
535 }
536
537 /*
538 * Function: csproc_get_prod_signed
539 *
540 * Description: Returns 1 if process is not signed with a developer identity.
541 * Note the inverted meaning from the cs_flag to make the error case safer.
542 * Will go away with rdar://problem/28322552.
543 */
544 int
545 csproc_get_prod_signed(struct proc *p)
546 {
547 return ((p->p_csflags & CS_DEV_CODE) == 0);
548 }
549
550
551 /*
552 * Function: csfg_get_platform_binary
553 *
554 * Description: This function returns the
555 * platform binary field for the
556 * fileglob fg
557 */
558 int
559 csfg_get_platform_binary(struct fileglob *fg)
560 {
561 int platform_binary = 0;
562 struct ubc_info *uip;
563 vnode_t vp;
564
565 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
566 return 0;
567
568 vp = (struct vnode *)fg->fg_data;
569 if (vp == NULL)
570 return 0;
571
572 vnode_lock(vp);
573 if (!UBCINFOEXISTS(vp))
574 goto out;
575
576 uip = vp->v_ubcinfo;
577 if (uip == NULL)
578 goto out;
579
580 if (uip->cs_blobs == NULL)
581 goto out;
582
583 /* It is OK to extract the teamid from the first blob
584 because all blobs of a vnode must have the same teamid */
585 platform_binary = uip->cs_blobs->csb_platform_binary;
586 out:
587 vnode_unlock(vp);
588
589 return platform_binary;
590 }
591
592 uint8_t *
593 csfg_get_cdhash(struct fileglob *fg, uint64_t offset, size_t *cdhash_size)
594 {
595 vnode_t vp;
596
597 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
598 return NULL;
599
600 vp = (struct vnode *)fg->fg_data;
601 if (vp == NULL)
602 return NULL;
603
604 struct cs_blob *csblob = NULL;
605 if ((csblob = ubc_cs_blob_get(vp, -1, offset)) == NULL)
606 return NULL;
607
608 if (cdhash_size)
609 *cdhash_size = CS_CDHASH_LEN;
610
611 return csblob->csb_cdhash;
612 }
613
614 /*
615 * Function: csfg_get_teamid
616 *
617 * Description: This returns a pointer to
618 * the teamid for the fileglob fg
619 */
620 const char *
621 csfg_get_teamid(struct fileglob *fg)
622 {
623 struct ubc_info *uip;
624 const char *str = NULL;
625 vnode_t vp;
626
627 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
628 return NULL;
629
630 vp = (struct vnode *)fg->fg_data;
631 if (vp == NULL)
632 return NULL;
633
634 vnode_lock(vp);
635 if (!UBCINFOEXISTS(vp))
636 goto out;
637
638 uip = vp->v_ubcinfo;
639 if (uip == NULL)
640 goto out;
641
642 if (uip->cs_blobs == NULL)
643 goto out;
644
645 /* It is OK to extract the teamid from the first blob
646 because all blobs of a vnode must have the same teamid */
647 str = uip->cs_blobs->csb_teamid;
648 out:
649 vnode_unlock(vp);
650
651 return str;
652 }
653
654 /*
655 * Function: csfg_get_prod_signed
656 *
657 * Description: Returns 1 if code is not signed with a developer identity.
658 * Note the inverted meaning from the cs_flag to make the error case safer.
659 * Will go away with rdar://problem/28322552.
660 */
661 int
662 csfg_get_prod_signed(struct fileglob *fg)
663 {
664 struct ubc_info *uip;
665 vnode_t vp;
666 int prod_signed = 0;
667
668 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
669 return NULL;
670
671 vp = (struct vnode *)fg->fg_data;
672 if (vp == NULL)
673 return NULL;
674
675 vnode_lock(vp);
676 if (!UBCINFOEXISTS(vp))
677 goto out;
678
679 uip = vp->v_ubcinfo;
680 if (uip == NULL)
681 goto out;
682
683 if (uip->cs_blobs == NULL)
684 goto out;
685
686 /* It is OK to extract the flag from the first blob
687 because all blobs of a vnode must have the same cs_flags */
688 prod_signed = (uip->cs_blobs->csb_flags & CS_DEV_CODE) == 0;
689 out:
690 vnode_unlock(vp);
691
692 return prod_signed;
693 }
694
695
696 uint32_t
697 cs_entitlement_flags(struct proc *p)
698 {
699 return (p->p_csflags & CS_ENTITLEMENT_FLAGS);
700 }
701
702 int
703 cs_restricted(struct proc *p)
704 {
705 return (p->p_csflags & CS_RESTRICT) ? 1 : 0;
706 }
707
708 /*
709 * Function: csfg_get_path
710 *
711 * Description: This populates the buffer passed in
712 * with the path of the vnode
713 * When calling this, the fileglob
714 * cannot go away. The caller must have a
715 * a reference on the fileglob or fileproc
716 */
717 int
718 csfg_get_path(struct fileglob *fg, char *path, int *len)
719 {
720 vnode_t vp = NULL;
721
722 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
723 return -1;
724
725 vp = (struct vnode *)fg->fg_data;
726
727 /* vn_getpath returns 0 for success,
728 or an error code */
729 return vn_getpath(vp, path, len);
730 }
731
732 /* Retrieve the entitlements blob for a process.
733 * Returns:
734 * EINVAL no text vnode associated with the process
735 * EBADEXEC invalid code signing data
736 * 0 no error occurred
737 *
738 * On success, out_start and out_length will point to the
739 * entitlements blob if found; or will be set to NULL/zero
740 * if there were no entitlements.
741 */
742
743 int
744 cs_entitlements_blob_get(proc_t p, void **out_start, size_t *out_length)
745 {
746 struct cs_blob *csblob;
747
748 *out_start = NULL;
749 *out_length = 0;
750
751 if (NULL == p->p_textvp)
752 return EINVAL;
753
754 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL)
755 return 0;
756
757 return csblob_get_entitlements(csblob, out_start, out_length);
758 }
759
760 /* Retrieve the codesign identity for a process.
761 * Returns:
762 * NULL an error occured
763 * string the cs_identity
764 */
765
766 const char *
767 cs_identity_get(proc_t p)
768 {
769 struct cs_blob *csblob;
770
771 if (NULL == p->p_textvp)
772 return NULL;
773
774 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL)
775 return NULL;
776
777 return csblob_get_identity(csblob);
778 }
779
780
781 /* Retrieve the codesign blob for a process.
782 * Returns:
783 * EINVAL no text vnode associated with the process
784 * 0 no error occurred
785 *
786 * On success, out_start and out_length will point to the
787 * cms blob if found; or will be set to NULL/zero
788 * if there were no blob.
789 */
790
791 int
792 cs_blob_get(proc_t p, void **out_start, size_t *out_length)
793 {
794 struct cs_blob *csblob;
795
796 *out_start = NULL;
797 *out_length = 0;
798
799 if (NULL == p->p_textvp)
800 return EINVAL;
801
802 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL)
803 return 0;
804
805 *out_start = (void *)csblob->csb_mem_kaddr;
806 *out_length = csblob->csb_mem_size;
807
808 return 0;
809 }
810
811 /*
812 * return cshash of a process, cdhash is of size CS_CDHASH_LEN
813 */
814
815 uint8_t *
816 cs_get_cdhash(struct proc *p)
817 {
818 struct cs_blob *csblob;
819
820 if (NULL == p->p_textvp)
821 return NULL;
822
823 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL)
824 return NULL;
825
826 return csblob->csb_cdhash;
827 }