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