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