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