2 * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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>
39 #include <sys/fcntl.h>
41 #include <sys/file_internal.h>
42 #include <sys/kauth.h>
43 #include <sys/mount.h>
46 #include <sys/socketvar.h>
47 #include <sys/vnode.h>
48 #include <sys/vnode_internal.h>
51 #include <sys/ubc_internal.h>
53 #include <security/mac.h>
54 #include <security/mac_policy.h>
55 #include <security/mac_framework.h>
57 #include <mach/mach_types.h>
58 #include <mach/vm_map.h>
59 #include <mach/mach_vm.h>
61 #include <kern/kern_types.h>
62 #include <kern/task.h>
64 #include <vm/vm_map.h>
65 #include <vm/vm_kern.h>
68 #include <kern/assert.h>
70 #include <pexpert/pexpert.h>
72 #include <mach/shared_region.h>
74 #include <libkern/section_keywords.h>
76 unsigned long cs_procs_killed
= 0;
77 unsigned long cs_procs_invalidated
= 0;
79 int cs_force_kill
= 0;
80 int cs_force_hard
= 0;
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;
89 #if CONFIG_ENFORCE_SIGNED_CODE
90 #define DEFAULT_CS_ENFORCEMENT_ENABLE 1
92 #define DEFAULT_CS_ENFORCEMENT_ENABLE 0
94 SECURITY_READ_ONLY_LATE(int) cs_enforcement_enable
= DEFAULT_CS_ENFORCEMENT_ENABLE
;
96 #if CONFIG_ENFORCE_LIBRARY_VALIDATION
97 #define DEFAULT_CS_LIBRARY_VA_ENABLE 1
99 #define DEFAULT_CS_LIBRARY_VA_ENABLE 0
101 SECURITY_READ_ONLY_LATE(int) cs_library_val_enable
= DEFAULT_CS_LIBRARY_VA_ENABLE
;
103 #endif /* !SECURE_KERNEL */
104 int cs_all_vnodes
= 0;
106 static lck_grp_t
*cs_lockgrp
;
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, "");
112 SYSCTL_INT(_vm
, OID_AUTO
, cs_all_vnodes
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &cs_all_vnodes
, 0, "");
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, "");
118 #if !CONFIG_ENFORCE_LIBRARY_VALIDATION
119 SYSCTL_INT(_vm
, OID_AUTO
, cs_library_validation
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &cs_library_val_enable
, 0, "");
121 #endif /* !SECURE_KERNEL */
123 int panic_on_cs_killed
= 0;
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
));
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;
141 PE_parse_boot_argn("cs_enforcement_panic", &panic
, sizeof(panic
));
142 cs_enforcement_panic
= (panic
!= 0);
145 PE_parse_boot_argn("cs_relax_platform_task_ports",
146 &cs_relax_platform_task_ports
,
147 sizeof(cs_relax_platform_task_ports
));
149 PE_parse_boot_argn("cs_debug", &cs_debug
, sizeof (cs_debug
));
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
));
155 #endif /* !SECURE_KERNEL */
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
);
163 cs_allow_invalid(struct proc
*p
)
166 lck_mtx_assert(&p
->p_mlock
, LCK_MTX_ASSERT_NOTOWNED
);
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.
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",
180 if(cs_debug
) printf("CODE SIGNING: cs_allow_invalid() "
184 p
->p_csflags
&= ~(CS_KILL
| CS_HARD
);
185 if (p
->p_csflags
& CS_VALID
)
187 p
->p_csflags
|= CS_DEBUGGED
;
192 vm_map_switch_protect(get_task_map(p
->task
), FALSE
);
194 return (p
->p_csflags
& (CS_KILL
| CS_HARD
)) == 0;
198 cs_invalid_page(addr64_t vaddr
, boolean_t
*cs_killed
)
201 int send_kill
= 0, retval
= 0, verbose
= cs_debug
;
207 printf("CODE SIGNING: cs_invalid_page(0x%llx): p=%d[%s]\n",
208 vaddr
, p
->p_pid
, p
->p_comm
);
212 /* XXX for testing */
214 p
->p_csflags
|= CS_KILL
;
216 p
->p_csflags
|= CS_HARD
;
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
;
226 /* CS_HARD means fail the mapping operation so the process stays valid. */
227 if (p
->p_csflags
& CS_HARD
) {
230 if (p
->p_csflags
& CS_VALID
) {
231 p
->p_csflags
&= ~CS_VALID
;
232 cs_procs_invalidated
++;
236 csflags
= p
->p_csflags
;
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" : "");
247 /* We will set the exit reason for the thread later */
248 threadsignal(current_thread(), SIGKILL
, EXC_BAD_ACCESS
, FALSE
);
252 } else if (cs_killed
) {
261 * Assumes p (if passed in) is locked with proc_lock().
265 cs_enforcement(struct proc
*p
)
268 if (cs_enforcement_enable
)
274 if (p
!= NULL
&& (p
->p_csflags
& CS_ENFORCEMENT
))
281 * Returns whether a given process is still valid.
284 cs_valid(struct proc
*p
)
290 if (p
!= NULL
&& (p
->p_csflags
& CS_VALID
))
297 * Library validation functions
300 cs_require_lv(struct proc
*p
)
303 if (cs_library_val_enable
)
309 if (p
!= NULL
&& (p
->p_csflags
& CS_REQUIRE_LV
))
316 * <rdar://problem/24634089> added to allow system level library
317 * validation check at mac_cred_label_update_execve time
320 cs_system_require_lv(void)
322 return cs_library_val_enable
? 1 : 0;
326 * Function: csblob_get_base_offset
328 * Description: This function returns the base offset into the (possibly universal) binary
333 csblob_get_base_offset(struct cs_blob
*blob
)
335 return blob
->csb_base_offset
;
339 * Function: csblob_get_size
341 * Description: This function returns the size of a given blob.
345 csblob_get_size(struct cs_blob
*blob
)
347 return blob
->csb_mem_size
;
351 * Function: csblob_get_addr
353 * Description: This function returns the address of a given blob.
357 csblob_get_addr(struct cs_blob
*blob
)
359 return blob
->csb_mem_kaddr
;
363 * Function: csblob_get_platform_binary
365 * Description: This function returns true if the binary is
366 * in the trust cache.
370 csblob_get_platform_binary(struct cs_blob
*blob
)
372 if (blob
&& blob
->csb_platform_binary
)
378 * Function: csblob_get_flags
380 * Description: This function returns the flags for a given blob
384 csblob_get_flags(struct cs_blob
*blob
)
386 return blob
->csb_flags
;
390 * Function: csblob_get_hashtype
392 * Description: This function returns the hash type for a given blob
396 csblob_get_hashtype(struct cs_blob
const * const blob
)
398 return blob
->csb_hashtype
!= NULL
? cs_hash_type(blob
->csb_hashtype
) : 0;
402 * Function: csproc_get_blob
404 * Description: This function returns the cs_blob
408 csproc_get_blob(struct proc
*p
)
413 if (NULL
== p
->p_textvp
)
416 if ((p
->p_csflags
& CS_SIGNED
) == 0) {
420 return ubc_cs_blob_get(p
->p_textvp
, -1, p
->p_textoff
);
424 * Function: csvnode_get_blob
426 * Description: This function returns the cs_blob
430 csvnode_get_blob(struct vnode
*vp
, off_t offset
)
432 return ubc_cs_blob_get(vp
, -1, offset
);
436 * Function: csblob_get_teamid
438 * Description: This function returns a pointer to the
442 csblob_get_teamid(struct cs_blob
*csblob
)
444 return csblob
->csb_teamid
;
448 * Function: csblob_get_identity
450 * Description: This function returns a pointer to the
454 csblob_get_identity(struct cs_blob
*csblob
)
456 const CS_CodeDirectory
*cd
;
458 cd
= (const CS_CodeDirectory
*)csblob_find_blob(csblob
, CSSLOT_CODEDIRECTORY
, CSMAGIC_CODEDIRECTORY
);
462 if (cd
->identOffset
== 0)
465 return ((const char *)cd
) + ntohl(cd
->identOffset
);
469 * Function: csblob_get_cdhash
471 * Description: This function returns a pointer to the
472 * cdhash of csblob (20 byte array)
475 csblob_get_cdhash(struct cs_blob
*csblob
)
477 return csblob
->csb_cdhash
;
481 * Function: csblob_get_signer_type
483 * Description: This function returns the signer type
487 csblob_get_signer_type(struct cs_blob
*csblob
)
489 return csblob
->csb_signer_type
;
493 csblob_entitlements_dictionary_copy(struct cs_blob
*csblob
)
495 if (!csblob
->csb_entitlements
) return NULL
;
496 osobject_retain(csblob
->csb_entitlements
);
497 return csblob
->csb_entitlements
;
501 csblob_entitlements_dictionary_set(struct cs_blob
*csblob
, void * entitlements
)
503 assert(csblob
->csb_entitlements
== NULL
);
504 if (entitlements
) osobject_retain(entitlements
);
505 csblob
->csb_entitlements
= entitlements
;
509 * Function: csproc_get_teamid
511 * Description: This function returns a pointer to the
512 * team id of the process p
515 csproc_get_teamid(struct proc
*p
)
517 struct cs_blob
*csblob
;
519 csblob
= csproc_get_blob(p
);
523 return csblob_get_teamid(csblob
);
527 * Function: csproc_get_signer_type
529 * Description: This function returns the signer type
533 csproc_get_signer_type(struct proc
*p
)
535 struct cs_blob
*csblob
;
537 csblob
= csproc_get_blob(p
);
539 return CS_SIGNER_TYPE_UNKNOWN
;
541 return csblob_get_signer_type(csblob
);
545 * Function: csvnode_get_teamid
547 * Description: This function returns a pointer to the
548 * team id of the binary at the given offset in vnode vp
551 csvnode_get_teamid(struct vnode
*vp
, off_t offset
)
553 struct cs_blob
*csblob
;
558 csblob
= ubc_cs_blob_get(vp
, -1, offset
);
562 return csblob_get_teamid(csblob
);
566 * Function: csproc_get_platform_binary
568 * Description: This function returns the value
569 * of the platform_binary field for proc p
572 csproc_get_platform_binary(struct proc
*p
)
574 struct cs_blob
*csblob
;
576 csblob
= csproc_get_blob(p
);
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
;
584 csproc_get_platform_path(struct proc
*p
)
586 struct cs_blob
*csblob
;
588 csblob
= csproc_get_blob(p
);
590 return (csblob
== NULL
) ? 0 : csblob
->csb_platform_path
;
593 #if DEVELOPMENT || DEBUG
595 csproc_clear_platform_binary(struct proc
*p
)
597 struct cs_blob
*csblob
= csproc_get_blob(p
);
599 if (csblob
== NULL
) {
604 printf("clearing platform binary on proc/task: pid = %d\n", p
->p_pid
);
607 csblob
->csb_platform_binary
= 0;
608 csblob
->csb_platform_path
= 0;
609 task_set_platform_binary(proc_task(p
), FALSE
);
614 * Function: csproc_get_prod_signed
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.
621 csproc_get_prod_signed(struct proc
*p
)
623 return ((p
->p_csflags
& CS_DEV_CODE
) == 0);
628 * Function: csfg_get_platform_binary
630 * Description: This function returns the
631 * platform binary field for the
635 csfg_get_platform_binary(struct fileglob
*fg
)
637 int platform_binary
= 0;
638 struct ubc_info
*uip
;
641 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
)
644 vp
= (struct vnode
*)fg
->fg_data
;
649 if (!UBCINFOEXISTS(vp
))
656 if (uip
->cs_blobs
== NULL
)
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
;
665 return platform_binary
;
669 csfg_get_cdhash(struct fileglob
*fg
, uint64_t offset
, size_t *cdhash_size
)
673 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
)
676 vp
= (struct vnode
*)fg
->fg_data
;
680 struct cs_blob
*csblob
= NULL
;
681 if ((csblob
= ubc_cs_blob_get(vp
, -1, offset
)) == NULL
)
685 *cdhash_size
= CS_CDHASH_LEN
;
687 return csblob
->csb_cdhash
;
691 * Function: csfg_get_signer_type
693 * Description: This returns the signer type
694 * for the fileglob fg
697 csfg_get_signer_type(struct fileglob
*fg
)
699 struct ubc_info
*uip
;
700 unsigned int signer_type
= CS_SIGNER_TYPE_UNKNOWN
;
703 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
)
704 return CS_SIGNER_TYPE_UNKNOWN
;
706 vp
= (struct vnode
*)fg
->fg_data
;
708 return CS_SIGNER_TYPE_UNKNOWN
;
711 if (!UBCINFOEXISTS(vp
))
718 if (uip
->cs_blobs
== NULL
)
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
;
731 * Function: csfg_get_teamid
733 * Description: This returns a pointer to
734 * the teamid for the fileglob fg
737 csfg_get_teamid(struct fileglob
*fg
)
739 struct ubc_info
*uip
;
740 const char *str
= NULL
;
743 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
)
746 vp
= (struct vnode
*)fg
->fg_data
;
751 if (!UBCINFOEXISTS(vp
))
758 if (uip
->cs_blobs
== NULL
)
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
;
771 * Function: csfg_get_prod_signed
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.
778 csfg_get_prod_signed(struct fileglob
*fg
)
780 struct ubc_info
*uip
;
784 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
)
787 vp
= (struct vnode
*)fg
->fg_data
;
792 if (!UBCINFOEXISTS(vp
))
799 if (uip
->cs_blobs
== NULL
)
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;
812 * Function: csfg_get_identity
814 * Description: This function returns the codesign identity
818 csfg_get_identity(struct fileglob
*fg
, off_t offset
)
821 struct cs_blob
*csblob
= NULL
;
823 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
)
826 vp
= (struct vnode
*)fg
->fg_data
;
830 csblob
= ubc_cs_blob_get(vp
, -1, offset
);
834 return csblob_get_identity(csblob
);
838 * Function: csfg_get_platform_identifier
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.
845 csfg_get_platform_identifier(struct fileglob
*fg
, off_t offset
)
849 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
)
852 vp
= (struct vnode
*)fg
->fg_data
;
856 return csvnode_get_platform_identifier(vp
, offset
);
860 * Function: csvnode_get_platform_identifier
862 * Description: This function returns the codesign platform
863 * identifier for the vnode. Assumes a vnode reference
867 csvnode_get_platform_identifier(struct vnode
*vp
, off_t offset
)
869 struct cs_blob
*csblob
;
870 const CS_CodeDirectory
*code_dir
;
872 csblob
= ubc_cs_blob_get(vp
, -1, offset
);
876 code_dir
= csblob
->csb_cd
;
877 if (code_dir
== NULL
|| ntohl(code_dir
->length
) < 8)
880 return code_dir
->platform
;
884 * Function: csproc_get_platform_identifier
886 * Description: This function returns the codesign platform
887 * identifier for the proc. Assumes proc will remain
888 * valid through call.
891 csproc_get_platform_identifier(struct proc
*p
)
893 if (NULL
== p
->p_textvp
)
896 return csvnode_get_platform_identifier(p
->p_textvp
, p
->p_textoff
);
900 cs_entitlement_flags(struct proc
*p
)
902 return (p
->p_csflags
& CS_ENTITLEMENT_FLAGS
);
906 cs_restricted(struct proc
*p
)
908 return (p
->p_csflags
& CS_RESTRICT
) ? 1 : 0;
912 * Function: csfg_get_path
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
921 csfg_get_path(struct fileglob
*fg
, char *path
, int *len
)
925 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
)
928 vp
= (struct vnode
*)fg
->fg_data
;
930 /* vn_getpath returns 0 for success,
932 return vn_getpath(vp
, path
, len
);
935 /* Retrieve the entitlements blob for a process.
937 * EINVAL no text vnode associated with the process
938 * EBADEXEC invalid code signing data
939 * 0 no error occurred
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.
947 cs_entitlements_blob_get(proc_t p
, void **out_start
, size_t *out_length
)
949 struct cs_blob
*csblob
;
954 if ((p
->p_csflags
& CS_SIGNED
) == 0) {
958 if (NULL
== p
->p_textvp
)
961 if ((csblob
= ubc_cs_blob_get(p
->p_textvp
, -1, p
->p_textoff
)) == NULL
)
964 return csblob_get_entitlements(csblob
, out_start
, out_length
);
967 /* Retrieve the codesign identity for a process.
969 * NULL an error occured
970 * string the cs_identity
974 cs_identity_get(proc_t p
)
976 struct cs_blob
*csblob
;
978 if ((p
->p_csflags
& CS_SIGNED
) == 0) {
982 if (NULL
== p
->p_textvp
)
985 if ((csblob
= ubc_cs_blob_get(p
->p_textvp
, -1, p
->p_textoff
)) == NULL
)
988 return csblob_get_identity(csblob
);
992 * DO NOT USE THIS FUNCTION!
993 * Use the properly guarded csproc_get_blob instead.
995 * This is currently here to allow detached signatures to work
996 * properly. The only user of this function is also checking
1001 cs_blob_get(proc_t p
, void **out_start
, size_t *out_length
)
1003 struct cs_blob
*csblob
;
1008 if (NULL
== p
->p_textvp
)
1011 if ((csblob
= ubc_cs_blob_get(p
->p_textvp
, -1, p
->p_textoff
)) == NULL
)
1014 *out_start
= (void *)csblob
->csb_mem_kaddr
;
1015 *out_length
= csblob
->csb_mem_size
;
1021 * return cshash of a process, cdhash is of size CS_CDHASH_LEN
1025 cs_get_cdhash(struct proc
*p
)
1027 struct cs_blob
*csblob
;
1029 if ((p
->p_csflags
& CS_SIGNED
) == 0) {
1033 if (NULL
== p
->p_textvp
)
1036 if ((csblob
= ubc_cs_blob_get(p
->p_textvp
, -1, p
->p_textoff
)) == NULL
)
1039 return csblob
->csb_cdhash
;