]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_cs.c
xnu-7195.101.1.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@
0a7de745 5 *
39236c6e
A
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.
0a7de745 14 *
39236c6e
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
39236c6e
A
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.
0a7de745 25 *
39236c6e
A
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>
f427ee49 62#include <kern/startup.h>
39236c6e
A
63#include <kern/task.h>
64
65#include <vm/vm_map.h>
a991bd8d 66#include <vm/pmap.h>
39236c6e
A
67#include <vm/vm_kern.h>
68
39236c6e
A
69
70#include <kern/assert.h>
71
72#include <pexpert/pexpert.h>
73
15129b1c
A
74#include <mach/shared_region.h>
75
4bd07ac2 76#include <libkern/section_keywords.h>
f427ee49
A
77#include <libkern/ptrauth_utils.h>
78
4bd07ac2 79
39236c6e
A
80unsigned long cs_procs_killed = 0;
81unsigned long cs_procs_invalidated = 0;
82
83int cs_force_kill = 0;
84int cs_force_hard = 0;
85int cs_debug = 0;
d9a64523
A
86// If set, AMFI will error out early on unsigned code, before evaluation the normal policy.
87int cs_debug_fail_on_unsigned_code = 0;
88// If the previous mode is enabled, we count the resulting failures here.
89unsigned int cs_debug_unsigned_exec_failures = 0;
90unsigned int cs_debug_unsigned_mmap_failures = 0;
91
f427ee49
A
92#if CONFIG_ENFORCE_SIGNED_CODE
93#define DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE 1
94#define DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE 1
95#else
96#define DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE 1
97#define DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE 0
98#endif
99
100#if CONFIG_ENFORCE_LIBRARY_VALIDATION
101#define DEFAULT_CS_LIBRARY_VA_ENABLE 1
102#else
103#define DEFAULT_CS_LIBRARY_VA_ENABLE 0
104#endif
105
39236c6e 106#if SECURE_KERNEL
f427ee49 107
d9a64523 108/*
0a7de745
A
109 * Here we split cs_enforcement_enable into cs_system_enforcement_enable and cs_process_enforcement_enable
110 *
111 * cs_system_enforcement_enable governs whether or not system level code signing enforcement mechanisms
112 * are applied on the system. Today, the only such mechanism is code signing enforcement of the dyld shared
113 * cache.
114 *
115 * cs_process_enforcement_enable governs whether code signing enforcement mechanisms are applied to all
116 * processes or only those that opt into such enforcement.
117 *
118 * (On iOS and related, both of these are set by default. On macOS, only cs_system_enforcement_enable
119 * is set by default. Processes can then be opted into code signing enforcement on a case by case basis.)
d9a64523 120 */
f427ee49
A
121SECURITY_READ_ONLY_EARLY(int) cs_system_enforcement_enable = DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE;
122SECURITY_READ_ONLY_EARLY(int) cs_process_enforcement_enable = DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE;
123SECURITY_READ_ONLY_EARLY(int) cs_library_val_enable = DEFAULT_CS_LIBRARY_VA_ENABLE;
124
3e170ce0 125#else /* !SECURE_KERNEL */
0a7de745 126int cs_enforcement_panic = 0;
5ba3f43e 127int cs_relax_platform_task_ports = 0;
3e170ce0 128
d9a64523
A
129SECURITY_READ_ONLY_LATE(int) cs_system_enforcement_enable = DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE;
130SECURITY_READ_ONLY_LATE(int) cs_process_enforcement_enable = DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE;
fe8ab488 131
4bd07ac2 132SECURITY_READ_ONLY_LATE(int) cs_library_val_enable = DEFAULT_CS_LIBRARY_VA_ENABLE;
fe8ab488 133
3e170ce0 134#endif /* !SECURE_KERNEL */
39236c6e
A
135int cs_all_vnodes = 0;
136
39236c6e
A
137SYSCTL_INT(_vm, OID_AUTO, cs_force_kill, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_force_kill, 0, "");
138SYSCTL_INT(_vm, OID_AUTO, cs_force_hard, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_force_hard, 0, "");
139SYSCTL_INT(_vm, OID_AUTO, cs_debug, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_debug, 0, "");
d9a64523 140SYSCTL_INT(_vm, OID_AUTO, cs_debug_fail_on_unsigned_code, CTLFLAG_RW | CTLFLAG_LOCKED,
0a7de745 141 &cs_debug_fail_on_unsigned_code, 0, "");
d9a64523 142SYSCTL_UINT(_vm, OID_AUTO, cs_debug_unsigned_exec_failures, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 143 &cs_debug_unsigned_exec_failures, 0, "");
d9a64523 144SYSCTL_UINT(_vm, OID_AUTO, cs_debug_unsigned_mmap_failures, CTLFLAG_RD | CTLFLAG_LOCKED,
0a7de745 145 &cs_debug_unsigned_mmap_failures, 0, "");
39236c6e
A
146
147SYSCTL_INT(_vm, OID_AUTO, cs_all_vnodes, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_all_vnodes, 0, "");
148
149#if !SECURE_KERNEL
d9a64523
A
150SYSCTL_INT(_vm, OID_AUTO, cs_system_enforcement, CTLFLAG_RD | CTLFLAG_LOCKED, &cs_system_enforcement_enable, 0, "");
151SYSCTL_INT(_vm, OID_AUTO, cs_process_enforcement, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_process_enforcement_enable, 0, "");
39236c6e 152SYSCTL_INT(_vm, OID_AUTO, cs_enforcement_panic, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_enforcement_panic, 0, "");
3e170ce0
A
153
154#if !CONFIG_ENFORCE_LIBRARY_VALIDATION
d9a64523 155SYSCTL_INT(_vm, OID_AUTO, cs_library_validation, CTLFLAG_RD | CTLFLAG_LOCKED, &cs_library_val_enable, 0, "");
39236c6e 156#endif
3e170ce0 157#endif /* !SECURE_KERNEL */
39236c6e 158
15129b1c 159int panic_on_cs_killed = 0;
5ba3f43e 160
f427ee49
A
161__startup_func
162static void
39236c6e
A
163cs_init(void)
164{
d9a64523
A
165#if MACH_ASSERT
166#if PLATFORM_WatchOS || __x86_64__
15129b1c 167 panic_on_cs_killed = 1;
d9a64523
A
168#endif /* watchos || x86_64 */
169#endif /* MACH_ASSERT */
15129b1c 170 PE_parse_boot_argn("panic_on_cs_killed", &panic_on_cs_killed,
0a7de745 171 sizeof(panic_on_cs_killed));
39236c6e
A
172#if !SECURE_KERNEL
173 int disable_cs_enforcement = 0;
0a7de745
A
174 PE_parse_boot_argn("cs_enforcement_disable", &disable_cs_enforcement,
175 sizeof(disable_cs_enforcement));
d9a64523
A
176 if (disable_cs_enforcement && PE_i_can_has_debugger(NULL) != 0) {
177 cs_system_enforcement_enable = 0;
178 cs_process_enforcement_enable = 0;
39236c6e
A
179 } else {
180 int panic = 0;
181 PE_parse_boot_argn("cs_enforcement_panic", &panic, sizeof(panic));
182 cs_enforcement_panic = (panic != 0);
183 }
184
5ba3f43e 185 PE_parse_boot_argn("cs_relax_platform_task_ports",
0a7de745
A
186 &cs_relax_platform_task_ports,
187 sizeof(cs_relax_platform_task_ports));
5ba3f43e 188
0a7de745 189 PE_parse_boot_argn("cs_debug", &cs_debug, sizeof(cs_debug));
3e170ce0
A
190
191#if !CONFIG_ENFORCE_LIBRARY_VALIDATION
192 PE_parse_boot_argn("cs_library_val_enable", &cs_library_val_enable,
0a7de745 193 sizeof(cs_library_val_enable));
39236c6e 194#endif
3e170ce0 195#endif /* !SECURE_KERNEL */
39236c6e 196}
f427ee49 197STARTUP(CODESIGNING, STARTUP_RANK_FIRST, cs_init);
39236c6e
A
198
199int
200cs_allow_invalid(struct proc *p)
201{
202#if MACH_ASSERT
203 lck_mtx_assert(&p->p_mlock, LCK_MTX_ASSERT_NOTOWNED);
204#endif
d9a64523 205#if CONFIG_MACF
39236c6e 206 /* There needs to be a MAC policy to implement this hook, or else the
0a7de745 207 * kill bits will be cleared here every time. If we have
39236c6e 208 * CONFIG_ENFORCE_SIGNED_CODE, we can assume there is a policy
0a7de745 209 * implementing the hook.
39236c6e 210 */
0a7de745
A
211 if (0 != mac_proc_check_run_cs_invalid(p)) {
212 if (cs_debug) {
213 printf("CODE SIGNING: cs_allow_invalid() "
214 "not allowed: pid %d\n",
215 p->p_pid);
216 }
39236c6e
A
217 return 0;
218 }
0a7de745
A
219 if (cs_debug) {
220 printf("CODE SIGNING: cs_allow_invalid() "
221 "allowed: pid %d\n",
222 p->p_pid);
223 }
39236c6e
A
224 proc_lock(p);
225 p->p_csflags &= ~(CS_KILL | CS_HARD);
0a7de745 226 if (p->p_csflags & CS_VALID) {
490019cf
A
227 p->p_csflags |= CS_DEBUGGED;
228 }
a991bd8d
A
229#if PMAP_CS
230 task_t procTask = proc_task(p);
231 if (procTask) {
232 vm_map_t proc_map = get_task_map_reference(procTask);
233 if (proc_map) {
234 if (vm_map_cs_wx_enable(proc_map) != KERN_SUCCESS) {
235 printf("CODE SIGNING: cs_allow_invalid() not allowed by pmap: pid %d\n", p->p_pid);
236 }
237 vm_map_deallocate(proc_map);
238 }
239 }
240#endif // MAP_CS
39236c6e 241 proc_unlock(p);
0a7de745 242
cb323159
A
243 /* allow a debugged process to hide some (debug-only!) memory */
244 task_set_memory_ownership_transfer(p->task, TRUE);
245
39236c6e
A
246 vm_map_switch_protect(get_task_map(p->task), FALSE);
247#endif
248 return (p->p_csflags & (CS_KILL | CS_HARD)) == 0;
249}
250
251int
39037602 252cs_invalid_page(addr64_t vaddr, boolean_t *cs_killed)
39236c6e 253{
0a7de745
A
254 struct proc *p;
255 int send_kill = 0, retval = 0, verbose = cs_debug;
39236c6e
A
256
257 p = current_proc();
258
0a7de745 259 if (verbose) {
39236c6e
A
260 printf("CODE SIGNING: cs_invalid_page(0x%llx): p=%d[%s]\n",
261 vaddr, p->p_pid, p->p_comm);
0a7de745 262 }
39236c6e
A
263
264 proc_lock(p);
265
266 /* XXX for testing */
0a7de745 267 if (cs_force_kill) {
39236c6e 268 p->p_csflags |= CS_KILL;
0a7de745
A
269 }
270 if (cs_force_hard) {
39236c6e 271 p->p_csflags |= CS_HARD;
0a7de745 272 }
39236c6e
A
273
274 /* CS_KILL triggers a kill signal, and no you can't have the page. Nothing else. */
275 if (p->p_csflags & CS_KILL) {
276 p->p_csflags |= CS_KILLED;
277 cs_procs_killed++;
278 send_kill = 1;
279 retval = 1;
280 }
0a7de745 281
39236c6e
A
282 /* CS_HARD means fail the mapping operation so the process stays valid. */
283 if (p->p_csflags & CS_HARD) {
284 retval = 1;
285 } else {
286 if (p->p_csflags & CS_VALID) {
287 p->p_csflags &= ~CS_VALID;
288 cs_procs_invalidated++;
289 verbose = 1;
f427ee49 290 cs_process_invalidated(NULL);
39236c6e
A
291 }
292 }
39236c6e
A
293 proc_unlock(p);
294
0a7de745 295 if (verbose) {
39236c6e 296 printf("CODE SIGNING: cs_invalid_page(0x%llx): "
0a7de745
A
297 "p=%d[%s] final status 0x%x, %s page%s\n",
298 vaddr, p->p_pid, p->p_comm, p->p_csflags,
299 retval ? "denying" : "allowing (remove VALID)",
300 send_kill ? " sending SIGKILL" : "");
301 }
39236c6e 302
39037602
A
303 if (send_kill) {
304 /* We will set the exit reason for the thread later */
305 threadsignal(current_thread(), SIGKILL, EXC_BAD_ACCESS, FALSE);
306 if (cs_killed) {
307 *cs_killed = TRUE;
308 }
309 } else if (cs_killed) {
310 *cs_killed = FALSE;
311 }
39236c6e 312
39236c6e
A
313 return retval;
314}
315
f427ee49
A
316/*
317 * Called after a process got its CS_VALID bit removed, either by
318 * a previous call to cs_invalid_page, or through other means.
319 * Called from fault handler with vm object lock held.
320 * Called with proc lock held for current_proc or, if passed in, p,
321 * to ensure MACF hook can suspend the task before other threads
322 * can access the memory that is paged in after cs_invalid_page
323 * returns 0 due to missing CS_HARD|CS_KILL.
324 */
325void
326cs_process_invalidated(struct proc * __unused p)
327{
328#if CONFIG_MACF
329 if (p == NULL) {
330 p = current_proc();
331 }
332 mac_proc_notify_cs_invalidated(p);
333#endif
334}
335
39236c6e
A
336/*
337 * Assumes p (if passed in) is locked with proc_lock().
338 */
339
340int
d9a64523 341cs_process_enforcement(struct proc *p)
39236c6e 342{
0a7de745 343 if (cs_process_enforcement_enable) {
39236c6e 344 return 1;
0a7de745
A
345 }
346
347 if (p == NULL) {
39236c6e 348 p = current_proc();
0a7de745 349 }
39236c6e 350
0a7de745 351 if (p != NULL && (p->p_csflags & CS_ENFORCEMENT)) {
39236c6e 352 return 1;
0a7de745 353 }
39236c6e
A
354
355 return 0;
356}
357
d9a64523
A
358int
359cs_process_global_enforcement(void)
360{
361 return cs_process_enforcement_enable ? 1 : 0;
362}
363
364int
365cs_system_enforcement(void)
366{
367 return cs_system_enforcement_enable ? 1 : 0;
368}
369
f427ee49
A
370int
371cs_vm_supports_4k_translations(void)
372{
373 return 0;
374}
375
376
39037602
A
377/*
378 * Returns whether a given process is still valid.
379 */
380int
381cs_valid(struct proc *p)
382{
0a7de745 383 if (p == NULL) {
39037602 384 p = current_proc();
0a7de745 385 }
39037602 386
0a7de745 387 if (p != NULL && (p->p_csflags & CS_VALID)) {
39037602 388 return 1;
0a7de745 389 }
39037602
A
390
391 return 0;
392}
393
fe8ab488 394/*
0a7de745 395 * Library validation functions
fe8ab488
A
396 */
397int
398cs_require_lv(struct proc *p)
399{
0a7de745 400 if (cs_library_val_enable) {
fe8ab488 401 return 1;
0a7de745 402 }
fe8ab488 403
0a7de745 404 if (p == NULL) {
fe8ab488 405 p = current_proc();
0a7de745
A
406 }
407
408 if (p != NULL && (p->p_csflags & CS_REQUIRE_LV)) {
fe8ab488 409 return 1;
0a7de745
A
410 }
411
fe8ab488
A
412 return 0;
413}
414
d9a64523
A
415int
416csproc_forced_lv(struct proc* p)
417{
418 if (p == NULL) {
419 p = current_proc();
420 }
421 if (p != NULL && (p->p_csflags & CS_FORCED_LV)) {
422 return 1;
423 }
424 return 0;
425}
426
39037602
A
427/*
428 * <rdar://problem/24634089> added to allow system level library
429 * validation check at mac_cred_label_update_execve time
430 */
431int
432cs_system_require_lv(void)
433{
434 return cs_library_val_enable ? 1 : 0;
435}
436
437/*
438 * Function: csblob_get_base_offset
439 *
527f9951 440 * Description: This function returns the base offset into the (possibly universal) binary
39037602 441 * for a given blob.
0a7de745 442 */
39037602
A
443
444off_t
445csblob_get_base_offset(struct cs_blob *blob)
446{
0a7de745 447 return blob->csb_base_offset;
39037602
A
448}
449
450/*
451 * Function: csblob_get_size
452 *
453 * Description: This function returns the size of a given blob.
0a7de745 454 */
39037602
A
455
456vm_size_t
457csblob_get_size(struct cs_blob *blob)
458{
0a7de745 459 return blob->csb_mem_size;
39037602
A
460}
461
462/*
463 * Function: csblob_get_addr
464 *
465 * Description: This function returns the address of a given blob.
0a7de745 466 */
39037602
A
467
468vm_address_t
469csblob_get_addr(struct cs_blob *blob)
470{
c3c9b80d 471 return (vm_address_t)blob->csb_mem_kaddr;
39037602
A
472}
473
fe8ab488 474/*
3e170ce0 475 * Function: csblob_get_platform_binary
fe8ab488 476 *
3e170ce0
A
477 * Description: This function returns true if the binary is
478 * in the trust cache.
0a7de745 479 */
fe8ab488 480
3e170ce0
A
481int
482csblob_get_platform_binary(struct cs_blob *blob)
483{
0a7de745
A
484 if (blob && blob->csb_platform_binary) {
485 return 1;
486 }
487 return 0;
3e170ce0 488}
fe8ab488 489
3e170ce0
A
490/*
491 * Function: csblob_get_flags
492 *
493 * Description: This function returns the flags for a given blob
0a7de745 494 */
fe8ab488 495
3e170ce0
A
496unsigned int
497csblob_get_flags(struct cs_blob *blob)
498{
0a7de745 499 return blob->csb_flags;
fe8ab488
A
500}
501
5ba3f43e
A
502/*
503 * Function: csblob_get_hashtype
504 *
505 * Description: This function returns the hash type for a given blob
0a7de745 506 */
5ba3f43e
A
507
508uint8_t
509csblob_get_hashtype(struct cs_blob const * const blob)
510{
0a7de745 511 return blob->csb_hashtype != NULL ? cs_hash_type(blob->csb_hashtype) : 0;
5ba3f43e
A
512}
513
fe8ab488
A
514/*
515 * Function: csproc_get_blob
516 *
517 * Description: This function returns the cs_blob
518 * for the process p
519 */
3e170ce0 520struct cs_blob *
fe8ab488
A
521csproc_get_blob(struct proc *p)
522{
0a7de745 523 if (NULL == p) {
fe8ab488 524 return NULL;
0a7de745 525 }
fe8ab488 526
0a7de745 527 if (NULL == p->p_textvp) {
fe8ab488 528 return NULL;
0a7de745 529 }
fe8ab488 530
527f9951
A
531 if ((p->p_csflags & CS_SIGNED) == 0) {
532 return NULL;
533 }
534
f427ee49 535 return ubc_cs_blob_get(p->p_textvp, -1, -1, p->p_textoff);
fe8ab488
A
536}
537
3e170ce0 538/*
527f9951 539 * Function: csvnode_get_blob
3e170ce0
A
540 *
541 * Description: This function returns the cs_blob
542 * for the vnode vp
543 */
544struct cs_blob *
545csvnode_get_blob(struct vnode *vp, off_t offset)
546{
f427ee49 547 return ubc_cs_blob_get(vp, -1, -1, offset);
3e170ce0
A
548}
549
550/*
551 * Function: csblob_get_teamid
552 *
553 * Description: This function returns a pointer to the
554 * team id of csblob
0a7de745 555 */
3e170ce0
A
556const char *
557csblob_get_teamid(struct cs_blob *csblob)
558{
559 return csblob->csb_teamid;
560}
561
562/*
563 * Function: csblob_get_identity
564 *
565 * Description: This function returns a pointer to the
566 * identity string
567 */
568const char *
569csblob_get_identity(struct cs_blob *csblob)
570{
571 const CS_CodeDirectory *cd;
572
573 cd = (const CS_CodeDirectory *)csblob_find_blob(csblob, CSSLOT_CODEDIRECTORY, CSMAGIC_CODEDIRECTORY);
0a7de745 574 if (cd == NULL) {
3e170ce0 575 return NULL;
0a7de745 576 }
3e170ce0 577
0a7de745 578 if (cd->identOffset == 0) {
3e170ce0 579 return NULL;
0a7de745 580 }
3e170ce0
A
581
582 return ((const char *)cd) + ntohl(cd->identOffset);
583}
584
585/*
586 * Function: csblob_get_cdhash
587 *
588 * Description: This function returns a pointer to the
589 * cdhash of csblob (20 byte array)
590 */
591const uint8_t *
592csblob_get_cdhash(struct cs_blob *csblob)
593{
f427ee49
A
594 ptrauth_utils_auth_blob_generic(csblob->csb_cdhash,
595 sizeof(csblob->csb_cdhash),
596 OS_PTRAUTH_DISCRIMINATOR("cs_blob.csb_cd_signature"),
597 PTRAUTH_ADDR_DIVERSIFY,
598 csblob->csb_cdhash_signature);
3e170ce0
A
599 return csblob->csb_cdhash;
600}
601
5ba3f43e
A
602/*
603 * Function: csblob_get_signer_type
604 *
605 * Description: This function returns the signer type
606 * as an integer
607 */
608unsigned int
609csblob_get_signer_type(struct cs_blob *csblob)
610{
611 return csblob->csb_signer_type;
612}
613
39037602
A
614void *
615csblob_entitlements_dictionary_copy(struct cs_blob *csblob)
616{
0a7de745
A
617 if (!csblob->csb_entitlements) {
618 return NULL;
619 }
620 osobject_retain(csblob->csb_entitlements);
621 return csblob->csb_entitlements;
39037602
A
622}
623
624void
625csblob_entitlements_dictionary_set(struct cs_blob *csblob, void * entitlements)
626{
0a7de745
A
627 assert(csblob->csb_entitlements == NULL);
628 if (entitlements) {
629 osobject_retain(entitlements);
630 }
631 csblob->csb_entitlements = entitlements;
39037602
A
632}
633
fe8ab488 634/*
0a7de745 635 * Function: csproc_get_teamid
fe8ab488
A
636 *
637 * Description: This function returns a pointer to the
638 * team id of the process p
0a7de745 639 */
fe8ab488
A
640const char *
641csproc_get_teamid(struct proc *p)
642{
643 struct cs_blob *csblob;
644
645 csblob = csproc_get_blob(p);
0a7de745
A
646 if (csblob == NULL) {
647 return NULL;
648 }
fe8ab488 649
3e170ce0 650 return csblob_get_teamid(csblob);
fe8ab488
A
651}
652
f427ee49
A
653const char *
654csproc_get_identity(struct proc *p)
655{
656 struct cs_blob *csblob = NULL;
657
658 csblob = csproc_get_blob(p);
659 if (csblob == NULL) {
660 return NULL;
661 }
662
663 return csblob_get_identity(csblob);
664}
665
5ba3f43e 666/*
0a7de745 667 * Function: csproc_get_signer_type
5ba3f43e
A
668 *
669 * Description: This function returns the signer type
670 * of the process p
0a7de745 671 */
5ba3f43e
A
672unsigned int
673csproc_get_signer_type(struct proc *p)
674{
675 struct cs_blob *csblob;
676
677 csblob = csproc_get_blob(p);
0a7de745
A
678 if (csblob == NULL) {
679 return CS_SIGNER_TYPE_UNKNOWN;
680 }
5ba3f43e
A
681
682 return csblob_get_signer_type(csblob);
683}
684
fe8ab488 685/*
0a7de745 686 * Function: csvnode_get_teamid
fe8ab488
A
687 *
688 * Description: This function returns a pointer to the
689 * team id of the binary at the given offset in vnode vp
0a7de745 690 */
fe8ab488
A
691const char *
692csvnode_get_teamid(struct vnode *vp, off_t offset)
693{
694 struct cs_blob *csblob;
695
0a7de745 696 if (vp == NULL) {
fe8ab488 697 return NULL;
0a7de745 698 }
fe8ab488 699
f427ee49 700 csblob = ubc_cs_blob_get(vp, -1, -1, offset);
0a7de745
A
701 if (csblob == NULL) {
702 return NULL;
703 }
fe8ab488 704
3e170ce0 705 return csblob_get_teamid(csblob);
fe8ab488
A
706}
707
708/*
709 * Function: csproc_get_platform_binary
710 *
711 * Description: This function returns the value
712 * of the platform_binary field for proc p
713 */
714int
715csproc_get_platform_binary(struct proc *p)
716{
717 struct cs_blob *csblob;
718
719 csblob = csproc_get_blob(p);
720
721 /* If there is no csblob this returns 0 because
0a7de745 722 * it is true that it is not a platform binary */
fe8ab488
A
723 return (csblob == NULL) ? 0 : csblob->csb_platform_binary;
724}
725
3e170ce0
A
726int
727csproc_get_platform_path(struct proc *p)
728{
527f9951
A
729 struct cs_blob *csblob;
730
0a7de745 731 csblob = csproc_get_blob(p);
3e170ce0
A
732
733 return (csblob == NULL) ? 0 : csblob->csb_platform_path;
734}
735
5ba3f43e
A
736#if DEVELOPMENT || DEBUG
737void
738csproc_clear_platform_binary(struct proc *p)
739{
740 struct cs_blob *csblob = csproc_get_blob(p);
741
742 if (csblob == NULL) {
743 return;
744 }
745
746 if (cs_debug) {
747 printf("clearing platform binary on proc/task: pid = %d\n", p->p_pid);
748 }
749
750 csblob->csb_platform_binary = 0;
751 csblob->csb_platform_path = 0;
752 task_set_platform_binary(proc_task(p), FALSE);
753}
754#endif
755
d9a64523
A
756void
757csproc_disable_enforcement(struct proc* __unused p)
758{
759#if !CONFIG_ENFORCE_SIGNED_CODE
760 if (p != NULL) {
761 proc_lock(p);
762 p->p_csflags &= (~CS_ENFORCEMENT);
f427ee49 763 vm_map_cs_enforcement_set(get_task_map(p->task), FALSE);
d9a64523
A
764 proc_unlock(p);
765 }
766#endif
767}
768
769/* Function: csproc_mark_invalid_allowed
770 *
771 * Description: Mark the process as being allowed to go invalid. Called as part of
772 * task_for_pid and ptrace policy. Note CS_INVALID_ALLOWED only matters for
773 * processes that have been opted into CS_ENFORCEMENT.
774 */
775void
776csproc_mark_invalid_allowed(struct proc* __unused p)
777{
778#if !CONFIG_ENFORCE_SIGNED_CODE
779 if (p != NULL) {
780 proc_lock(p);
781 p->p_csflags |= CS_INVALID_ALLOWED;
782 proc_unlock(p);
783 }
784#endif
785}
786
787/*
788 * Function: csproc_check_invalid_allowed
789 *
790 * Description: Returns 1 if the process has been marked as allowed to go invalid
791 * because it gave its task port to an allowed process.
792 */
793int
794csproc_check_invalid_allowed(struct proc* __unused p)
795{
796#if !CONFIG_ENFORCE_SIGNED_CODE
797 if (p == NULL) {
798 p = current_proc();
799 }
800
0a7de745 801 if (p != NULL && (p->p_csflags & CS_INVALID_ALLOWED)) {
d9a64523 802 return 1;
0a7de745 803 }
d9a64523
A
804#endif
805 return 0;
806}
807
743345f9
A
808/*
809 * Function: csproc_get_prod_signed
810 *
811 * Description: Returns 1 if process is not signed with a developer identity.
812 * Note the inverted meaning from the cs_flag to make the error case safer.
813 * Will go away with rdar://problem/28322552.
814 */
815int
816csproc_get_prod_signed(struct proc *p)
817{
0a7de745 818 return (p->p_csflags & CS_DEV_CODE) == 0;
743345f9
A
819}
820
821
fe8ab488
A
822/*
823 * Function: csfg_get_platform_binary
824 *
0a7de745
A
825 * Description: This function returns the
826 * platform binary field for the
827 * fileglob fg
fe8ab488 828 */
0a7de745 829int
fe8ab488
A
830csfg_get_platform_binary(struct fileglob *fg)
831{
832 int platform_binary = 0;
833 struct ubc_info *uip;
834 vnode_t vp;
835
0a7de745 836 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
fe8ab488 837 return 0;
0a7de745
A
838 }
839
fe8ab488 840 vp = (struct vnode *)fg->fg_data;
0a7de745 841 if (vp == NULL) {
fe8ab488 842 return 0;
0a7de745 843 }
fe8ab488
A
844
845 vnode_lock(vp);
0a7de745 846 if (!UBCINFOEXISTS(vp)) {
fe8ab488 847 goto out;
0a7de745
A
848 }
849
fe8ab488 850 uip = vp->v_ubcinfo;
0a7de745 851 if (uip == NULL) {
fe8ab488 852 goto out;
0a7de745
A
853 }
854
855 if (uip->cs_blobs == NULL) {
fe8ab488 856 goto out;
0a7de745 857 }
fe8ab488
A
858
859 /* It is OK to extract the teamid from the first blob
0a7de745 860 * because all blobs of a vnode must have the same teamid */
fe8ab488
A
861 platform_binary = uip->cs_blobs->csb_platform_binary;
862out:
863 vnode_unlock(vp);
864
865 return platform_binary;
866}
867
f427ee49
A
868int
869csfg_get_supplement_platform_binary(struct fileglob *fg __unused)
870{
871#if CONFIG_SUPPLEMENTAL_SIGNATURES
872 int platform_binary = 0;
873 struct ubc_info *uip;
874 vnode_t vp;
875
876 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
877 return 0;
878 }
879
880 vp = (struct vnode *)fg->fg_data;
881 if (vp == NULL) {
882 return 0;
883 }
884
885 vnode_lock(vp);
886 if (!UBCINFOEXISTS(vp)) {
887 goto out;
888 }
889
890 uip = vp->v_ubcinfo;
891 if (uip == NULL) {
892 goto out;
893 }
894
895 if (uip->cs_blob_supplement == NULL) {
896 goto out;
897 }
898
899 platform_binary = uip->cs_blob_supplement->csb_platform_binary;
900out:
901 vnode_unlock(vp);
902
903 return platform_binary;
904#else
905 // Supplemental signatures are only allowed in CONFIG_SUPPLEMENTAL_SIGNATURES
906 // Return false if anyone asks about them
907 return 0;
908#endif
909}
910
3e170ce0
A
911uint8_t *
912csfg_get_cdhash(struct fileglob *fg, uint64_t offset, size_t *cdhash_size)
913{
914 vnode_t vp;
915
0a7de745 916 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
3e170ce0 917 return NULL;
0a7de745 918 }
3e170ce0
A
919
920 vp = (struct vnode *)fg->fg_data;
0a7de745 921 if (vp == NULL) {
3e170ce0 922 return NULL;
0a7de745 923 }
3e170ce0
A
924
925 struct cs_blob *csblob = NULL;
f427ee49 926 if ((csblob = ubc_cs_blob_get(vp, -1, -1, offset)) == NULL) {
3e170ce0 927 return NULL;
0a7de745 928 }
3e170ce0 929
0a7de745 930 if (cdhash_size) {
3e170ce0 931 *cdhash_size = CS_CDHASH_LEN;
0a7de745 932 }
f427ee49
A
933 ptrauth_utils_auth_blob_generic(csblob->csb_cdhash,
934 sizeof(csblob->csb_cdhash),
935 OS_PTRAUTH_DISCRIMINATOR("cs_blob.csb_cd_signature"),
936 PTRAUTH_ADDR_DIVERSIFY,
937 csblob->csb_cdhash_signature);
938 return csblob->csb_cdhash;
939}
940
941uint8_t *
942csfg_get_supplement_cdhash(struct fileglob *fg __unused, uint64_t offset __unused, size_t *cdhash_size __unused)
943{
944#if CONFIG_SUPPLEMENTAL_SIGNATURES
945 vnode_t vp;
946
947 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
948 return NULL;
949 }
3e170ce0 950
f427ee49
A
951 vp = (struct vnode *)fg->fg_data;
952 if (vp == NULL) {
953 return NULL;
954 }
955
956 struct cs_blob *csblob = NULL;
957 if ((csblob = ubc_cs_blob_get_supplement(vp, offset)) == NULL) {
958 return NULL;
959 }
960
961 if (cdhash_size) {
962 *cdhash_size = CS_CDHASH_LEN;
963 }
964 ptrauth_utils_auth_blob_generic(csblob->csb_cdhash,
965 sizeof(csblob->csb_cdhash),
966 OS_PTRAUTH_DISCRIMINATOR("cs_blob.csb_cd_signature"),
967 PTRAUTH_ADDR_DIVERSIFY,
968 csblob->csb_cdhash_signature);
3e170ce0 969 return csblob->csb_cdhash;
f427ee49
A
970#else
971 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
972 // return NULL if anyone asks about them
973 return NULL;
974#endif
975}
976
977const uint8_t *
978csfg_get_supplement_linkage_cdhash(struct fileglob *fg __unused, uint64_t offset __unused, size_t *cdhash_size __unused)
979{
980#if CONFIG_SUPPLEMENTAL_SIGNATURES
981 vnode_t vp;
982
983 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
984 return NULL;
985 }
986
987 vp = (struct vnode *)fg->fg_data;
988 if (vp == NULL) {
989 return NULL;
990 }
991
992 struct cs_blob *csblob = NULL;
993 if ((csblob = ubc_cs_blob_get_supplement(vp, offset)) == NULL) {
994 return NULL;
995 }
996
997 if (cdhash_size) {
998 *cdhash_size = CS_CDHASH_LEN;
999 }
1000
1001 return csblob->csb_linkage;
1002#else
1003 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1004 // return NULL if anyone asks about them
1005 return NULL;
1006#endif
3e170ce0
A
1007}
1008
5ba3f43e
A
1009/*
1010 * Function: csfg_get_signer_type
1011 *
1012 * Description: This returns the signer type
0a7de745 1013 * for the fileglob fg
5ba3f43e
A
1014 */
1015unsigned int
1016csfg_get_signer_type(struct fileglob *fg)
1017{
1018 struct ubc_info *uip;
1019 unsigned int signer_type = CS_SIGNER_TYPE_UNKNOWN;
1020 vnode_t vp;
1021
0a7de745 1022 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
5ba3f43e 1023 return CS_SIGNER_TYPE_UNKNOWN;
0a7de745
A
1024 }
1025
5ba3f43e 1026 vp = (struct vnode *)fg->fg_data;
0a7de745 1027 if (vp == NULL) {
5ba3f43e 1028 return CS_SIGNER_TYPE_UNKNOWN;
0a7de745 1029 }
5ba3f43e
A
1030
1031 vnode_lock(vp);
0a7de745 1032 if (!UBCINFOEXISTS(vp)) {
5ba3f43e 1033 goto out;
0a7de745
A
1034 }
1035
5ba3f43e 1036 uip = vp->v_ubcinfo;
0a7de745 1037 if (uip == NULL) {
5ba3f43e 1038 goto out;
0a7de745
A
1039 }
1040
1041 if (uip->cs_blobs == NULL) {
5ba3f43e 1042 goto out;
0a7de745 1043 }
5ba3f43e
A
1044
1045 /* It is OK to extract the signer type from the first blob,
0a7de745 1046 * because all blobs of a vnode must have the same signer type. */
5ba3f43e
A
1047 signer_type = uip->cs_blobs->csb_signer_type;
1048out:
1049 vnode_unlock(vp);
1050
1051 return signer_type;
1052}
1053
f427ee49
A
1054unsigned int
1055csfg_get_supplement_signer_type(struct fileglob *fg __unused)
1056{
1057#if CONFIG_SUPPLEMENTAL_SIGNATURES
1058 struct ubc_info *uip;
1059 unsigned int signer_type = CS_SIGNER_TYPE_UNKNOWN;
1060 vnode_t vp;
1061
1062 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1063 return CS_SIGNER_TYPE_UNKNOWN;
1064 }
1065
1066 vp = (struct vnode *)fg->fg_data;
1067 if (vp == NULL) {
1068 return CS_SIGNER_TYPE_UNKNOWN;
1069 }
1070
1071 vnode_lock(vp);
1072 if (!UBCINFOEXISTS(vp)) {
1073 goto out;
1074 }
1075
1076 uip = vp->v_ubcinfo;
1077 if (uip == NULL) {
1078 goto out;
1079 }
1080
1081 if (uip->cs_blob_supplement == NULL) {
1082 goto out;
1083 }
1084
1085 signer_type = uip->cs_blob_supplement->csb_signer_type;
1086out:
1087 vnode_unlock(vp);
1088
1089 return signer_type;
1090#else
1091 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1092 // Return unknown if anyone asks
1093 return CS_SIGNER_TYPE_UNKNOWN;
1094#endif
1095}
1096
fe8ab488
A
1097/*
1098 * Function: csfg_get_teamid
1099 *
1100 * Description: This returns a pointer to
0a7de745 1101 * the teamid for the fileglob fg
fe8ab488
A
1102 */
1103const char *
1104csfg_get_teamid(struct fileglob *fg)
1105{
1106 struct ubc_info *uip;
1107 const char *str = NULL;
1108 vnode_t vp;
1109
0a7de745 1110 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
fe8ab488 1111 return NULL;
0a7de745
A
1112 }
1113
fe8ab488 1114 vp = (struct vnode *)fg->fg_data;
0a7de745 1115 if (vp == NULL) {
fe8ab488 1116 return NULL;
0a7de745 1117 }
fe8ab488
A
1118
1119 vnode_lock(vp);
0a7de745 1120 if (!UBCINFOEXISTS(vp)) {
fe8ab488 1121 goto out;
0a7de745
A
1122 }
1123
fe8ab488 1124 uip = vp->v_ubcinfo;
0a7de745 1125 if (uip == NULL) {
fe8ab488 1126 goto out;
0a7de745
A
1127 }
1128
1129 if (uip->cs_blobs == NULL) {
fe8ab488 1130 goto out;
0a7de745 1131 }
fe8ab488
A
1132
1133 /* It is OK to extract the teamid from the first blob
0a7de745 1134 * because all blobs of a vnode must have the same teamid */
fe8ab488
A
1135 str = uip->cs_blobs->csb_teamid;
1136out:
1137 vnode_unlock(vp);
1138
1139 return str;
1140}
1141
f427ee49
A
1142const char *
1143csfg_get_supplement_teamid(struct fileglob *fg __unused)
1144{
1145#if CONFIG_SUPPLEMENTAL_SIGNATURES
1146 struct ubc_info *uip;
1147 const char *str = NULL;
1148 vnode_t vp;
1149
1150 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1151 return NULL;
1152 }
1153
1154 vp = (struct vnode *)fg->fg_data;
1155 if (vp == NULL) {
1156 return NULL;
1157 }
1158
1159 vnode_lock(vp);
1160 if (!UBCINFOEXISTS(vp)) {
1161 goto out;
1162 }
1163
1164 uip = vp->v_ubcinfo;
1165 if (uip == NULL) {
1166 goto out;
1167 }
1168
1169 if (uip->cs_blob_supplement == NULL) {
1170 goto out;
1171 }
1172
1173 str = uip->cs_blob_supplement->csb_supplement_teamid;
1174out:
1175 vnode_unlock(vp);
1176
1177 return str;
1178#else
1179 // Supplemental Signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1180 // Return NULL if anyone asks
1181 return NULL;
1182#endif
1183}
1184
743345f9
A
1185/*
1186 * Function: csfg_get_prod_signed
1187 *
1188 * Description: Returns 1 if code is not signed with a developer identity.
1189 * Note the inverted meaning from the cs_flag to make the error case safer.
1190 * Will go away with rdar://problem/28322552.
1191 */
1192int
1193csfg_get_prod_signed(struct fileglob *fg)
1194{
1195 struct ubc_info *uip;
1196 vnode_t vp;
1197 int prod_signed = 0;
1198
0a7de745 1199 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
5ba3f43e 1200 return 0;
0a7de745
A
1201 }
1202
743345f9 1203 vp = (struct vnode *)fg->fg_data;
0a7de745 1204 if (vp == NULL) {
5ba3f43e 1205 return 0;
0a7de745 1206 }
743345f9
A
1207
1208 vnode_lock(vp);
0a7de745 1209 if (!UBCINFOEXISTS(vp)) {
743345f9 1210 goto out;
0a7de745
A
1211 }
1212
743345f9 1213 uip = vp->v_ubcinfo;
0a7de745 1214 if (uip == NULL) {
743345f9 1215 goto out;
0a7de745
A
1216 }
1217
1218 if (uip->cs_blobs == NULL) {
743345f9 1219 goto out;
0a7de745 1220 }
743345f9
A
1221
1222 /* It is OK to extract the flag from the first blob
0a7de745 1223 * because all blobs of a vnode must have the same cs_flags */
743345f9
A
1224 prod_signed = (uip->cs_blobs->csb_flags & CS_DEV_CODE) == 0;
1225out:
1226 vnode_unlock(vp);
1227
1228 return prod_signed;
1229}
1230
f427ee49
A
1231int
1232csfg_get_supplement_prod_signed(struct fileglob *fg __unused)
1233{
1234#if CONFIG_SUPPLEMENTAL_SIGNATURES
1235 struct ubc_info *uip;
1236 vnode_t vp;
1237 int prod_signed = 0;
1238
1239 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1240 return 0;
1241 }
1242
1243 vp = (struct vnode *)fg->fg_data;
1244 if (vp == NULL) {
1245 return 0;
1246 }
1247
1248 vnode_lock(vp);
1249 if (!UBCINFOEXISTS(vp)) {
1250 goto out;
1251 }
1252
1253 uip = vp->v_ubcinfo;
1254 if (uip == NULL) {
1255 goto out;
1256 }
1257
1258 if (uip->cs_blob_supplement == NULL) {
1259 goto out;
1260 }
1261
1262 /* It is OK to extract the flag from the first blob
1263 * because all blobs of a vnode must have the same cs_flags */
1264 prod_signed = (uip->cs_blob_supplement->csb_flags & CS_DEV_CODE) == 0;
1265out:
1266 vnode_unlock(vp);
1267
1268 return prod_signed;
1269#else
1270 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1271 // Indicate development signed if anyone tries to ask about one.
1272 return 0;
1273#endif
1274}
1275
a39ff7e2
A
1276/*
1277 * Function: csfg_get_identity
1278 *
1279 * Description: This function returns the codesign identity
1280 * for the fileglob
1281 */
1282const char *
1283csfg_get_identity(struct fileglob *fg, off_t offset)
1284{
1285 vnode_t vp;
1286 struct cs_blob *csblob = NULL;
1287
0a7de745 1288 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
a39ff7e2 1289 return NULL;
0a7de745 1290 }
a39ff7e2
A
1291
1292 vp = (struct vnode *)fg->fg_data;
0a7de745 1293 if (vp == NULL) {
a39ff7e2 1294 return NULL;
0a7de745 1295 }
a39ff7e2 1296
f427ee49 1297 csblob = ubc_cs_blob_get(vp, -1, -1, offset);
0a7de745 1298 if (csblob == NULL) {
a39ff7e2 1299 return NULL;
0a7de745 1300 }
a39ff7e2
A
1301
1302 return csblob_get_identity(csblob);
1303}
1304
1305/*
1306 * Function: csfg_get_platform_identifier
1307 *
1308 * Description: This function returns the codesign platform
1309 * identifier for the fileglob. Assumes the fileproc
1310 * is being held busy to keep the fileglob consistent.
1311 */
1312uint8_t
1313csfg_get_platform_identifier(struct fileglob *fg, off_t offset)
1314{
1315 vnode_t vp;
1316
0a7de745 1317 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
a39ff7e2 1318 return 0;
0a7de745 1319 }
a39ff7e2
A
1320
1321 vp = (struct vnode *)fg->fg_data;
0a7de745 1322 if (vp == NULL) {
a39ff7e2 1323 return 0;
0a7de745 1324 }
a39ff7e2
A
1325
1326 return csvnode_get_platform_identifier(vp, offset);
1327}
1328
1329/*
1330 * Function: csvnode_get_platform_identifier
1331 *
1332 * Description: This function returns the codesign platform
1333 * identifier for the vnode. Assumes a vnode reference
1334 * is held.
1335 */
1336uint8_t
1337csvnode_get_platform_identifier(struct vnode *vp, off_t offset)
1338{
1339 struct cs_blob *csblob;
1340 const CS_CodeDirectory *code_dir;
1341
f427ee49 1342 csblob = ubc_cs_blob_get(vp, -1, -1, offset);
0a7de745 1343 if (csblob == NULL) {
a39ff7e2 1344 return 0;
0a7de745 1345 }
a39ff7e2
A
1346
1347 code_dir = csblob->csb_cd;
0a7de745 1348 if (code_dir == NULL || ntohl(code_dir->length) < 8) {
a39ff7e2 1349 return 0;
0a7de745 1350 }
a39ff7e2
A
1351
1352 return code_dir->platform;
1353}
1354
1355/*
1356 * Function: csproc_get_platform_identifier
1357 *
1358 * Description: This function returns the codesign platform
1359 * identifier for the proc. Assumes proc will remain
1360 * valid through call.
1361 */
1362uint8_t
1363csproc_get_platform_identifier(struct proc *p)
1364{
0a7de745 1365 if (NULL == p->p_textvp) {
a39ff7e2 1366 return 0;
0a7de745 1367 }
a39ff7e2
A
1368
1369 return csvnode_get_platform_identifier(p->p_textvp, p->p_textoff);
1370}
743345f9 1371
fe8ab488
A
1372uint32_t
1373cs_entitlement_flags(struct proc *p)
1374{
0a7de745 1375 return p->p_csflags & CS_ENTITLEMENT_FLAGS;
fe8ab488
A
1376}
1377
3e170ce0
A
1378int
1379cs_restricted(struct proc *p)
1380{
1381 return (p->p_csflags & CS_RESTRICT) ? 1 : 0;
1382}
1383
d9a64523
A
1384int
1385csproc_hardened_runtime(struct proc* p)
1386{
1387 return (p->p_csflags & CS_RUNTIME) ? 1 : 0;
1388}
1389
fe8ab488
A
1390/*
1391 * Function: csfg_get_path
1392 *
1393 * Description: This populates the buffer passed in
1394 * with the path of the vnode
1395 * When calling this, the fileglob
1396 * cannot go away. The caller must have a
1397 * a reference on the fileglob or fileproc
1398 */
1399int
1400csfg_get_path(struct fileglob *fg, char *path, int *len)
1401{
1402 vnode_t vp = NULL;
1403
0a7de745 1404 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
fe8ab488 1405 return -1;
0a7de745
A
1406 }
1407
fe8ab488
A
1408 vp = (struct vnode *)fg->fg_data;
1409
1410 /* vn_getpath returns 0 for success,
0a7de745 1411 * or an error code */
fe8ab488
A
1412 return vn_getpath(vp, path, len);
1413}
3e170ce0 1414
f427ee49
A
1415/*
1416 * Retrieve the entitlements blob for a vnode
3e170ce0
A
1417 * Returns:
1418 * EINVAL no text vnode associated with the process
1419 * EBADEXEC invalid code signing data
1420 * 0 no error occurred
1421 *
1422 * On success, out_start and out_length will point to the
1423 * entitlements blob if found; or will be set to NULL/zero
1424 * if there were no entitlements.
1425 */
3e170ce0 1426int
f427ee49 1427cs_entitlements_blob_get_vnode(vnode_t vnode, off_t offset, void **out_start, size_t *out_length)
3e170ce0
A
1428{
1429 struct cs_blob *csblob;
1430
1431 *out_start = NULL;
1432 *out_length = 0;
1433
f427ee49 1434 if (vnode == NULL) {
3e170ce0 1435 return EINVAL;
0a7de745 1436 }
3e170ce0 1437
f427ee49 1438 if ((csblob = ubc_cs_blob_get(vnode, -1, -1, offset)) == NULL) {
3e170ce0 1439 return 0;
0a7de745 1440 }
3e170ce0
A
1441
1442 return csblob_get_entitlements(csblob, out_start, out_length);
1443}
1444
f427ee49
A
1445/*
1446 * Retrieve the entitlements blob for a process.
1447 * Returns:
1448 * EINVAL no text vnode associated with the process
1449 * EBADEXEC invalid code signing data
1450 * 0 no error occurred
1451 *
1452 * On success, out_start and out_length will point to the
1453 * entitlements blob if found; or will be set to NULL/zero
1454 * if there were no entitlements.
1455 */
1456int
1457cs_entitlements_blob_get(proc_t p, void **out_start, size_t *out_length)
1458{
1459 if ((p->p_csflags & CS_SIGNED) == 0) {
1460 return 0;
1461 }
1462
1463 return cs_entitlements_blob_get_vnode(p->p_textvp, p->p_textoff, out_start, out_length);
1464}
1465
cb323159
A
1466
1467/* Retrieve the cached entitlements for a process
1468 * Returns:
1469 * EINVAL no text vnode associated with the process
1470 * EBADEXEC invalid code signing data
1471 * 0 no error occurred
1472 *
1473 * Note: the entitlements may be NULL if there is nothing cached.
1474 */
1475
1476int
1477cs_entitlements_dictionary_copy(proc_t p, void **entitlements)
1478{
1479 struct cs_blob *csblob;
1480
1481 *entitlements = NULL;
1482
1483 if ((p->p_csflags & CS_SIGNED) == 0) {
1484 return 0;
1485 }
1486
1487 if (NULL == p->p_textvp) {
1488 return EINVAL;
1489 }
1490
f427ee49 1491 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, -1, p->p_textoff)) == NULL) {
cb323159
A
1492 return 0;
1493 }
1494
1495 *entitlements = csblob_entitlements_dictionary_copy(csblob);
1496 return 0;
1497}
1498
3e170ce0
A
1499/* Retrieve the codesign identity for a process.
1500 * Returns:
1501 * NULL an error occured
1502 * string the cs_identity
1503 */
1504
1505const char *
1506cs_identity_get(proc_t p)
1507{
1508 struct cs_blob *csblob;
1509
527f9951
A
1510 if ((p->p_csflags & CS_SIGNED) == 0) {
1511 return NULL;
1512 }
1513
0a7de745 1514 if (NULL == p->p_textvp) {
3e170ce0 1515 return NULL;
0a7de745 1516 }
3e170ce0 1517
f427ee49 1518 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, -1, p->p_textoff)) == NULL) {
3e170ce0 1519 return NULL;
0a7de745 1520 }
3e170ce0
A
1521
1522 return csblob_get_identity(csblob);
1523}
1524
527f9951
A
1525/*
1526 * DO NOT USE THIS FUNCTION!
1527 * Use the properly guarded csproc_get_blob instead.
3e170ce0 1528 *
527f9951
A
1529 * This is currently here to allow detached signatures to work
1530 * properly. The only user of this function is also checking
1531 * for CS_VALID.
3e170ce0
A
1532 */
1533
1534int
1535cs_blob_get(proc_t p, void **out_start, size_t *out_length)
1536{
1537 struct cs_blob *csblob;
1538
1539 *out_start = NULL;
1540 *out_length = 0;
1541
0a7de745 1542 if (NULL == p->p_textvp) {
3e170ce0 1543 return EINVAL;
0a7de745 1544 }
3e170ce0 1545
f427ee49 1546 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, -1, p->p_textoff)) == NULL) {
3e170ce0 1547 return 0;
0a7de745 1548 }
3e170ce0 1549
c3c9b80d 1550 *out_start = csblob->csb_mem_kaddr;
3e170ce0
A
1551 *out_length = csblob->csb_mem_size;
1552
1553 return 0;
1554}
1555
1556/*
1557 * return cshash of a process, cdhash is of size CS_CDHASH_LEN
1558 */
1559
1560uint8_t *
1561cs_get_cdhash(struct proc *p)
1562{
1563 struct cs_blob *csblob;
1564
527f9951
A
1565 if ((p->p_csflags & CS_SIGNED) == 0) {
1566 return NULL;
1567 }
1568
0a7de745 1569 if (NULL == p->p_textvp) {
3e170ce0 1570 return NULL;
0a7de745 1571 }
3e170ce0 1572
f427ee49 1573 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, -1, p->p_textoff)) == NULL) {
3e170ce0 1574 return NULL;
0a7de745 1575 }
3e170ce0 1576
f427ee49
A
1577 ptrauth_utils_auth_blob_generic(csblob->csb_cdhash,
1578 sizeof(csblob->csb_cdhash),
1579 OS_PTRAUTH_DISCRIMINATOR("cs_blob.csb_cd_signature"),
1580 PTRAUTH_ADDR_DIVERSIFY,
1581 csblob->csb_cdhash_signature);
3e170ce0
A
1582 return csblob->csb_cdhash;
1583}