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