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#include <mach/host_security.h>
110
111#include <kern/host.h>
112#include <kern/task.h> /* for current_task() */
113#include <kern/assert.h>
114
115
116/*
117 * Credential debugging; we can track entry into a function that might
118 * change a credential, and we can track actual credential changes that
119 * result.
120 *
121 * Note: Does *NOT* currently include per-thread credential changes
122 *
123 * We don't use kauth_cred_print() in current debugging, but it
124 * can be used if needed when debugging is active.
125 */
126#if DEBUG_CRED
127#define DEBUG_CRED_ENTER printf
128#define DEBUG_CRED_CHANGE printf
129extern void kauth_cred_print(kauth_cred_t cred);
130#else /* !DEBUG_CRED */
131#define DEBUG_CRED_ENTER(fmt, ...) do {} while (0)
132#define DEBUG_CRED_CHANGE(fmt, ...) do {} while (0)
133#endif /* !DEBUG_CRED */
134
135#if DEVELOPMENT || DEBUG
136extern void task_importance_update_owner_info(task_t);
137#endif
138
139
140/*
141 * setprivexec
142 *
143 * Description: (dis)allow this process to hold task, thread, or execption
144 * ports of processes about to exec.
145 *
146 * Parameters: uap->flag New value for flag
147 *
148 * Returns: int Previous value of flag
149 *
150 * XXX: Belongs in kern_proc.c
151 */
152int
153setprivexec(proc_t p, struct setprivexec_args *uap, int32_t *retval)
154{
155 AUDIT_ARG(value32, uap->flag);
156 *retval = p->p_debugger;
157 p->p_debugger = (uap->flag != 0);
158 return(0);
159}
160
161
162/*
163 * getpid
164 *
165 * Description: get the process ID
166 *
167 * Parameters: (void)
168 *
169 * Returns: pid_t Current process ID
170 *
171 * XXX: Belongs in kern_proc.c
172 */
173int
174getpid(proc_t p, __unused struct getpid_args *uap, int32_t *retval)
175{
176
177 *retval = p->p_pid;
178 return (0);
179}
180
181
182/*
183 * getppid
184 *
185 * Description: get the parent process ID
186 *
187 * Parameters: (void)
188 *
189 * Returns: pid_t Parent process ID
190 *
191 * XXX: Belongs in kern_proc.c
192 */
193int
194getppid(proc_t p, __unused struct getppid_args *uap, int32_t *retval)
195{
196
197 *retval = p->p_ppid;
198 return (0);
199}
200
201
202/*
203 * getpgrp
204 *
205 * Description: get the process group ID of the calling process
206 *
207 * Parameters: (void)
208 *
209 * Returns: pid_t Process group ID
210 *
211 * XXX: Belongs in kern_proc.c
212 */
213int
214getpgrp(proc_t p, __unused struct getpgrp_args *uap, int32_t *retval)
215{
216
217 *retval = p->p_pgrpid;
218 return (0);
219}
220
221
222/*
223 * getpgid
224 *
225 * Description: Get an arbitary pid's process group id
226 *
227 * Parameters: uap->pid The target pid
228 *
229 * Returns: 0 Success
230 * ESRCH No such process
231 *
232 * Notes: We are permitted to return EPERM in the case that the target
233 * process is not in the same session as the calling process,
234 * which could be a security consideration
235 *
236 * XXX: Belongs in kern_proc.c
237 */
238int
239getpgid(proc_t p, struct getpgid_args *uap, int32_t *retval)
240{
241 proc_t pt;
242 int refheld = 0;
243
244 pt = p;
245 if (uap->pid == 0)
246 goto found;
247
248 if ((pt = proc_find(uap->pid)) == 0)
249 return (ESRCH);
250 refheld = 1;
251found:
252 *retval = pt->p_pgrpid;
253 if (refheld != 0)
254 proc_rele(pt);
255 return (0);
256}
257
258
259/*
260 * getsid
261 *
262 * Description: Get an arbitary pid's session leaders process group ID
263 *
264 * Parameters: uap->pid The target pid
265 *
266 * Returns: 0 Success
267 * ESRCH No such process
268 *
269 * Notes: We are permitted to return EPERM in the case that the target
270 * process is not in the same session as the calling process,
271 * which could be a security consideration
272 *
273 * XXX: Belongs in kern_proc.c
274 */
275int
276getsid(proc_t p, struct getsid_args *uap, int32_t *retval)
277{
278 proc_t pt;
279 int refheld = 0;
280 struct session * sessp;
281
282 pt = p;
283 if (uap->pid == 0)
284 goto found;
285
286 if ((pt = proc_find(uap->pid)) == 0)
287 return (ESRCH);
288 refheld = 1;
289found:
290 sessp = proc_session(pt);
291 *retval = sessp->s_sid;
292 session_rele(sessp);
293
294 if (refheld != 0)
295 proc_rele(pt);
296 return (0);
297}
298
299
300/*
301 * getuid
302 *
303 * Description: get real user ID for caller
304 *
305 * Parameters: (void)
306 *
307 * Returns: uid_t The real uid of the caller
308 */
309int
310getuid(__unused proc_t p, __unused struct getuid_args *uap, int32_t *retval)
311{
312
313 *retval = kauth_getruid();
314 return (0);
315}
316
317
318/*
319 * geteuid
320 *
321 * Description: get effective user ID for caller
322 *
323 * Parameters: (void)
324 *
325 * Returns: uid_t The effective uid of the caller
326 */
327int
328geteuid(__unused proc_t p, __unused struct geteuid_args *uap, int32_t *retval)
329{
330
331 *retval = kauth_getuid();
332 return (0);
333}
334
335
336/*
337 * gettid
338 *
339 * Description: Return the per-thread override identity.
340 *
341 * Parameters: uap->uidp Address of uid_t to get uid
342 * uap->gidp Address of gid_t to get gid
343 *
344 * Returns: 0 Success
345 * ESRCH No per thread identity active
346 */
347int
348gettid(__unused proc_t p, struct gettid_args *uap, int32_t *retval)
349{
350 struct uthread *uthread = get_bsdthread_info(current_thread());
351 int error;
352
353 /*
354 * If this thread is not running with an override identity, we can't
355 * return one to the caller, so return an error instead.
356 */
357 if (!(uthread->uu_flag & UT_SETUID))
358 return (ESRCH);
359
360 if ((error = suword(uap->uidp, kauth_cred_getruid(uthread->uu_ucred))))
361 return (error);
362 if ((error = suword(uap->gidp, kauth_cred_getrgid(uthread->uu_ucred))))
363 return (error);
364
365 *retval = 0;
366 return (0);
367}
368
369
370/*
371 * getgid
372 *
373 * Description: get the real group ID for the calling process
374 *
375 * Parameters: (void)
376 *
377 * Returns: gid_t The real gid of the caller
378 */
379int
380getgid(__unused proc_t p, __unused struct getgid_args *uap, int32_t *retval)
381{
382
383 *retval = kauth_getrgid();
384 return (0);
385}
386
387
388/*
389 * getegid
390 *
391 * Description: get the effective group ID for the calling process
392 *
393 * Parameters: (void)
394 *
395 * Returns: gid_t The effective gid of the caller
396 *
397 * Notes: As an implementation detail, the effective gid is stored as
398 * the first element of the supplementary group list.
399 *
400 * This could be implemented in Libc instead because of the above
401 * detail.
402 */
403int
404getegid(__unused proc_t p, __unused struct getegid_args *uap, int32_t *retval)
405{
406
407 *retval = kauth_getgid();
408 return (0);
409}
410
411
412/*
413 * getgroups
414 *
415 * Description: get the list of supplementary groups for the calling process
416 *
417 * Parameters: uap->gidsetsize # of gid_t's in user buffer
418 * uap->gidset Pointer to user buffer
419 *
420 * Returns: 0 Success
421 * EINVAL User buffer too small
422 * copyout:EFAULT User buffer invalid
423 *
424 * Retval: -1 Error
425 * !0 # of groups
426 *
427 * Notes: The caller may specify a 0 value for gidsetsize, and we will
428 * then return how large a buffer is required (in gid_t's) to
429 * contain the answer at the time of the call. Otherwise, we
430 * return the number of gid_t's catually copied to user space.
431 *
432 * When called with a 0 gidsetsize from a multithreaded program,
433 * there is no guarantee that another thread may not change the
434 * number of supplementary groups, and therefore a subsequent
435 * call could still fail, unless the maximum possible buffer
436 * size is supplied by the user.
437 *
438 * As an implementation detail, the effective gid is stored as
439 * the first element of the supplementary group list, and will
440 * be returned by this call.
441 */
442int
443getgroups(__unused proc_t p, struct getgroups_args *uap, int32_t *retval)
444{
445 int ngrp;
446 int error;
447 kauth_cred_t cred;
448 posix_cred_t pcred;
449
450 /* grab reference while we muck around with the credential */
451 cred = kauth_cred_get_with_ref();
452 pcred = posix_cred_get(cred);
453
454 if ((ngrp = uap->gidsetsize) == 0) {
455 *retval = pcred->cr_ngroups;
456 kauth_cred_unref(&cred);
457 return (0);
458 }
459 if (ngrp < pcred->cr_ngroups) {
460 kauth_cred_unref(&cred);
461 return (EINVAL);
462 }
463 ngrp = pcred->cr_ngroups;
464 if ((error = copyout((caddr_t)pcred->cr_groups,
465 uap->gidset,
466 ngrp * sizeof(gid_t)))) {
467 kauth_cred_unref(&cred);
468 return (error);
469 }
470 kauth_cred_unref(&cred);
471 *retval = ngrp;
472 return (0);
473}
474
475
476/*
477 * Return the per-thread/per-process supplementary groups list.
478 *
479 * XXX implement getsgroups
480 *
481 */
482
483int
484getsgroups(__unused proc_t p, __unused struct getsgroups_args *uap, __unused int32_t *retval)
485{
486 return(ENOTSUP);
487}
488
489/*
490 * Return the per-thread/per-process whiteout groups list.
491 *
492 * XXX implement getwgroups
493 *
494 */
495
496int
497getwgroups(__unused proc_t p, __unused struct getwgroups_args *uap, __unused int32_t *retval)
498{
499 return(ENOTSUP);
500}
501
502
503/*
504 * setsid
505 *
506 * Description: Create a new session and set the process group ID to the
507 * session ID
508 *
509 * Parameters: (void)
510 *
511 * Returns: 0 Success
512 * EPERM Permission denied
513 *
514 * Notes: If the calling process is not the process group leader; there
515 * is no existing process group with its ID, and we are not
516 * currently in vfork, then this function will create a new
517 * session, a new process group, and put the caller in the
518 * process group (as the sole member) and make it the session
519 * leader (as the sole process in the session).
520 *
521 * The existing controlling tty (if any) will be dissociated
522 * from the process, and the next non-O_NOCTTY open of a tty
523 * will establish a new controlling tty.
524 *
525 * XXX: Belongs in kern_proc.c
526 */
527int
528setsid(proc_t p, __unused struct setsid_args *uap, int32_t *retval)
529{
530 struct pgrp * pg = PGRP_NULL;
531
532 if (p->p_pgrpid == p->p_pid || (pg = pgfind(p->p_pid)) || p->p_lflag & P_LINVFORK) {
533 if (pg != PGRP_NULL)
534 pg_rele(pg);
535 return (EPERM);
536 } else {
537 /* enter pgrp works with its own pgrp refcount */
538 (void)enterpgrp(p, p->p_pid, 1);
539 *retval = p->p_pid;
540 return (0);
541 }
542}
543
544
545/*
546 * setpgid
547 *
548 * Description: set process group ID for job control
549 *
550 * Parameters: uap->pid Process to change
551 * uap->pgid Process group to join or create
552 *
553 * Returns: 0 Success
554 * ESRCH pid is not the caller or a child of
555 * the caller
556 * enterpgrp:ESRCH No such process
557 * EACCES Permission denied due to exec
558 * EINVAL Invalid argument
559 * EPERM The target process is not in the same
560 * session as the calling process
561 * EPERM The target process is a session leader
562 * EPERM pid and pgid are not the same, and
563 * there is no process in the calling
564 * process whose process group ID matches
565 * pgid
566 *
567 * Notes: This function will cause the target process to either join
568 * an existing process process group, or create a new process
569 * group in the session of the calling process. It cannot be
570 * used to change the process group ID of a process which is
571 * already a session leader.
572 *
573 * If the target pid is 0, the pid of the calling process is
574 * substituted as the new target; if pgid is 0, the target pid
575 * is used as the target process group ID.
576 *
577 * Legacy: This system call entry point is also used to implement the
578 * legacy library routine setpgrp(), which under POSIX
579 *
580 * XXX: Belongs in kern_proc.c
581 */
582int
583setpgid(proc_t curp, struct setpgid_args *uap, __unused int32_t *retval)
584{
585 proc_t targp = PROC_NULL; /* target process */
586 struct pgrp *pg = PGRP_NULL; /* target pgrp */
587 int error = 0;
588 int refheld = 0;
589 int samesess = 0;
590 struct session * curp_sessp = SESSION_NULL;
591 struct session * targp_sessp = SESSION_NULL;
592
593 curp_sessp = proc_session(curp);
594
595 if (uap->pid != 0 && uap->pid != curp->p_pid) {
596 if ((targp = proc_find(uap->pid)) == 0 || !inferior(targp)) {
597 if (targp != PROC_NULL)
598 refheld = 1;
599 error = ESRCH;
600 goto out;
601 }
602 refheld = 1;
603 targp_sessp = proc_session(targp);
604 if (targp_sessp != curp_sessp) {
605 error = EPERM;
606 goto out;
607 }
608 if (targp->p_flag & P_EXEC) {
609 error = EACCES;
610 goto out;
611 }
612 } else {
613 targp = curp;
614 targp_sessp = proc_session(targp);
615 }
616
617 if (SESS_LEADER(targp, targp_sessp)) {
618 error = EPERM;
619 goto out;
620 }
621 if (targp_sessp != SESSION_NULL) {
622 session_rele(targp_sessp);
623 targp_sessp = SESSION_NULL;
624 }
625
626 if (uap->pgid < 0) {
627 error = EINVAL;
628 goto out;
629 }
630 if (uap->pgid == 0)
631 uap->pgid = targp->p_pid;
632 else if (uap->pgid != targp->p_pid) {
633 if ((pg = pgfind(uap->pgid)) == 0){
634 error = EPERM;
635 goto out;
636 }
637 samesess = (pg->pg_session != curp_sessp);
638 pg_rele(pg);
639 if (samesess != 0) {
640 error = EPERM;
641 goto out;
642 }
643 }
644 error = enterpgrp(targp, uap->pgid, 0);
645out:
646 if (targp_sessp != SESSION_NULL)
647 session_rele(targp_sessp);
648 if (curp_sessp != SESSION_NULL)
649 session_rele(curp_sessp);
650 if (refheld != 0)
651 proc_rele(targp);
652 return(error);
653}
654
655
656/*
657 * issetugid
658 *
659 * Description: Is current process tainted by uid or gid changes system call
660 *
661 * Parameters: (void)
662 *
663 * Returns: 0 Not tainted
664 * 1 Tainted
665 *
666 * Notes: A process is considered tainted if it was created as a retult
667 * of an execve call from an imnage that had either the SUID or
668 * SGID bit set on the executable, or if it has changed any of its
669 * real, effective, or saved user or group IDs since beginning
670 * execution.
671 */
672int
673proc_issetugid (proc_t p)
674{
675 return (p->p_flag & P_SUGID) ? 1 : 0;
676}
677
678int
679issetugid(proc_t p, __unused struct issetugid_args *uap, int32_t *retval)
680{
681 /*
682 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
683 * we use P_SUGID because we consider changing the owners as
684 * "tainting" as well.
685 * This is significant for procs that start as root and "become"
686 * a user without an exec - programs cannot know *everything*
687 * that libc *might* have put in their data segment.
688 */
689
690 *retval = proc_issetugid(p);
691 return (0);
692}
693
694
695/*
696 * setuid
697 *
698 * Description: Set user ID system call
699 *
700 * Parameters: uap->uid uid to set
701 *
702 * Returns: 0 Success
703 * suser:EPERM Permission denied
704 *
705 * Notes: If called by a privileged process, this function will set the
706 * real, effective, and saved uid to the requested value.
707 *
708 * If called from an unprivileged process, but uid is equal to the
709 * real or saved uid, then the effective uid will be set to the
710 * requested value, but the real and saved uid will not change.
711 *
712 * If the credential is changed as a result of this call, then we
713 * flag the process as having set privilege since the last exec.
714 */
715int
716setuid(proc_t p, struct setuid_args *uap, __unused int32_t *retval)
717{
718 uid_t uid;
719 uid_t svuid = KAUTH_UID_NONE;
720 uid_t ruid = KAUTH_UID_NONE;
721 uid_t gmuid = KAUTH_UID_NONE;
722 int error;
723 kauth_cred_t my_cred, my_new_cred;
724 posix_cred_t my_pcred;
725
726 uid = uap->uid;
727
728 /* get current credential and take a reference while we muck with it */
729 my_cred = kauth_cred_proc_ref(p);
730 my_pcred = posix_cred_get(my_cred);
731
732 DEBUG_CRED_ENTER("setuid (%d/%d): %p %d\n", p->p_pid, (p->p_pptr ? p->p_pptr->p_pid : 0), my_cred, uap->uid);
733 AUDIT_ARG(uid, uid);
734
735 for (;;) {
736 if (uid != my_pcred->cr_ruid && /* allow setuid(getuid()) */
737 uid != my_pcred->cr_svuid && /* allow setuid(saved uid) */
738 (error = suser(my_cred, &p->p_acflag))) {
739 kauth_cred_unref(&my_cred);
740 return (error);
741 }
742
743 /*
744 * If we are privileged, then set the saved and real UID too;
745 * otherwise, just set the effective UID
746 */
747 if (suser(my_cred, &p->p_acflag) == 0) {
748 svuid = uid;
749 ruid = uid;
750 } else {
751 svuid = KAUTH_UID_NONE;
752 ruid = KAUTH_UID_NONE;
753 }
754 /*
755 * Only set the gmuid if the current cred has not opt'ed out;
756 * this normally only happens when calling setgroups() instead
757 * of initgroups() to set an explicit group list, or one of the
758 * other group manipulation functions is invoked and results in
759 * a dislocation (i.e. the credential group membership changes
760 * to something other than the default list for the user, as
761 * in entering a group or leaving an exclusion group).
762 */
763 if (!(my_pcred->cr_flags & CRF_NOMEMBERD))
764 gmuid = uid;
765
766 /*
767 * Set the credential with new info. If there is no change,
768 * we get back the same credential we passed in; if there is
769 * a change, we drop the reference on the credential we
770 * passed in. The subsequent compare is safe, because it is
771 * a pointer compare rather than a contents compare.
772 */
773 my_new_cred = kauth_cred_setresuid(my_cred, ruid, uid, svuid, gmuid);
774 if (my_cred != my_new_cred) {
775
776 DEBUG_CRED_CHANGE("setuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags);
777
778 /*
779 * If we're changing the ruid from A to B, we might race with another thread that's setting ruid from B to A.
780 * The current locking mechanisms don't allow us to make the entire credential switch operation atomic,
781 * thus we may be able to change the process credentials from ruid A to B, but get preempted before incrementing the proc
782 * count of B. If a second thread sees the new process credentials and switches back to ruid A, that other thread
783 * may be able to decrement the proc count of B before we can increment it. This results in a panic.
784 * Incrementing the proc count of the target ruid, B, before setting the process credentials prevents this race.
785 */
786 if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
787 (void)chgproccnt(ruid, 1);
788 }
789
790 proc_ucred_lock(p);
791 /*
792 * We need to protect for a race where another thread
793 * also changed the credential after we took our
794 * reference. If p_ucred has changed then we should
795 * restart this again with the new cred.
796 *
797 * Note: the kauth_cred_setresuid has consumed a reference to my_cred, it p_ucred != my_cred, then my_cred must not be dereferenced!
798 */
799 if (p->p_ucred != my_cred) {
800 proc_ucred_unlock(p);
801 /*
802 * We didn't successfully switch to the new ruid, so decrement
803 * the procs/uid count that we incremented above.
804 */
805 if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
806 (void)chgproccnt(ruid, -1);
807 }
808 kauth_cred_unref(&my_new_cred);
809 my_cred = kauth_cred_proc_ref(p);
810 my_pcred = posix_cred_get(my_cred);
811 /* try again */
812 continue;
813 }
814 p->p_ucred = my_new_cred;
815 /* update cred on proc */
816 PROC_UPDATE_CREDS_ONPROC(p);
817
818 OSBitOrAtomic(P_SUGID, &p->p_flag);
819 proc_ucred_unlock(p);
820 /*
821 * If we've updated the ruid, decrement the count of procs running
822 * under the previous ruid
823 */
824 if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
825 (void)chgproccnt(my_pcred->cr_ruid, -1);
826 }
827 }
828 break;
829 }
830 /* Drop old proc reference or our extra reference */
831 kauth_cred_unref(&my_cred);
832
833 set_security_token(p);
834 return (0);
835}
836
837
838/*
839 * seteuid
840 *
841 * Description: Set effective user ID system call
842 *
843 * Parameters: uap->euid effective uid to set
844 *
845 * Returns: 0 Success
846 * suser:EPERM Permission denied
847 *
848 * Notes: If called by a privileged process, or called from an
849 * unprivileged process but euid is equal to the real or saved
850 * uid, then the effective uid will be set to the requested
851 * value, but the real and saved uid will not change.
852 *
853 * If the credential is changed as a result of this call, then we
854 * flag the process as having set privilege since the last exec.
855 */
856int
857seteuid(proc_t p, struct seteuid_args *uap, __unused int32_t *retval)
858{
859 uid_t euid;
860 int error;
861 kauth_cred_t my_cred, my_new_cred;
862 posix_cred_t my_pcred;
863
864 DEBUG_CRED_ENTER("seteuid: %d\n", uap->euid);
865
866 euid = uap->euid;
867 AUDIT_ARG(euid, euid);
868
869 my_cred = kauth_cred_proc_ref(p);
870 my_pcred = posix_cred_get(my_cred);
871
872 for (;;) {
873
874 if (euid != my_pcred->cr_ruid && euid != my_pcred->cr_svuid &&
875 (error = suser(my_cred, &p->p_acflag))) {
876 kauth_cred_unref(&my_cred);
877 return (error);
878 }
879
880 /*
881 * Set the credential with new info. If there is no change,
882 * we get back the same credential we passed in; if there is
883 * a change, we drop the reference on the credential we
884 * passed in. The subsequent compare is safe, because it is
885 * a pointer compare rather than a contents compare.
886 */
887 my_new_cred = kauth_cred_setresuid(my_cred, KAUTH_UID_NONE, euid, KAUTH_UID_NONE, my_pcred->cr_gmuid);
888
889 if (my_cred != my_new_cred) {
890
891 DEBUG_CRED_CHANGE("seteuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags);
892
893 proc_ucred_lock(p);
894 /*
895 * We need to protect for a race where another thread
896 * also changed the credential after we took our
897 * reference. If p_ucred has changed then we
898 * should restart this again with the new cred.
899 */
900 if (p->p_ucred != my_cred) {
901 proc_ucred_unlock(p);
902 kauth_cred_unref(&my_new_cred);
903 my_cred = kauth_cred_proc_ref(p);
904 my_pcred = posix_cred_get(my_cred);
905 /* try again */
906 continue;
907 }
908 p->p_ucred = my_new_cred;
909 /* update cred on proc */
910 PROC_UPDATE_CREDS_ONPROC(p);
911 OSBitOrAtomic(P_SUGID, &p->p_flag);
912 proc_ucred_unlock(p);
913 }
914 break;
915 }
916 /* drop old proc reference or our extra reference */
917 kauth_cred_unref(&my_cred);
918
919 set_security_token(p);
920 return (0);
921}
922
923
924/*
925 * setreuid
926 *
927 * Description: Set real and effective user ID system call
928 *
929 * Parameters: uap->ruid real uid to set
930 * uap->euid effective uid to set
931 *
932 * Returns: 0 Success
933 * suser:EPERM Permission denied
934 *
935 * Notes: A value of -1 is a special case indicating that the uid for
936 * which that value is specified not be changed. If both values
937 * are specified as -1, no action is taken.
938 *
939 * If called by a privileged process, the real and effective uid
940 * will be set to the new value(s) specified.
941 *
942 * If called from an unprivileged process, the real uid may be
943 * set to the current value of the real uid, or to the current
944 * value of the saved uid. The effective uid may be set to the
945 * current value of any of the effective, real, or saved uid.
946 *
947 * If the newly requested real uid or effective uid does not
948 * match the saved uid, then set the saved uid to the new
949 * effective uid (potentially unrecoverably dropping saved
950 * privilege).
951 *
952 * If the credential is changed as a result of this call, then we
953 * flag the process as having set privilege since the last exec.
954 */
955int
956setreuid(proc_t p, struct setreuid_args *uap, __unused int32_t *retval)
957{
958 uid_t ruid, euid;
959 int error;
960 kauth_cred_t my_cred, my_new_cred;
961 posix_cred_t my_pcred;
962
963 DEBUG_CRED_ENTER("setreuid %d %d\n", uap->ruid, uap->euid);
964
965 ruid = uap->ruid;
966 euid = uap->euid;
967 if (ruid == (uid_t)-1)
968 ruid = KAUTH_UID_NONE;
969 if (euid == (uid_t)-1)
970 euid = KAUTH_UID_NONE;
971 AUDIT_ARG(euid, euid);
972 AUDIT_ARG(ruid, ruid);
973
974 my_cred = kauth_cred_proc_ref(p);
975 my_pcred = posix_cred_get(my_cred);
976
977 for (;;) {
978
979 if (((ruid != KAUTH_UID_NONE && /* allow no change of ruid */
980 ruid != my_pcred->cr_ruid && /* allow ruid = ruid */
981 ruid != my_pcred->cr_uid && /* allow ruid = euid */
982 ruid != my_pcred->cr_svuid) || /* allow ruid = svuid */
983 (euid != KAUTH_UID_NONE && /* allow no change of euid */
984 euid != my_pcred->cr_uid && /* allow euid = euid */
985 euid != my_pcred->cr_ruid && /* allow euid = ruid */
986 euid != my_pcred->cr_svuid)) && /* allow euid = svuid */
987 (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */
988 kauth_cred_unref(&my_cred);
989 return (error);
990 }
991
992 uid_t new_euid;
993 uid_t svuid = KAUTH_UID_NONE;
994
995 new_euid = my_pcred->cr_uid;
996 /*
997 * Set the credential with new info. If there is no change,
998 * we get back the same credential we passed in; if there is
999 * a change, we drop the reference on the credential we
1000 * passed in. The subsequent compare is safe, because it is
1001 * a pointer compare rather than a contents compare.
1002 */
1003 if (euid != KAUTH_UID_NONE && my_pcred->cr_uid != euid) {
1004 /* changing the effective UID */
1005 new_euid = euid;
1006 OSBitOrAtomic(P_SUGID, &p->p_flag);
1007 }
1008 /*
1009 * If the newly requested real uid or effective uid does
1010 * not match the saved uid, then set the saved uid to the
1011 * new effective uid. We are protected from escalation
1012 * by the prechecking.
1013 */
1014 if (my_pcred->cr_svuid != uap->ruid &&
1015 my_pcred->cr_svuid != uap->euid) {
1016 svuid = new_euid;
1017 OSBitOrAtomic(P_SUGID, &p->p_flag);
1018 }
1019
1020 my_new_cred = kauth_cred_setresuid(my_cred, ruid, euid, svuid, my_pcred->cr_gmuid);
1021
1022 if (my_cred != my_new_cred) {
1023
1024 DEBUG_CRED_CHANGE("setreuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags);
1025
1026 /*
1027 * If we're changing the ruid from A to B, we might race with another thread that's setting ruid from B to A.
1028 * The current locking mechanisms don't allow us to make the entire credential switch operation atomic,
1029 * thus we may be able to change the process credentials from ruid A to B, but get preempted before incrementing the proc
1030 * count of B. If a second thread sees the new process credentials and switches back to ruid A, that other thread
1031 * may be able to decrement the proc count of B before we can increment it. This results in a panic.
1032 * Incrementing the proc count of the target ruid, B, before setting the process credentials prevents this race.
1033 */
1034 if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
1035 (void)chgproccnt(ruid, 1);
1036 }
1037
1038 proc_ucred_lock(p);
1039 /*
1040 * We need to protect for a race where another thread
1041 * also changed the credential after we took our
1042 * reference. If p_ucred has changed then we should
1043 * restart this again with the new cred.
1044 *
1045 * Note: the kauth_cred_setresuid has consumed a reference to my_cred, it p_ucred != my_cred, then my_cred must not be dereferenced!
1046 */
1047 if (p->p_ucred != my_cred) {
1048 proc_ucred_unlock(p);
1049 if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
1050 /*
1051 * We didn't successfully switch to the new ruid, so decrement
1052 * the procs/uid count that we incremented above.
1053 */
1054 (void)chgproccnt(ruid, -1);
1055 }
1056 kauth_cred_unref(&my_new_cred);
1057 my_cred = kauth_cred_proc_ref(p);
1058 my_pcred = posix_cred_get(my_cred);
1059 /* try again */
1060 continue;
1061 }
1062
1063 p->p_ucred = my_new_cred;
1064 /* update cred on proc */
1065 PROC_UPDATE_CREDS_ONPROC(p);
1066 OSBitOrAtomic(P_SUGID, &p->p_flag);
1067 proc_ucred_unlock(p);
1068
1069 if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
1070 /*
1071 * We switched to a new ruid, so decrement the count of procs running
1072 * under the previous ruid
1073 */
1074 (void)chgproccnt(my_pcred->cr_ruid, -1);
1075 }
1076 }
1077 break;
1078 }
1079 /* drop old proc reference or our extra reference */
1080 kauth_cred_unref(&my_cred);
1081
1082 set_security_token(p);
1083 return (0);
1084}
1085
1086
1087/*
1088 * setgid
1089 *
1090 * Description: Set group ID system call
1091 *
1092 * Parameters: uap->gid gid to set
1093 *
1094 * Returns: 0 Success
1095 * suser:EPERM Permission denied
1096 *
1097 * Notes: If called by a privileged process, this function will set the
1098 * real, effective, and saved gid to the requested value.
1099 *
1100 * If called from an unprivileged process, but gid is equal to the
1101 * real or saved gid, then the effective gid will be set to the
1102 * requested value, but the real and saved gid will not change.
1103 *
1104 * If the credential is changed as a result of this call, then we
1105 * flag the process as having set privilege since the last exec.
1106 *
1107 * As an implementation detail, the effective gid is stored as
1108 * the first element of the supplementary group list, and
1109 * therefore the effective group list may be reordered to keep
1110 * the supplementary group list unchanged.
1111 */
1112int
1113setgid(proc_t p, struct setgid_args *uap, __unused int32_t *retval)
1114{
1115 gid_t gid;
1116 gid_t rgid = KAUTH_GID_NONE;
1117 gid_t svgid = KAUTH_GID_NONE;
1118 int error;
1119 kauth_cred_t my_cred, my_new_cred;
1120 posix_cred_t my_pcred;
1121
1122 DEBUG_CRED_ENTER("setgid(%d/%d): %d\n", p->p_pid, (p->p_pptr ? p->p_pptr->p_pid : 0), uap->gid);
1123
1124 gid = uap->gid;
1125 AUDIT_ARG(gid, gid);
1126
1127 /* get current credential and take a reference while we muck with it */
1128 my_cred = kauth_cred_proc_ref(p);
1129 my_pcred = posix_cred_get(my_cred);
1130
1131 for (;;) {
1132 if (gid != my_pcred->cr_rgid && /* allow setgid(getgid()) */
1133 gid != my_pcred->cr_svgid && /* allow setgid(saved gid) */
1134 (error = suser(my_cred, &p->p_acflag))) {
1135 kauth_cred_unref(&my_cred);
1136 return (error);
1137 }
1138
1139 /*
1140 * If we are privileged, then set the saved and real GID too;
1141 * otherwise, just set the effective GID
1142 */
1143 if (suser(my_cred, &p->p_acflag) == 0) {
1144 svgid = gid;
1145 rgid = gid;
1146 } else {
1147 svgid = KAUTH_GID_NONE;
1148 rgid = KAUTH_GID_NONE;
1149 }
1150
1151 /*
1152 * Set the credential with new info. If there is no change,
1153 * we get back the same credential we passed in; if there is
1154 * a change, we drop the reference on the credential we
1155 * passed in. The subsequent compare is safe, because it is
1156 * a pointer compare rather than a contents compare.
1157 */
1158 my_new_cred = kauth_cred_setresgid(my_cred, rgid, gid, svgid);
1159 if (my_cred != my_new_cred) {
1160
1161 DEBUG_CRED_CHANGE("setgid(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
1162
1163 proc_ucred_lock(p);
1164 /*
1165 * We need to protect for a race where another thread
1166 * also changed the credential after we took our
1167 * reference. If p_ucred has changed then we
1168 * should restart this again with the new cred.
1169 */
1170 if (p->p_ucred != my_cred) {
1171 proc_ucred_unlock(p);
1172 kauth_cred_unref(&my_new_cred);
1173 /* try again */
1174 my_cred = kauth_cred_proc_ref(p);
1175 my_pcred = posix_cred_get(my_cred);
1176 continue;
1177 }
1178 p->p_ucred = my_new_cred;
1179 /* update cred on proc */
1180 PROC_UPDATE_CREDS_ONPROC(p);
1181 OSBitOrAtomic(P_SUGID, &p->p_flag);
1182 proc_ucred_unlock(p);
1183 }
1184 break;
1185 }
1186 /* Drop old proc reference or our extra reference */
1187 kauth_cred_unref(&my_cred);
1188
1189 set_security_token(p);
1190 return (0);
1191}
1192
1193
1194/*
1195 * setegid
1196 *
1197 * Description: Set effective group ID system call
1198 *
1199 * Parameters: uap->egid effective gid to set
1200 *
1201 * Returns: 0 Success
1202 * suser:EPERM
1203 *
1204 * Notes: If called by a privileged process, or called from an
1205 * unprivileged process but egid is equal to the real or saved
1206 * gid, then the effective gid will be set to the requested
1207 * value, but the real and saved gid will not change.
1208 *
1209 * If the credential is changed as a result of this call, then we
1210 * flag the process as having set privilege since the last exec.
1211 *
1212 * As an implementation detail, the effective gid is stored as
1213 * the first element of the supplementary group list, and
1214 * therefore the effective group list may be reordered to keep
1215 * the supplementary group list unchanged.
1216 */
1217int
1218setegid(proc_t p, struct setegid_args *uap, __unused int32_t *retval)
1219{
1220 gid_t egid;
1221 int error;
1222 kauth_cred_t my_cred, my_new_cred;
1223 posix_cred_t my_pcred;
1224
1225 DEBUG_CRED_ENTER("setegid %d\n", uap->egid);
1226
1227 egid = uap->egid;
1228 AUDIT_ARG(egid, egid);
1229
1230 /* get current credential and take a reference while we muck with it */
1231 my_cred = kauth_cred_proc_ref(p);
1232 my_pcred = posix_cred_get(my_cred);
1233
1234
1235 for (;;) {
1236 if (egid != my_pcred->cr_rgid &&
1237 egid != my_pcred->cr_svgid &&
1238 (error = suser(my_cred, &p->p_acflag))) {
1239 kauth_cred_unref(&my_cred);
1240 return (error);
1241 }
1242 /*
1243 * Set the credential with new info. If there is no change,
1244 * we get back the same credential we passed in; if there is
1245 * a change, we drop the reference on the credential we
1246 * passed in. The subsequent compare is safe, because it is
1247 * a pointer compare rather than a contents compare.
1248 */
1249 my_new_cred = kauth_cred_setresgid(my_cred, KAUTH_GID_NONE, egid, KAUTH_GID_NONE);
1250 if (my_cred != my_new_cred) {
1251
1252 DEBUG_CRED_CHANGE("setegid(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags);
1253
1254 proc_ucred_lock(p);
1255 /*
1256 * We need to protect for a race where another thread
1257 * also changed the credential after we took our
1258 * reference. If p_ucred has changed then we
1259 * should restart this again with the new cred.
1260 */
1261 if (p->p_ucred != my_cred) {
1262 proc_ucred_unlock(p);
1263 kauth_cred_unref(&my_new_cred);
1264 /* try again */
1265 my_cred = kauth_cred_proc_ref(p);
1266 my_pcred = posix_cred_get(my_cred);
1267 continue;
1268 }
1269 p->p_ucred = my_new_cred;
1270 /* update cred on proc */
1271 PROC_UPDATE_CREDS_ONPROC(p);
1272 OSBitOrAtomic(P_SUGID, &p->p_flag);
1273 proc_ucred_unlock(p);
1274 }
1275 break;
1276 }
1277
1278 /* Drop old proc reference or our extra reference */
1279 kauth_cred_unref(&my_cred);
1280
1281 set_security_token(p);
1282 return (0);
1283}
1284
1285/*
1286 * setregid
1287 *
1288 * Description: Set real and effective group ID system call
1289 *
1290 * Parameters: uap->rgid real gid to set
1291 * uap->egid effective gid to set
1292 *
1293 * Returns: 0 Success
1294 * suser:EPERM Permission denied
1295 *
1296 * Notes: A value of -1 is a special case indicating that the gid for
1297 * which that value is specified not be changed. If both values
1298 * are specified as -1, no action is taken.
1299 *
1300 * If called by a privileged process, the real and effective gid
1301 * will be set to the new value(s) specified.
1302 *
1303 * If called from an unprivileged process, the real gid may be
1304 * set to the current value of the real gid, or to the current
1305 * value of the saved gid. The effective gid may be set to the
1306 * current value of any of the effective, real, or saved gid.
1307 *
1308 * If the new real and effective gid will not be equal, or the
1309 * new real or effective gid is not the same as the saved gid,
1310 * then the saved gid will be updated to reflect the new
1311 * effective gid (potentially unrecoverably dropping saved
1312 * privilege).
1313 *
1314 * If the credential is changed as a result of this call, then we
1315 * flag the process as having set privilege since the last exec.
1316 *
1317 * As an implementation detail, the effective gid is stored as
1318 * the first element of the supplementary group list, and
1319 * therefore the effective group list may be reordered to keep
1320 * the supplementary group list unchanged.
1321 */
1322int
1323setregid(proc_t p, struct setregid_args *uap, __unused int32_t *retval)
1324{
1325 gid_t rgid, egid;
1326 int error;
1327 kauth_cred_t my_cred, my_new_cred;
1328 posix_cred_t my_pcred;
1329
1330 DEBUG_CRED_ENTER("setregid %d %d\n", uap->rgid, uap->egid);
1331
1332 rgid = uap->rgid;
1333 egid = uap->egid;
1334
1335 if (rgid == (uid_t)-1)
1336 rgid = KAUTH_GID_NONE;
1337 if (egid == (uid_t)-1)
1338 egid = KAUTH_GID_NONE;
1339 AUDIT_ARG(egid, egid);
1340 AUDIT_ARG(rgid, rgid);
1341
1342 /* get current credential and take a reference while we muck with it */
1343 my_cred = kauth_cred_proc_ref(p);
1344 my_pcred = posix_cred_get(my_cred);
1345
1346 for (;;) {
1347
1348 if (((rgid != KAUTH_UID_NONE && /* allow no change of rgid */
1349 rgid != my_pcred->cr_rgid && /* allow rgid = rgid */
1350 rgid != my_pcred->cr_gid && /* allow rgid = egid */
1351 rgid != my_pcred->cr_svgid) || /* allow rgid = svgid */
1352 (egid != KAUTH_UID_NONE && /* allow no change of egid */
1353 egid != my_pcred->cr_groups[0] && /* allow no change of egid */
1354 egid != my_pcred->cr_gid && /* allow egid = egid */
1355 egid != my_pcred->cr_rgid && /* allow egid = rgid */
1356 egid != my_pcred->cr_svgid)) && /* allow egid = svgid */
1357 (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */
1358 kauth_cred_unref(&my_cred);
1359 return (error);
1360 }
1361
1362 uid_t new_egid = my_pcred->cr_gid;
1363 uid_t new_rgid = my_pcred->cr_rgid;
1364 uid_t svgid = KAUTH_UID_NONE;
1365
1366
1367 /*
1368 * Set the credential with new info. If there is no change,
1369 * we get back the same credential we passed in; if there is
1370 * a change, we drop the reference on the credential we
1371 * passed in. The subsequent compare is safe, because it is
1372 * a pointer compare rather than a contents compare.
1373 */
1374 if (egid != KAUTH_UID_NONE && my_pcred->cr_gid != egid) {
1375 /* changing the effective GID */
1376 new_egid = egid;
1377 OSBitOrAtomic(P_SUGID, &p->p_flag);
1378 }
1379 if (rgid != KAUTH_UID_NONE && my_pcred->cr_rgid != rgid) {
1380 /* changing the real GID */
1381 new_rgid = rgid;
1382 OSBitOrAtomic(P_SUGID, &p->p_flag);
1383 }
1384 /*
1385 * If the newly requested real gid or effective gid does
1386 * not match the saved gid, then set the saved gid to the
1387 * new effective gid. We are protected from escalation
1388 * by the prechecking.
1389 */
1390 if (my_pcred->cr_svgid != uap->rgid &&
1391 my_pcred->cr_svgid != uap->egid) {
1392 svgid = new_egid;
1393 OSBitOrAtomic(P_SUGID, &p->p_flag);
1394 }
1395
1396 my_new_cred = kauth_cred_setresgid(my_cred, rgid, egid, svgid);
1397 if (my_cred != my_new_cred) {
1398
1399 DEBUG_CRED_CHANGE("setregid(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags);
1400
1401 proc_ucred_lock(p);
1402 /* need to protect for a race where another thread
1403 * also changed the credential after we took our
1404 * reference. If p_ucred has changed then we
1405 * should restart this again with the new cred.
1406 */
1407 if (p->p_ucred != my_cred) {
1408 proc_ucred_unlock(p);
1409 kauth_cred_unref(&my_new_cred);
1410 /* try again */
1411 my_cred = kauth_cred_proc_ref(p);
1412 my_pcred = posix_cred_get(my_cred);
1413 continue;
1414 }
1415 p->p_ucred = my_new_cred;
1416 /* update cred on proc */
1417 PROC_UPDATE_CREDS_ONPROC(p);
1418 OSBitOrAtomic(P_SUGID, &p->p_flag); /* XXX redundant? */
1419 proc_ucred_unlock(p);
1420 }
1421 break;
1422 }
1423 /* Drop old proc reference or our extra reference */
1424 kauth_cred_unref(&my_cred);
1425
1426 set_security_token(p);
1427 return (0);
1428}
1429
1430
1431/*
1432 * Set the per-thread override identity. The first parameter can be the
1433 * current real UID, KAUTH_UID_NONE, or, if the caller is privileged, it
1434 * can be any UID. If it is KAUTH_UID_NONE, then as a special case, this
1435 * means "revert to the per process credential"; otherwise, if permitted,
1436 * it changes the effective, real, and saved UIDs and GIDs for the current
1437 * thread to the requested UID and single GID, and clears all other GIDs.
1438 */
1439int
1440settid(proc_t p, struct settid_args *uap, __unused int32_t *retval)
1441{
1442 kauth_cred_t uc;
1443 struct uthread *uthread = get_bsdthread_info(current_thread());
1444 uid_t uid;
1445 gid_t gid;
1446
1447 uid = uap->uid;
1448 gid = uap->gid;
1449 AUDIT_ARG(uid, uid);
1450 AUDIT_ARG(gid, gid);
1451
1452 if (proc_suser(p) != 0)
1453 return (EPERM);
1454
1455 if (uid == KAUTH_UID_NONE) {
1456
1457 /* must already be assuming another identity in order to revert back */
1458 if ((uthread->uu_flag & UT_SETUID) == 0)
1459 return (EPERM);
1460
1461 /* revert to delayed binding of process credential */
1462 uc = kauth_cred_proc_ref(p);
1463 kauth_cred_unref(&uthread->uu_ucred);
1464 uthread->uu_ucred = uc;
1465 uthread->uu_flag &= ~UT_SETUID;
1466 } else {
1467 kauth_cred_t my_cred, my_new_cred;
1468
1469 /* cannot already be assuming another identity */
1470 if ((uthread->uu_flag & UT_SETUID) != 0) {
1471 return (EPERM);
1472 }
1473
1474 /*
1475 * Get a new credential instance from the old if this one
1476 * changes; otherwise kauth_cred_setuidgid() returns the
1477 * same credential. We take an extra reference on the
1478 * current credential while we muck with it, so we can do
1479 * the post-compare for changes by pointer.
1480 */
1481 kauth_cred_ref(uthread->uu_ucred);
1482 my_cred = uthread->uu_ucred;
1483 my_new_cred = kauth_cred_setuidgid(my_cred, uid, gid);
1484 if (my_cred != my_new_cred)
1485 uthread->uu_ucred = my_new_cred;
1486 uthread->uu_flag |= UT_SETUID;
1487
1488 /* Drop old uthread reference or our extra reference */
1489 kauth_cred_unref(&my_cred);
1490 }
1491 /*
1492 * XXX should potentially set per thread security token (there is
1493 * XXX none).
1494 * XXX it is unclear whether P_SUGID should be st at this point;
1495 * XXX in theory, it is being deprecated.
1496 */
1497 return (0);
1498}
1499
1500
1501/*
1502 * Set the per-thread override identity. Use this system call for a thread to
1503 * assume the identity of another process or to revert back to normal identity
1504 * of the current process.
1505 *
1506 * When the "assume" argument is non zero the current thread will assume the
1507 * identity of the process represented by the pid argument.
1508 *
1509 * When the assume argument is zero we revert back to our normal identity.
1510 */
1511int
1512settid_with_pid(proc_t p, struct settid_with_pid_args *uap, __unused int32_t *retval)
1513{
1514 proc_t target_proc;
1515 struct uthread *uthread = get_bsdthread_info(current_thread());
1516 kauth_cred_t my_cred, my_target_cred, my_new_cred;
1517 posix_cred_t my_target_pcred;
1518
1519 AUDIT_ARG(pid, uap->pid);
1520 AUDIT_ARG(value32, uap->assume);
1521
1522 if (proc_suser(p) != 0) {
1523 return (EPERM);
1524 }
1525
1526 /*
1527 * XXX should potentially set per thread security token (there is
1528 * XXX none).
1529 * XXX it is unclear whether P_SUGID should be st at this point;
1530 * XXX in theory, it is being deprecated.
1531 */
1532
1533 /*
1534 * assume argument tells us to assume the identity of the process with the
1535 * id passed in the pid argument.
1536 */
1537 if (uap->assume != 0) {
1538 /* can't do this if we have already assumed an identity */
1539 if ((uthread->uu_flag & UT_SETUID) != 0)
1540 return (EPERM);
1541
1542 target_proc = proc_find(uap->pid);
1543 /* can't assume the identity of the kernel process */
1544 if (target_proc == NULL || target_proc == kernproc) {
1545 if (target_proc!= NULL)
1546 proc_rele(target_proc);
1547 return (ESRCH);
1548 }
1549
1550 /*
1551 * Take a reference on the credential used in our target
1552 * process then use it as the identity for our current
1553 * thread. We take an extra reference on the current
1554 * credential while we muck with it, so we can do the
1555 * post-compare for changes by pointer.
1556 *
1557 * The post-compare is needed for the case that our process
1558 * credential has been changed to be identical to our thread
1559 * credential following our assumption of a per-thread one,
1560 * since the credential cache will maintain a unique instance.
1561 */
1562 kauth_cred_ref(uthread->uu_ucred);
1563 my_cred = uthread->uu_ucred;
1564 my_target_cred = kauth_cred_proc_ref(target_proc);
1565 my_target_pcred = posix_cred_get(my_target_cred);
1566 my_new_cred = kauth_cred_setuidgid(my_cred, my_target_pcred->cr_uid, my_target_pcred->cr_gid);
1567 if (my_cred != my_new_cred)
1568 uthread->uu_ucred = my_new_cred;
1569
1570 uthread->uu_flag |= UT_SETUID;
1571
1572 /* Drop old uthread reference or our extra reference */
1573 proc_rele(target_proc);
1574 kauth_cred_unref(&my_cred);
1575 kauth_cred_unref(&my_target_cred);
1576
1577 return (0);
1578 }
1579
1580 /*
1581 * Otherwise, we are reverting back to normal mode of operation where
1582 * delayed binding of the process credential sets the credential in
1583 * the thread (uu_ucred)
1584 */
1585 if ((uthread->uu_flag & UT_SETUID) == 0)
1586 return (EPERM);
1587
1588 /* revert to delayed binding of process credential */
1589 my_new_cred = kauth_cred_proc_ref(p);
1590 kauth_cred_unref(&uthread->uu_ucred);
1591 uthread->uu_ucred = my_new_cred;
1592 uthread->uu_flag &= ~UT_SETUID;
1593
1594 return (0);
1595}
1596
1597
1598/*
1599 * setgroups1
1600 *
1601 * Description: Internal implementation for both the setgroups and initgroups
1602 * system calls
1603 *
1604 * Parameters: gidsetsize Number of groups in set
1605 * gidset Pointer to group list
1606 * gmuid Base gid (initgroups only!)
1607 *
1608 * Returns: 0 Success
1609 * suser:EPERM Permision denied
1610 * EINVAL Invalid gidsetsize value
1611 * copyin:EFAULT Bad gidset or gidsetsize is
1612 * too large
1613 *
1614 * Notes: When called from a thread running under an assumed per-thread
1615 * identity, this function will operate against the per-thread
1616 * credential, rather than against the process credential. In
1617 * this specific case, the process credential is verified to
1618 * still be privileged at the time of the call, rather than the
1619 * per-thread credential for this operation to be permitted.
1620 *
1621 * This effectively means that setgroups/initigroups calls in
1622 * a thread running a per-thread credential should occur *after*
1623 * the settid call that created it, not before (unlike setuid,
1624 * which must be called after, since it will result in privilege
1625 * being dropped).
1626 *
1627 * When called normally (i.e. no per-thread assumed identity),
1628 * the per process credential is updated per POSIX.
1629 *
1630 * If the credential is changed as a result of this call, then we
1631 * flag the process as having set privilege since the last exec.
1632 */
1633static int
1634setgroups1(proc_t p, u_int gidsetsize, user_addr_t gidset, uid_t gmuid, __unused int32_t *retval)
1635{
1636 u_int ngrp;
1637 gid_t newgroups[NGROUPS] = { 0 };
1638 int error;
1639 kauth_cred_t my_cred, my_new_cred;
1640 struct uthread *uthread = get_bsdthread_info(current_thread());
1641
1642 DEBUG_CRED_ENTER("setgroups1 (%d/%d): %d 0x%016x %d\n", p->p_pid, (p->p_pptr ? p->p_pptr->p_pid : 0), gidsetsize, gidset, gmuid);
1643
1644 ngrp = gidsetsize;
1645 if (ngrp > NGROUPS)
1646 return (EINVAL);
1647
1648 if ( ngrp < 1 ) {
1649 ngrp = 1;
1650 } else {
1651 error = copyin(gidset,
1652 (caddr_t)newgroups, ngrp * sizeof(gid_t));
1653 if (error) {
1654 return (error);
1655 }
1656 }
1657
1658 my_cred = kauth_cred_proc_ref(p);
1659 if ((error = suser(my_cred, &p->p_acflag))) {
1660 kauth_cred_unref(&my_cred);
1661 return (error);
1662 }
1663
1664 if ((uthread->uu_flag & UT_SETUID) != 0) {
1665#if DEBUG_CRED
1666 int my_cred_flags = uthread->uu_ucred->cr_flags;
1667#endif /* DEBUG_CRED */
1668 kauth_cred_unref(&my_cred);
1669
1670 /*
1671 * If this thread is under an assumed identity, set the
1672 * supplementary grouplist on the thread credential instead
1673 * of the process one. If we were the only reference holder,
1674 * the credential is updated in place, otherwise, our reference
1675 * is dropped and we get back a different cred with a reference
1676 * already held on it. Because this is per-thread, we don't
1677 * need the referencing/locking/retry required for per-process.
1678 */
1679 my_cred = uthread->uu_ucred;
1680 uthread->uu_ucred = kauth_cred_setgroups(my_cred, &newgroups[0], ngrp, gmuid);
1681#if DEBUG_CRED
1682 if (my_cred != uthread->uu_ucred) {
1683 DEBUG_CRED_CHANGE("setgroups1(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred_flags, uthread->uu_ucred , uthread->uu_ucred ->cr_flags);
1684 }
1685#endif /* DEBUG_CRED */
1686 } else {
1687
1688 /*
1689 * get current credential and take a reference while we muck
1690 * with it
1691 */
1692 for (;;) {
1693 /*
1694 * Set the credential with new info. If there is no
1695 * change, we get back the same credential we passed
1696 * in; if there is a change, we drop the reference on
1697 * the credential we passed in. The subsequent
1698 * compare is safe, because it is a pointer compare
1699 * rather than a contents compare.
1700 */
1701 my_new_cred = kauth_cred_setgroups(my_cred, &newgroups[0], ngrp, gmuid);
1702 if (my_cred != my_new_cred) {
1703
1704 DEBUG_CRED_CHANGE("setgroups1(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
1705
1706 proc_ucred_lock(p);
1707 /*
1708 * We need to protect for a race where another
1709 * thread also changed the credential after we
1710 * took our reference. If p_ucred has
1711 * changed then we should restart this again
1712 * with the new cred.
1713 */
1714 if (p->p_ucred != my_cred) {
1715 proc_ucred_unlock(p);
1716 kauth_cred_unref(&my_new_cred);
1717 my_cred = kauth_cred_proc_ref(p);
1718 /* try again */
1719 continue;
1720 }
1721 p->p_ucred = my_new_cred;
1722 /* update cred on proc */
1723 PROC_UPDATE_CREDS_ONPROC(p);
1724 OSBitOrAtomic(P_SUGID, &p->p_flag);
1725 proc_ucred_unlock(p);
1726 }
1727 break;
1728 }
1729 /* Drop old proc reference or our extra reference */
1730 AUDIT_ARG(groupset, posix_cred_get(my_cred)->cr_groups, ngrp);
1731 kauth_cred_unref(&my_cred);
1732
1733
1734 set_security_token(p);
1735 }
1736
1737 return (0);
1738}
1739
1740
1741/*
1742 * initgroups
1743 *
1744 * Description: Initialize the default supplementary groups list and set the
1745 * gmuid for use by the external group resolver (if any)
1746 *
1747 * Parameters: uap->gidsetsize Number of groups in set
1748 * uap->gidset Pointer to group list
1749 * uap->gmuid Base gid
1750 *
1751 * Returns: 0 Success
1752 * setgroups1:EPERM Permision denied
1753 * setgroups1:EINVAL Invalid gidsetsize value
1754 * setgroups1:EFAULT Bad gidset or gidsetsize is
1755 *
1756 * Notes: This function opts *IN* to memberd participation
1757 *
1758 * The normal purpose of this function is for a privileged
1759 * process to indicate supplementary groups and identity for
1760 * participation in extended group membership resolution prior
1761 * to dropping privilege by assuming a specific user identity.
1762 *
1763 * It is the first half of the primary mechanism whereby user
1764 * identity is established to the system by programs such as
1765 * /usr/bin/login. The second half is the drop of uid privilege
1766 * for a specific uid corresponding to the user.
1767 *
1768 * See also: setgroups1()
1769 */
1770int
1771initgroups(proc_t p, struct initgroups_args *uap, __unused int32_t *retval)
1772{
1773 DEBUG_CRED_ENTER("initgroups\n");
1774
1775 return(setgroups1(p, uap->gidsetsize, uap->gidset, uap->gmuid, retval));
1776}
1777
1778
1779/*
1780 * setgroups
1781 *
1782 * Description: Initialize the default supplementary groups list
1783 *
1784 * Parameters: gidsetsize Number of groups in set
1785 * gidset Pointer to group list
1786 *
1787 * Returns: 0 Success
1788 * setgroups1:EPERM Permision denied
1789 * setgroups1:EINVAL Invalid gidsetsize value
1790 * setgroups1:EFAULT Bad gidset or gidsetsize is
1791 *
1792 * Notes: This functions opts *OUT* of memberd participation.
1793 *
1794 * This function exists for compatibility with POSIX. Most user
1795 * programs should use initgroups() instead to ensure correct
1796 * participation in group membership resolution when utilizing
1797 * a directory service for authentication.
1798 *
1799 * It is identical to an initgroups() call with a gmuid argument
1800 * of KAUTH_UID_NONE.
1801 *
1802 * See also: setgroups1()
1803 */
1804int
1805setgroups(proc_t p, struct setgroups_args *uap, __unused int32_t *retval)
1806{
1807 DEBUG_CRED_ENTER("setgroups\n");
1808
1809 return(setgroups1(p, uap->gidsetsize, uap->gidset, KAUTH_UID_NONE, retval));
1810}
1811
1812
1813/*
1814 * Set the per-thread/per-process supplementary groups list.
1815 *
1816 * XXX implement setsgroups
1817 *
1818 */
1819
1820int
1821setsgroups(__unused proc_t p, __unused struct setsgroups_args *uap, __unused int32_t *retval)
1822{
1823 return(ENOTSUP);
1824}
1825
1826/*
1827 * Set the per-thread/per-process whiteout groups list.
1828 *
1829 * XXX implement setwgroups
1830 *
1831 */
1832
1833int
1834setwgroups(__unused proc_t p, __unused struct setwgroups_args *uap, __unused int32_t *retval)
1835{
1836 return(ENOTSUP);
1837}
1838
1839
1840/*
1841 * Check if gid is a member of the group set.
1842 *
1843 * XXX This interface is going away; use kauth_cred_ismember_gid() directly
1844 * XXX instead.
1845 */
1846int
1847groupmember(gid_t gid, kauth_cred_t cred)
1848{
1849 int is_member;
1850
1851 if (kauth_cred_ismember_gid(cred, gid, &is_member) == 0 && is_member)
1852 return (1);
1853 return (0);
1854}
1855
1856
1857/*
1858 * Test whether the specified credentials imply "super-user"
1859 * privilege; if so, and we have accounting info, set the flag
1860 * indicating use of super-powers.
1861 * Returns 0 or error.
1862 *
1863 * XXX This interface is going away; use kauth_cred_issuser() directly
1864 * XXX instead.
1865 *
1866 * Note: This interface exists to implement the "has used privilege"
1867 * bit (ASU) in the p_acflags field of the process, which is
1868 * only externalized via private sysctl and in process accounting
1869 * records. The flag is technically not required in either case.
1870 */
1871int
1872suser(kauth_cred_t cred, u_short *acflag)
1873{
1874#if DIAGNOSTIC
1875 if (!IS_VALID_CRED(cred))
1876 panic("suser");
1877#endif
1878 if (kauth_cred_getuid(cred) == 0) {
1879 if (acflag)
1880 *acflag |= ASU;
1881 return (0);
1882 }
1883 return (EPERM);
1884}
1885
1886
1887/*
1888 * getlogin
1889 *
1890 * Description: Get login name, if available.
1891 *
1892 * Parameters: uap->namebuf User buffer for return
1893 * uap->namelen User buffer length
1894 *
1895 * Returns: 0 Success
1896 * copyout:EFAULT
1897 *
1898 * Notes: Intended to obtain a string containing the user name of the
1899 * user associated with the controlling terminal for the calling
1900 * process.
1901 *
1902 * Not very useful on modern systems, due to inherent length
1903 * limitations for the static array in the session structure
1904 * which is used to store the login name.
1905 *
1906 * Permitted to return NULL
1907 *
1908 * XXX: Belongs in kern_proc.c
1909 */
1910int
1911getlogin(proc_t p, struct getlogin_args *uap, __unused int32_t *retval)
1912{
1913 char buffer[MAXLOGNAME+1];
1914 struct session * sessp;
1915
1916 bzero(buffer, MAXLOGNAME+1);
1917
1918 sessp = proc_session(p);
1919
1920 if (uap->namelen > MAXLOGNAME)
1921 uap->namelen = MAXLOGNAME;
1922
1923 if(sessp != SESSION_NULL) {
1924 session_lock(sessp);
1925 bcopy( sessp->s_login, buffer, uap->namelen);
1926 session_unlock(sessp);
1927 }
1928 session_rele(sessp);
1929
1930 return (copyout((caddr_t)buffer, uap->namebuf, uap->namelen));
1931}
1932
1933
1934/*
1935 * setlogin
1936 *
1937 * Description: Set login name.
1938 *
1939 * Parameters: uap->namebuf User buffer containing name
1940 *
1941 * Returns: 0 Success
1942 * suser:EPERM Permission denied
1943 * copyinstr:EFAULT User buffer invalid
1944 * copyinstr:EINVAL Supplied name was too long
1945 *
1946 * Notes: This is a utility system call to support getlogin().
1947 *
1948 * XXX: Belongs in kern_proc.c
1949 */
1950int
1951setlogin(proc_t p, struct setlogin_args *uap, __unused int32_t *retval)
1952{
1953 int error;
1954 size_t dummy=0;
1955 char buffer[MAXLOGNAME+1];
1956 struct session * sessp;
1957
1958 if ((error = proc_suser(p)))
1959 return (error);
1960
1961 bzero(&buffer[0], MAXLOGNAME+1);
1962
1963
1964 error = copyinstr(uap->namebuf,
1965 (caddr_t) &buffer[0],
1966 MAXLOGNAME - 1, (size_t *)&dummy);
1967
1968 sessp = proc_session(p);
1969
1970 if (sessp != SESSION_NULL) {
1971 session_lock(sessp);
1972 bcopy(buffer, sessp->s_login, MAXLOGNAME);
1973 session_unlock(sessp);
1974 session_rele(sessp);
1975 }
1976
1977
1978 if (!error) {
1979 AUDIT_ARG(text, buffer);
1980 } else if (error == ENAMETOOLONG)
1981 error = EINVAL;
1982 return (error);
1983}
1984
1985
1986/* Set the secrity token of the task with current euid and eguid */
1987/*
1988 * XXX This needs to change to give the task a reference and/or an opaque
1989 * XXX identifier.
1990 */
1991int
1992set_security_token(proc_t p)
1993{
1994 return set_security_token_task_internal(p, p->task);
1995}
1996
1997/*
1998 * Set the secrity token of the task with current euid and eguid
1999 * The function takes a proc and a task, where proc->task might point to a
2000 * different task if called from exec.
2001 */
2002
2003int
2004set_security_token_task_internal(proc_t p, void *t)
2005{
2006 security_token_t sec_token;
2007 audit_token_t audit_token;
2008 kauth_cred_t my_cred;
2009 posix_cred_t my_pcred;
2010 host_priv_t host_priv;
2011 task_t task = t;
2012
2013 /*
2014 * Don't allow a vfork child to override the parent's token settings
2015 * (since they share a task). Instead, the child will just have to
2016 * suffer along using the parent's token until the exec(). It's all
2017 * undefined behavior anyway, right?
2018 */
2019 if (task == current_task()) {
2020 uthread_t uthread;
2021 uthread = (uthread_t)get_bsdthread_info(current_thread());
2022 if (uthread->uu_flag & UT_VFORK)
2023 return (1);
2024 }
2025
2026 my_cred = kauth_cred_proc_ref(p);
2027 my_pcred = posix_cred_get(my_cred);
2028
2029 /* XXX mach_init doesn't have a p_ucred when it calls this function */
2030 if (IS_VALID_CRED(my_cred)) {
2031 sec_token.val[0] = kauth_cred_getuid(my_cred);
2032 sec_token.val[1] = kauth_cred_getgid(my_cred);
2033 } else {
2034 sec_token.val[0] = 0;
2035 sec_token.val[1] = 0;
2036 }
2037
2038 /*
2039 * The current layout of the Mach audit token explicitly
2040 * adds these fields. But nobody should rely on such
2041 * a literal representation. Instead, the BSM library
2042 * provides a function to convert an audit token into
2043 * a BSM subject. Use of that mechanism will isolate
2044 * the user of the trailer from future representation
2045 * changes.
2046 */
2047 audit_token.val[0] = my_cred->cr_audit.as_aia_p->ai_auid;
2048 audit_token.val[1] = my_pcred->cr_uid;
2049 audit_token.val[2] = my_pcred->cr_gid;
2050 audit_token.val[3] = my_pcred->cr_ruid;
2051 audit_token.val[4] = my_pcred->cr_rgid;
2052 audit_token.val[5] = p->p_pid;
2053 audit_token.val[6] = my_cred->cr_audit.as_aia_p->ai_asid;
2054 audit_token.val[7] = p->p_idversion;
2055
2056 host_priv = (sec_token.val[0]) ? HOST_PRIV_NULL : host_priv_self();
2057#if CONFIG_MACF
2058 if (host_priv != HOST_PRIV_NULL && mac_system_check_host_priv(my_cred))
2059 host_priv = HOST_PRIV_NULL;
2060#endif
2061 kauth_cred_unref(&my_cred);
2062
2063#if DEVELOPMENT || DEBUG
2064 /*
2065 * Update the pid an proc name for importance base if any
2066 */
2067 task_importance_update_owner_info(task);
2068#endif
2069
2070 return (host_security_set_task_token(host_security_self(),
2071 task,
2072 sec_token,
2073 audit_token,
2074 host_priv) != KERN_SUCCESS);
2075}
2076
2077
2078int get_audit_token_pid(audit_token_t *audit_token);
2079
2080int
2081get_audit_token_pid(audit_token_t *audit_token)
2082{
2083 /* keep in-sync with set_security_token (above) */
2084 if (audit_token)
2085 return (int)audit_token->val[5];
2086 return -1;
2087}
2088
2089
2090/*
2091 * Fill in a struct xucred based on a kauth_cred_t.
2092 */
2093__private_extern__
2094void
2095cru2x(kauth_cred_t cr, struct xucred *xcr)
2096{
2097 posix_cred_t pcr = posix_cred_get(cr);
2098
2099 bzero(xcr, sizeof(*xcr));
2100 xcr->cr_version = XUCRED_VERSION;
2101 xcr->cr_uid = kauth_cred_getuid(cr);
2102 xcr->cr_ngroups = pcr->cr_ngroups;
2103 bcopy(pcr->cr_groups, xcr->cr_groups, sizeof(xcr->cr_groups));
2104}
2105