1/*
2 * Copyright (c) 2000-2008 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 * Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved
30 *
31 *
32 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
33 * The Regents of the University of California. All rights reserved.
34 * (c) UNIX System Laboratories, Inc.
35 * All or some portions of this file are derived from material licensed
36 * to the University of California by American Telephone and Telegraph
37 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
38 * the permission of UNIX System Laboratories, Inc.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 * 3. All advertising materials mentioning features or use of this software
49 * must display the following acknowledgement:
50 * This product includes software developed by the University of
51 * California, Berkeley and its contributors.
52 * 4. Neither the name of the University nor the names of its contributors
53 * may be used to endorse or promote products derived from this software
54 * without specific prior written permission.
55 *
56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 * SUCH DAMAGE.
67 *
68 * @(#)kern_prot.c 8.9 (Berkeley) 2/14/95
69 *
70 *
71 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
72 * support for mandatory and extensible security protections. This notice
73 * is included in support of clause 2.2 (b) of the Apple Public License,
74 * Version 2.0.
75 *
76 *
77 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
78 * support for mandatory and extensible security protections. This notice
79 * is included in support of clause 2.2 (b) of the Apple Public License,
80 * Version 2.0.
81 *
82 */
83
84/*
85 * System calls related to processes and protection
86 */
87
88#include <sys/param.h>
89#include <sys/acct.h>
90#include <sys/systm.h>
91#include <sys/ucred.h>
92#include <sys/proc_internal.h>
93#include <sys/user.h>
94#include <sys/kauth.h>
95#include <sys/timeb.h>
96#include <sys/times.h>
97#include <sys/malloc.h>
98#include <sys/persona.h>
99
100#include <security/audit/audit.h>
101
102#if CONFIG_MACF
103#include <security/mac_framework.h>
104#endif
105
106#include <sys/mount_internal.h>
107#include <sys/sysproto.h>
108#include <mach/message.h>
109
110#include <kern/host.h>
111#include <kern/task.h> /* for current_task() */
112#include <kern/assert.h>
113
114#if DEVELOPMENT || DEBUG
115extern void task_importance_update_owner_info(task_t);
116#endif
117
118/* Used by pmap.c to copy kauth_cred_t structs */
119void kauth_cred_copy(const uintptr_t kv, const uintptr_t new_data);
120
121/*
122 * setprivexec
123 *
124 * Description: (dis)allow this process to hold task, thread, or execption
125 * ports of processes about to exec.
126 *
127 * Parameters: uap->flag New value for flag
128 *
129 * Returns: int Previous value of flag
130 *
131 * XXX: Belongs in kern_proc.c
132 */
133int
134setprivexec(proc_t p, struct setprivexec_args *uap, int32_t *retval)
135{
136 AUDIT_ARG(value32, uap->flag);
137 *retval = p->p_debugger;
138 p->p_debugger = (uap->flag != 0);
139 return 0;
140}
141
142
143/*
144 * getpid
145 *
146 * Description: get the process ID
147 *
148 * Parameters: (void)
149 *
150 * Returns: pid_t Current process ID
151 *
152 * XXX: Belongs in kern_proc.c
153 */
154int
155getpid(proc_t p, __unused struct getpid_args *uap, int32_t *retval)
156{
157 *retval = proc_getpid(p);
158 return 0;
159}
160
161
162/*
163 * getppid
164 *
165 * Description: get the parent process ID
166 *
167 * Parameters: (void)
168 *
169 * Returns: pid_t Parent process ID
170 *
171 * XXX: Belongs in kern_proc.c
172 */
173int
174getppid(proc_t p, __unused struct getppid_args *uap, int32_t *retval)
175{
176 *retval = p->p_ppid;
177 return 0;
178}
179
180
181/*
182 * getpgrp
183 *
184 * Description: get the process group ID of the calling process
185 *
186 * Parameters: (void)
187 *
188 * Returns: pid_t Process group ID
189 *
190 * XXX: Belongs in kern_proc.c
191 */
192int
193getpgrp(proc_t p, __unused struct getpgrp_args *uap, int32_t *retval)
194{
195 *retval = p->p_pgrpid;
196 return 0;
197}
198
199
200/*
201 * getpgid
202 *
203 * Description: Get an arbitary pid's process group id
204 *
205 * Parameters: uap->pid The target pid
206 *
207 * Returns: 0 Success
208 * ESRCH No such process
209 *
210 * Notes: We are permitted to return EPERM in the case that the target
211 * process is not in the same session as the calling process,
212 * which could be a security consideration
213 *
214 * XXX: Belongs in kern_proc.c
215 */
216int
217getpgid(proc_t p, struct getpgid_args *uap, int32_t *retval)
218{
219 proc_t pt;
220 int refheld = 0;
221
222 pt = p;
223 if (uap->pid == 0) {
224 goto found;
225 }
226
227 if ((pt = proc_find(pid: uap->pid)) == 0) {
228 return ESRCH;
229 }
230 refheld = 1;
231found:
232 *retval = pt->p_pgrpid;
233 if (refheld != 0) {
234 proc_rele(p: pt);
235 }
236 return 0;
237}
238
239
240/*
241 * getsid
242 *
243 * Description: Get an arbitary pid's session leaders process group ID
244 *
245 * Parameters: uap->pid The target pid
246 *
247 * Returns: 0 Success
248 * ESRCH No such process
249 *
250 * Notes: We are permitted to return EPERM in the case that the target
251 * process is not in the same session as the calling process,
252 * which could be a security consideration
253 *
254 * XXX: Belongs in kern_proc.c
255 */
256int
257getsid(proc_t p, struct getsid_args *uap, int32_t *retval)
258{
259 proc_t pt;
260
261 if (uap->pid == 0) {
262 *retval = proc_sessionid(p);
263 return 0;
264 }
265
266 if ((pt = proc_find(pid: uap->pid)) != PROC_NULL) {
267 *retval = proc_sessionid(p: pt);
268 proc_rele(p: pt);
269 return 0;
270 }
271
272 return ESRCH;
273}
274
275
276/*
277 * getuid
278 *
279 * Description: get real user ID for caller
280 *
281 * Parameters: (void)
282 *
283 * Returns: uid_t The real uid of the caller
284 */
285int
286getuid(__unused proc_t p, __unused struct getuid_args *uap, int32_t *retval)
287{
288 *retval = kauth_getruid();
289 return 0;
290}
291
292
293/*
294 * geteuid
295 *
296 * Description: get effective user ID for caller
297 *
298 * Parameters: (void)
299 *
300 * Returns: uid_t The effective uid of the caller
301 */
302int
303geteuid(__unused proc_t p, __unused struct geteuid_args *uap, int32_t *retval)
304{
305 *retval = kauth_getuid();
306 return 0;
307}
308
309
310/*
311 * gettid
312 *
313 * Description: Return the per-thread override identity.
314 *
315 * Parameters: uap->uidp Address of uid_t to get uid
316 * uap->gidp Address of gid_t to get gid
317 *
318 * Returns: 0 Success
319 * ESRCH No per thread identity active
320 */
321int
322gettid(__unused proc_t p, struct gettid_args *uap, int32_t *retval)
323{
324 thread_ro_t tro = current_thread_ro();
325 kauth_cred_t tro_cred = tro->tro_cred;
326 int error;
327
328 /*
329 * If this thread is not running with an override identity, we can't
330 * return one to the caller, so return an error instead.
331 */
332 if (tro->tro_realcred == tro->tro_cred) {
333 return ESRCH;
334 }
335
336 if ((error = suword(addr: uap->uidp, word: kauth_cred_getruid(cred: tro_cred)))) {
337 return error;
338 }
339 if ((error = suword(addr: uap->gidp, word: kauth_cred_getrgid(cred: tro_cred)))) {
340 return error;
341 }
342
343 *retval = 0;
344 return 0;
345}
346
347
348/*
349 * getgid
350 *
351 * Description: get the real group ID for the calling process
352 *
353 * Parameters: (void)
354 *
355 * Returns: gid_t The real gid of the caller
356 */
357int
358getgid(__unused proc_t p, __unused struct getgid_args *uap, int32_t *retval)
359{
360 *retval = kauth_getrgid();
361 return 0;
362}
363
364
365/*
366 * getegid
367 *
368 * Description: get the effective group ID for the calling process
369 *
370 * Parameters: (void)
371 *
372 * Returns: gid_t The effective gid of the caller
373 *
374 * Notes: As an implementation detail, the effective gid is stored as
375 * the first element of the supplementary group list.
376 *
377 * This could be implemented in Libc instead because of the above
378 * detail.
379 */
380int
381getegid(__unused proc_t p, __unused struct getegid_args *uap, int32_t *retval)
382{
383 *retval = kauth_getgid();
384 return 0;
385}
386
387
388/*
389 * getgroups
390 *
391 * Description: get the list of supplementary groups for the calling process
392 *
393 * Parameters: uap->gidsetsize # of gid_t's in user buffer
394 * uap->gidset Pointer to user buffer
395 *
396 * Returns: 0 Success
397 * EINVAL User buffer too small
398 * copyout:EFAULT User buffer invalid
399 *
400 * Retval: -1 Error
401 * !0 # of groups
402 *
403 * Notes: The caller may specify a 0 value for gidsetsize, and we will
404 * then return how large a buffer is required (in gid_t's) to
405 * contain the answer at the time of the call. Otherwise, we
406 * return the number of gid_t's catually copied to user space.
407 *
408 * When called with a 0 gidsetsize from a multithreaded program,
409 * there is no guarantee that another thread may not change the
410 * number of supplementary groups, and therefore a subsequent
411 * call could still fail, unless the maximum possible buffer
412 * size is supplied by the user.
413 *
414 * As an implementation detail, the effective gid is stored as
415 * the first element of the supplementary group list, and will
416 * be returned by this call.
417 */
418int
419getgroups(__unused proc_t p, struct getgroups_args *uap, int32_t *retval)
420{
421 int ngrp;
422 int error;
423 kauth_cred_t cred;
424 posix_cred_t pcred;
425
426 /* grab reference while we muck around with the credential */
427 cred = kauth_cred_get_with_ref();
428 pcred = posix_cred_get(cred);
429
430 if ((ngrp = uap->gidsetsize) == 0) {
431 *retval = pcred->cr_ngroups;
432 kauth_cred_unref(&cred);
433 return 0;
434 }
435 if (ngrp < pcred->cr_ngroups) {
436 kauth_cred_unref(&cred);
437 return EINVAL;
438 }
439 ngrp = pcred->cr_ngroups;
440 if ((error = copyout((caddr_t)pcred->cr_groups,
441 uap->gidset,
442 ngrp * sizeof(gid_t)))) {
443 kauth_cred_unref(&cred);
444 return error;
445 }
446 kauth_cred_unref(&cred);
447 *retval = ngrp;
448 return 0;
449}
450
451
452/*
453 * Return the per-thread/per-process supplementary groups list.
454 *
455 * XXX implement getsgroups
456 *
457 */
458
459int
460getsgroups(__unused proc_t p, __unused struct getsgroups_args *uap, __unused int32_t *retval)
461{
462 return ENOTSUP;
463}
464
465/*
466 * Return the per-thread/per-process whiteout groups list.
467 *
468 * XXX implement getwgroups
469 *
470 */
471
472int
473getwgroups(__unused proc_t p, __unused struct getwgroups_args *uap, __unused int32_t *retval)
474{
475 return ENOTSUP;
476}
477
478/*
479 * setsid_internal
480 *
481 * Description: Core implementation of setsid().
482 */
483int
484setsid_internal(proc_t p)
485{
486 struct pgrp * pg = PGRP_NULL;
487
488 if (p->p_pgrpid == proc_getpid(p) ||
489 (pg = pgrp_find(proc_getpid(p)))) {
490 pgrp_rele(pgrp: pg);
491 return EPERM;
492 }
493
494 /* enter pgrp works with its own pgrp refcount */
495 (void)enterpgrp(p, pgid: proc_getpid(p), mksess: 1);
496 return 0;
497}
498
499/*
500 * setsid
501 *
502 * Description: Create a new session and set the process group ID to the
503 * session ID
504 *
505 * Parameters: (void)
506 *
507 * Returns: 0 Success
508 * EPERM Permission denied
509 *
510 * Notes: If the calling process is not the process group leader; there
511 * is no existing process group with its ID, then this function will
512 * create a new session, a new process group, and put the caller in the
513 * process group (as the sole member) and make it the session
514 * leader (as the sole process in the session).
515 *
516 * The existing controlling tty (if any) will be dissociated
517 * from the process, and the next non-O_NOCTTY open of a tty
518 * will establish a new controlling tty.
519 *
520 * XXX: Belongs in kern_proc.c
521 */
522int
523setsid(proc_t p, __unused struct setsid_args *uap, int32_t *retval)
524{
525 int rc = setsid_internal(p);
526 if (rc == 0) {
527 *retval = proc_getpid(p);
528 }
529 return rc;
530}
531
532
533/*
534 * setpgid
535 *
536 * Description: set process group ID for job control
537 *
538 * Parameters: uap->pid Process to change
539 * uap->pgid Process group to join or create
540 *
541 * Returns: 0 Success
542 * ESRCH pid is not the caller or a child of
543 * the caller
544 * enterpgrp:ESRCH No such process
545 * EACCES Permission denied due to exec
546 * EINVAL Invalid argument
547 * EPERM The target process is not in the same
548 * session as the calling process
549 * EPERM The target process is a session leader
550 * EPERM pid and pgid are not the same, and
551 * there is no process in the calling
552 * process whose process group ID matches
553 * pgid
554 *
555 * Notes: This function will cause the target process to either join
556 * an existing process process group, or create a new process
557 * group in the session of the calling process. It cannot be
558 * used to change the process group ID of a process which is
559 * already a session leader.
560 *
561 * If the target pid is 0, the pid of the calling process is
562 * substituted as the new target; if pgid is 0, the target pid
563 * is used as the target process group ID.
564 *
565 * Legacy: This system call entry point is also used to implement the
566 * legacy library routine setpgrp(), which under POSIX
567 *
568 * XXX: Belongs in kern_proc.c
569 */
570int
571setpgid(proc_t curp, struct setpgid_args *uap, __unused int32_t *retval)
572{
573 proc_t targp = PROC_NULL; /* target process */
574 struct pgrp *curp_pg = PGRP_NULL;
575 struct pgrp *targp_pg = PGRP_NULL;
576 int error = 0;
577 int refheld = 0;
578 int samesess = 0;
579
580 curp_pg = proc_pgrp(curp, NULL);
581
582 if (uap->pid != 0 && uap->pid != proc_getpid(curp)) {
583 if ((targp = proc_find(pid: uap->pid)) == 0 || !inferior(p: targp)) {
584 if (targp != PROC_NULL) {
585 refheld = 1;
586 }
587 error = ESRCH;
588 goto out;
589 }
590 refheld = 1;
591 targp_pg = proc_pgrp(targp, NULL);
592 if (targp_pg->pg_session != curp_pg->pg_session) {
593 error = EPERM;
594 goto out;
595 }
596 if (targp->p_flag & P_EXEC) {
597 error = EACCES;
598 goto out;
599 }
600 } else {
601 targp = curp;
602 targp_pg = proc_pgrp(targp, NULL);
603 }
604
605 if (SESS_LEADER(targp, targp_pg->pg_session)) {
606 error = EPERM;
607 goto out;
608 }
609
610 if (uap->pgid < 0) {
611 error = EINVAL;
612 goto out;
613 }
614 if (uap->pgid == 0) {
615 uap->pgid = proc_getpid(targp);
616 } else if (uap->pgid != proc_getpid(targp)) {
617 struct pgrp *pg = PGRP_NULL;
618
619 if ((pg = pgrp_find(uap->pgid)) == PGRP_NULL) {
620 error = EPERM;
621 goto out;
622 }
623 samesess = (pg->pg_session != curp_pg->pg_session);
624 pgrp_rele(pgrp: pg);
625 if (samesess != 0) {
626 error = EPERM;
627 goto out;
628 }
629 }
630 error = enterpgrp(p: targp, pgid: uap->pgid, mksess: 0);
631out:
632 pgrp_rele(pgrp: curp_pg);
633 pgrp_rele(pgrp: targp_pg);
634 if (refheld != 0) {
635 proc_rele(p: targp);
636 }
637 return error;
638}
639
640
641/*
642 * issetugid
643 *
644 * Description: Is current process tainted by uid or gid changes system call
645 *
646 * Parameters: (void)
647 *
648 * Returns: 0 Not tainted
649 * 1 Tainted
650 *
651 * Notes: A process is considered tainted if it was created as a retult
652 * of an execve call from an imnage that had either the SUID or
653 * SGID bit set on the executable, or if it has changed any of its
654 * real, effective, or saved user or group IDs since beginning
655 * execution.
656 */
657int
658proc_issetugid(proc_t p)
659{
660 return (p->p_flag & P_SUGID) ? 1 : 0;
661}
662
663int
664issetugid(proc_t p, __unused struct issetugid_args *uap, int32_t *retval)
665{
666 /*
667 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
668 * we use P_SUGID because we consider changing the owners as
669 * "tainting" as well.
670 * This is significant for procs that start as root and "become"
671 * a user without an exec - programs cannot know *everything*
672 * that libc *might* have put in their data segment.
673 */
674
675 *retval = proc_issetugid(p);
676 return 0;
677}
678
679/*
680 * setuid
681 *
682 * Description: Set user ID system call
683 *
684 * Parameters: uap->uid uid to set
685 *
686 * Returns: 0 Success
687 * suser:EPERM Permission denied
688 *
689 * Notes: If called by a privileged process, this function will set the
690 * real, effective, and saved uid to the requested value.
691 *
692 * If called from an unprivileged process, but uid is equal to the
693 * real or saved uid, then the effective uid will be set to the
694 * requested value, but the real and saved uid will not change.
695 *
696 * If the credential is changed as a result of this call, then we
697 * flag the process as having set privilege since the last exec.
698 */
699int
700setuid(proc_t p, struct setuid_args *uap, __unused int32_t *retval)
701{
702 __block int error = 0;
703 __block uid_t old_ruid;
704 __block uid_t ruid;
705 uid_t want_uid;
706 bool changed;
707
708 want_uid = uap->uid;
709 AUDIT_ARG(uid, want_uid);
710
711 changed = kauth_cred_proc_update(p, action: PROC_SETTOKEN_SETUGID,
712 fn: ^bool (kauth_cred_t parent, kauth_cred_t model) {
713 posix_cred_t cur_pcred = posix_cred_get(cred: parent);
714 uid_t svuid = KAUTH_UID_NONE;
715 uid_t gmuid = KAUTH_UID_NONE;
716
717 ruid = KAUTH_UID_NONE;
718 old_ruid = cur_pcred->cr_ruid;
719
720#if CONFIG_MACF
721 if ((error = mac_proc_check_setuid(curp: p, cred: parent, uid: want_uid)) != 0) {
722 return false;
723 }
724#endif
725
726 if (want_uid != cur_pcred->cr_ruid && /* allow setuid(getuid()) */
727 want_uid != cur_pcred->cr_svuid && /* allow setuid(saved uid) */
728 (error = suser(cred: parent, acflag: &p->p_acflag))) {
729 return false;
730 }
731
732 /*
733 * If we are privileged, then set the saved and real UID too;
734 * otherwise, just set the effective UID
735 */
736 if (suser(cred: parent, acflag: &p->p_acflag) == 0) {
737 svuid = want_uid;
738 ruid = want_uid;
739 }
740
741 /*
742 * Only set the gmuid if the current cred has not opt'ed out;
743 * this normally only happens when calling setgroups() instead
744 * of initgroups() to set an explicit group list, or one of the
745 * other group manipulation functions is invoked and results in
746 * a dislocation (i.e. the credential group membership changes
747 * to something other than the default list for the user, as
748 * in entering a group or leaving an exclusion group).
749 */
750 if (!(cur_pcred->cr_flags & CRF_NOMEMBERD)) {
751 gmuid = want_uid;
752 }
753
754 return kauth_cred_model_setresuid(model,
755 ruid, euid: want_uid, svuid, gmuid);
756 });
757
758 if (changed && ruid != KAUTH_UID_NONE && old_ruid != ruid &&
759 !proc_has_persona(p)) {
760 (void)chgproccnt(uid: ruid, diff: 1);
761 (void)chgproccnt(uid: old_ruid, diff: -1);
762 }
763
764 return error;
765}
766
767
768/*
769 * seteuid
770 *
771 * Description: Set effective user ID system call
772 *
773 * Parameters: uap->euid effective uid to set
774 *
775 * Returns: 0 Success
776 * suser:EPERM Permission denied
777 *
778 * Notes: If called by a privileged process, or called from an
779 * unprivileged process but euid is equal to the real or saved
780 * uid, then the effective uid will be set to the requested
781 * value, but the real and saved uid will not change.
782 *
783 * If the credential is changed as a result of this call, then we
784 * flag the process as having set privilege since the last exec.
785 */
786int
787seteuid(proc_t p, struct seteuid_args *uap, __unused int32_t *retval)
788{
789 __block int error = 0;
790 uid_t want_euid;
791
792 want_euid = uap->euid;
793 AUDIT_ARG(euid, want_euid);
794
795 kauth_cred_proc_update(p, action: PROC_SETTOKEN_SETUGID,
796 fn: ^bool (kauth_cred_t parent, kauth_cred_t model) {
797 posix_cred_t cur_pcred = posix_cred_get(cred: parent);
798
799#if CONFIG_MACF
800 if ((error = mac_proc_check_seteuid(curp: p, cred: parent, euid: want_euid)) != 0) {
801 return false;
802 }
803#endif
804
805 if (want_euid != cur_pcred->cr_ruid && want_euid != cur_pcred->cr_svuid &&
806 (error = suser(cred: parent, acflag: &p->p_acflag))) {
807 return false;
808 }
809
810 return kauth_cred_model_setresuid(model,
811 KAUTH_UID_NONE, euid: want_euid,
812 KAUTH_UID_NONE, gmuid: cur_pcred->cr_gmuid);
813 });
814
815 return error;
816}
817
818
819/*
820 * setreuid
821 *
822 * Description: Set real and effective user ID system call
823 *
824 * Parameters: uap->ruid real uid to set
825 * uap->euid effective uid to set
826 *
827 * Returns: 0 Success
828 * suser:EPERM Permission denied
829 *
830 * Notes: A value of -1 is a special case indicating that the uid for
831 * which that value is specified not be changed. If both values
832 * are specified as -1, no action is taken.
833 *
834 * If called by a privileged process, the real and effective uid
835 * will be set to the new value(s) specified.
836 *
837 * If called from an unprivileged process, the real uid may be
838 * set to the current value of the real uid, or to the current
839 * value of the saved uid. The effective uid may be set to the
840 * current value of any of the effective, real, or saved uid.
841 *
842 * If the newly requested real uid or effective uid does not
843 * match the saved uid, then set the saved uid to the new
844 * effective uid (potentially unrecoverably dropping saved
845 * privilege).
846 *
847 * If the credential is changed as a result of this call, then we
848 * flag the process as having set privilege since the last exec.
849 */
850int
851setreuid(proc_t p, struct setreuid_args *uap, __unused int32_t *retval)
852{
853 __block int error = 0;
854 __block uid_t old_ruid;
855 uid_t want_ruid, want_euid;
856 bool changed;
857
858 want_ruid = uap->ruid;
859 want_euid = uap->euid;
860
861 if (want_ruid == (uid_t)-1) {
862 want_ruid = KAUTH_UID_NONE;
863 }
864
865 if (want_euid == (uid_t)-1) {
866 want_euid = KAUTH_UID_NONE;
867 }
868
869 AUDIT_ARG(euid, want_euid);
870 AUDIT_ARG(ruid, want_ruid);
871
872 changed = kauth_cred_proc_update(p, action: PROC_SETTOKEN_SETUGID,
873 fn: ^bool (kauth_cred_t parent, kauth_cred_t model) {
874 posix_cred_t cur_pcred = posix_cred_get(cred: parent);
875 uid_t svuid = KAUTH_UID_NONE;
876
877#if CONFIG_MACF
878 if ((error = mac_proc_check_setreuid(curp: p, cred: parent, ruid: want_ruid, euid: want_euid)) != 0) {
879 return false;
880 }
881#endif
882
883 if (((want_ruid != KAUTH_UID_NONE && /* allow no change of ruid */
884 want_ruid != cur_pcred->cr_ruid && /* allow ruid = ruid */
885 want_ruid != cur_pcred->cr_uid && /* allow ruid = euid */
886 want_ruid != cur_pcred->cr_svuid) || /* allow ruid = svuid */
887 (want_euid != KAUTH_UID_NONE && /* allow no change of euid */
888 want_euid != cur_pcred->cr_uid && /* allow euid = euid */
889 want_euid != cur_pcred->cr_ruid && /* allow euid = ruid */
890 want_euid != cur_pcred->cr_svuid)) && /* allow euid = svuid */
891 (error = suser(cred: parent, acflag: &p->p_acflag))) { /* allow root user any */
892 return false;
893 }
894
895 uid_t new_euid = cur_pcred->cr_uid;
896
897 if (want_euid != KAUTH_UID_NONE && cur_pcred->cr_uid != want_euid) {
898 new_euid = want_euid;
899 }
900
901 old_ruid = cur_pcred->cr_ruid;
902
903 /*
904 * If the newly requested real uid or effective uid does
905 * not match the saved uid, then set the saved uid to the
906 * new effective uid. We are protected from escalation
907 * by the prechecking.
908 */
909 if (cur_pcred->cr_svuid != uap->ruid &&
910 cur_pcred->cr_svuid != uap->euid) {
911 svuid = new_euid;
912 }
913
914 return kauth_cred_model_setresuid(model, ruid: want_ruid, euid: want_euid,
915 svuid, gmuid: cur_pcred->cr_gmuid);
916 });
917
918 if (changed && want_ruid != KAUTH_UID_NONE && want_ruid != old_ruid &&
919 !proc_has_persona(p)) {
920 (void)chgproccnt(uid: want_ruid, diff: 1);
921 (void)chgproccnt(uid: old_ruid, diff: -1);
922 }
923
924 return error;
925}
926
927
928/*
929 * setgid
930 *
931 * Description: Set group ID system call
932 *
933 * Parameters: uap->gid gid to set
934 *
935 * Returns: 0 Success
936 * suser:EPERM Permission denied
937 *
938 * Notes: If called by a privileged process, this function will set the
939 * real, effective, and saved gid to the requested value.
940 *
941 * If called from an unprivileged process, but gid is equal to the
942 * real or saved gid, then the effective gid will be set to the
943 * requested value, but the real and saved gid will not change.
944 *
945 * If the credential is changed as a result of this call, then we
946 * flag the process as having set privilege since the last exec.
947 *
948 * As an implementation detail, the effective gid is stored as
949 * the first element of the supplementary group list, and
950 * therefore the effective group list may be reordered to keep
951 * the supplementary group list unchanged.
952 */
953int
954setgid(proc_t p, struct setgid_args *uap, __unused int32_t *retval)
955{
956 __block int error = 0;
957 gid_t want_gid;
958
959 want_gid = uap->gid;
960 AUDIT_ARG(gid, want_gid);
961
962 kauth_cred_proc_update(p, action: PROC_SETTOKEN_SETUGID,
963 fn: ^bool (kauth_cred_t parent, kauth_cred_t model) {
964 posix_cred_t cur_pcred = posix_cred_get(cred: parent);
965 gid_t rgid = KAUTH_GID_NONE;
966 gid_t svgid = KAUTH_GID_NONE;
967
968#if CONFIG_MACF
969 if ((error = mac_proc_check_setgid(curp: p, cred: parent, gid: want_gid)) != 0) {
970 return false;
971 }
972#endif
973
974 if (want_gid != cur_pcred->cr_rgid && /* allow setgid(getgid()) */
975 want_gid != cur_pcred->cr_svgid && /* allow setgid(saved gid) */
976 (error = suser(cred: parent, acflag: &p->p_acflag))) {
977 return false;
978 }
979
980 /*
981 * If we are privileged, then set the saved and real GID too;
982 * otherwise, just set the effective GID
983 */
984 if (suser(cred: parent, acflag: &p->p_acflag) == 0) {
985 svgid = want_gid;
986 rgid = want_gid;
987 }
988
989 return kauth_cred_model_setresgid(model, rgid, egid: want_gid, svgid);
990 });
991
992 return error;
993}
994
995
996/*
997 * setegid
998 *
999 * Description: Set effective group ID system call
1000 *
1001 * Parameters: uap->egid effective gid to set
1002 *
1003 * Returns: 0 Success
1004 * suser:EPERM
1005 *
1006 * Notes: If called by a privileged process, or called from an
1007 * unprivileged process but egid is equal to the real or saved
1008 * gid, then the effective gid will be set to the requested
1009 * value, but the real and saved gid will not change.
1010 *
1011 * If the credential is changed as a result of this call, then we
1012 * flag the process as having set privilege since the last exec.
1013 *
1014 * As an implementation detail, the effective gid is stored as
1015 * the first element of the supplementary group list, and
1016 * therefore the effective group list may be reordered to keep
1017 * the supplementary group list unchanged.
1018 */
1019int
1020setegid(proc_t p, struct setegid_args *uap, __unused int32_t *retval)
1021{
1022 __block int error = 0;
1023 gid_t want_egid;
1024
1025 want_egid = uap->egid;
1026 AUDIT_ARG(egid, want_egid);
1027
1028 kauth_cred_proc_update(p, action: PROC_SETTOKEN_SETUGID,
1029 fn: ^bool (kauth_cred_t parent, kauth_cred_t model) {
1030 posix_cred_t cur_pcred = posix_cred_get(cred: parent);
1031
1032#if CONFIG_MACF
1033 if ((error = mac_proc_check_setegid(curp: p, cred: parent, egid: want_egid)) != 0) {
1034 return false;
1035 }
1036#endif
1037
1038 if (want_egid != cur_pcred->cr_rgid &&
1039 want_egid != cur_pcred->cr_svgid &&
1040 (error = suser(cred: parent, acflag: &p->p_acflag))) {
1041 return false;
1042 }
1043
1044 return kauth_cred_model_setresgid(model, KAUTH_GID_NONE,
1045 egid: want_egid, KAUTH_GID_NONE);
1046 });
1047
1048 return error;
1049}
1050
1051/*
1052 * setregid
1053 *
1054 * Description: Set real and effective group ID system call
1055 *
1056 * Parameters: uap->rgid real gid to set
1057 * uap->egid effective gid to set
1058 *
1059 * Returns: 0 Success
1060 * suser:EPERM Permission denied
1061 *
1062 * Notes: A value of -1 is a special case indicating that the gid for
1063 * which that value is specified not be changed. If both values
1064 * are specified as -1, no action is taken.
1065 *
1066 * If called by a privileged process, the real and effective gid
1067 * will be set to the new value(s) specified.
1068 *
1069 * If called from an unprivileged process, the real gid may be
1070 * set to the current value of the real gid, or to the current
1071 * value of the saved gid. The effective gid may be set to the
1072 * current value of any of the effective, real, or saved gid.
1073 *
1074 * If the new real and effective gid will not be equal, or the
1075 * new real or effective gid is not the same as the saved gid,
1076 * then the saved gid will be updated to reflect the new
1077 * effective gid (potentially unrecoverably dropping saved
1078 * privilege).
1079 *
1080 * If the credential is changed as a result of this call, then we
1081 * flag the process as having set privilege since the last exec.
1082 *
1083 * As an implementation detail, the effective gid is stored as
1084 * the first element of the supplementary group list, and
1085 * therefore the effective group list may be reordered to keep
1086 * the supplementary group list unchanged.
1087 */
1088int
1089setregid(proc_t p, struct setregid_args *uap, __unused int32_t *retval)
1090{
1091 __block int error = 0;
1092 gid_t want_rgid;
1093 gid_t want_egid;
1094
1095 want_rgid = uap->rgid;
1096 want_egid = uap->egid;
1097
1098 if (want_rgid == (gid_t)-1) {
1099 want_rgid = KAUTH_GID_NONE;
1100 }
1101
1102 if (want_egid == (gid_t)-1) {
1103 want_egid = KAUTH_GID_NONE;
1104 }
1105
1106 AUDIT_ARG(egid, want_egid);
1107 AUDIT_ARG(rgid, want_rgid);
1108
1109 kauth_cred_proc_update(p, action: PROC_SETTOKEN_SETUGID,
1110 fn: ^bool (kauth_cred_t parent, kauth_cred_t model) {
1111 posix_cred_t cur_pcred = posix_cred_get(cred: parent);
1112 uid_t svgid = KAUTH_UID_NONE;
1113
1114#if CONFIG_MACF
1115 if ((error = mac_proc_check_setregid(curp: p, cred: parent, rgid: want_rgid,
1116 egid: want_egid)) != 0) {
1117 return false;
1118 }
1119#endif
1120
1121 if (((want_rgid != KAUTH_UID_NONE && /* allow no change of rgid */
1122 want_rgid != cur_pcred->cr_rgid && /* allow rgid = rgid */
1123 want_rgid != cur_pcred->cr_gid && /* allow rgid = egid */
1124 want_rgid != cur_pcred->cr_svgid) || /* allow rgid = svgid */
1125 (want_egid != KAUTH_UID_NONE && /* allow no change of egid */
1126 want_egid != cur_pcred->cr_groups[0] && /* allow no change of egid */
1127 want_egid != cur_pcred->cr_gid && /* allow egid = egid */
1128 want_egid != cur_pcred->cr_rgid && /* allow egid = rgid */
1129 want_egid != cur_pcred->cr_svgid)) && /* allow egid = svgid */
1130 (error = suser(cred: parent, acflag: &p->p_acflag))) { /* allow root user any */
1131 return false;
1132 }
1133
1134 uid_t new_egid = cur_pcred->cr_gid;
1135 if (want_egid != KAUTH_UID_NONE && cur_pcred->cr_gid != want_egid) {
1136 /* changing the effective GID */
1137 new_egid = want_egid;
1138 }
1139
1140 /*
1141 * If the newly requested real gid or effective gid does
1142 * not match the saved gid, then set the saved gid to the
1143 * new effective gid. We are protected from escalation
1144 * by the prechecking.
1145 */
1146 if (cur_pcred->cr_svgid != want_rgid &&
1147 cur_pcred->cr_svgid != want_egid) {
1148 svgid = new_egid;
1149 }
1150
1151 return kauth_cred_model_setresgid(model, rgid: want_rgid, egid: want_egid, svgid);
1152 });
1153
1154 return error;
1155}
1156
1157
1158static void
1159kern_settid_assume_cred(thread_ro_t tro, kauth_cred_t tmp)
1160{
1161 kauth_cred_t cred = NOCRED;
1162
1163 kauth_cred_set(&cred, tmp);
1164 zalloc_ro_update_field(ZONE_ID_THREAD_RO, tro, tro_cred, &cred);
1165}
1166
1167/*
1168 * Set the per-thread override identity. The first parameter can be the
1169 * current real UID, KAUTH_UID_NONE, or, if the caller is privileged, it
1170 * can be any UID. If it is KAUTH_UID_NONE, then as a special case, this
1171 * means "revert to the per process credential"; otherwise, if permitted,
1172 * it changes the effective, real, and saved UIDs and GIDs for the current
1173 * thread to the requested UID and single GID, and clears all other GIDs.
1174 */
1175static int
1176kern_settid(proc_t p, uid_t uid, gid_t gid)
1177{
1178 kauth_cred_t cred;
1179 struct thread_ro *tro = current_thread_ro();
1180#if CONFIG_MACF
1181 int error;
1182
1183 if ((error = mac_proc_check_settid(curp: p, uid, gid)) != 0) {
1184 return error;
1185 }
1186#endif
1187
1188 if (proc_suser(p) != 0) {
1189 return EPERM;
1190 }
1191
1192 if (uid == KAUTH_UID_NONE) {
1193 /* must already be assuming another identity in order to revert back */
1194 if (tro->tro_realcred == tro->tro_cred) {
1195 return EPERM;
1196 }
1197
1198 /* revert to delayed binding of process credential */
1199 kern_settid_assume_cred(tro, tmp: tro->tro_realcred);
1200 } else {
1201 /* cannot already be assuming another identity */
1202 if (tro->tro_realcred != tro->tro_cred) {
1203 return EPERM;
1204 }
1205
1206 /*
1207 * Get a new credential instance from the old if this one
1208 * changes; otherwise kauth_cred_setuidgid() returns the
1209 * same credential. We take an extra reference on the
1210 * current credential while we muck with it, so we can do
1211 * the post-compare for changes by pointer.
1212 */
1213 cred = kauth_cred_derive(cred: tro->tro_cred,
1214 fn: ^bool (kauth_cred_t parent __unused, kauth_cred_t model) {
1215 return kauth_cred_model_setuidgid(model, uid, gid);
1216 });
1217 kern_settid_assume_cred(tro, tmp: cred);
1218 kauth_cred_unref(&cred);
1219 }
1220
1221 /*
1222 * XXX should potentially set per thread security token (there is
1223 * XXX none).
1224 * XXX it is unclear whether P_SUGID should be st at this point;
1225 * XXX in theory, it is being deprecated.
1226 */
1227 return 0;
1228}
1229
1230int
1231sys_settid(proc_t p, struct settid_args *uap, __unused int32_t *retval)
1232{
1233 AUDIT_ARG(uid, uap->uid);
1234 AUDIT_ARG(gid, uap->gid);
1235
1236 return kern_settid(p, uid: uap->uid, gid: uap->gid);
1237}
1238
1239
1240/*
1241 * Set the per-thread override identity. Use this system call for a thread to
1242 * assume the identity of another process or to revert back to normal identity
1243 * of the current process.
1244 *
1245 * When the "assume" argument is non zero the current thread will assume the
1246 * identity of the process represented by the pid argument.
1247 *
1248 * When the assume argument is zero we revert back to our normal identity.
1249 */
1250int
1251sys_settid_with_pid(proc_t p, struct settid_with_pid_args *uap, __unused int32_t *retval)
1252{
1253 uid_t uid;
1254 gid_t gid;
1255
1256 AUDIT_ARG(pid, uap->pid);
1257 AUDIT_ARG(value32, uap->assume);
1258
1259 /*
1260 * XXX should potentially set per thread security token (there is
1261 * XXX none).
1262 * XXX it is unclear whether P_SUGID should be st at this point;
1263 * XXX in theory, it is being deprecated.
1264 */
1265
1266 /*
1267 * assume argument tells us to assume the identity of the process with the
1268 * id passed in the pid argument.
1269 */
1270 if (uap->assume != 0) {
1271 kauth_cred_t cred;
1272
1273 if (uap->pid == 0) {
1274 return ESRCH;
1275 }
1276
1277 cred = kauth_cred_proc_ref_for_pid(pid: uap->pid);
1278 if (cred == NOCRED) {
1279 return ESRCH;
1280 }
1281
1282 uid = kauth_cred_getuid(cred: cred);
1283 gid = kauth_cred_getgid(cred: cred);
1284 kauth_cred_unref(&cred);
1285 } else {
1286 /*
1287 * Otherwise, we are reverting back to normal mode of operation
1288 * where delayed binding of the process credential sets the
1289 * credential in the thread_ro (tro_cred)
1290 */
1291 uid = KAUTH_UID_NONE;
1292 gid = KAUTH_GID_NONE;
1293 }
1294
1295 return kern_settid(p, uid, gid);
1296}
1297
1298
1299/*
1300 * setgroups1
1301 *
1302 * Description: Internal implementation for both the setgroups and initgroups
1303 * system calls
1304 *
1305 * Parameters: gidsetsize Number of groups in set
1306 * gidset Pointer to group list
1307 * gmuid Base gid (initgroups only!)
1308 *
1309 * Returns: 0 Success
1310 * suser:EPERM Permision denied
1311 * EINVAL Invalid gidsetsize value
1312 * copyin:EFAULT Bad gidset or gidsetsize is
1313 * too large
1314 *
1315 * Notes: When called from a thread running under an assumed per-thread
1316 * identity, this function will operate against the per-thread
1317 * credential, rather than against the process credential. In
1318 * this specific case, the process credential is verified to
1319 * still be privileged at the time of the call, rather than the
1320 * per-thread credential for this operation to be permitted.
1321 *
1322 * This effectively means that setgroups/initigroups calls in
1323 * a thread running a per-thread credential should occur *after*
1324 * the settid call that created it, not before (unlike setuid,
1325 * which must be called after, since it will result in privilege
1326 * being dropped).
1327 *
1328 * When called normally (i.e. no per-thread assumed identity),
1329 * the per process credential is updated per POSIX.
1330 *
1331 * If the credential is changed as a result of this call, then we
1332 * flag the process as having set privilege since the last exec.
1333 */
1334static int
1335setgroups1(proc_t p, u_int ngrp, user_addr_t gidset, uid_t gmuid, __unused int32_t *retval)
1336{
1337 gid_t newgroups[NGROUPS] = { 0 };
1338 int error;
1339
1340 if (ngrp > NGROUPS) {
1341 return EINVAL;
1342 }
1343
1344 if (ngrp >= 1) {
1345 error = copyin(gidset,
1346 (caddr_t)newgroups, ngrp * sizeof(gid_t));
1347 if (error) {
1348 return error;
1349 }
1350 }
1351 return setgroups_internal(p, gidsetsize: ngrp, gidset: newgroups, gmuid);
1352}
1353
1354int
1355setgroups_internal(proc_t p, u_int ngrp, gid_t *newgroups, uid_t gmuid)
1356{
1357 thread_ro_t tro = current_thread_ro();
1358 kauth_cred_t cred;
1359 int error;
1360
1361 error = proc_suser(p);
1362 if (error) {
1363 return error;
1364 }
1365
1366 if (ngrp < 1) {
1367 ngrp = 1;
1368 newgroups[0] = 0;
1369 }
1370
1371 kauth_cred_derive_t fn = ^bool (kauth_cred_t parent __unused, kauth_cred_t model) {
1372 return kauth_cred_model_setgroups(model, groups: newgroups, groupcount: ngrp, gmuid);
1373 };
1374
1375 if (tro->tro_realcred != tro->tro_cred) {
1376 /*
1377 * If this thread is under an assumed identity, set the
1378 * supplementary grouplist on the thread credential instead
1379 * of the process one. If we were the only reference holder,
1380 * the credential is updated in place, otherwise, our reference
1381 * is dropped and we get back a different cred with a reference
1382 * already held on it. Because this is per-thread, we don't
1383 * need the referencing/locking/retry required for per-process.
1384 */
1385 cred = kauth_cred_derive(cred: tro->tro_cred, fn);
1386 kern_settid_assume_cred(tro, tmp: cred);
1387 kauth_cred_unref(&cred);
1388 } else {
1389 kauth_cred_proc_update(p, action: PROC_SETTOKEN_SETUGID, fn);
1390 AUDIT_ARG(groupset, &newgroups[0], ngrp);
1391 }
1392
1393 return 0;
1394}
1395
1396
1397/*
1398 * initgroups
1399 *
1400 * Description: Initialize the default supplementary groups list and set the
1401 * gmuid for use by the external group resolver (if any)
1402 *
1403 * Parameters: uap->gidsetsize Number of groups in set
1404 * uap->gidset Pointer to group list
1405 * uap->gmuid Base gid
1406 *
1407 * Returns: 0 Success
1408 * setgroups1:EPERM Permision denied
1409 * setgroups1:EINVAL Invalid gidsetsize value
1410 * setgroups1:EFAULT Bad gidset or gidsetsize is
1411 *
1412 * Notes: This function opts *IN* to memberd participation
1413 *
1414 * The normal purpose of this function is for a privileged
1415 * process to indicate supplementary groups and identity for
1416 * participation in extended group membership resolution prior
1417 * to dropping privilege by assuming a specific user identity.
1418 *
1419 * It is the first half of the primary mechanism whereby user
1420 * identity is established to the system by programs such as
1421 * /usr/bin/login. The second half is the drop of uid privilege
1422 * for a specific uid corresponding to the user.
1423 *
1424 * See also: setgroups1()
1425 */
1426int
1427initgroups(proc_t p, struct initgroups_args *uap, __unused int32_t *retval)
1428{
1429 return setgroups1(p, ngrp: uap->gidsetsize, gidset: uap->gidset, gmuid: uap->gmuid, retval);
1430}
1431
1432
1433/*
1434 * setgroups
1435 *
1436 * Description: Initialize the default supplementary groups list
1437 *
1438 * Parameters: gidsetsize Number of groups in set
1439 * gidset Pointer to group list
1440 *
1441 * Returns: 0 Success
1442 * setgroups1:EPERM Permision denied
1443 * setgroups1:EINVAL Invalid gidsetsize value
1444 * setgroups1:EFAULT Bad gidset or gidsetsize is
1445 *
1446 * Notes: This functions opts *OUT* of memberd participation.
1447 *
1448 * This function exists for compatibility with POSIX. Most user
1449 * programs should use initgroups() instead to ensure correct
1450 * participation in group membership resolution when utilizing
1451 * a directory service for authentication.
1452 *
1453 * It is identical to an initgroups() call with a gmuid argument
1454 * of KAUTH_UID_NONE.
1455 *
1456 * See also: setgroups1()
1457 */
1458int
1459setgroups(proc_t p, struct setgroups_args *uap, __unused int32_t *retval)
1460{
1461 return setgroups1(p, ngrp: uap->gidsetsize, gidset: uap->gidset, KAUTH_UID_NONE, retval);
1462}
1463
1464
1465/*
1466 * Set the per-thread/per-process supplementary groups list.
1467 *
1468 * XXX implement setsgroups
1469 *
1470 */
1471
1472int
1473setsgroups(__unused proc_t p, __unused struct setsgroups_args *uap, __unused int32_t *retval)
1474{
1475 return ENOTSUP;
1476}
1477
1478/*
1479 * Set the per-thread/per-process whiteout groups list.
1480 *
1481 * XXX implement setwgroups
1482 *
1483 */
1484
1485int
1486setwgroups(__unused proc_t p, __unused struct setwgroups_args *uap, __unused int32_t *retval)
1487{
1488 return ENOTSUP;
1489}
1490
1491
1492/*
1493 * Check if gid is a member of the group set.
1494 *
1495 * XXX This interface is going away; use kauth_cred_ismember_gid() directly
1496 * XXX instead.
1497 */
1498int
1499groupmember(gid_t gid, kauth_cred_t cred)
1500{
1501 int is_member;
1502
1503 if (kauth_cred_ismember_gid(cred: cred, gid: gid, resultp: &is_member) == 0 && is_member) {
1504 return 1;
1505 }
1506 return 0;
1507}
1508
1509
1510/*
1511 * Test whether the specified credentials imply "super-user"
1512 * privilege; if so, and we have accounting info, set the flag
1513 * indicating use of super-powers.
1514 * Returns 0 or error.
1515 *
1516 * XXX This interface is going away; use kauth_cred_issuser() directly
1517 * XXX instead.
1518 *
1519 * Note: This interface exists to implement the "has used privilege"
1520 * bit (ASU) in the p_acflags field of the process, which is
1521 * only externalized via private sysctl and in process accounting
1522 * records. The flag is technically not required in either case.
1523 */
1524int
1525suser(kauth_cred_t cred, u_short *acflag)
1526{
1527 if (kauth_cred_getuid(cred: cred) == 0) {
1528 if (acflag) {
1529 *acflag |= ASU;
1530 }
1531 return 0;
1532 }
1533 return EPERM;
1534}
1535
1536
1537/*
1538 * getlogin
1539 *
1540 * Description: Get login name, if available.
1541 *
1542 * Parameters: uap->namebuf User buffer for return
1543 * uap->namelen User buffer length
1544 *
1545 * Returns: 0 Success
1546 * copyout:EFAULT
1547 *
1548 * Notes: Intended to obtain a string containing the user name of the
1549 * user associated with the controlling terminal for the calling
1550 * process.
1551 *
1552 * Not very useful on modern systems, due to inherent length
1553 * limitations for the static array in the session structure
1554 * which is used to store the login name.
1555 *
1556 * Permitted to return NULL
1557 *
1558 * XXX: Belongs in kern_proc.c
1559 */
1560int
1561getlogin(proc_t p, struct getlogin_args *uap, __unused int32_t *retval)
1562{
1563 char buffer[MAXLOGNAME];
1564 struct session *sessp;
1565 struct pgrp *pg;
1566
1567 if (uap->namelen > MAXLOGNAME) {
1568 uap->namelen = MAXLOGNAME;
1569 }
1570
1571 if ((pg = proc_pgrp(p, &sessp)) != PGRP_NULL) {
1572 session_lock(sess: sessp);
1573 bcopy(src: sessp->s_login, dst: buffer, n: uap->namelen);
1574 session_unlock(sess: sessp);
1575 pgrp_rele(pgrp: pg);
1576 } else {
1577 bzero(s: buffer, n: uap->namelen);
1578 }
1579
1580 return copyout((caddr_t)buffer, uap->namebuf, uap->namelen);
1581}
1582
1583void
1584setlogin_internal(proc_t p, const char login[static MAXLOGNAME])
1585{
1586 struct session *sessp;
1587 struct pgrp *pg;
1588
1589 if ((pg = proc_pgrp(p, &sessp)) != PGRP_NULL) {
1590 session_lock(sess: sessp);
1591 bcopy(src: login, dst: sessp->s_login, MAXLOGNAME);
1592 session_unlock(sess: sessp);
1593 pgrp_rele(pgrp: pg);
1594 }
1595}
1596
1597/*
1598 * setlogin
1599 *
1600 * Description: Set login name.
1601 *
1602 * Parameters: uap->namebuf User buffer containing name
1603 *
1604 * Returns: 0 Success
1605 * suser:EPERM Permission denied
1606 * copyinstr:EFAULT User buffer invalid
1607 * copyinstr:EINVAL Supplied name was too long
1608 *
1609 * Notes: This is a utility system call to support getlogin().
1610 *
1611 * XXX: Belongs in kern_proc.c
1612 */
1613int
1614setlogin(proc_t p, struct setlogin_args *uap, __unused int32_t *retval)
1615{
1616 int error;
1617 size_t dummy = 0;
1618 char buffer[MAXLOGNAME + 1];
1619
1620 if ((error = proc_suser(p))) {
1621 return error;
1622 }
1623
1624 bzero(s: &buffer[0], MAXLOGNAME + 1);
1625
1626
1627 error = copyinstr(uaddr: uap->namebuf,
1628 kaddr: (caddr_t) &buffer[0],
1629 MAXLOGNAME - 1, done: (size_t *)&dummy);
1630
1631 setlogin_internal(p, login: buffer);
1632
1633 if (!error) {
1634 AUDIT_ARG(text, buffer);
1635 } else if (error == ENAMETOOLONG) {
1636 error = EINVAL;
1637 }
1638 return error;
1639}
1640
1641
1642static void
1643proc_calc_audit_token(proc_t p, kauth_cred_t my_cred, audit_token_t *audit_token)
1644{
1645 posix_cred_t my_pcred = posix_cred_get(cred: my_cred);
1646
1647 /*
1648 * The current layout of the Mach audit token explicitly
1649 * adds these fields. But nobody should rely on such
1650 * a literal representation. Instead, the BSM library
1651 * provides a function to convert an audit token into
1652 * a BSM subject. Use of that mechanism will isolate
1653 * the user of the trailer from future representation
1654 * changes.
1655 */
1656 audit_token->val[0] = my_cred->cr_audit.as_aia_p->ai_auid;
1657 audit_token->val[1] = my_pcred->cr_uid;
1658 audit_token->val[2] = my_pcred->cr_gid;
1659 audit_token->val[3] = my_pcred->cr_ruid;
1660 audit_token->val[4] = my_pcred->cr_rgid;
1661 audit_token->val[5] = proc_getpid(p);
1662 audit_token->val[6] = my_cred->cr_audit.as_aia_p->ai_asid;
1663 audit_token->val[7] = proc_pidversion(p);
1664}
1665
1666/* Set the secrity token of the task with current euid and eguid */
1667int
1668set_security_token(proc_t p, struct ucred *my_cred)
1669{
1670 security_token_t sec_token;
1671 audit_token_t audit_token;
1672 host_priv_t host_priv;
1673 task_t task = proc_task(p);
1674
1675 proc_calc_audit_token(p, my_cred, audit_token: &audit_token);
1676
1677 sec_token.val[0] = kauth_cred_getuid(cred: my_cred);
1678 sec_token.val[1] = kauth_cred_getgid(cred: my_cred);
1679
1680 host_priv = (sec_token.val[0]) ? HOST_PRIV_NULL : host_priv_self();
1681#if CONFIG_MACF
1682 if (host_priv != HOST_PRIV_NULL && mac_system_check_host_priv(cred: my_cred)) {
1683 host_priv = HOST_PRIV_NULL;
1684 }
1685#endif
1686
1687#if DEVELOPMENT || DEBUG
1688 /*
1689 * Update the pid an proc name for importance base if any
1690 */
1691 task_importance_update_owner_info(task);
1692#endif
1693
1694 return task_set_security_tokens(task, sec_token, audit_token,
1695 host_priv) != KERN_SUCCESS;
1696}
1697
1698void
1699proc_parent_audit_token(proc_t p, audit_token_t *token_out)
1700{
1701 proc_t parent;
1702 kauth_cred_t my_cred;
1703
1704 proc_list_lock();
1705
1706 parent = p->p_pptr;
1707 my_cred = kauth_cred_proc_ref(procp: parent);
1708 proc_calc_audit_token(p: parent, my_cred, audit_token: token_out);
1709 kauth_cred_unref(&my_cred);
1710
1711 proc_list_unlock();
1712}
1713
1714
1715int get_audit_token_pid(audit_token_t *audit_token);
1716
1717int
1718get_audit_token_pid(audit_token_t *audit_token)
1719{
1720 /* keep in-sync with set_security_token (above) */
1721 if (audit_token) {
1722 return (int)audit_token->val[5];
1723 }
1724 return -1;
1725}
1726
1727
1728/*
1729 * Fill in a struct xucred based on a kauth_cred_t.
1730 */
1731void
1732cru2x(kauth_cred_t cr, struct xucred *xcr)
1733{
1734 posix_cred_t pcr = posix_cred_get(cred: cr);
1735
1736 bzero(s: xcr, n: sizeof(*xcr));
1737 xcr->cr_version = XUCRED_VERSION;
1738 xcr->cr_uid = kauth_cred_getuid(cred: cr);
1739 xcr->cr_ngroups = pcr->cr_ngroups;
1740 bcopy(src: pcr->cr_groups, dst: xcr->cr_groups, n: sizeof(xcr->cr_groups));
1741}
1742
1743/*
1744 * Copy kauth_cred into a virtual address by assignment.
1745 * Needed because elements of kauth_cred are PACed
1746 * so memcpy doesn't work.
1747 */
1748void
1749kauth_cred_copy(const uintptr_t kv, const uintptr_t new_data)
1750{
1751 *(kauth_cred_t)kv = *(kauth_cred_t)new_data;
1752}
1753