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