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