xref: /xnu-8792.81.2/bsd/kern/kern_prot.c (revision 19c3b8c28c31cb8130e034cfb5df6bf9ba342d90)
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