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 = proc_update_label(p, true, ^(kauth_cred_t cur_cred) {
712 posix_cred_t cur_pcred = posix_cred_get(cur_cred);
713 uid_t svuid = KAUTH_UID_NONE;
714 uid_t gmuid = KAUTH_UID_NONE;
715
716 ruid = KAUTH_UID_NONE;
717 old_ruid = cur_pcred->cr_ruid;
718
719 #if CONFIG_MACF
720 if ((error = mac_proc_check_setuid(p, cur_cred, want_uid)) != 0) {
721 return cur_cred;
722 }
723 #endif
724
725 if (want_uid != cur_pcred->cr_ruid && /* allow setuid(getuid()) */
726 want_uid != cur_pcred->cr_svuid && /* allow setuid(saved uid) */
727 (error = suser(cur_cred, &p->p_acflag))) {
728 return cur_cred;
729 }
730
731 /*
732 * If we are privileged, then set the saved and real UID too;
733 * otherwise, just set the effective UID
734 */
735 if (suser(cur_cred, &p->p_acflag) == 0) {
736 svuid = want_uid;
737 ruid = want_uid;
738 }
739
740 /*
741 * Only set the gmuid if the current cred has not opt'ed out;
742 * this normally only happens when calling setgroups() instead
743 * of initgroups() to set an explicit group list, or one of the
744 * other group manipulation functions is invoked and results in
745 * a dislocation (i.e. the credential group membership changes
746 * to something other than the default list for the user, as
747 * in entering a group or leaving an exclusion group).
748 */
749 if (!(cur_pcred->cr_flags & CRF_NOMEMBERD)) {
750 gmuid = want_uid;
751 }
752
753 return kauth_cred_setresuid(cur_cred, ruid, want_uid, svuid, gmuid);
754 });
755
756 if (changed && ruid != KAUTH_UID_NONE && old_ruid != ruid &&
757 !proc_has_persona(p)) {
758 (void)chgproccnt(ruid, 1);
759 (void)chgproccnt(old_ruid, -1);
760 }
761
762 return error;
763 }
764
765
766 /*
767 * seteuid
768 *
769 * Description: Set effective user ID system call
770 *
771 * Parameters: uap->euid effective uid to set
772 *
773 * Returns: 0 Success
774 * suser:EPERM Permission denied
775 *
776 * Notes: If called by a privileged process, or called from an
777 * unprivileged process but euid is equal to the real or saved
778 * uid, then the effective uid will be set to the requested
779 * value, but the real and saved uid will not change.
780 *
781 * If the credential is changed as a result of this call, then we
782 * flag the process as having set privilege since the last exec.
783 */
784 int
seteuid(proc_t p,struct seteuid_args * uap,__unused int32_t * retval)785 seteuid(proc_t p, struct seteuid_args *uap, __unused int32_t *retval)
786 {
787 __block int error = 0;
788 uid_t want_euid;
789 bool changed;
790
791 want_euid = uap->euid;
792 AUDIT_ARG(euid, want_euid);
793
794 changed = proc_update_label(p, true, ^(kauth_cred_t cur_cred) {
795 posix_cred_t cur_pcred = posix_cred_get(cur_cred);
796
797 #if CONFIG_MACF
798 if ((error = mac_proc_check_seteuid(p, cur_cred, want_euid)) != 0) {
799 return cur_cred;
800 }
801 #endif
802
803 if (want_euid != cur_pcred->cr_ruid && want_euid != cur_pcred->cr_svuid &&
804 (error = suser(cur_cred, &p->p_acflag))) {
805 return cur_cred;
806 }
807
808 return kauth_cred_setresuid(cur_cred, KAUTH_UID_NONE, want_euid,
809 KAUTH_UID_NONE, cur_pcred->cr_gmuid);
810 });
811
812 return error;
813 }
814
815
816 /*
817 * setreuid
818 *
819 * Description: Set real and effective user ID system call
820 *
821 * Parameters: uap->ruid real uid to set
822 * uap->euid effective uid to set
823 *
824 * Returns: 0 Success
825 * suser:EPERM Permission denied
826 *
827 * Notes: A value of -1 is a special case indicating that the uid for
828 * which that value is specified not be changed. If both values
829 * are specified as -1, no action is taken.
830 *
831 * If called by a privileged process, the real and effective uid
832 * will be set to the new value(s) specified.
833 *
834 * If called from an unprivileged process, the real uid may be
835 * set to the current value of the real uid, or to the current
836 * value of the saved uid. The effective uid may be set to the
837 * current value of any of the effective, real, or saved uid.
838 *
839 * If the newly requested real uid or effective uid does not
840 * match the saved uid, then set the saved uid to the new
841 * effective uid (potentially unrecoverably dropping saved
842 * privilege).
843 *
844 * If the credential is changed as a result of this call, then we
845 * flag the process as having set privilege since the last exec.
846 */
847 int
setreuid(proc_t p,struct setreuid_args * uap,__unused int32_t * retval)848 setreuid(proc_t p, struct setreuid_args *uap, __unused int32_t *retval)
849 {
850 __block int error = 0;
851 __block uid_t old_ruid;
852 uid_t want_ruid, want_euid;
853 bool changed;
854
855 want_ruid = uap->ruid;
856 want_euid = uap->euid;
857
858 if (want_ruid == (uid_t)-1) {
859 want_ruid = KAUTH_UID_NONE;
860 }
861
862 if (want_euid == (uid_t)-1) {
863 want_euid = KAUTH_UID_NONE;
864 }
865
866 AUDIT_ARG(euid, want_euid);
867 AUDIT_ARG(ruid, want_ruid);
868
869 changed = proc_update_label(p, true, ^(kauth_cred_t cur_cred) {
870 posix_cred_t cur_pcred = posix_cred_get(cur_cred);
871 uid_t svuid = KAUTH_UID_NONE;
872
873 #if CONFIG_MACF
874 if ((error = mac_proc_check_setreuid(p, cur_cred, want_ruid, want_euid)) != 0) {
875 return cur_cred;
876 }
877 #endif
878
879 if (((want_ruid != KAUTH_UID_NONE && /* allow no change of ruid */
880 want_ruid != cur_pcred->cr_ruid && /* allow ruid = ruid */
881 want_ruid != cur_pcred->cr_uid && /* allow ruid = euid */
882 want_ruid != cur_pcred->cr_svuid) || /* allow ruid = svuid */
883 (want_euid != KAUTH_UID_NONE && /* allow no change of euid */
884 want_euid != cur_pcred->cr_uid && /* allow euid = euid */
885 want_euid != cur_pcred->cr_ruid && /* allow euid = ruid */
886 want_euid != cur_pcred->cr_svuid)) && /* allow euid = svuid */
887 (error = suser(cur_cred, &p->p_acflag))) { /* allow root user any */
888 return cur_cred;
889 }
890
891 uid_t new_euid = cur_pcred->cr_uid;
892
893 if (want_euid != KAUTH_UID_NONE && cur_pcred->cr_uid != want_euid) {
894 new_euid = want_euid;
895 }
896
897 old_ruid = cur_pcred->cr_ruid;
898
899 /*
900 * If the newly requested real uid or effective uid does
901 * not match the saved uid, then set the saved uid to the
902 * new effective uid. We are protected from escalation
903 * by the prechecking.
904 */
905 if (cur_pcred->cr_svuid != uap->ruid &&
906 cur_pcred->cr_svuid != uap->euid) {
907 svuid = new_euid;
908 }
909
910 return kauth_cred_setresuid(cur_cred, want_ruid, want_euid,
911 svuid, cur_pcred->cr_gmuid);
912 });
913
914 if (changed && want_ruid != KAUTH_UID_NONE && want_ruid != old_ruid &&
915 !proc_has_persona(p)) {
916 (void)chgproccnt(want_ruid, 1);
917 (void)chgproccnt(old_ruid, -1);
918 }
919
920 return error;
921 }
922
923
924 /*
925 * setgid
926 *
927 * Description: Set group ID system call
928 *
929 * Parameters: uap->gid gid to set
930 *
931 * Returns: 0 Success
932 * suser:EPERM Permission denied
933 *
934 * Notes: If called by a privileged process, this function will set the
935 * real, effective, and saved gid to the requested value.
936 *
937 * If called from an unprivileged process, but gid is equal to the
938 * real or saved gid, then the effective gid will be set to the
939 * requested value, but the real and saved gid will not change.
940 *
941 * If the credential is changed as a result of this call, then we
942 * flag the process as having set privilege since the last exec.
943 *
944 * As an implementation detail, the effective gid is stored as
945 * the first element of the supplementary group list, and
946 * therefore the effective group list may be reordered to keep
947 * the supplementary group list unchanged.
948 */
949 int
setgid(proc_t p,struct setgid_args * uap,__unused int32_t * retval)950 setgid(proc_t p, struct setgid_args *uap, __unused int32_t *retval)
951 {
952 __block int error = 0;
953 gid_t want_gid;
954 bool changed;
955
956 want_gid = uap->gid;
957 AUDIT_ARG(gid, want_gid);
958
959 changed = proc_update_label(p, true, ^(kauth_cred_t cur_cred) {
960 posix_cred_t cur_pcred = posix_cred_get(cur_cred);
961 gid_t rgid = KAUTH_GID_NONE;
962 gid_t svgid = KAUTH_GID_NONE;
963
964 #if CONFIG_MACF
965 if ((error = mac_proc_check_setgid(p, cur_cred, want_gid)) != 0) {
966 return cur_cred;
967 }
968 #endif
969
970 if (want_gid != cur_pcred->cr_rgid && /* allow setgid(getgid()) */
971 want_gid != cur_pcred->cr_svgid && /* allow setgid(saved gid) */
972 (error = suser(cur_cred, &p->p_acflag))) {
973 return cur_cred;
974 }
975
976 /*
977 * If we are privileged, then set the saved and real GID too;
978 * otherwise, just set the effective GID
979 */
980 if (suser(cur_cred, &p->p_acflag) == 0) {
981 svgid = want_gid;
982 rgid = want_gid;
983 }
984
985 return kauth_cred_setresgid(cur_cred, rgid, want_gid, svgid);
986 });
987
988 return error;
989 }
990
991
992 /*
993 * setegid
994 *
995 * Description: Set effective group ID system call
996 *
997 * Parameters: uap->egid effective gid to set
998 *
999 * Returns: 0 Success
1000 * suser:EPERM
1001 *
1002 * Notes: If called by a privileged process, or called from an
1003 * unprivileged process but egid is equal to the real or saved
1004 * gid, then the effective gid will be set to the requested
1005 * value, but the real and saved gid will not change.
1006 *
1007 * If the credential is changed as a result of this call, then we
1008 * flag the process as having set privilege since the last exec.
1009 *
1010 * As an implementation detail, the effective gid is stored as
1011 * the first element of the supplementary group list, and
1012 * therefore the effective group list may be reordered to keep
1013 * the supplementary group list unchanged.
1014 */
1015 int
setegid(proc_t p,struct setegid_args * uap,__unused int32_t * retval)1016 setegid(proc_t p, struct setegid_args *uap, __unused int32_t *retval)
1017 {
1018 __block int error = 0;
1019 gid_t want_egid;
1020 bool changed;
1021
1022 want_egid = uap->egid;
1023 AUDIT_ARG(egid, want_egid);
1024
1025 changed = proc_update_label(p, true, ^(kauth_cred_t cur_cred) {
1026 posix_cred_t cur_pcred = posix_cred_get(cur_cred);
1027
1028 #if CONFIG_MACF
1029 if ((error = mac_proc_check_setegid(p, cur_cred, want_egid)) != 0) {
1030 return cur_cred;
1031 }
1032 #endif
1033
1034 if (want_egid != cur_pcred->cr_rgid &&
1035 want_egid != cur_pcred->cr_svgid &&
1036 (error = suser(cur_cred, &p->p_acflag))) {
1037 return cur_cred;
1038 }
1039
1040 return kauth_cred_setresgid(cur_cred, KAUTH_GID_NONE,
1041 want_egid, KAUTH_GID_NONE);
1042 });
1043
1044 return error;
1045 }
1046
1047 /*
1048 * setregid
1049 *
1050 * Description: Set real and effective group ID system call
1051 *
1052 * Parameters: uap->rgid real gid to set
1053 * uap->egid effective gid to set
1054 *
1055 * Returns: 0 Success
1056 * suser:EPERM Permission denied
1057 *
1058 * Notes: A value of -1 is a special case indicating that the gid for
1059 * which that value is specified not be changed. If both values
1060 * are specified as -1, no action is taken.
1061 *
1062 * If called by a privileged process, the real and effective gid
1063 * will be set to the new value(s) specified.
1064 *
1065 * If called from an unprivileged process, the real gid may be
1066 * set to the current value of the real gid, or to the current
1067 * value of the saved gid. The effective gid may be set to the
1068 * current value of any of the effective, real, or saved gid.
1069 *
1070 * If the new real and effective gid will not be equal, or the
1071 * new real or effective gid is not the same as the saved gid,
1072 * then the saved gid will be updated to reflect the new
1073 * effective gid (potentially unrecoverably dropping saved
1074 * privilege).
1075 *
1076 * If the credential is changed as a result of this call, then we
1077 * flag the process as having set privilege since the last exec.
1078 *
1079 * As an implementation detail, the effective gid is stored as
1080 * the first element of the supplementary group list, and
1081 * therefore the effective group list may be reordered to keep
1082 * the supplementary group list unchanged.
1083 */
1084 int
setregid(proc_t p,struct setregid_args * uap,__unused int32_t * retval)1085 setregid(proc_t p, struct setregid_args *uap, __unused int32_t *retval)
1086 {
1087 __block int error = 0;
1088 gid_t want_rgid;
1089 gid_t want_egid;
1090 bool changed;
1091
1092 want_rgid = uap->rgid;
1093 want_egid = uap->egid;
1094
1095 if (want_rgid == (gid_t)-1) {
1096 want_rgid = KAUTH_GID_NONE;
1097 }
1098
1099 if (want_egid == (gid_t)-1) {
1100 want_egid = KAUTH_GID_NONE;
1101 }
1102
1103 AUDIT_ARG(egid, want_egid);
1104 AUDIT_ARG(rgid, want_rgid);
1105
1106 changed = proc_update_label(p, true, ^(kauth_cred_t cur_cred) {
1107 posix_cred_t cur_pcred = posix_cred_get(cur_cred);
1108 uid_t svgid = KAUTH_UID_NONE;
1109
1110 #if CONFIG_MACF
1111 if ((error = mac_proc_check_setregid(p, cur_cred, want_rgid,
1112 want_egid)) != 0) {
1113 return cur_cred;
1114 }
1115 #endif
1116
1117 if (((want_rgid != KAUTH_UID_NONE && /* allow no change of rgid */
1118 want_rgid != cur_pcred->cr_rgid && /* allow rgid = rgid */
1119 want_rgid != cur_pcred->cr_gid && /* allow rgid = egid */
1120 want_rgid != cur_pcred->cr_svgid) || /* allow rgid = svgid */
1121 (want_egid != KAUTH_UID_NONE && /* allow no change of egid */
1122 want_egid != cur_pcred->cr_groups[0] && /* allow no change of egid */
1123 want_egid != cur_pcred->cr_gid && /* allow egid = egid */
1124 want_egid != cur_pcred->cr_rgid && /* allow egid = rgid */
1125 want_egid != cur_pcred->cr_svgid)) && /* allow egid = svgid */
1126 (error = suser(cur_cred, &p->p_acflag))) { /* allow root user any */
1127 return cur_cred;
1128 }
1129
1130 uid_t new_egid = cur_pcred->cr_gid;
1131 if (want_egid != KAUTH_UID_NONE && cur_pcred->cr_gid != want_egid) {
1132 /* changing the effective GID */
1133 new_egid = want_egid;
1134 }
1135
1136 /*
1137 * If the newly requested real gid or effective gid does
1138 * not match the saved gid, then set the saved gid to the
1139 * new effective gid. We are protected from escalation
1140 * by the prechecking.
1141 */
1142 if (cur_pcred->cr_svgid != want_rgid &&
1143 cur_pcred->cr_svgid != want_egid) {
1144 svgid = new_egid;
1145 }
1146
1147 return kauth_cred_setresgid(cur_cred, want_rgid, want_egid, svgid);
1148 });
1149
1150 return error;
1151 }
1152
1153
1154 /*
1155 * Set the per-thread override identity. The first parameter can be the
1156 * current real UID, KAUTH_UID_NONE, or, if the caller is privileged, it
1157 * can be any UID. If it is KAUTH_UID_NONE, then as a special case, this
1158 * means "revert to the per process credential"; otherwise, if permitted,
1159 * it changes the effective, real, and saved UIDs and GIDs for the current
1160 * thread to the requested UID and single GID, and clears all other GIDs.
1161 */
1162 int
settid(proc_t p,struct settid_args * uap,__unused int32_t * retval)1163 settid(proc_t p, struct settid_args *uap, __unused int32_t *retval)
1164 {
1165 kauth_cred_t cred;
1166 struct thread_ro *tro = current_thread_ro();
1167 uid_t uid;
1168 gid_t gid;
1169 #if CONFIG_MACF
1170 int error;
1171 #endif
1172
1173 uid = uap->uid;
1174 gid = uap->gid;
1175 AUDIT_ARG(uid, uid);
1176 AUDIT_ARG(gid, gid);
1177
1178 #if CONFIG_MACF
1179 if ((error = mac_proc_check_settid(p, uid, gid)) != 0) {
1180 return error;
1181 }
1182 #endif
1183
1184 if (proc_suser(p) != 0) {
1185 return EPERM;
1186 }
1187
1188 if (uid == KAUTH_UID_NONE) {
1189 /* must already be assuming another identity in order to revert back */
1190 if ((tro->tro_flags & TRO_SETUID) == 0) {
1191 return EPERM;
1192 }
1193
1194 /* revert to delayed binding of process credential */
1195 cred = kauth_cred_proc_ref(p);
1196 thread_ro_update_cred(tro, cred);
1197 thread_ro_update_flags(tro, TRO_NONE, TRO_SETUID);
1198 kauth_cred_unref(&cred);
1199 } else {
1200 /* cannot already be assuming another identity */
1201 if ((tro->tro_flags & TRO_SETUID) != 0) {
1202 return EPERM;
1203 }
1204
1205 /*
1206 * Get a new credential instance from the old if this one
1207 * changes; otherwise kauth_cred_setuidgid() returns the
1208 * same credential. We take an extra reference on the
1209 * current credential while we muck with it, so we can do
1210 * the post-compare for changes by pointer.
1211 */
1212 cred = tro->tro_cred;
1213 kauth_cred_ref(cred);
1214 cred = kauth_cred_setuidgid(cred, uid, gid);
1215 thread_ro_update_cred(tro, cred);
1216 thread_ro_update_flags(tro, TRO_SETUID, TRO_NONE);
1217 kauth_cred_unref(&cred);
1218 }
1219
1220 /*
1221 * XXX should potentially set per thread security token (there is
1222 * XXX none).
1223 * XXX it is unclear whether P_SUGID should be st at this point;
1224 * XXX in theory, it is being deprecated.
1225 */
1226 return 0;
1227 }
1228
1229
1230 /*
1231 * Set the per-thread override identity. Use this system call for a thread to
1232 * assume the identity of another process or to revert back to normal identity
1233 * of the current process.
1234 *
1235 * When the "assume" argument is non zero the current thread will assume the
1236 * identity of the process represented by the pid argument.
1237 *
1238 * When the assume argument is zero we revert back to our normal identity.
1239 */
1240 int
settid_with_pid(proc_t p,struct settid_with_pid_args * uap,__unused int32_t * retval)1241 settid_with_pid(proc_t p, struct settid_with_pid_args *uap, __unused int32_t *retval)
1242 {
1243 proc_t target_proc;
1244 thread_ro_t tro = current_thread_ro();
1245 kauth_cred_t cred, my_target_cred;
1246 posix_cred_t my_target_pcred;
1247 uid_t uid;
1248 gid_t gid;
1249 int error;
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 target_proc = proc_find(uap->pid);
1267 if (target_proc == NULL || target_proc == kernproc) {
1268 if (target_proc != NULL) {
1269 proc_rele(target_proc);
1270 }
1271 return ESRCH;
1272 }
1273 my_target_cred = kauth_cred_proc_ref(target_proc);
1274 my_target_pcred = posix_cred_get(my_target_cred);
1275 uid = my_target_pcred->cr_uid;
1276 gid = my_target_pcred->cr_gid;
1277 kauth_cred_unref(&my_target_cred);
1278 proc_rele(target_proc);
1279
1280 #if CONFIG_MACF
1281 if ((error = mac_proc_check_settid(p, uid, gid)) != 0) {
1282 return error;
1283 }
1284 #endif
1285
1286 /* can't do this if we have already assumed an identity */
1287 if (proc_suser(p) != 0 || (tro->tro_flags & TRO_SETUID) != 0) {
1288 return EPERM;
1289 }
1290
1291 /*
1292 * Take a reference on the credential used in our target
1293 * process then use it as the identity for our current
1294 * thread. We take an extra reference on the current
1295 * credential while we muck with it, so we can do the
1296 * post-compare for changes by pointer.
1297 *
1298 * The post-compare is needed for the case that our process
1299 * credential has been changed to be identical to our thread
1300 * credential following our assumption of a per-thread one,
1301 * since the credential cache will maintain a unique instance.
1302 */
1303 cred = tro->tro_cred;
1304 kauth_cred_ref(cred);
1305 cred = kauth_cred_setuidgid(cred, uid, gid);
1306 thread_ro_update_cred(tro, cred);
1307 thread_ro_update_flags(tro, TRO_SETUID, TRO_NONE);
1308 kauth_cred_unref(&cred);
1309
1310 return 0;
1311 }
1312
1313 /*
1314 * Otherwise, we are reverting back to normal mode of operation where
1315 * delayed binding of the process credential sets the credential in
1316 * the thread_ro (tro_cred)
1317 */
1318
1319 if ((error = mac_proc_check_settid(p, KAUTH_UID_NONE, KAUTH_GID_NONE)) != 0) {
1320 return error;
1321 }
1322
1323 if (proc_suser(p) != 0 || (tro->tro_flags & TRO_SETUID) == 0) {
1324 return EPERM;
1325 }
1326
1327 /* revert to delayed binding of process credential */
1328 cred = kauth_cred_proc_ref(p);
1329 thread_ro_update_cred(tro, cred);
1330 thread_ro_update_flags(tro, TRO_NONE, TRO_SETUID);
1331 kauth_cred_unref(&cred);
1332
1333 return 0;
1334 }
1335
1336
1337 /*
1338 * setgroups1
1339 *
1340 * Description: Internal implementation for both the setgroups and initgroups
1341 * system calls
1342 *
1343 * Parameters: gidsetsize Number of groups in set
1344 * gidset Pointer to group list
1345 * gmuid Base gid (initgroups only!)
1346 *
1347 * Returns: 0 Success
1348 * suser:EPERM Permision denied
1349 * EINVAL Invalid gidsetsize value
1350 * copyin:EFAULT Bad gidset or gidsetsize is
1351 * too large
1352 *
1353 * Notes: When called from a thread running under an assumed per-thread
1354 * identity, this function will operate against the per-thread
1355 * credential, rather than against the process credential. In
1356 * this specific case, the process credential is verified to
1357 * still be privileged at the time of the call, rather than the
1358 * per-thread credential for this operation to be permitted.
1359 *
1360 * This effectively means that setgroups/initigroups calls in
1361 * a thread running a per-thread credential should occur *after*
1362 * the settid call that created it, not before (unlike setuid,
1363 * which must be called after, since it will result in privilege
1364 * being dropped).
1365 *
1366 * When called normally (i.e. no per-thread assumed identity),
1367 * the per process credential is updated per POSIX.
1368 *
1369 * If the credential is changed as a result of this call, then we
1370 * flag the process as having set privilege since the last exec.
1371 */
1372 static int
setgroups1(proc_t p,u_int ngrp,user_addr_t gidset,uid_t gmuid,__unused int32_t * retval)1373 setgroups1(proc_t p, u_int ngrp, user_addr_t gidset, uid_t gmuid, __unused int32_t *retval)
1374 {
1375 gid_t newgroups[NGROUPS] = { 0 };
1376 int error;
1377
1378 if (ngrp > NGROUPS) {
1379 return EINVAL;
1380 }
1381
1382 if (ngrp >= 1) {
1383 error = copyin(gidset,
1384 (caddr_t)newgroups, ngrp * sizeof(gid_t));
1385 if (error) {
1386 return error;
1387 }
1388 }
1389 return setgroups_internal(p, ngrp, newgroups, gmuid);
1390 }
1391
1392 int
setgroups_internal(proc_t p,u_int ngrp,gid_t * newgroups,uid_t gmuid)1393 setgroups_internal(proc_t p, u_int ngrp, gid_t *newgroups, uid_t gmuid)
1394 {
1395 thread_ro_t tro = current_thread_ro();
1396 kauth_cred_t cred;
1397 int error;
1398
1399 cred = kauth_cred_proc_ref(p);
1400 error = suser(cred, &p->p_acflag);
1401 kauth_cred_unref(&cred);
1402
1403 if (error) {
1404 return error;
1405 }
1406
1407 if (ngrp < 1) {
1408 ngrp = 1;
1409 newgroups[0] = 0;
1410 }
1411
1412 if ((tro->tro_flags & TRO_SETUID) != 0) {
1413 /*
1414 * If this thread is under an assumed identity, set the
1415 * supplementary grouplist on the thread credential instead
1416 * of the process one. If we were the only reference holder,
1417 * the credential is updated in place, otherwise, our reference
1418 * is dropped and we get back a different cred with a reference
1419 * already held on it. Because this is per-thread, we don't
1420 * need the referencing/locking/retry required for per-process.
1421 */
1422 cred = tro->tro_cred;
1423 kauth_cred_ref(cred);
1424 cred = kauth_cred_setgroups(cred, &newgroups[0], ngrp, gmuid);
1425 thread_ro_update_cred(tro, cred);
1426 kauth_cred_unref(&cred);
1427 } else {
1428 proc_update_label(p, true, ^(kauth_cred_t cur_cred) {
1429 return kauth_cred_setgroups(cur_cred, &newgroups[0], ngrp, gmuid);
1430 });
1431
1432 AUDIT_ARG(groupset, &newgroups[0], ngrp);
1433 }
1434
1435 return 0;
1436 }
1437
1438
1439 /*
1440 * initgroups
1441 *
1442 * Description: Initialize the default supplementary groups list and set the
1443 * gmuid for use by the external group resolver (if any)
1444 *
1445 * Parameters: uap->gidsetsize Number of groups in set
1446 * uap->gidset Pointer to group list
1447 * uap->gmuid Base gid
1448 *
1449 * Returns: 0 Success
1450 * setgroups1:EPERM Permision denied
1451 * setgroups1:EINVAL Invalid gidsetsize value
1452 * setgroups1:EFAULT Bad gidset or gidsetsize is
1453 *
1454 * Notes: This function opts *IN* to memberd participation
1455 *
1456 * The normal purpose of this function is for a privileged
1457 * process to indicate supplementary groups and identity for
1458 * participation in extended group membership resolution prior
1459 * to dropping privilege by assuming a specific user identity.
1460 *
1461 * It is the first half of the primary mechanism whereby user
1462 * identity is established to the system by programs such as
1463 * /usr/bin/login. The second half is the drop of uid privilege
1464 * for a specific uid corresponding to the user.
1465 *
1466 * See also: setgroups1()
1467 */
1468 int
initgroups(proc_t p,struct initgroups_args * uap,__unused int32_t * retval)1469 initgroups(proc_t p, struct initgroups_args *uap, __unused int32_t *retval)
1470 {
1471 return setgroups1(p, uap->gidsetsize, uap->gidset, uap->gmuid, retval);
1472 }
1473
1474
1475 /*
1476 * setgroups
1477 *
1478 * Description: Initialize the default supplementary groups list
1479 *
1480 * Parameters: gidsetsize Number of groups in set
1481 * gidset Pointer to group list
1482 *
1483 * Returns: 0 Success
1484 * setgroups1:EPERM Permision denied
1485 * setgroups1:EINVAL Invalid gidsetsize value
1486 * setgroups1:EFAULT Bad gidset or gidsetsize is
1487 *
1488 * Notes: This functions opts *OUT* of memberd participation.
1489 *
1490 * This function exists for compatibility with POSIX. Most user
1491 * programs should use initgroups() instead to ensure correct
1492 * participation in group membership resolution when utilizing
1493 * a directory service for authentication.
1494 *
1495 * It is identical to an initgroups() call with a gmuid argument
1496 * of KAUTH_UID_NONE.
1497 *
1498 * See also: setgroups1()
1499 */
1500 int
setgroups(proc_t p,struct setgroups_args * uap,__unused int32_t * retval)1501 setgroups(proc_t p, struct setgroups_args *uap, __unused int32_t *retval)
1502 {
1503 return setgroups1(p, uap->gidsetsize, uap->gidset, KAUTH_UID_NONE, retval);
1504 }
1505
1506
1507 /*
1508 * Set the per-thread/per-process supplementary groups list.
1509 *
1510 * XXX implement setsgroups
1511 *
1512 */
1513
1514 int
setsgroups(__unused proc_t p,__unused struct setsgroups_args * uap,__unused int32_t * retval)1515 setsgroups(__unused proc_t p, __unused struct setsgroups_args *uap, __unused int32_t *retval)
1516 {
1517 return ENOTSUP;
1518 }
1519
1520 /*
1521 * Set the per-thread/per-process whiteout groups list.
1522 *
1523 * XXX implement setwgroups
1524 *
1525 */
1526
1527 int
setwgroups(__unused proc_t p,__unused struct setwgroups_args * uap,__unused int32_t * retval)1528 setwgroups(__unused proc_t p, __unused struct setwgroups_args *uap, __unused int32_t *retval)
1529 {
1530 return ENOTSUP;
1531 }
1532
1533
1534 /*
1535 * Check if gid is a member of the group set.
1536 *
1537 * XXX This interface is going away; use kauth_cred_ismember_gid() directly
1538 * XXX instead.
1539 */
1540 int
groupmember(gid_t gid,kauth_cred_t cred)1541 groupmember(gid_t gid, kauth_cred_t cred)
1542 {
1543 int is_member;
1544
1545 if (kauth_cred_ismember_gid(cred, gid, &is_member) == 0 && is_member) {
1546 return 1;
1547 }
1548 return 0;
1549 }
1550
1551
1552 /*
1553 * Test whether the specified credentials imply "super-user"
1554 * privilege; if so, and we have accounting info, set the flag
1555 * indicating use of super-powers.
1556 * Returns 0 or error.
1557 *
1558 * XXX This interface is going away; use kauth_cred_issuser() directly
1559 * XXX instead.
1560 *
1561 * Note: This interface exists to implement the "has used privilege"
1562 * bit (ASU) in the p_acflags field of the process, which is
1563 * only externalized via private sysctl and in process accounting
1564 * records. The flag is technically not required in either case.
1565 */
1566 int
suser(kauth_cred_t cred,u_short * acflag)1567 suser(kauth_cred_t cred, u_short *acflag)
1568 {
1569 if (kauth_cred_getuid(cred) == 0) {
1570 if (acflag) {
1571 *acflag |= ASU;
1572 }
1573 return 0;
1574 }
1575 return EPERM;
1576 }
1577
1578
1579 /*
1580 * getlogin
1581 *
1582 * Description: Get login name, if available.
1583 *
1584 * Parameters: uap->namebuf User buffer for return
1585 * uap->namelen User buffer length
1586 *
1587 * Returns: 0 Success
1588 * copyout:EFAULT
1589 *
1590 * Notes: Intended to obtain a string containing the user name of the
1591 * user associated with the controlling terminal for the calling
1592 * process.
1593 *
1594 * Not very useful on modern systems, due to inherent length
1595 * limitations for the static array in the session structure
1596 * which is used to store the login name.
1597 *
1598 * Permitted to return NULL
1599 *
1600 * XXX: Belongs in kern_proc.c
1601 */
1602 int
getlogin(proc_t p,struct getlogin_args * uap,__unused int32_t * retval)1603 getlogin(proc_t p, struct getlogin_args *uap, __unused int32_t *retval)
1604 {
1605 char buffer[MAXLOGNAME];
1606 struct session *sessp;
1607 struct pgrp *pg;
1608
1609 if (uap->namelen > MAXLOGNAME) {
1610 uap->namelen = MAXLOGNAME;
1611 }
1612
1613 if ((pg = proc_pgrp(p, &sessp)) != PGRP_NULL) {
1614 session_lock(sessp);
1615 bcopy(sessp->s_login, buffer, uap->namelen);
1616 session_unlock(sessp);
1617 pgrp_rele(pg);
1618 } else {
1619 bzero(buffer, uap->namelen);
1620 }
1621
1622 return copyout((caddr_t)buffer, uap->namebuf, uap->namelen);
1623 }
1624
1625 void
setlogin_internal(proc_t p,const char login[static MAXLOGNAME])1626 setlogin_internal(proc_t p, const char login[static MAXLOGNAME])
1627 {
1628 struct session *sessp;
1629 struct pgrp *pg;
1630
1631 if ((pg = proc_pgrp(p, &sessp)) != PGRP_NULL) {
1632 session_lock(sessp);
1633 bcopy(login, sessp->s_login, MAXLOGNAME);
1634 session_unlock(sessp);
1635 pgrp_rele(pg);
1636 }
1637 }
1638
1639 /*
1640 * setlogin
1641 *
1642 * Description: Set login name.
1643 *
1644 * Parameters: uap->namebuf User buffer containing name
1645 *
1646 * Returns: 0 Success
1647 * suser:EPERM Permission denied
1648 * copyinstr:EFAULT User buffer invalid
1649 * copyinstr:EINVAL Supplied name was too long
1650 *
1651 * Notes: This is a utility system call to support getlogin().
1652 *
1653 * XXX: Belongs in kern_proc.c
1654 */
1655 int
setlogin(proc_t p,struct setlogin_args * uap,__unused int32_t * retval)1656 setlogin(proc_t p, struct setlogin_args *uap, __unused int32_t *retval)
1657 {
1658 int error;
1659 size_t dummy = 0;
1660 char buffer[MAXLOGNAME + 1];
1661
1662 if ((error = proc_suser(p))) {
1663 return error;
1664 }
1665
1666 bzero(&buffer[0], MAXLOGNAME + 1);
1667
1668
1669 error = copyinstr(uap->namebuf,
1670 (caddr_t) &buffer[0],
1671 MAXLOGNAME - 1, (size_t *)&dummy);
1672
1673 setlogin_internal(p, buffer);
1674
1675 if (!error) {
1676 AUDIT_ARG(text, buffer);
1677 } else if (error == ENAMETOOLONG) {
1678 error = EINVAL;
1679 }
1680 return error;
1681 }
1682
1683
1684 /* Set the secrity token of the task with current euid and eguid */
1685 /*
1686 * XXX This needs to change to give the task a reference and/or an opaque
1687 * XXX identifier.
1688 */
1689 int
set_security_token(proc_t p)1690 set_security_token(proc_t p)
1691 {
1692 return set_security_token_task_internal(p, proc_task(p));
1693 }
1694
1695 static void
proc_calc_audit_token(proc_t p,kauth_cred_t my_cred,audit_token_t * audit_token)1696 proc_calc_audit_token(proc_t p, kauth_cred_t my_cred, audit_token_t *audit_token)
1697 {
1698 posix_cred_t my_pcred = posix_cred_get(my_cred);
1699
1700 /*
1701 * The current layout of the Mach audit token explicitly
1702 * adds these fields. But nobody should rely on such
1703 * a literal representation. Instead, the BSM library
1704 * provides a function to convert an audit token into
1705 * a BSM subject. Use of that mechanism will isolate
1706 * the user of the trailer from future representation
1707 * changes.
1708 */
1709 audit_token->val[0] = my_cred->cr_audit.as_aia_p->ai_auid;
1710 audit_token->val[1] = my_pcred->cr_uid;
1711 audit_token->val[2] = my_pcred->cr_gid;
1712 audit_token->val[3] = my_pcred->cr_ruid;
1713 audit_token->val[4] = my_pcred->cr_rgid;
1714 audit_token->val[5] = proc_getpid(p);
1715 audit_token->val[6] = my_cred->cr_audit.as_aia_p->ai_asid;
1716 audit_token->val[7] = proc_pidversion(p);
1717 }
1718
1719 /*
1720 * Set the secrity token of the task with current euid and eguid
1721 * The function takes a proc and a task, where proc->task might point to a
1722 * different task if called from exec.
1723 */
1724
1725 int
set_security_token_task_internal(proc_t p,void * t)1726 set_security_token_task_internal(proc_t p, void *t)
1727 {
1728 kauth_cred_t my_cred;
1729 security_token_t sec_token;
1730 audit_token_t audit_token;
1731 host_priv_t host_priv;
1732 task_t task = t;
1733
1734
1735 my_cred = kauth_cred_proc_ref(p);
1736
1737 proc_calc_audit_token(p, my_cred, &audit_token);
1738
1739 sec_token.val[0] = kauth_cred_getuid(my_cred);
1740 sec_token.val[1] = kauth_cred_getgid(my_cred);
1741
1742 host_priv = (sec_token.val[0]) ? HOST_PRIV_NULL : host_priv_self();
1743 #if CONFIG_MACF
1744 if (host_priv != HOST_PRIV_NULL && mac_system_check_host_priv(my_cred)) {
1745 host_priv = HOST_PRIV_NULL;
1746 }
1747 #endif
1748 kauth_cred_unref(&my_cred);
1749
1750 #if DEVELOPMENT || DEBUG
1751 /*
1752 * Update the pid an proc name for importance base if any
1753 */
1754 task_importance_update_owner_info(task);
1755 #endif
1756
1757 return task_set_security_tokens(task, sec_token, audit_token,
1758 host_priv) != KERN_SUCCESS;
1759 }
1760
1761 void
proc_parent_audit_token(proc_t p,audit_token_t * token_out)1762 proc_parent_audit_token(proc_t p, audit_token_t *token_out)
1763 {
1764 proc_t parent;
1765 kauth_cred_t my_cred;
1766
1767 proc_list_lock();
1768
1769 parent = p->p_pptr;
1770 my_cred = kauth_cred_proc_ref(parent);
1771 proc_calc_audit_token(parent, my_cred, token_out);
1772 kauth_cred_unref(&my_cred);
1773
1774 proc_list_unlock();
1775 }
1776
1777
1778 int get_audit_token_pid(audit_token_t *audit_token);
1779
1780 int
get_audit_token_pid(audit_token_t * audit_token)1781 get_audit_token_pid(audit_token_t *audit_token)
1782 {
1783 /* keep in-sync with set_security_token (above) */
1784 if (audit_token) {
1785 return (int)audit_token->val[5];
1786 }
1787 return -1;
1788 }
1789
1790
1791 /*
1792 * Fill in a struct xucred based on a kauth_cred_t.
1793 */
1794 void
cru2x(kauth_cred_t cr,struct xucred * xcr)1795 cru2x(kauth_cred_t cr, struct xucred *xcr)
1796 {
1797 posix_cred_t pcr = posix_cred_get(cr);
1798
1799 bzero(xcr, sizeof(*xcr));
1800 xcr->cr_version = XUCRED_VERSION;
1801 xcr->cr_uid = kauth_cred_getuid(cr);
1802 xcr->cr_ngroups = pcr->cr_ngroups;
1803 bcopy(pcr->cr_groups, xcr->cr_groups, sizeof(xcr->cr_groups));
1804 }
1805
1806 /*
1807 * Copy kauth_cred into a virtual address by assignment.
1808 * Needed because elements of kauth_cred are PACed
1809 * so memcpy doesn't work.
1810 */
1811 void
kauth_cred_copy(const uintptr_t kv,const uintptr_t new_data)1812 kauth_cred_copy(const uintptr_t kv, const uintptr_t new_data)
1813 {
1814 *(kauth_cred_t)kv = *(kauth_cred_t)new_data;
1815 }
1816