xref: /xnu-12377.81.4/bsd/kern/kern_prot.c (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
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