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