1 /*
2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 *
28 *
29 * Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved
30 *
31 *
32 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
33 * The Regents of the University of California. All rights reserved.
34 * (c) UNIX System Laboratories, Inc.
35 * All or some portions of this file are derived from material licensed
36 * to the University of California by American Telephone and Telegraph
37 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
38 * the permission of UNIX System Laboratories, Inc.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 * 3. All advertising materials mentioning features or use of this software
49 * must display the following acknowledgement:
50 * This product includes software developed by the University of
51 * California, Berkeley and its contributors.
52 * 4. Neither the name of the University nor the names of its contributors
53 * may be used to endorse or promote products derived from this software
54 * without specific prior written permission.
55 *
56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 * SUCH DAMAGE.
67 *
68 * @(#)kern_prot.c 8.9 (Berkeley) 2/14/95
69 *
70 *
71 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
72 * support for mandatory and extensible security protections. This notice
73 * is included in support of clause 2.2 (b) of the Apple Public License,
74 * Version 2.0.
75 *
76 *
77 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
78 * support for mandatory and extensible security protections. This notice
79 * is included in support of clause 2.2 (b) of the Apple Public License,
80 * Version 2.0.
81 *
82 */
83
84 /*
85 * System calls related to processes and protection
86 */
87
88 #include <sys/param.h>
89 #include <sys/acct.h>
90 #include <sys/systm.h>
91 #include <sys/ucred.h>
92 #include <sys/proc_internal.h>
93 #include <sys/user.h>
94 #include <sys/kauth.h>
95 #include <sys/timeb.h>
96 #include <sys/times.h>
97 #include <sys/malloc.h>
98 #include <sys/persona.h>
99
100 #include <security/audit/audit.h>
101
102 #if CONFIG_MACF
103 #include <security/mac_framework.h>
104 #endif
105
106 #include <sys/mount_internal.h>
107 #include <sys/sysproto.h>
108 #include <mach/message.h>
109
110 #include <kern/host.h>
111 #include <kern/task.h> /* for current_task() */
112 #include <kern/assert.h>
113
114 #if DEVELOPMENT || DEBUG
115 extern void task_importance_update_owner_info(task_t);
116 #endif
117
118 /* Used by pmap.c to copy kauth_cred_t structs */
119 void kauth_cred_copy(const uintptr_t kv, const uintptr_t new_data);
120
121 /*
122 * setprivexec
123 *
124 * Description: (dis)allow this process to hold task, thread, or execption
125 * ports of processes about to exec.
126 *
127 * Parameters: uap->flag New value for flag
128 *
129 * Returns: int Previous value of flag
130 *
131 * XXX: Belongs in kern_proc.c
132 */
133 int
setprivexec(proc_t p,struct setprivexec_args * uap,int32_t * retval)134 setprivexec(proc_t p, struct setprivexec_args *uap, int32_t *retval)
135 {
136 AUDIT_ARG(value32, uap->flag);
137 *retval = p->p_debugger;
138 p->p_debugger = (uap->flag != 0);
139 return 0;
140 }
141
142
143 /*
144 * getpid
145 *
146 * Description: get the process ID
147 *
148 * Parameters: (void)
149 *
150 * Returns: pid_t Current process ID
151 *
152 * XXX: Belongs in kern_proc.c
153 */
154 int
getpid(proc_t p,__unused struct getpid_args * uap,int32_t * retval)155 getpid(proc_t p, __unused struct getpid_args *uap, int32_t *retval)
156 {
157 *retval = proc_getpid(p);
158 return 0;
159 }
160
161
162 /*
163 * getppid
164 *
165 * Description: get the parent process ID
166 *
167 * Parameters: (void)
168 *
169 * Returns: pid_t Parent process ID
170 *
171 * XXX: Belongs in kern_proc.c
172 */
173 int
getppid(proc_t p,__unused struct getppid_args * uap,int32_t * retval)174 getppid(proc_t p, __unused struct getppid_args *uap, int32_t *retval)
175 {
176 *retval = p->p_ppid;
177 return 0;
178 }
179
180
181 /*
182 * getpgrp
183 *
184 * Description: get the process group ID of the calling process
185 *
186 * Parameters: (void)
187 *
188 * Returns: pid_t Process group ID
189 *
190 * XXX: Belongs in kern_proc.c
191 */
192 int
getpgrp(proc_t p,__unused struct getpgrp_args * uap,int32_t * retval)193 getpgrp(proc_t p, __unused struct getpgrp_args *uap, int32_t *retval)
194 {
195 *retval = p->p_pgrpid;
196 return 0;
197 }
198
199
200 /*
201 * getpgid
202 *
203 * Description: Get an arbitary pid's process group id
204 *
205 * Parameters: uap->pid The target pid
206 *
207 * Returns: 0 Success
208 * ESRCH No such process
209 *
210 * Notes: We are permitted to return EPERM in the case that the target
211 * process is not in the same session as the calling process,
212 * which could be a security consideration
213 *
214 * XXX: Belongs in kern_proc.c
215 */
216 int
getpgid(proc_t p,struct getpgid_args * uap,int32_t * retval)217 getpgid(proc_t p, struct getpgid_args *uap, int32_t *retval)
218 {
219 proc_t pt;
220 int refheld = 0;
221
222 pt = p;
223 if (uap->pid == 0) {
224 goto found;
225 }
226
227 if ((pt = proc_find(uap->pid)) == 0) {
228 return ESRCH;
229 }
230 refheld = 1;
231 found:
232 *retval = pt->p_pgrpid;
233 if (refheld != 0) {
234 proc_rele(pt);
235 }
236 return 0;
237 }
238
239
240 /*
241 * getsid
242 *
243 * Description: Get an arbitary pid's session leaders process group ID
244 *
245 * Parameters: uap->pid The target pid
246 *
247 * Returns: 0 Success
248 * ESRCH No such process
249 *
250 * Notes: We are permitted to return EPERM in the case that the target
251 * process is not in the same session as the calling process,
252 * which could be a security consideration
253 *
254 * XXX: Belongs in kern_proc.c
255 */
256 int
getsid(proc_t p,struct getsid_args * uap,int32_t * retval)257 getsid(proc_t p, struct getsid_args *uap, int32_t *retval)
258 {
259 proc_t pt;
260
261 if (uap->pid == 0) {
262 *retval = proc_sessionid(p);
263 return 0;
264 }
265
266 if ((pt = proc_find(uap->pid)) != PROC_NULL) {
267 *retval = proc_sessionid(pt);
268 proc_rele(pt);
269 return 0;
270 }
271
272 return ESRCH;
273 }
274
275
276 /*
277 * getuid
278 *
279 * Description: get real user ID for caller
280 *
281 * Parameters: (void)
282 *
283 * Returns: uid_t The real uid of the caller
284 */
285 int
getuid(__unused proc_t p,__unused struct getuid_args * uap,int32_t * retval)286 getuid(__unused proc_t p, __unused struct getuid_args *uap, int32_t *retval)
287 {
288 *retval = kauth_getruid();
289 return 0;
290 }
291
292
293 /*
294 * geteuid
295 *
296 * Description: get effective user ID for caller
297 *
298 * Parameters: (void)
299 *
300 * Returns: uid_t The effective uid of the caller
301 */
302 int
geteuid(__unused proc_t p,__unused struct geteuid_args * uap,int32_t * retval)303 geteuid(__unused proc_t p, __unused struct geteuid_args *uap, int32_t *retval)
304 {
305 *retval = kauth_getuid();
306 return 0;
307 }
308
309
310 /*
311 * gettid
312 *
313 * Description: Return the per-thread override identity.
314 *
315 * Parameters: uap->uidp Address of uid_t to get uid
316 * uap->gidp Address of gid_t to get gid
317 *
318 * Returns: 0 Success
319 * ESRCH No per thread identity active
320 */
321 int
gettid(__unused proc_t p,struct gettid_args * uap,int32_t * retval)322 gettid(__unused proc_t p, struct gettid_args *uap, int32_t *retval)
323 {
324 thread_ro_t tro = current_thread_ro();
325 kauth_cred_t tro_cred = tro->tro_cred;
326 int error;
327
328 /*
329 * If this thread is not running with an override identity, we can't
330 * return one to the caller, so return an error instead.
331 */
332 if (!(tro->tro_flags & TRO_SETUID)) {
333 return ESRCH;
334 }
335
336 if ((error = suword(uap->uidp, kauth_cred_getruid(tro_cred)))) {
337 return error;
338 }
339 if ((error = suword(uap->gidp, kauth_cred_getrgid(tro_cred)))) {
340 return error;
341 }
342
343 *retval = 0;
344 return 0;
345 }
346
347
348 /*
349 * getgid
350 *
351 * Description: get the real group ID for the calling process
352 *
353 * Parameters: (void)
354 *
355 * Returns: gid_t The real gid of the caller
356 */
357 int
getgid(__unused proc_t p,__unused struct getgid_args * uap,int32_t * retval)358 getgid(__unused proc_t p, __unused struct getgid_args *uap, int32_t *retval)
359 {
360 *retval = kauth_getrgid();
361 return 0;
362 }
363
364
365 /*
366 * getegid
367 *
368 * Description: get the effective group ID for the calling process
369 *
370 * Parameters: (void)
371 *
372 * Returns: gid_t The effective gid of the caller
373 *
374 * Notes: As an implementation detail, the effective gid is stored as
375 * the first element of the supplementary group list.
376 *
377 * This could be implemented in Libc instead because of the above
378 * detail.
379 */
380 int
getegid(__unused proc_t p,__unused struct getegid_args * uap,int32_t * retval)381 getegid(__unused proc_t p, __unused struct getegid_args *uap, int32_t *retval)
382 {
383 *retval = kauth_getgid();
384 return 0;
385 }
386
387
388 /*
389 * getgroups
390 *
391 * Description: get the list of supplementary groups for the calling process
392 *
393 * Parameters: uap->gidsetsize # of gid_t's in user buffer
394 * uap->gidset Pointer to user buffer
395 *
396 * Returns: 0 Success
397 * EINVAL User buffer too small
398 * copyout:EFAULT User buffer invalid
399 *
400 * Retval: -1 Error
401 * !0 # of groups
402 *
403 * Notes: The caller may specify a 0 value for gidsetsize, and we will
404 * then return how large a buffer is required (in gid_t's) to
405 * contain the answer at the time of the call. Otherwise, we
406 * return the number of gid_t's catually copied to user space.
407 *
408 * When called with a 0 gidsetsize from a multithreaded program,
409 * there is no guarantee that another thread may not change the
410 * number of supplementary groups, and therefore a subsequent
411 * call could still fail, unless the maximum possible buffer
412 * size is supplied by the user.
413 *
414 * As an implementation detail, the effective gid is stored as
415 * the first element of the supplementary group list, and will
416 * be returned by this call.
417 */
418 int
getgroups(__unused proc_t p,struct getgroups_args * uap,int32_t * retval)419 getgroups(__unused proc_t p, struct getgroups_args *uap, int32_t *retval)
420 {
421 int ngrp;
422 int error;
423 kauth_cred_t cred;
424 posix_cred_t pcred;
425
426 /* grab reference while we muck around with the credential */
427 cred = kauth_cred_get_with_ref();
428 pcred = posix_cred_get(cred);
429
430 if ((ngrp = uap->gidsetsize) == 0) {
431 *retval = pcred->cr_ngroups;
432 kauth_cred_unref(&cred);
433 return 0;
434 }
435 if (ngrp < pcred->cr_ngroups) {
436 kauth_cred_unref(&cred);
437 return EINVAL;
438 }
439 ngrp = pcred->cr_ngroups;
440 if ((error = copyout((caddr_t)pcred->cr_groups,
441 uap->gidset,
442 ngrp * sizeof(gid_t)))) {
443 kauth_cred_unref(&cred);
444 return error;
445 }
446 kauth_cred_unref(&cred);
447 *retval = ngrp;
448 return 0;
449 }
450
451
452 /*
453 * Return the per-thread/per-process supplementary groups list.
454 *
455 * XXX implement getsgroups
456 *
457 */
458
459 int
getsgroups(__unused proc_t p,__unused struct getsgroups_args * uap,__unused int32_t * retval)460 getsgroups(__unused proc_t p, __unused struct getsgroups_args *uap, __unused int32_t *retval)
461 {
462 return ENOTSUP;
463 }
464
465 /*
466 * Return the per-thread/per-process whiteout groups list.
467 *
468 * XXX implement getwgroups
469 *
470 */
471
472 int
getwgroups(__unused proc_t p,__unused struct getwgroups_args * uap,__unused int32_t * retval)473 getwgroups(__unused proc_t p, __unused struct getwgroups_args *uap, __unused int32_t *retval)
474 {
475 return ENOTSUP;
476 }
477
478 /*
479 * setsid_internal
480 *
481 * Description: Core implementation of setsid().
482 */
483 int
setsid_internal(proc_t p)484 setsid_internal(proc_t p)
485 {
486 struct pgrp * pg = PGRP_NULL;
487
488 if (p->p_pgrpid == proc_getpid(p) ||
489 (pg = pgrp_find(proc_getpid(p)))) {
490 pgrp_rele(pg);
491 return EPERM;
492 }
493
494 /* enter pgrp works with its own pgrp refcount */
495 (void)enterpgrp(p, proc_getpid(p), 1);
496 return 0;
497 }
498
499 /*
500 * setsid
501 *
502 * Description: Create a new session and set the process group ID to the
503 * session ID
504 *
505 * Parameters: (void)
506 *
507 * Returns: 0 Success
508 * EPERM Permission denied
509 *
510 * Notes: If the calling process is not the process group leader; there
511 * is no existing process group with its ID, then this function will
512 * create a new session, a new process group, and put the caller in the
513 * process group (as the sole member) and make it the session
514 * leader (as the sole process in the session).
515 *
516 * The existing controlling tty (if any) will be dissociated
517 * from the process, and the next non-O_NOCTTY open of a tty
518 * will establish a new controlling tty.
519 *
520 * XXX: Belongs in kern_proc.c
521 */
522 int
setsid(proc_t p,__unused struct setsid_args * uap,int32_t * retval)523 setsid(proc_t p, __unused struct setsid_args *uap, int32_t *retval)
524 {
525 int rc = setsid_internal(p);
526 if (rc == 0) {
527 *retval = proc_getpid(p);
528 }
529 return rc;
530 }
531
532
533 /*
534 * setpgid
535 *
536 * Description: set process group ID for job control
537 *
538 * Parameters: uap->pid Process to change
539 * uap->pgid Process group to join or create
540 *
541 * Returns: 0 Success
542 * ESRCH pid is not the caller or a child of
543 * the caller
544 * enterpgrp:ESRCH No such process
545 * EACCES Permission denied due to exec
546 * EINVAL Invalid argument
547 * EPERM The target process is not in the same
548 * session as the calling process
549 * EPERM The target process is a session leader
550 * EPERM pid and pgid are not the same, and
551 * there is no process in the calling
552 * process whose process group ID matches
553 * pgid
554 *
555 * Notes: This function will cause the target process to either join
556 * an existing process process group, or create a new process
557 * group in the session of the calling process. It cannot be
558 * used to change the process group ID of a process which is
559 * already a session leader.
560 *
561 * If the target pid is 0, the pid of the calling process is
562 * substituted as the new target; if pgid is 0, the target pid
563 * is used as the target process group ID.
564 *
565 * Legacy: This system call entry point is also used to implement the
566 * legacy library routine setpgrp(), which under POSIX
567 *
568 * XXX: Belongs in kern_proc.c
569 */
570 int
setpgid(proc_t curp,struct setpgid_args * uap,__unused int32_t * retval)571 setpgid(proc_t curp, struct setpgid_args *uap, __unused int32_t *retval)
572 {
573 proc_t targp = PROC_NULL; /* target process */
574 struct pgrp *curp_pg = PGRP_NULL;
575 struct pgrp *targp_pg = PGRP_NULL;
576 int error = 0;
577 int refheld = 0;
578 int samesess = 0;
579
580 curp_pg = proc_pgrp(curp, NULL);
581
582 if (uap->pid != 0 && uap->pid != proc_getpid(curp)) {
583 if ((targp = proc_find(uap->pid)) == 0 || !inferior(targp)) {
584 if (targp != PROC_NULL) {
585 refheld = 1;
586 }
587 error = ESRCH;
588 goto out;
589 }
590 refheld = 1;
591 targp_pg = proc_pgrp(targp, NULL);
592 if (targp_pg->pg_session != curp_pg->pg_session) {
593 error = EPERM;
594 goto out;
595 }
596 if (targp->p_flag & P_EXEC) {
597 error = EACCES;
598 goto out;
599 }
600 } else {
601 targp = curp;
602 targp_pg = proc_pgrp(targp, NULL);
603 }
604
605 if (SESS_LEADER(targp, targp_pg->pg_session)) {
606 error = EPERM;
607 goto out;
608 }
609
610 if (uap->pgid < 0) {
611 error = EINVAL;
612 goto out;
613 }
614 if (uap->pgid == 0) {
615 uap->pgid = proc_getpid(targp);
616 } else if (uap->pgid != proc_getpid(targp)) {
617 struct pgrp *pg = PGRP_NULL;
618
619 if ((pg = pgrp_find(uap->pgid)) == PGRP_NULL) {
620 error = EPERM;
621 goto out;
622 }
623 samesess = (pg->pg_session != curp_pg->pg_session);
624 pgrp_rele(pg);
625 if (samesess != 0) {
626 error = EPERM;
627 goto out;
628 }
629 }
630 error = enterpgrp(targp, uap->pgid, 0);
631 out:
632 pgrp_rele(curp_pg);
633 pgrp_rele(targp_pg);
634 if (refheld != 0) {
635 proc_rele(targp);
636 }
637 return error;
638 }
639
640
641 /*
642 * issetugid
643 *
644 * Description: Is current process tainted by uid or gid changes system call
645 *
646 * Parameters: (void)
647 *
648 * Returns: 0 Not tainted
649 * 1 Tainted
650 *
651 * Notes: A process is considered tainted if it was created as a retult
652 * of an execve call from an imnage that had either the SUID or
653 * SGID bit set on the executable, or if it has changed any of its
654 * real, effective, or saved user or group IDs since beginning
655 * execution.
656 */
657 int
proc_issetugid(proc_t p)658 proc_issetugid(proc_t p)
659 {
660 return (p->p_flag & P_SUGID) ? 1 : 0;
661 }
662
663 int
issetugid(proc_t p,__unused struct issetugid_args * uap,int32_t * retval)664 issetugid(proc_t p, __unused struct issetugid_args *uap, int32_t *retval)
665 {
666 /*
667 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
668 * we use P_SUGID because we consider changing the owners as
669 * "tainting" as well.
670 * This is significant for procs that start as root and "become"
671 * a user without an exec - programs cannot know *everything*
672 * that libc *might* have put in their data segment.
673 */
674
675 *retval = proc_issetugid(p);
676 return 0;
677 }
678
679 /*
680 * setuid
681 *
682 * Description: Set user ID system call
683 *
684 * Parameters: uap->uid uid to set
685 *
686 * Returns: 0 Success
687 * suser:EPERM Permission denied
688 *
689 * Notes: If called by a privileged process, this function will set the
690 * real, effective, and saved uid to the requested value.
691 *
692 * If called from an unprivileged process, but uid is equal to the
693 * real or saved uid, then the effective uid will be set to the
694 * requested value, but the real and saved uid will not change.
695 *
696 * If the credential is changed as a result of this call, then we
697 * flag the process as having set privilege since the last exec.
698 */
699 int
setuid(proc_t p,struct setuid_args * uap,__unused int32_t * retval)700 setuid(proc_t p, struct setuid_args *uap, __unused int32_t *retval)
701 {
702 __block int error = 0;
703 __block uid_t old_ruid;
704 __block uid_t ruid;
705 uid_t want_uid;
706 bool changed;
707
708 want_uid = uap->uid;
709 AUDIT_ARG(uid, want_uid);
710
711 changed = kauth_cred_proc_update(p, PROC_SETTOKEN_SETUGID,
712 ^bool (kauth_cred_t parent, kauth_cred_t model) {
713 posix_cred_t cur_pcred = posix_cred_get(parent);
714 uid_t svuid = KAUTH_UID_NONE;
715 uid_t gmuid = KAUTH_UID_NONE;
716
717 ruid = KAUTH_UID_NONE;
718 old_ruid = cur_pcred->cr_ruid;
719
720 #if CONFIG_MACF
721 if ((error = mac_proc_check_setuid(p, parent, want_uid)) != 0) {
722 return false;
723 }
724 #endif
725
726 if (want_uid != cur_pcred->cr_ruid && /* allow setuid(getuid()) */
727 want_uid != cur_pcred->cr_svuid && /* allow setuid(saved uid) */
728 (error = suser(parent, &p->p_acflag))) {
729 return false;
730 }
731
732 /*
733 * If we are privileged, then set the saved and real UID too;
734 * otherwise, just set the effective UID
735 */
736 if (suser(parent, &p->p_acflag) == 0) {
737 svuid = want_uid;
738 ruid = want_uid;
739 }
740
741 /*
742 * Only set the gmuid if the current cred has not opt'ed out;
743 * this normally only happens when calling setgroups() instead
744 * of initgroups() to set an explicit group list, or one of the
745 * other group manipulation functions is invoked and results in
746 * a dislocation (i.e. the credential group membership changes
747 * to something other than the default list for the user, as
748 * in entering a group or leaving an exclusion group).
749 */
750 if (!(cur_pcred->cr_flags & CRF_NOMEMBERD)) {
751 gmuid = want_uid;
752 }
753
754 return kauth_cred_model_setresuid(model,
755 ruid, want_uid, svuid, gmuid);
756 });
757
758 if (changed && ruid != KAUTH_UID_NONE && old_ruid != ruid &&
759 !proc_has_persona(p)) {
760 (void)chgproccnt(ruid, 1);
761 (void)chgproccnt(old_ruid, -1);
762 }
763
764 return error;
765 }
766
767
768 /*
769 * seteuid
770 *
771 * Description: Set effective user ID system call
772 *
773 * Parameters: uap->euid effective uid to set
774 *
775 * Returns: 0 Success
776 * suser:EPERM Permission denied
777 *
778 * Notes: If called by a privileged process, or called from an
779 * unprivileged process but euid is equal to the real or saved
780 * uid, then the effective uid will be set to the requested
781 * value, but the real and saved uid will not change.
782 *
783 * If the credential is changed as a result of this call, then we
784 * flag the process as having set privilege since the last exec.
785 */
786 int
seteuid(proc_t p,struct seteuid_args * uap,__unused int32_t * retval)787 seteuid(proc_t p, struct seteuid_args *uap, __unused int32_t *retval)
788 {
789 __block int error = 0;
790 uid_t want_euid;
791
792 want_euid = uap->euid;
793 AUDIT_ARG(euid, want_euid);
794
795 kauth_cred_proc_update(p, PROC_SETTOKEN_SETUGID,
796 ^bool (kauth_cred_t parent, kauth_cred_t model) {
797 posix_cred_t cur_pcred = posix_cred_get(parent);
798
799 #if CONFIG_MACF
800 if ((error = mac_proc_check_seteuid(p, parent, want_euid)) != 0) {
801 return false;
802 }
803 #endif
804
805 if (want_euid != cur_pcred->cr_ruid && want_euid != cur_pcred->cr_svuid &&
806 (error = suser(parent, &p->p_acflag))) {
807 return false;
808 }
809
810 return kauth_cred_model_setresuid(model,
811 KAUTH_UID_NONE, want_euid,
812 KAUTH_UID_NONE, cur_pcred->cr_gmuid);
813 });
814
815 return error;
816 }
817
818
819 /*
820 * setreuid
821 *
822 * Description: Set real and effective user ID system call
823 *
824 * Parameters: uap->ruid real uid to set
825 * uap->euid effective uid to set
826 *
827 * Returns: 0 Success
828 * suser:EPERM Permission denied
829 *
830 * Notes: A value of -1 is a special case indicating that the uid for
831 * which that value is specified not be changed. If both values
832 * are specified as -1, no action is taken.
833 *
834 * If called by a privileged process, the real and effective uid
835 * will be set to the new value(s) specified.
836 *
837 * If called from an unprivileged process, the real uid may be
838 * set to the current value of the real uid, or to the current
839 * value of the saved uid. The effective uid may be set to the
840 * current value of any of the effective, real, or saved uid.
841 *
842 * If the newly requested real uid or effective uid does not
843 * match the saved uid, then set the saved uid to the new
844 * effective uid (potentially unrecoverably dropping saved
845 * privilege).
846 *
847 * If the credential is changed as a result of this call, then we
848 * flag the process as having set privilege since the last exec.
849 */
850 int
setreuid(proc_t p,struct setreuid_args * uap,__unused int32_t * retval)851 setreuid(proc_t p, struct setreuid_args *uap, __unused int32_t *retval)
852 {
853 __block int error = 0;
854 __block uid_t old_ruid;
855 uid_t want_ruid, want_euid;
856 bool changed;
857
858 want_ruid = uap->ruid;
859 want_euid = uap->euid;
860
861 if (want_ruid == (uid_t)-1) {
862 want_ruid = KAUTH_UID_NONE;
863 }
864
865 if (want_euid == (uid_t)-1) {
866 want_euid = KAUTH_UID_NONE;
867 }
868
869 AUDIT_ARG(euid, want_euid);
870 AUDIT_ARG(ruid, want_ruid);
871
872 changed = kauth_cred_proc_update(p, PROC_SETTOKEN_SETUGID,
873 ^bool (kauth_cred_t parent, kauth_cred_t model) {
874 posix_cred_t cur_pcred = posix_cred_get(parent);
875 uid_t svuid = KAUTH_UID_NONE;
876
877 #if CONFIG_MACF
878 if ((error = mac_proc_check_setreuid(p, parent, want_ruid, want_euid)) != 0) {
879 return false;
880 }
881 #endif
882
883 if (((want_ruid != KAUTH_UID_NONE && /* allow no change of ruid */
884 want_ruid != cur_pcred->cr_ruid && /* allow ruid = ruid */
885 want_ruid != cur_pcred->cr_uid && /* allow ruid = euid */
886 want_ruid != cur_pcred->cr_svuid) || /* allow ruid = svuid */
887 (want_euid != KAUTH_UID_NONE && /* allow no change of euid */
888 want_euid != cur_pcred->cr_uid && /* allow euid = euid */
889 want_euid != cur_pcred->cr_ruid && /* allow euid = ruid */
890 want_euid != cur_pcred->cr_svuid)) && /* allow euid = svuid */
891 (error = suser(parent, &p->p_acflag))) { /* allow root user any */
892 return false;
893 }
894
895 uid_t new_euid = cur_pcred->cr_uid;
896
897 if (want_euid != KAUTH_UID_NONE && cur_pcred->cr_uid != want_euid) {
898 new_euid = want_euid;
899 }
900
901 old_ruid = cur_pcred->cr_ruid;
902
903 /*
904 * If the newly requested real uid or effective uid does
905 * not match the saved uid, then set the saved uid to the
906 * new effective uid. We are protected from escalation
907 * by the prechecking.
908 */
909 if (cur_pcred->cr_svuid != uap->ruid &&
910 cur_pcred->cr_svuid != uap->euid) {
911 svuid = new_euid;
912 }
913
914 return kauth_cred_model_setresuid(model, want_ruid, want_euid,
915 svuid, cur_pcred->cr_gmuid);
916 });
917
918 if (changed && want_ruid != KAUTH_UID_NONE && want_ruid != old_ruid &&
919 !proc_has_persona(p)) {
920 (void)chgproccnt(want_ruid, 1);
921 (void)chgproccnt(old_ruid, -1);
922 }
923
924 return error;
925 }
926
927
928 /*
929 * setgid
930 *
931 * Description: Set group ID system call
932 *
933 * Parameters: uap->gid gid to set
934 *
935 * Returns: 0 Success
936 * suser:EPERM Permission denied
937 *
938 * Notes: If called by a privileged process, this function will set the
939 * real, effective, and saved gid to the requested value.
940 *
941 * If called from an unprivileged process, but gid is equal to the
942 * real or saved gid, then the effective gid will be set to the
943 * requested value, but the real and saved gid will not change.
944 *
945 * If the credential is changed as a result of this call, then we
946 * flag the process as having set privilege since the last exec.
947 *
948 * As an implementation detail, the effective gid is stored as
949 * the first element of the supplementary group list, and
950 * therefore the effective group list may be reordered to keep
951 * the supplementary group list unchanged.
952 */
953 int
setgid(proc_t p,struct setgid_args * uap,__unused int32_t * retval)954 setgid(proc_t p, struct setgid_args *uap, __unused int32_t *retval)
955 {
956 __block int error = 0;
957 gid_t want_gid;
958
959 want_gid = uap->gid;
960 AUDIT_ARG(gid, want_gid);
961
962 kauth_cred_proc_update(p, PROC_SETTOKEN_SETUGID,
963 ^bool (kauth_cred_t parent, kauth_cred_t model) {
964 posix_cred_t cur_pcred = posix_cred_get(parent);
965 gid_t rgid = KAUTH_GID_NONE;
966 gid_t svgid = KAUTH_GID_NONE;
967
968 #if CONFIG_MACF
969 if ((error = mac_proc_check_setgid(p, parent, want_gid)) != 0) {
970 return false;
971 }
972 #endif
973
974 if (want_gid != cur_pcred->cr_rgid && /* allow setgid(getgid()) */
975 want_gid != cur_pcred->cr_svgid && /* allow setgid(saved gid) */
976 (error = suser(parent, &p->p_acflag))) {
977 return false;
978 }
979
980 /*
981 * If we are privileged, then set the saved and real GID too;
982 * otherwise, just set the effective GID
983 */
984 if (suser(parent, &p->p_acflag) == 0) {
985 svgid = want_gid;
986 rgid = want_gid;
987 }
988
989 return kauth_cred_model_setresgid(model, rgid, want_gid, svgid);
990 });
991
992 return error;
993 }
994
995
996 /*
997 * setegid
998 *
999 * Description: Set effective group ID system call
1000 *
1001 * Parameters: uap->egid effective gid to set
1002 *
1003 * Returns: 0 Success
1004 * suser:EPERM
1005 *
1006 * Notes: If called by a privileged process, or called from an
1007 * unprivileged process but egid is equal to the real or saved
1008 * gid, then the effective gid will be set to the requested
1009 * value, but the real and saved gid will not change.
1010 *
1011 * If the credential is changed as a result of this call, then we
1012 * flag the process as having set privilege since the last exec.
1013 *
1014 * As an implementation detail, the effective gid is stored as
1015 * the first element of the supplementary group list, and
1016 * therefore the effective group list may be reordered to keep
1017 * the supplementary group list unchanged.
1018 */
1019 int
setegid(proc_t p,struct setegid_args * uap,__unused int32_t * retval)1020 setegid(proc_t p, struct setegid_args *uap, __unused int32_t *retval)
1021 {
1022 __block int error = 0;
1023 gid_t want_egid;
1024
1025 want_egid = uap->egid;
1026 AUDIT_ARG(egid, want_egid);
1027
1028 kauth_cred_proc_update(p, PROC_SETTOKEN_SETUGID,
1029 ^bool (kauth_cred_t parent, kauth_cred_t model) {
1030 posix_cred_t cur_pcred = posix_cred_get(parent);
1031
1032 #if CONFIG_MACF
1033 if ((error = mac_proc_check_setegid(p, parent, want_egid)) != 0) {
1034 return false;
1035 }
1036 #endif
1037
1038 if (want_egid != cur_pcred->cr_rgid &&
1039 want_egid != cur_pcred->cr_svgid &&
1040 (error = suser(parent, &p->p_acflag))) {
1041 return false;
1042 }
1043
1044 return kauth_cred_model_setresgid(model, KAUTH_GID_NONE,
1045 want_egid, KAUTH_GID_NONE);
1046 });
1047
1048 return error;
1049 }
1050
1051 /*
1052 * setregid
1053 *
1054 * Description: Set real and effective group ID system call
1055 *
1056 * Parameters: uap->rgid real gid to set
1057 * uap->egid effective gid to set
1058 *
1059 * Returns: 0 Success
1060 * suser:EPERM Permission denied
1061 *
1062 * Notes: A value of -1 is a special case indicating that the gid for
1063 * which that value is specified not be changed. If both values
1064 * are specified as -1, no action is taken.
1065 *
1066 * If called by a privileged process, the real and effective gid
1067 * will be set to the new value(s) specified.
1068 *
1069 * If called from an unprivileged process, the real gid may be
1070 * set to the current value of the real gid, or to the current
1071 * value of the saved gid. The effective gid may be set to the
1072 * current value of any of the effective, real, or saved gid.
1073 *
1074 * If the new real and effective gid will not be equal, or the
1075 * new real or effective gid is not the same as the saved gid,
1076 * then the saved gid will be updated to reflect the new
1077 * effective gid (potentially unrecoverably dropping saved
1078 * privilege).
1079 *
1080 * If the credential is changed as a result of this call, then we
1081 * flag the process as having set privilege since the last exec.
1082 *
1083 * As an implementation detail, the effective gid is stored as
1084 * the first element of the supplementary group list, and
1085 * therefore the effective group list may be reordered to keep
1086 * the supplementary group list unchanged.
1087 */
1088 int
setregid(proc_t p,struct setregid_args * uap,__unused int32_t * retval)1089 setregid(proc_t p, struct setregid_args *uap, __unused int32_t *retval)
1090 {
1091 __block int error = 0;
1092 gid_t want_rgid;
1093 gid_t want_egid;
1094
1095 want_rgid = uap->rgid;
1096 want_egid = uap->egid;
1097
1098 if (want_rgid == (gid_t)-1) {
1099 want_rgid = KAUTH_GID_NONE;
1100 }
1101
1102 if (want_egid == (gid_t)-1) {
1103 want_egid = KAUTH_GID_NONE;
1104 }
1105
1106 AUDIT_ARG(egid, want_egid);
1107 AUDIT_ARG(rgid, want_rgid);
1108
1109 kauth_cred_proc_update(p, PROC_SETTOKEN_SETUGID,
1110 ^bool (kauth_cred_t parent, kauth_cred_t model) {
1111 posix_cred_t cur_pcred = posix_cred_get(parent);
1112 uid_t svgid = KAUTH_UID_NONE;
1113
1114 #if CONFIG_MACF
1115 if ((error = mac_proc_check_setregid(p, parent, want_rgid,
1116 want_egid)) != 0) {
1117 return false;
1118 }
1119 #endif
1120
1121 if (((want_rgid != KAUTH_UID_NONE && /* allow no change of rgid */
1122 want_rgid != cur_pcred->cr_rgid && /* allow rgid = rgid */
1123 want_rgid != cur_pcred->cr_gid && /* allow rgid = egid */
1124 want_rgid != cur_pcred->cr_svgid) || /* allow rgid = svgid */
1125 (want_egid != KAUTH_UID_NONE && /* allow no change of egid */
1126 want_egid != cur_pcred->cr_groups[0] && /* allow no change of egid */
1127 want_egid != cur_pcred->cr_gid && /* allow egid = egid */
1128 want_egid != cur_pcred->cr_rgid && /* allow egid = rgid */
1129 want_egid != cur_pcred->cr_svgid)) && /* allow egid = svgid */
1130 (error = suser(parent, &p->p_acflag))) { /* allow root user any */
1131 return false;
1132 }
1133
1134 uid_t new_egid = cur_pcred->cr_gid;
1135 if (want_egid != KAUTH_UID_NONE && cur_pcred->cr_gid != want_egid) {
1136 /* changing the effective GID */
1137 new_egid = want_egid;
1138 }
1139
1140 /*
1141 * If the newly requested real gid or effective gid does
1142 * not match the saved gid, then set the saved gid to the
1143 * new effective gid. We are protected from escalation
1144 * by the prechecking.
1145 */
1146 if (cur_pcred->cr_svgid != want_rgid &&
1147 cur_pcred->cr_svgid != want_egid) {
1148 svgid = new_egid;
1149 }
1150
1151 return kauth_cred_model_setresgid(model, want_rgid, want_egid, svgid);
1152 });
1153
1154 return error;
1155 }
1156
1157
1158 /*
1159 * Set the per-thread override identity. The first parameter can be the
1160 * current real UID, KAUTH_UID_NONE, or, if the caller is privileged, it
1161 * can be any UID. If it is KAUTH_UID_NONE, then as a special case, this
1162 * means "revert to the per process credential"; otherwise, if permitted,
1163 * it changes the effective, real, and saved UIDs and GIDs for the current
1164 * thread to the requested UID and single GID, and clears all other GIDs.
1165 */
1166 static int
kern_settid(proc_t p,uid_t uid,gid_t gid)1167 kern_settid(proc_t p, uid_t uid, gid_t gid)
1168 {
1169 kauth_cred_t cred;
1170 struct thread_ro *tro = current_thread_ro();
1171 #if CONFIG_MACF
1172 int error;
1173
1174 if ((error = mac_proc_check_settid(p, uid, gid)) != 0) {
1175 return error;
1176 }
1177 #endif
1178
1179 if (proc_suser(p) != 0) {
1180 return EPERM;
1181 }
1182
1183 if (uid == KAUTH_UID_NONE) {
1184 /* must already be assuming another identity in order to revert back */
1185 if ((tro->tro_flags & TRO_SETUID) == 0) {
1186 return EPERM;
1187 }
1188
1189 /* revert to delayed binding of process credential */
1190 cred = kauth_cred_proc_ref(p);
1191 thread_ro_update_cred(tro, cred);
1192 thread_ro_update_flags(tro, TRO_NONE, TRO_SETUID);
1193 kauth_cred_unref(&cred);
1194 } else {
1195 /* cannot already be assuming another identity */
1196 if ((tro->tro_flags & TRO_SETUID) != 0) {
1197 return EPERM;
1198 }
1199
1200 /*
1201 * Get a new credential instance from the old if this one
1202 * changes; otherwise kauth_cred_setuidgid() returns the
1203 * same credential. We take an extra reference on the
1204 * current credential while we muck with it, so we can do
1205 * the post-compare for changes by pointer.
1206 */
1207 cred = kauth_cred_derive(tro->tro_cred,
1208 ^bool (kauth_cred_t parent __unused, kauth_cred_t model) {
1209 return kauth_cred_model_setuidgid(model, uid, gid);
1210 });
1211 thread_ro_update_cred(tro, cred);
1212 thread_ro_update_flags(tro, TRO_SETUID, TRO_NONE);
1213 kauth_cred_unref(&cred);
1214 }
1215
1216 /*
1217 * XXX should potentially set per thread security token (there is
1218 * XXX none).
1219 * XXX it is unclear whether P_SUGID should be st at this point;
1220 * XXX in theory, it is being deprecated.
1221 */
1222 return 0;
1223 }
1224
1225 int
sys_settid(proc_t p,struct settid_args * uap,__unused int32_t * retval)1226 sys_settid(proc_t p, struct settid_args *uap, __unused int32_t *retval)
1227 {
1228 AUDIT_ARG(uid, uap->uid);
1229 AUDIT_ARG(gid, uap->gid);
1230
1231 return kern_settid(p, uap->uid, uap->gid);
1232 }
1233
1234
1235 /*
1236 * Set the per-thread override identity. Use this system call for a thread to
1237 * assume the identity of another process or to revert back to normal identity
1238 * of the current process.
1239 *
1240 * When the "assume" argument is non zero the current thread will assume the
1241 * identity of the process represented by the pid argument.
1242 *
1243 * When the assume argument is zero we revert back to our normal identity.
1244 */
1245 int
sys_settid_with_pid(proc_t p,struct settid_with_pid_args * uap,__unused int32_t * retval)1246 sys_settid_with_pid(proc_t p, struct settid_with_pid_args *uap, __unused int32_t *retval)
1247 {
1248 uid_t uid;
1249 gid_t gid;
1250
1251 AUDIT_ARG(pid, uap->pid);
1252 AUDIT_ARG(value32, uap->assume);
1253
1254 /*
1255 * XXX should potentially set per thread security token (there is
1256 * XXX none).
1257 * XXX it is unclear whether P_SUGID should be st at this point;
1258 * XXX in theory, it is being deprecated.
1259 */
1260
1261 /*
1262 * assume argument tells us to assume the identity of the process with the
1263 * id passed in the pid argument.
1264 */
1265 if (uap->assume != 0) {
1266 proc_t target_proc;
1267 kauth_cred_t target_cred;
1268
1269 if (uap->pid == 0) {
1270 return ESRCH;
1271 }
1272
1273 target_proc = proc_find(uap->pid);
1274 if (target_proc == NULL) {
1275 return ESRCH;
1276 }
1277
1278 proc_ucred_lock(target_proc);
1279 target_cred = proc_ucred_locked(target_proc);
1280 uid = posix_cred_get(target_cred)->cr_uid;
1281 gid = posix_cred_get(target_cred)->cr_gid;
1282 proc_ucred_unlock(target_proc);
1283
1284 proc_rele(target_proc);
1285 } else {
1286 /*
1287 * Otherwise, we are reverting back to normal mode of operation
1288 * where delayed binding of the process credential sets the
1289 * credential in the thread_ro (tro_cred)
1290 */
1291 uid = KAUTH_UID_NONE;
1292 gid = KAUTH_GID_NONE;
1293 }
1294
1295 return kern_settid(p, uid, gid);
1296 }
1297
1298
1299 /*
1300 * setgroups1
1301 *
1302 * Description: Internal implementation for both the setgroups and initgroups
1303 * system calls
1304 *
1305 * Parameters: gidsetsize Number of groups in set
1306 * gidset Pointer to group list
1307 * gmuid Base gid (initgroups only!)
1308 *
1309 * Returns: 0 Success
1310 * suser:EPERM Permision denied
1311 * EINVAL Invalid gidsetsize value
1312 * copyin:EFAULT Bad gidset or gidsetsize is
1313 * too large
1314 *
1315 * Notes: When called from a thread running under an assumed per-thread
1316 * identity, this function will operate against the per-thread
1317 * credential, rather than against the process credential. In
1318 * this specific case, the process credential is verified to
1319 * still be privileged at the time of the call, rather than the
1320 * per-thread credential for this operation to be permitted.
1321 *
1322 * This effectively means that setgroups/initigroups calls in
1323 * a thread running a per-thread credential should occur *after*
1324 * the settid call that created it, not before (unlike setuid,
1325 * which must be called after, since it will result in privilege
1326 * being dropped).
1327 *
1328 * When called normally (i.e. no per-thread assumed identity),
1329 * the per process credential is updated per POSIX.
1330 *
1331 * If the credential is changed as a result of this call, then we
1332 * flag the process as having set privilege since the last exec.
1333 */
1334 static int
setgroups1(proc_t p,u_int ngrp,user_addr_t gidset,uid_t gmuid,__unused int32_t * retval)1335 setgroups1(proc_t p, u_int ngrp, user_addr_t gidset, uid_t gmuid, __unused int32_t *retval)
1336 {
1337 gid_t newgroups[NGROUPS] = { 0 };
1338 int error;
1339
1340 if (ngrp > NGROUPS) {
1341 return EINVAL;
1342 }
1343
1344 if (ngrp >= 1) {
1345 error = copyin(gidset,
1346 (caddr_t)newgroups, ngrp * sizeof(gid_t));
1347 if (error) {
1348 return error;
1349 }
1350 }
1351 return setgroups_internal(p, ngrp, newgroups, gmuid);
1352 }
1353
1354 int
setgroups_internal(proc_t p,u_int ngrp,gid_t * newgroups,uid_t gmuid)1355 setgroups_internal(proc_t p, u_int ngrp, gid_t *newgroups, uid_t gmuid)
1356 {
1357 thread_ro_t tro = current_thread_ro();
1358 kauth_cred_t cred;
1359 int error;
1360
1361 cred = kauth_cred_proc_ref(p);
1362 error = suser(cred, &p->p_acflag);
1363 kauth_cred_unref(&cred);
1364
1365 if (error) {
1366 return error;
1367 }
1368
1369 if (ngrp < 1) {
1370 ngrp = 1;
1371 newgroups[0] = 0;
1372 }
1373
1374 kauth_cred_derive_t fn = ^bool (kauth_cred_t parent __unused, kauth_cred_t model) {
1375 return kauth_cred_model_setgroups(model, newgroups, ngrp, gmuid);
1376 };
1377
1378 if ((tro->tro_flags & TRO_SETUID) != 0) {
1379 /*
1380 * If this thread is under an assumed identity, set the
1381 * supplementary grouplist on the thread credential instead
1382 * of the process one. If we were the only reference holder,
1383 * the credential is updated in place, otherwise, our reference
1384 * is dropped and we get back a different cred with a reference
1385 * already held on it. Because this is per-thread, we don't
1386 * need the referencing/locking/retry required for per-process.
1387 */
1388 cred = kauth_cred_derive(tro->tro_cred, fn);
1389 thread_ro_update_cred(tro, cred);
1390 kauth_cred_unref(&cred);
1391 } else {
1392 kauth_cred_proc_update(p, PROC_SETTOKEN_SETUGID, fn);
1393 AUDIT_ARG(groupset, &newgroups[0], ngrp);
1394 }
1395
1396 return 0;
1397 }
1398
1399
1400 /*
1401 * initgroups
1402 *
1403 * Description: Initialize the default supplementary groups list and set the
1404 * gmuid for use by the external group resolver (if any)
1405 *
1406 * Parameters: uap->gidsetsize Number of groups in set
1407 * uap->gidset Pointer to group list
1408 * uap->gmuid Base gid
1409 *
1410 * Returns: 0 Success
1411 * setgroups1:EPERM Permision denied
1412 * setgroups1:EINVAL Invalid gidsetsize value
1413 * setgroups1:EFAULT Bad gidset or gidsetsize is
1414 *
1415 * Notes: This function opts *IN* to memberd participation
1416 *
1417 * The normal purpose of this function is for a privileged
1418 * process to indicate supplementary groups and identity for
1419 * participation in extended group membership resolution prior
1420 * to dropping privilege by assuming a specific user identity.
1421 *
1422 * It is the first half of the primary mechanism whereby user
1423 * identity is established to the system by programs such as
1424 * /usr/bin/login. The second half is the drop of uid privilege
1425 * for a specific uid corresponding to the user.
1426 *
1427 * See also: setgroups1()
1428 */
1429 int
initgroups(proc_t p,struct initgroups_args * uap,__unused int32_t * retval)1430 initgroups(proc_t p, struct initgroups_args *uap, __unused int32_t *retval)
1431 {
1432 return setgroups1(p, uap->gidsetsize, uap->gidset, uap->gmuid, retval);
1433 }
1434
1435
1436 /*
1437 * setgroups
1438 *
1439 * Description: Initialize the default supplementary groups list
1440 *
1441 * Parameters: gidsetsize Number of groups in set
1442 * gidset Pointer to group list
1443 *
1444 * Returns: 0 Success
1445 * setgroups1:EPERM Permision denied
1446 * setgroups1:EINVAL Invalid gidsetsize value
1447 * setgroups1:EFAULT Bad gidset or gidsetsize is
1448 *
1449 * Notes: This functions opts *OUT* of memberd participation.
1450 *
1451 * This function exists for compatibility with POSIX. Most user
1452 * programs should use initgroups() instead to ensure correct
1453 * participation in group membership resolution when utilizing
1454 * a directory service for authentication.
1455 *
1456 * It is identical to an initgroups() call with a gmuid argument
1457 * of KAUTH_UID_NONE.
1458 *
1459 * See also: setgroups1()
1460 */
1461 int
setgroups(proc_t p,struct setgroups_args * uap,__unused int32_t * retval)1462 setgroups(proc_t p, struct setgroups_args *uap, __unused int32_t *retval)
1463 {
1464 return setgroups1(p, uap->gidsetsize, uap->gidset, KAUTH_UID_NONE, retval);
1465 }
1466
1467
1468 /*
1469 * Set the per-thread/per-process supplementary groups list.
1470 *
1471 * XXX implement setsgroups
1472 *
1473 */
1474
1475 int
setsgroups(__unused proc_t p,__unused struct setsgroups_args * uap,__unused int32_t * retval)1476 setsgroups(__unused proc_t p, __unused struct setsgroups_args *uap, __unused int32_t *retval)
1477 {
1478 return ENOTSUP;
1479 }
1480
1481 /*
1482 * Set the per-thread/per-process whiteout groups list.
1483 *
1484 * XXX implement setwgroups
1485 *
1486 */
1487
1488 int
setwgroups(__unused proc_t p,__unused struct setwgroups_args * uap,__unused int32_t * retval)1489 setwgroups(__unused proc_t p, __unused struct setwgroups_args *uap, __unused int32_t *retval)
1490 {
1491 return ENOTSUP;
1492 }
1493
1494
1495 /*
1496 * Check if gid is a member of the group set.
1497 *
1498 * XXX This interface is going away; use kauth_cred_ismember_gid() directly
1499 * XXX instead.
1500 */
1501 int
groupmember(gid_t gid,kauth_cred_t cred)1502 groupmember(gid_t gid, kauth_cred_t cred)
1503 {
1504 int is_member;
1505
1506 if (kauth_cred_ismember_gid(cred, gid, &is_member) == 0 && is_member) {
1507 return 1;
1508 }
1509 return 0;
1510 }
1511
1512
1513 /*
1514 * Test whether the specified credentials imply "super-user"
1515 * privilege; if so, and we have accounting info, set the flag
1516 * indicating use of super-powers.
1517 * Returns 0 or error.
1518 *
1519 * XXX This interface is going away; use kauth_cred_issuser() directly
1520 * XXX instead.
1521 *
1522 * Note: This interface exists to implement the "has used privilege"
1523 * bit (ASU) in the p_acflags field of the process, which is
1524 * only externalized via private sysctl and in process accounting
1525 * records. The flag is technically not required in either case.
1526 */
1527 int
suser(kauth_cred_t cred,u_short * acflag)1528 suser(kauth_cred_t cred, u_short *acflag)
1529 {
1530 if (kauth_cred_getuid(cred) == 0) {
1531 if (acflag) {
1532 *acflag |= ASU;
1533 }
1534 return 0;
1535 }
1536 return EPERM;
1537 }
1538
1539
1540 /*
1541 * getlogin
1542 *
1543 * Description: Get login name, if available.
1544 *
1545 * Parameters: uap->namebuf User buffer for return
1546 * uap->namelen User buffer length
1547 *
1548 * Returns: 0 Success
1549 * copyout:EFAULT
1550 *
1551 * Notes: Intended to obtain a string containing the user name of the
1552 * user associated with the controlling terminal for the calling
1553 * process.
1554 *
1555 * Not very useful on modern systems, due to inherent length
1556 * limitations for the static array in the session structure
1557 * which is used to store the login name.
1558 *
1559 * Permitted to return NULL
1560 *
1561 * XXX: Belongs in kern_proc.c
1562 */
1563 int
getlogin(proc_t p,struct getlogin_args * uap,__unused int32_t * retval)1564 getlogin(proc_t p, struct getlogin_args *uap, __unused int32_t *retval)
1565 {
1566 char buffer[MAXLOGNAME];
1567 struct session *sessp;
1568 struct pgrp *pg;
1569
1570 if (uap->namelen > MAXLOGNAME) {
1571 uap->namelen = MAXLOGNAME;
1572 }
1573
1574 if ((pg = proc_pgrp(p, &sessp)) != PGRP_NULL) {
1575 session_lock(sessp);
1576 bcopy(sessp->s_login, buffer, uap->namelen);
1577 session_unlock(sessp);
1578 pgrp_rele(pg);
1579 } else {
1580 bzero(buffer, uap->namelen);
1581 }
1582
1583 return copyout((caddr_t)buffer, uap->namebuf, uap->namelen);
1584 }
1585
1586 void
setlogin_internal(proc_t p,const char login[static MAXLOGNAME])1587 setlogin_internal(proc_t p, const char login[static MAXLOGNAME])
1588 {
1589 struct session *sessp;
1590 struct pgrp *pg;
1591
1592 if ((pg = proc_pgrp(p, &sessp)) != PGRP_NULL) {
1593 session_lock(sessp);
1594 bcopy(login, sessp->s_login, MAXLOGNAME);
1595 session_unlock(sessp);
1596 pgrp_rele(pg);
1597 }
1598 }
1599
1600 /*
1601 * setlogin
1602 *
1603 * Description: Set login name.
1604 *
1605 * Parameters: uap->namebuf User buffer containing name
1606 *
1607 * Returns: 0 Success
1608 * suser:EPERM Permission denied
1609 * copyinstr:EFAULT User buffer invalid
1610 * copyinstr:EINVAL Supplied name was too long
1611 *
1612 * Notes: This is a utility system call to support getlogin().
1613 *
1614 * XXX: Belongs in kern_proc.c
1615 */
1616 int
setlogin(proc_t p,struct setlogin_args * uap,__unused int32_t * retval)1617 setlogin(proc_t p, struct setlogin_args *uap, __unused int32_t *retval)
1618 {
1619 int error;
1620 size_t dummy = 0;
1621 char buffer[MAXLOGNAME + 1];
1622
1623 if ((error = proc_suser(p))) {
1624 return error;
1625 }
1626
1627 bzero(&buffer[0], MAXLOGNAME + 1);
1628
1629
1630 error = copyinstr(uap->namebuf,
1631 (caddr_t) &buffer[0],
1632 MAXLOGNAME - 1, (size_t *)&dummy);
1633
1634 setlogin_internal(p, buffer);
1635
1636 if (!error) {
1637 AUDIT_ARG(text, buffer);
1638 } else if (error == ENAMETOOLONG) {
1639 error = EINVAL;
1640 }
1641 return error;
1642 }
1643
1644
1645 static void
proc_calc_audit_token(proc_t p,kauth_cred_t my_cred,audit_token_t * audit_token)1646 proc_calc_audit_token(proc_t p, kauth_cred_t my_cred, audit_token_t *audit_token)
1647 {
1648 posix_cred_t my_pcred = posix_cred_get(my_cred);
1649
1650 /*
1651 * The current layout of the Mach audit token explicitly
1652 * adds these fields. But nobody should rely on such
1653 * a literal representation. Instead, the BSM library
1654 * provides a function to convert an audit token into
1655 * a BSM subject. Use of that mechanism will isolate
1656 * the user of the trailer from future representation
1657 * changes.
1658 */
1659 audit_token->val[0] = my_cred->cr_audit.as_aia_p->ai_auid;
1660 audit_token->val[1] = my_pcred->cr_uid;
1661 audit_token->val[2] = my_pcred->cr_gid;
1662 audit_token->val[3] = my_pcred->cr_ruid;
1663 audit_token->val[4] = my_pcred->cr_rgid;
1664 audit_token->val[5] = proc_getpid(p);
1665 audit_token->val[6] = my_cred->cr_audit.as_aia_p->ai_asid;
1666 audit_token->val[7] = proc_pidversion(p);
1667 }
1668
1669 /* Set the secrity token of the task with current euid and eguid */
1670 int
set_security_token(proc_t p,struct ucred * my_cred)1671 set_security_token(proc_t p, struct ucred *my_cred)
1672 {
1673 security_token_t sec_token;
1674 audit_token_t audit_token;
1675 host_priv_t host_priv;
1676 task_t task = proc_task(p);
1677
1678 proc_calc_audit_token(p, my_cred, &audit_token);
1679
1680 sec_token.val[0] = kauth_cred_getuid(my_cred);
1681 sec_token.val[1] = kauth_cred_getgid(my_cred);
1682
1683 host_priv = (sec_token.val[0]) ? HOST_PRIV_NULL : host_priv_self();
1684 #if CONFIG_MACF
1685 if (host_priv != HOST_PRIV_NULL && mac_system_check_host_priv(my_cred)) {
1686 host_priv = HOST_PRIV_NULL;
1687 }
1688 #endif
1689
1690 #if DEVELOPMENT || DEBUG
1691 /*
1692 * Update the pid an proc name for importance base if any
1693 */
1694 task_importance_update_owner_info(task);
1695 #endif
1696
1697 return task_set_security_tokens(task, sec_token, audit_token,
1698 host_priv) != KERN_SUCCESS;
1699 }
1700
1701 void
proc_parent_audit_token(proc_t p,audit_token_t * token_out)1702 proc_parent_audit_token(proc_t p, audit_token_t *token_out)
1703 {
1704 proc_t parent;
1705 kauth_cred_t my_cred;
1706
1707 proc_list_lock();
1708
1709 parent = p->p_pptr;
1710 my_cred = kauth_cred_proc_ref(parent);
1711 proc_calc_audit_token(parent, my_cred, token_out);
1712 kauth_cred_unref(&my_cred);
1713
1714 proc_list_unlock();
1715 }
1716
1717
1718 int get_audit_token_pid(audit_token_t *audit_token);
1719
1720 int
get_audit_token_pid(audit_token_t * audit_token)1721 get_audit_token_pid(audit_token_t *audit_token)
1722 {
1723 /* keep in-sync with set_security_token (above) */
1724 if (audit_token) {
1725 return (int)audit_token->val[5];
1726 }
1727 return -1;
1728 }
1729
1730
1731 /*
1732 * Fill in a struct xucred based on a kauth_cred_t.
1733 */
1734 void
cru2x(kauth_cred_t cr,struct xucred * xcr)1735 cru2x(kauth_cred_t cr, struct xucred *xcr)
1736 {
1737 posix_cred_t pcr = posix_cred_get(cr);
1738
1739 bzero(xcr, sizeof(*xcr));
1740 xcr->cr_version = XUCRED_VERSION;
1741 xcr->cr_uid = kauth_cred_getuid(cr);
1742 xcr->cr_ngroups = pcr->cr_ngroups;
1743 bcopy(pcr->cr_groups, xcr->cr_groups, sizeof(xcr->cr_groups));
1744 }
1745
1746 /*
1747 * Copy kauth_cred into a virtual address by assignment.
1748 * Needed because elements of kauth_cred are PACed
1749 * so memcpy doesn't work.
1750 */
1751 void
kauth_cred_copy(const uintptr_t kv,const uintptr_t new_data)1752 kauth_cred_copy(const uintptr_t kv, const uintptr_t new_data)
1753 {
1754 *(kauth_cred_t)kv = *(kauth_cred_t)new_data;
1755 }
1756