1/*
2 * Copyright (c) 2007-2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29/*-
30 * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
31 * Copyright (c) 2001 Ilmar S. Habibulin
32 * Copyright (c) 2001, 2002, 2003, 2004 Networks Associates Technology, Inc.
33 *
34 * This software was developed by Robert Watson and Ilmar Habibulin for the
35 * TrustedBSD Project.
36 *
37 * This software was developed for the FreeBSD Project in part by Network
38 * Associates Laboratories, the Security Research Division of Network
39 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
40 * as part of the DARPA CHATS research program.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 *
63 */
64
65#include <string.h>
66#include <sys/param.h>
67#include <sys/ucred.h>
68#include <sys/malloc.h>
69#include <sys/sbuf.h>
70#include <sys/vnode.h>
71#include <sys/proc.h>
72#include <sys/proc_internal.h>
73#include <sys/kauth.h>
74#include <sys/imgact.h>
75#include <sys/reason.h>
76#include <sys/vnode_internal.h>
77#include <mach/mach_types.h>
78#include <kern/task.h>
79#include <kern/zalloc.h>
80
81#include <os/hash.h>
82
83#include <security/mac_internal.h>
84#include <security/mac_mach_internal.h>
85
86#include <bsd/security/audit/audit.h>
87
88#include <os/log.h>
89#include <kern/cs_blobs.h>
90#include <sys/spawn.h>
91#include <sys/spawn_internal.h>
92
93struct label *
94mac_cred_label_alloc(void)
95{
96 struct label *label;
97
98 label = mac_labelzone_alloc(MAC_WAITOK);
99 if (label == NULL) {
100 return NULL;
101 }
102 MAC_PERFORM(cred_label_init, label);
103 return label;
104}
105
106void
107mac_cred_label_init(struct ucred *cred)
108{
109 cred->cr_label = mac_cred_label_alloc();
110}
111
112void
113mac_cred_label_seal(struct ucred *cred)
114{
115#if DEVELOPMENT || DEBUG
116 struct label **seal = (struct label **)-1;
117
118 zalloc_ro_update_field(ZONE_ID_MAC_LABEL, cred->cr_label, l_owner, &seal);
119#else
120 (void)cred;
121#endif
122}
123
124void
125mac_cred_label_free(struct label *label)
126{
127#if DEVELOPMENT || DEBUG
128 struct label **seal = (struct label **)-1;
129
130 if (label->l_owner == seal) {
131 seal = NULL;
132 zalloc_ro_update_field(ZONE_ID_MAC_LABEL, label, l_owner, &seal);
133 }
134#endif
135
136 MAC_PERFORM(cred_label_destroy, label);
137 mac_labelzone_free(l: label);
138}
139
140struct label *
141mac_cred_label(struct ucred *cred)
142{
143 return cred->cr_label;
144}
145
146bool
147mac_cred_label_is_equal(const struct label *a, const struct label *b)
148{
149 return memcmp(s1: a->l_perpolicy, s2: b->l_perpolicy, n: sizeof(a->l_perpolicy)) == 0;
150}
151
152uint32_t
153mac_cred_label_hash_update(const struct label *a, uint32_t hash)
154{
155 return os_hash_jenkins_update(data: a->l_perpolicy, length: sizeof(a->l_perpolicy), hash);
156}
157
158int
159mac_cred_label_externalize_audit(struct proc *p, struct mac *mac)
160{
161 kauth_cred_t cr;
162 int error;
163
164 cr = kauth_cred_proc_ref(procp: p);
165
166 error = MAC_EXTERNALIZE_AUDIT(cred, mac_cred_label(cr),
167 mac->m_string, mac->m_buflen);
168
169 kauth_cred_unref(&cr);
170 return error;
171}
172
173void
174mac_cred_label_destroy(kauth_cred_t cred)
175{
176 struct label *label = mac_cred_label(cred);
177 cred->cr_label = NULL;
178 mac_cred_label_free(label);
179}
180
181int
182mac_cred_label_externalize(struct label *label, char *elements,
183 char *outbuf, size_t outbuflen, int flags __unused)
184{
185 int error = 0;
186
187 error = MAC_EXTERNALIZE(cred, label, elements, outbuf, outbuflen);
188
189 return error;
190}
191
192int
193mac_cred_label_internalize(struct label *label, char *string)
194{
195 int error;
196
197 error = MAC_INTERNALIZE(cred, label, string);
198
199 return error;
200}
201
202/*
203 * By default, fork just adds a reference to the parent
204 * credential. Policies may need to know about this reference
205 * if they are tracking exit calls to know when to free the
206 * label.
207 */
208void
209mac_cred_label_associate_fork(kauth_cred_t cred, proc_t proc)
210{
211 MAC_PERFORM(cred_label_associate_fork, cred, proc);
212}
213
214/*
215 * Initialize MAC label for the first kernel process, from which other
216 * kernel processes and threads are spawned.
217 */
218void
219mac_cred_label_associate_kernel(kauth_cred_t cred)
220{
221 MAC_PERFORM(cred_label_associate_kernel, cred);
222}
223
224/*
225 * Initialize MAC label for the first userland process, from which other
226 * userland processes and threads are spawned.
227 */
228void
229mac_cred_label_associate_user(kauth_cred_t cred)
230{
231 MAC_PERFORM(cred_label_associate_user, cred);
232}
233
234/*
235 * When a new process is created, its label must be initialized. Generally,
236 * this involves inheritence from the parent process, modulo possible
237 * deltas. This function allows that processing to take place.
238 */
239void
240mac_cred_label_associate(struct ucred *parent_cred, struct ucred *child_cred)
241{
242 MAC_PERFORM(cred_label_associate, parent_cred, child_cred);
243}
244
245int
246mac_execve_enter(user_addr_t mac_p, struct image_params *imgp)
247{
248 if (mac_p == USER_ADDR_NULL) {
249 return 0;
250 }
251
252 return mac_do_set(p: current_proc(), mac_p,
253 setter: ^(char *input, __unused size_t len) {
254 struct label *execlabel;
255 int error;
256
257 execlabel = mac_cred_label_alloc();
258 if ((error = mac_cred_label_internalize(label: execlabel, string: input))) {
259 mac_cred_label_free(label: execlabel);
260 execlabel = NULL;
261 }
262
263 imgp->ip_execlabelp = execlabel;
264 return error;
265 });
266}
267
268/*
269 * When the subject's label changes, it may require revocation of privilege
270 * to mapped objects. This can't be done on-the-fly later with a unified
271 * buffer cache.
272 *
273 * XXX: CRF_MAC_ENFORCE should be in a kauth_cred_t field, rather
274 * XXX: than a posix_cred_t field.
275 */
276void
277mac_cred_label_update(kauth_cred_t cred, struct label *newlabel)
278{
279 posix_cred_t pcred = posix_cred_get(cred);
280
281 /* force label to be part of "matching" for credential */
282 pcred->cr_flags |= CRF_MAC_ENFORCE;
283
284 /* inform the policies of the update */
285 MAC_PERFORM(cred_label_update, cred, newlabel);
286}
287
288int
289mac_cred_check_label_update(kauth_cred_t cred, struct label *newlabel)
290{
291 int error;
292
293#if SECURITY_MAC_CHECK_ENFORCE
294 /* 21167099 - only check if we allow write */
295 if (!mac_proc_enforce) {
296 return 0;
297 }
298#endif
299
300 MAC_CHECK(cred_check_label_update, cred, newlabel);
301
302 return error;
303}
304
305int
306mac_cred_check_visible(kauth_cred_t u1, kauth_cred_t u2)
307{
308 int error;
309
310#if SECURITY_MAC_CHECK_ENFORCE
311 /* 21167099 - only check if we allow write */
312 if (!mac_proc_enforce) {
313 return 0;
314 }
315#endif
316
317 MAC_CHECK(cred_check_visible, u1, u2);
318
319 return error;
320}
321
322int
323mac_proc_check_debug(proc_ident_t tracing_ident, kauth_cred_t tracing_cred, proc_ident_t traced_ident)
324{
325 int error;
326 bool enforce;
327 proc_t tracingp;
328
329#if SECURITY_MAC_CHECK_ENFORCE
330 /* 21167099 - only check if we allow write */
331 if (!mac_proc_enforce) {
332 return 0;
333 }
334#endif
335 /*
336 * Once all mac hooks adopt proc_ident_t, finding proc_t and releasing
337 * it below should go to mac_proc_check_enforce().
338 */
339 if ((tracingp = proc_find_ident(i: tracing_ident)) == PROC_NULL) {
340 return ESRCH;
341 }
342 enforce = mac_proc_check_enforce(p: tracingp);
343 proc_rele(p: tracingp);
344
345 if (!enforce) {
346 return 0;
347 }
348 MAC_CHECK(proc_check_debug, tracing_cred, traced_ident);
349
350 return error;
351}
352
353int
354mac_proc_check_dump_core(struct proc *proc)
355{
356 int error;
357
358#if SECURITY_MAC_CHECK_ENFORCE
359 /* 21167099 - only check if we allow write */
360 if (!mac_proc_enforce) {
361 return 0;
362 }
363#endif
364 if (!mac_proc_check_enforce(p: proc)) {
365 return 0;
366 }
367
368 MAC_CHECK(proc_check_dump_core, proc);
369
370 return error;
371}
372
373int
374mac_proc_check_remote_thread_create(struct task *task, int flavor, thread_state_t new_state, mach_msg_type_number_t new_state_count)
375{
376 proc_t curp = current_proc();
377 proc_t proc;
378 int error;
379
380#if SECURITY_MAC_CHECK_ENFORCE
381 /* 21167099 - only check if we allow write */
382 if (!mac_proc_enforce) {
383 return 0;
384 }
385#endif
386 if (!mac_proc_check_enforce(p: curp)) {
387 return 0;
388 }
389
390 proc = proc_find(pid: task_pid(task));
391 if (proc == PROC_NULL) {
392 return ESRCH;
393 }
394
395 MAC_CHECK(proc_check_remote_thread_create, current_cached_proc_cred(curp),
396 proc, flavor, new_state, new_state_count);
397 proc_rele(p: proc);
398
399 return error;
400}
401
402void
403mac_proc_notify_service_port_derive(struct mach_service_port_info *sp_info)
404{
405 MAC_PERFORM(proc_notify_service_port_derive,
406 current_cached_proc_cred(PROC_NULL), sp_info);
407}
408
409int
410mac_proc_check_fork(proc_t curp)
411{
412 int error;
413
414#if SECURITY_MAC_CHECK_ENFORCE
415 /* 21167099 - only check if we allow write */
416 if (!mac_proc_enforce) {
417 return 0;
418 }
419#endif
420 if (!mac_proc_check_enforce(p: curp)) {
421 return 0;
422 }
423
424 MAC_CHECK(proc_check_fork, current_cached_proc_cred(curp), curp);
425
426 return error;
427}
428
429int
430mac_proc_check_get_task(struct ucred *cred, proc_ident_t pident, mach_task_flavor_t flavor)
431{
432 int error;
433
434 assert(flavor <= TASK_FLAVOR_NAME);
435
436 MAC_CHECK(proc_check_get_task_with_flavor, cred, pident, flavor);
437
438 return error;
439}
440
441int
442mac_proc_check_expose_task(struct ucred *cred, proc_ident_t pident, mach_task_flavor_t flavor)
443{
444 int error;
445
446 assert(flavor <= TASK_FLAVOR_NAME);
447
448 MAC_CHECK(proc_check_expose_task_with_flavor, cred, pident, flavor);
449
450 return error;
451}
452
453int
454mac_proc_check_inherit_ipc_ports(
455 struct proc *p,
456 struct vnode *cur_vp,
457 off_t cur_offset,
458 struct vnode *img_vp,
459 off_t img_offset,
460 struct vnode *scriptvp)
461{
462 int error;
463
464 MAC_CHECK(proc_check_inherit_ipc_ports, p, cur_vp, cur_offset, img_vp, img_offset, scriptvp);
465
466 return error;
467}
468
469/*
470 * The type of maxprot in proc_check_map_anon must be equivalent to vm_prot_t
471 * (defined in <mach/vm_prot.h>). mac_policy.h does not include any header
472 * files, so cannot use the typedef itself.
473 */
474int
475mac_proc_check_map_anon(proc_t proc, kauth_cred_t cred, user_addr_t u_addr,
476 user_size_t u_size, int prot, int flags, int *maxprot)
477{
478 int error;
479
480#if SECURITY_MAC_CHECK_ENFORCE
481 /* 21167099 - only check if we allow write */
482 if (!mac_vm_enforce) {
483 return 0;
484 }
485#endif
486 if (!mac_proc_check_enforce(p: proc)) {
487 return 0;
488 }
489
490 MAC_CHECK(proc_check_map_anon, proc, cred, u_addr, u_size, prot, flags, maxprot);
491
492 return error;
493}
494
495
496int
497mac_proc_check_memorystatus_control(proc_t proc, uint32_t command, pid_t pid)
498{
499 int error;
500
501#if SECURITY_MAC_CHECK_ENFORCE
502 /* 21167099 - only check if we allow write */
503 if (!mac_proc_enforce) {
504 return 0;
505 }
506#endif
507 if (!mac_proc_check_enforce(p: proc)) {
508 return 0;
509 }
510
511 MAC_CHECK(proc_check_memorystatus_control, current_cached_proc_cred(proc),
512 command, pid);
513
514 return error;
515}
516
517int
518mac_proc_check_mprotect(proc_t proc,
519 user_addr_t addr, user_size_t size, int prot)
520{
521 int error;
522
523#if SECURITY_MAC_CHECK_ENFORCE
524 /* 21167099 - only check if we allow write */
525 if (!mac_vm_enforce) {
526 return 0;
527 }
528#endif
529 if (!mac_proc_check_enforce(p: proc)) {
530 return 0;
531 }
532
533 MAC_CHECK(proc_check_mprotect, current_cached_proc_cred(proc),
534 proc, addr, size, prot);
535
536 return error;
537}
538
539int
540mac_proc_check_run_cs_invalid(proc_t proc)
541{
542 int error;
543
544#if SECURITY_MAC_CHECK_ENFORCE
545 /* 21167099 - only check if we allow write */
546 if (!mac_vm_enforce) {
547 return 0;
548 }
549#endif
550
551 MAC_CHECK(proc_check_run_cs_invalid, proc);
552
553 return error;
554}
555
556void
557mac_proc_notify_cs_invalidated(proc_t proc)
558{
559 MAC_PERFORM(proc_notify_cs_invalidated, proc);
560}
561
562int
563mac_proc_check_sched(proc_t curp, struct proc *proc)
564{
565 int error;
566
567#if SECURITY_MAC_CHECK_ENFORCE
568 /* 21167099 - only check if we allow write */
569 if (!mac_proc_enforce) {
570 return 0;
571 }
572#endif
573 if (!mac_proc_check_enforce(p: curp)) {
574 return 0;
575 }
576
577 MAC_CHECK(proc_check_sched, current_cached_proc_cred(curp), proc);
578
579 return error;
580}
581
582int
583mac_proc_check_signal(proc_t curp, struct proc *proc, int signum)
584{
585 int error;
586
587#if SECURITY_MAC_CHECK_ENFORCE
588 /* 21167099 - only check if we allow write */
589 if (!mac_proc_enforce) {
590 return 0;
591 }
592#endif
593 if (!mac_proc_check_enforce(p: curp)) {
594 return 0;
595 }
596
597 MAC_CHECK(proc_check_signal, current_cached_proc_cred(curp), proc, signum);
598
599 return error;
600}
601
602int
603mac_proc_check_syscall_unix(proc_t curp, int scnum)
604{
605 int error;
606
607#if SECURITY_MAC_CHECK_ENFORCE
608 /* 21167099 - only check if we allow write */
609 if (!mac_proc_enforce) {
610 return 0;
611 }
612#endif
613 if (!mac_proc_check_enforce(p: curp)) {
614 return 0;
615 }
616
617 MAC_CHECK(proc_check_syscall_unix, curp, scnum);
618
619 return error;
620}
621
622int
623mac_proc_check_wait(proc_t curp, struct proc *proc)
624{
625 int error;
626
627#if SECURITY_MAC_CHECK_ENFORCE
628 /* 21167099 - only check if we allow write */
629 if (!mac_proc_enforce) {
630 return 0;
631 }
632#endif
633 if (!mac_proc_check_enforce(p: curp)) {
634 return 0;
635 }
636
637 MAC_CHECK(proc_check_wait, current_cached_proc_cred(curp), proc);
638
639 return error;
640}
641
642void
643mac_proc_notify_exit(struct proc *proc)
644{
645 MAC_PERFORM(proc_notify_exit, proc);
646}
647
648int
649mac_proc_check_suspend_resume(proc_t proc, int sr)
650{
651 proc_t curp = current_proc();
652 int error;
653
654#if SECURITY_MAC_CHECK_ENFORCE
655 /* 21167099 - only check if we allow write */
656 if (!mac_proc_enforce) {
657 return 0;
658 }
659#endif
660 if (!mac_proc_check_enforce(p: curp)) {
661 return 0;
662 }
663
664 MAC_CHECK(proc_check_suspend_resume, current_cached_proc_cred(curp),
665 proc, sr);
666
667 return error;
668}
669
670int
671mac_proc_check_ledger(proc_t curp, proc_t proc, int ledger_op)
672{
673 int error = 0;
674
675#if SECURITY_MAC_CHECK_ENFORCE
676 /* 21167099 - only check if we allow write */
677 if (!mac_proc_enforce) {
678 return 0;
679 }
680#endif
681 if (!mac_proc_check_enforce(p: curp)) {
682 return 0;
683 }
684
685 MAC_CHECK(proc_check_ledger, current_cached_proc_cred(curp),
686 proc, ledger_op);
687
688 return error;
689}
690
691int
692mac_proc_check_proc_info(proc_t curp, proc_t target, int callnum, int flavor)
693{
694 int error = 0;
695
696#if SECURITY_MAC_CHECK_ENFORCE
697 /* 21167099 - only check if we allow write */
698 if (!mac_proc_enforce) {
699 return 0;
700 }
701#endif
702 if (!mac_proc_check_enforce(p: curp)) {
703 return 0;
704 }
705
706 MAC_CHECK(proc_check_proc_info, current_cached_proc_cred(curp),
707 target, callnum, flavor);
708
709 return error;
710}
711
712int
713mac_proc_check_get_cs_info(proc_t curp, proc_t target, unsigned int op)
714{
715 int error = 0;
716
717#if SECURITY_MAC_CHECK_ENFORCE
718 /* 21167099 - only check if we allow write */
719 if (!mac_proc_enforce) {
720 return 0;
721 }
722#endif
723 if (!mac_proc_check_enforce(p: curp)) {
724 return 0;
725 }
726
727 MAC_CHECK(proc_check_get_cs_info, current_cached_proc_cred(curp),
728 target, op);
729
730 return error;
731}
732
733int
734mac_proc_check_set_cs_info(proc_t curp, proc_t target, unsigned int op)
735{
736 int error = 0;
737
738#if SECURITY_MAC_CHECK_ENFORCE
739 /* 21167099 - only check if we allow write */
740 if (!mac_proc_enforce) {
741 return 0;
742 }
743#endif
744 if (!mac_proc_check_enforce(p: curp)) {
745 return 0;
746 }
747
748 MAC_CHECK(proc_check_set_cs_info, current_cached_proc_cred(curp),
749 target, op);
750
751 return error;
752}
753
754int
755mac_proc_check_setuid(proc_t curp, kauth_cred_t cred, uid_t uid)
756{
757 int error = 0;
758
759#if SECURITY_MAC_CHECK_ENFORCE
760 /* 21167099 - only check if we allow write */
761 if (!mac_proc_enforce) {
762 return 0;
763 }
764#endif
765 if (!mac_proc_check_enforce(p: curp)) {
766 return 0;
767 }
768
769 MAC_CHECK(proc_check_setuid, cred, uid);
770
771 return error;
772}
773
774int
775mac_proc_check_seteuid(proc_t curp, kauth_cred_t cred, uid_t euid)
776{
777 int error = 0;
778
779#if SECURITY_MAC_CHECK_ENFORCE
780 /* 21167099 - only check if we allow write */
781 if (!mac_proc_enforce) {
782 return 0;
783 }
784#endif
785 if (!mac_proc_check_enforce(p: curp)) {
786 return 0;
787 }
788
789 MAC_CHECK(proc_check_seteuid, cred, euid);
790
791 return error;
792}
793
794int
795mac_proc_check_setreuid(proc_t curp, kauth_cred_t cred, uid_t ruid, uid_t euid)
796{
797 int error = 0;
798
799#if SECURITY_MAC_CHECK_ENFORCE
800 /* 21167099 - only check if we allow write */
801 if (!mac_proc_enforce) {
802 return 0;
803 }
804#endif
805 if (!mac_proc_check_enforce(p: curp)) {
806 return 0;
807 }
808
809 MAC_CHECK(proc_check_setreuid, cred, ruid, euid);
810
811 return error;
812}
813
814int
815mac_proc_check_setgid(proc_t curp, kauth_cred_t cred, gid_t gid)
816{
817 int error = 0;
818
819#if SECURITY_MAC_CHECK_ENFORCE
820 /* 21167099 - only check if we allow write */
821 if (!mac_proc_enforce) {
822 return 0;
823 }
824#endif
825 if (!mac_proc_check_enforce(p: curp)) {
826 return 0;
827 }
828
829 MAC_CHECK(proc_check_setgid, cred, gid);
830
831 return error;
832}
833
834int
835mac_proc_check_setegid(proc_t curp, kauth_cred_t cred, gid_t egid)
836{
837 int error = 0;
838
839#if SECURITY_MAC_CHECK_ENFORCE
840 /* 21167099 - only check if we allow write */
841 if (!mac_proc_enforce) {
842 return 0;
843 }
844#endif
845 if (!mac_proc_check_enforce(p: curp)) {
846 return 0;
847 }
848
849 MAC_CHECK(proc_check_setegid, cred, egid);
850
851 return error;
852}
853
854int
855mac_proc_check_setregid(proc_t curp, kauth_cred_t cred, gid_t rgid, gid_t egid)
856{
857 int error = 0;
858
859#if SECURITY_MAC_CHECK_ENFORCE
860 /* 21167099 - only check if we allow write */
861 if (!mac_proc_enforce) {
862 return 0;
863 }
864#endif
865 if (!mac_proc_check_enforce(p: curp)) {
866 return 0;
867 }
868
869 MAC_CHECK(proc_check_setregid, cred, rgid, egid);
870
871 return error;
872}
873
874int
875mac_proc_check_settid(proc_t curp, uid_t uid, gid_t gid)
876{
877 int error = 0;
878
879#if SECURITY_MAC_CHECK_ENFORCE
880 /* 21167099 - only check if we allow write */
881 if (!mac_proc_enforce) {
882 return 0;
883 }
884#endif
885 if (!mac_proc_check_enforce(p: curp)) {
886 return 0;
887 }
888
889 MAC_CHECK(proc_check_settid, current_cached_proc_cred(curp),
890 kauth_cred_get(), uid, gid);
891
892 return error;
893}
894
895int
896mac_proc_check_launch_constraints(proc_t curp, struct image_params *imgp, os_reason_t *reasonp)
897{
898 char *fatal_failure_desc = NULL;
899 size_t fatal_failure_desc_len = 0;
900
901 pid_t original_parent_id = proc_original_ppid(curp);
902
903 pid_t responsible_pid = curp->p_responsible_pid;
904
905 int error = 0;
906
907 /* Vnode of the file */
908 struct vnode *vp = imgp->ip_vp;
909
910 char *vn_path = NULL;
911 vm_size_t vn_pathlen = MAXPATHLEN;
912#if SECURITY_MAC_CHECK_ENFORCE
913 /* 21167099 - only check if we allow write */
914 if (!mac_proc_enforce || !mac_vnode_enforce) {
915 return 0;
916 }
917#endif
918
919 MAC_POLICY_ITERATE({
920 mpo_proc_check_launch_constraints_t *hook = mpc->mpc_ops->mpo_proc_check_launch_constraints;
921 if (hook == NULL) {
922 continue;
923 }
924
925 size_t spawnattrlen = 0;
926 void *spawnattr = exec_spawnattr_getmacpolicyinfo(&imgp->ip_px_smpx, mpc->mpc_name, &spawnattrlen);
927 struct _posix_spawnattr *psa = (struct _posix_spawnattr *) imgp->ip_px_sa;
928 struct launch_constraint_data lcd;
929 lcd.launch_type = CS_LAUNCH_TYPE_NONE;
930
931 /* Check to see if psa_launch_type was initalized */
932 if (psa != (struct _posix_spawnattr*)NULL) {
933 lcd.launch_type = psa->psa_launch_type;
934 }
935
936 error = mac_error_select(
937 hook(curp, original_parent_id, responsible_pid,
938 spawnattr, spawnattrlen, &lcd, &fatal_failure_desc, &fatal_failure_desc_len), error);
939
940 /*
941 * Early exit in case of failure in case we have multiple registered callers.
942 * This is to avoid other MACF policies from stomping on each other's failure description
943 */
944 if (fatal_failure_desc_len) {
945 goto policy_fail;
946 }
947 });
948
949policy_fail:
950 if (fatal_failure_desc_len) {
951 /*
952 * A fatal code signature validation failure occured, formulate a crash
953 * reason.
954 */
955
956 char const *path = NULL;
957
958 vn_path = zalloc(view: ZV_NAMEI);
959 if (vn_getpath(vp, pathbuf: vn_path, len: (int*)&vn_pathlen) == 0) {
960 path = vn_path;
961 } else {
962 path = "(get vnode path failed)";
963 }
964
965 if (error == 0) {
966 panic("%s: MAC hook returned no error, but status is claimed to be fatal? "
967 "path: '%s', fatal_failure_desc_len: %ld, fatal_failure_desc:\n%s\n",
968 __func__, path, fatal_failure_desc_len, fatal_failure_desc);
969 }
970
971 os_reason_t reason = os_reason_create(OS_REASON_CODESIGNING,
972 CODESIGNING_EXIT_REASON_LAUNCH_CONSTRAINT_VIOLATION);
973
974 *reasonp = reason;
975
976 reason->osr_flags = (OS_REASON_FLAG_GENERATE_CRASH_REPORT |
977 OS_REASON_FLAG_CONSISTENT_FAILURE);
978
979 if (fatal_failure_desc != NULL) {
980 mach_vm_address_t data_addr = 0;
981
982 int reason_error = 0;
983 int kcdata_error = 0;
984
985 if ((reason_error = os_reason_alloc_buffer_noblock(cur_reason: reason,
986 osr_bufsize: kcdata_estimate_required_buffer_size(num_items: 1,
987 payload_size: (uint32_t)fatal_failure_desc_len))) == 0) {
988 if ((kcdata_error = kcdata_get_memory_addr(data: &reason->osr_kcd_descriptor,
989 EXIT_REASON_USER_DESC, size: (uint32_t)fatal_failure_desc_len,
990 user_addr: &data_addr)) == KERN_SUCCESS) {
991 kcdata_memcpy(data: &reason->osr_kcd_descriptor, dst_addr: (mach_vm_address_t)data_addr,
992 src_addr: fatal_failure_desc, size: (uint32_t)fatal_failure_desc_len);
993 }
994 }
995 }
996 }
997
998 if (vn_path) {
999 zfree(ZV_NAMEI, vn_path);
1000 }
1001
1002 if (fatal_failure_desc_len > 0 && fatal_failure_desc != NULL) {
1003 kfree_data(fatal_failure_desc, fatal_failure_desc_len);
1004 }
1005
1006 return error;
1007}
1008