kern_prot.c revision 139804
1139804Simp/*-
21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes * (c) UNIX System Laboratories, Inc.
51541Srgrimes * All or some portions of this file are derived from material licensed
61541Srgrimes * to the University of California by American Telephone and Telegraph
71541Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with
81541Srgrimes * the permission of UNIX System Laboratories, Inc.
987218Srwatson * Copyright (c) 2000-2001 Robert N. M. Watson.  All rights reserved.
101541Srgrimes *
111541Srgrimes * Redistribution and use in source and binary forms, with or without
121541Srgrimes * modification, are permitted provided that the following conditions
131541Srgrimes * are met:
141541Srgrimes * 1. Redistributions of source code must retain the above copyright
151541Srgrimes *    notice, this list of conditions and the following disclaimer.
161541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
171541Srgrimes *    notice, this list of conditions and the following disclaimer in the
181541Srgrimes *    documentation and/or other materials provided with the distribution.
191541Srgrimes * 4. Neither the name of the University nor the names of its contributors
201541Srgrimes *    may be used to endorse or promote products derived from this software
211541Srgrimes *    without specific prior written permission.
221541Srgrimes *
231541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
241541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
251541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
261541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
271541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
281541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
291541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
301541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
311541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
321541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
331541Srgrimes * SUCH DAMAGE.
341541Srgrimes *
351541Srgrimes *	@(#)kern_prot.c	8.6 (Berkeley) 1/21/94
361541Srgrimes */
371541Srgrimes
381541Srgrimes/*
391541Srgrimes * System calls related to processes and protection
401541Srgrimes */
411541Srgrimes
42116182Sobrien#include <sys/cdefs.h>
43116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_prot.c 139804 2005-01-06 23:35:40Z imp $");
44116182Sobrien
4531778Seivind#include "opt_compat.h"
46101001Srwatson#include "opt_mac.h"
4731778Seivind
481541Srgrimes#include <sys/param.h>
4976166Smarkm#include <sys/systm.h>
501541Srgrimes#include <sys/acct.h>
51132548Srwatson#include <sys/kdb.h>
5241059Speter#include <sys/kernel.h>
5370317Sjake#include <sys/lock.h>
54101173Srwatson#include <sys/mac.h>
5591140Stanimura#include <sys/malloc.h>
5676166Smarkm#include <sys/mutex.h>
5791140Stanimura#include <sys/sx.h>
581541Srgrimes#include <sys/proc.h>
5976166Smarkm#include <sys/sysproto.h>
6087218Srwatson#include <sys/jail.h>
6131891Ssef#include <sys/pioctl.h>
6265495Struckman#include <sys/resourcevar.h>
6392976Srwatson#include <sys/socket.h>
6492976Srwatson#include <sys/socketvar.h>
6561287Srwatson#include <sys/sysctl.h>
661541Srgrimes
6730354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials");
6830354Sphk
6989414SarrSYSCTL_DECL(_security);
7089414SarrSYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0,
7187138Srwatson    "BSD security policy");
7287138Srwatson
7312221Sbde#ifndef _SYS_SYSPROTO_H_
7411332Sswallacestruct getpid_args {
751541Srgrimes	int	dummy;
761541Srgrimes};
7712221Sbde#endif
7858717Sdillon/*
7982749Sdillon * MPSAFE
8082749Sdillon */
811541Srgrimes/* ARGSUSED */
821549Srgrimesint
8393580Sjhbgetpid(struct thread *td, struct getpid_args *uap)
841541Srgrimes{
8583366Sjulian	struct proc *p = td->td_proc;
861541Srgrimes
8783366Sjulian	td->td_retval[0] = p->p_pid;
88130344Sphk#if defined(COMPAT_43)
8974728Sjhb	PROC_LOCK(p);
9083366Sjulian	td->td_retval[1] = p->p_pptr->p_pid;
9174728Sjhb	PROC_UNLOCK(p);
921541Srgrimes#endif
931541Srgrimes	return (0);
941541Srgrimes}
951541Srgrimes
9612221Sbde#ifndef _SYS_SYSPROTO_H_
9711332Sswallacestruct getppid_args {
9811332Sswallace        int     dummy;
9911332Sswallace};
10012221Sbde#endif
10182749Sdillon/*
10282749Sdillon * MPSAFE
10382749Sdillon */
1041541Srgrimes/* ARGSUSED */
1051549Srgrimesint
10693580Sjhbgetppid(struct thread *td, struct getppid_args *uap)
1071541Srgrimes{
10883366Sjulian	struct proc *p = td->td_proc;
1091541Srgrimes
11074728Sjhb	PROC_LOCK(p);
11183366Sjulian	td->td_retval[0] = p->p_pptr->p_pid;
11274728Sjhb	PROC_UNLOCK(p);
1131541Srgrimes	return (0);
1141541Srgrimes}
1151541Srgrimes
11687466Srwatson/*
11787218Srwatson * Get process group ID; note that POSIX getpgrp takes no parameter.
11858717Sdillon */
11912221Sbde#ifndef _SYS_SYSPROTO_H_
12011332Sswallacestruct getpgrp_args {
12111332Sswallace        int     dummy;
12211332Sswallace};
12312221Sbde#endif
12482749Sdillon/*
12582749Sdillon * MPSAFE
12682749Sdillon */
1271549Srgrimesint
12893580Sjhbgetpgrp(struct thread *td, struct getpgrp_args *uap)
1291541Srgrimes{
13083366Sjulian	struct proc *p = td->td_proc;
1311541Srgrimes
13291140Stanimura	PROC_LOCK(p);
13383366Sjulian	td->td_retval[0] = p->p_pgrp->pg_id;
13491140Stanimura	PROC_UNLOCK(p);
1351541Srgrimes	return (0);
1361541Srgrimes}
1371541Srgrimes
13828401Speter/* Get an arbitary pid's process group id */
13912221Sbde#ifndef _SYS_SYSPROTO_H_
14028401Speterstruct getpgid_args {
14128401Speter	pid_t	pid;
14228401Speter};
14328401Speter#endif
14482749Sdillon/*
14582749Sdillon * MPSAFE
14682749Sdillon */
14728401Speterint
14893580Sjhbgetpgid(struct thread *td, struct getpgid_args *uap)
14928401Speter{
150114031Sjhb	struct proc *p;
15192985Sjhb	int error;
15241726Struckman
15391140Stanimura	if (uap->pid == 0) {
154114031Sjhb		p = td->td_proc;
15591140Stanimura		PROC_LOCK(p);
156114031Sjhb	} else {
157114031Sjhb		p = pfind(uap->pid);
158114031Sjhb		if (p == NULL)
159114031Sjhb			return (ESRCH);
160114031Sjhb		error = p_cansee(td, p);
161114031Sjhb		if (error) {
162114031Sjhb			PROC_UNLOCK(p);
163114031Sjhb			return (error);
164114031Sjhb		}
16575893Sjhb	}
166114031Sjhb	td->td_retval[0] = p->p_pgrp->pg_id;
167114031Sjhb	PROC_UNLOCK(p);
168114031Sjhb	return (0);
16928401Speter}
17028401Speter
17128401Speter/*
17228401Speter * Get an arbitary pid's session id.
17328401Speter */
17428401Speter#ifndef _SYS_SYSPROTO_H_
17528401Speterstruct getsid_args {
17628401Speter	pid_t	pid;
17728401Speter};
17828401Speter#endif
17982749Sdillon/*
18082749Sdillon * MPSAFE
18182749Sdillon */
18228401Speterint
18393580Sjhbgetsid(struct thread *td, struct getsid_args *uap)
18428401Speter{
185114031Sjhb	struct proc *p;
18687218Srwatson	int error;
18741726Struckman
18891140Stanimura	if (uap->pid == 0) {
189114031Sjhb		p = td->td_proc;
19091140Stanimura		PROC_LOCK(p);
191114031Sjhb	} else {
192114031Sjhb		p = pfind(uap->pid);
193114031Sjhb		if (p == NULL)
194114031Sjhb			return (ESRCH);
195114031Sjhb		error = p_cansee(td, p);
196114031Sjhb		if (error) {
197114031Sjhb			PROC_UNLOCK(p);
198114031Sjhb			return (error);
199114031Sjhb		}
20075893Sjhb	}
201114031Sjhb	td->td_retval[0] = p->p_session->s_sid;
202114031Sjhb	PROC_UNLOCK(p);
203114031Sjhb	return (0);
20428401Speter}
20528401Speter
20628401Speter#ifndef _SYS_SYSPROTO_H_
20711332Sswallacestruct getuid_args {
20811332Sswallace        int     dummy;
20911332Sswallace};
21012221Sbde#endif
21182749Sdillon/*
21282749Sdillon * MPSAFE
21382749Sdillon */
2141541Srgrimes/* ARGSUSED */
2151549Srgrimesint
21693580Sjhbgetuid(struct thread *td, struct getuid_args *uap)
2171541Srgrimes{
2181541Srgrimes
21992987Sjhb	td->td_retval[0] = td->td_ucred->cr_ruid;
220130344Sphk#if defined(COMPAT_43)
22192987Sjhb	td->td_retval[1] = td->td_ucred->cr_uid;
2221541Srgrimes#endif
2231541Srgrimes	return (0);
2241541Srgrimes}
2251541Srgrimes
22612221Sbde#ifndef _SYS_SYSPROTO_H_
22711332Sswallacestruct geteuid_args {
22811332Sswallace        int     dummy;
22911332Sswallace};
23012221Sbde#endif
23187218Srwatson/*
23287218Srwatson * MPSAFE
23387218Srwatson */
2341541Srgrimes/* ARGSUSED */
2351549Srgrimesint
23693580Sjhbgeteuid(struct thread *td, struct geteuid_args *uap)
2371541Srgrimes{
23892987Sjhb
23992987Sjhb	td->td_retval[0] = td->td_ucred->cr_uid;
2401541Srgrimes	return (0);
2411541Srgrimes}
2421541Srgrimes
24312221Sbde#ifndef _SYS_SYSPROTO_H_
24411332Sswallacestruct getgid_args {
24511332Sswallace        int     dummy;
24611332Sswallace};
24712221Sbde#endif
24882749Sdillon/*
24982749Sdillon * MPSAFE
25082749Sdillon */
2511541Srgrimes/* ARGSUSED */
2521549Srgrimesint
25393580Sjhbgetgid(struct thread *td, struct getgid_args *uap)
2541541Srgrimes{
2551541Srgrimes
25692987Sjhb	td->td_retval[0] = td->td_ucred->cr_rgid;
257130344Sphk#if defined(COMPAT_43)
25892987Sjhb	td->td_retval[1] = td->td_ucred->cr_groups[0];
2591541Srgrimes#endif
2601541Srgrimes	return (0);
2611541Srgrimes}
2621541Srgrimes
2631541Srgrimes/*
2641541Srgrimes * Get effective group ID.  The "egid" is groups[0], and could be obtained
2651541Srgrimes * via getgroups.  This syscall exists because it is somewhat painful to do
2661541Srgrimes * correctly in a library function.
2671541Srgrimes */
26812221Sbde#ifndef _SYS_SYSPROTO_H_
26911332Sswallacestruct getegid_args {
27011332Sswallace        int     dummy;
27111332Sswallace};
27212221Sbde#endif
27382749Sdillon/*
27482749Sdillon * MPSAFE
27582749Sdillon */
2761541Srgrimes/* ARGSUSED */
2771549Srgrimesint
27893580Sjhbgetegid(struct thread *td, struct getegid_args *uap)
2791541Srgrimes{
2801541Srgrimes
28192987Sjhb	td->td_retval[0] = td->td_ucred->cr_groups[0];
2821541Srgrimes	return (0);
2831541Srgrimes}
2841541Srgrimes
28512221Sbde#ifndef _SYS_SYSPROTO_H_
2861541Srgrimesstruct getgroups_args {
2871541Srgrimes	u_int	gidsetsize;
2881541Srgrimes	gid_t	*gidset;
2891541Srgrimes};
29012221Sbde#endif
29182749Sdillon/*
29282749Sdillon * MPSAFE
29382749Sdillon */
2941549Srgrimesint
29593580Sjhbgetgroups(struct thread *td, register struct getgroups_args *uap)
2961541Srgrimes{
29782749Sdillon	struct ucred *cred;
29877183Srwatson	u_int ngrp;
29987218Srwatson	int error;
3001541Srgrimes
30192987Sjhb	cred = td->td_ucred;
3021541Srgrimes	if ((ngrp = uap->gidsetsize) == 0) {
30383366Sjulian		td->td_retval[0] = cred->cr_ngroups;
30492987Sjhb		return (0);
3051541Srgrimes	}
30692987Sjhb	if (ngrp < cred->cr_ngroups)
30792987Sjhb		return (EINVAL);
30877183Srwatson	ngrp = cred->cr_ngroups;
30999009Salfred	error = copyout(cred->cr_groups, uap->gidset, ngrp * sizeof(gid_t));
31093264Sdillon	if (error == 0)
31193557Sjhb		td->td_retval[0] = ngrp;
31293264Sdillon	return (error);
3131541Srgrimes}
3141541Srgrimes
31512221Sbde#ifndef _SYS_SYSPROTO_H_
31612207Sbdestruct setsid_args {
31711332Sswallace        int     dummy;
31811332Sswallace};
31912221Sbde#endif
32082749Sdillon/*
32182749Sdillon * MPSAFE
32282749Sdillon */
3231541Srgrimes/* ARGSUSED */
3241549Srgrimesint
32593580Sjhbsetsid(register struct thread *td, struct setsid_args *uap)
3261541Srgrimes{
32791140Stanimura	struct pgrp *pgrp;
32882749Sdillon	int error;
32983366Sjulian	struct proc *p = td->td_proc;
33091140Stanimura	struct pgrp *newpgrp;
33191140Stanimura	struct session *newsess;
3321541Srgrimes
33391140Stanimura	error = 0;
33491140Stanimura	pgrp = NULL;
33591140Stanimura
336111119Simp	MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
337111119Simp	MALLOC(newsess, struct session *, sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO);
33891140Stanimura
33994859Sjhb	sx_xlock(&proctree_lock);
34091140Stanimura
34191140Stanimura	if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) {
34291140Stanimura		if (pgrp != NULL)
34391140Stanimura			PGRP_UNLOCK(pgrp);
34482749Sdillon		error = EPERM;
34591140Stanimura	} else {
34691140Stanimura		(void)enterpgrp(p, p->p_pid, newpgrp, newsess);
34783366Sjulian		td->td_retval[0] = p->p_pid;
34894859Sjhb		newpgrp = NULL;
34994859Sjhb		newsess = NULL;
3501541Srgrimes	}
35191140Stanimura
35294859Sjhb	sx_xunlock(&proctree_lock);
35391140Stanimura
35495973Stanimura	if (newpgrp != NULL)
35595973Stanimura		FREE(newpgrp, M_PGRP);
35695973Stanimura	if (newsess != NULL)
35795973Stanimura		FREE(newsess, M_SESSION);
35891140Stanimura
35994859Sjhb	return (error);
3601541Srgrimes}
3611541Srgrimes
3621541Srgrimes/*
3631541Srgrimes * set process group (setpgid/old setpgrp)
3641541Srgrimes *
3651541Srgrimes * caller does setpgid(targpid, targpgid)
3661541Srgrimes *
3671541Srgrimes * pid must be caller or child of caller (ESRCH)
3681541Srgrimes * if a child
3691541Srgrimes *	pid must be in same session (EPERM)
3701541Srgrimes *	pid can't have done an exec (EACCES)
3711541Srgrimes * if pgid != pid
3721541Srgrimes * 	there must exist some pid in same session having pgid (EPERM)
3731541Srgrimes * pid must not be session leader (EPERM)
3741541Srgrimes */
37512221Sbde#ifndef _SYS_SYSPROTO_H_
3761541Srgrimesstruct setpgid_args {
37787218Srwatson	int	pid;		/* target process id */
37887218Srwatson	int	pgid;		/* target pgrp id */
3791541Srgrimes};
38012221Sbde#endif
38182749Sdillon/*
38282749Sdillon * MPSAFE
38382749Sdillon */
3841541Srgrimes/* ARGSUSED */
3851549Srgrimesint
38693580Sjhbsetpgid(struct thread *td, register struct setpgid_args *uap)
3871541Srgrimes{
38883366Sjulian	struct proc *curp = td->td_proc;
38987218Srwatson	register struct proc *targp;	/* target process */
39087218Srwatson	register struct pgrp *pgrp;	/* target pgrp */
39175448Srwatson	int error;
39291140Stanimura	struct pgrp *newpgrp;
3931541Srgrimes
39420677Sbde	if (uap->pgid < 0)
39520677Sbde		return (EINVAL);
39691140Stanimura
39791140Stanimura	error = 0;
39891140Stanimura
399111119Simp	MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
40091140Stanimura
40194859Sjhb	sx_xlock(&proctree_lock);
4021541Srgrimes	if (uap->pid != 0 && uap->pid != curp->p_pid) {
40391140Stanimura		if ((targp = pfind(uap->pid)) == NULL) {
40482749Sdillon			error = ESRCH;
40594859Sjhb			goto done;
40675893Sjhb		}
40791140Stanimura		if (!inferior(targp)) {
40891140Stanimura			PROC_UNLOCK(targp);
40991371Stanimura			error = ESRCH;
41094859Sjhb			goto done;
41191140Stanimura		}
412132568Srwatson		if ((error = p_cansee(td, targp))) {
41375893Sjhb			PROC_UNLOCK(targp);
41494859Sjhb			goto done;
41575893Sjhb		}
41675893Sjhb		if (targp->p_pgrp == NULL ||
41775893Sjhb		    targp->p_session != curp->p_session) {
41875893Sjhb			PROC_UNLOCK(targp);
41982749Sdillon			error = EPERM;
42094859Sjhb			goto done;
42175893Sjhb		}
42275893Sjhb		if (targp->p_flag & P_EXEC) {
42375893Sjhb			PROC_UNLOCK(targp);
42482749Sdillon			error = EACCES;
42594859Sjhb			goto done;
42675893Sjhb		}
42791140Stanimura		PROC_UNLOCK(targp);
42891140Stanimura	} else
4291541Srgrimes		targp = curp;
43075893Sjhb	if (SESS_LEADER(targp)) {
43182749Sdillon		error = EPERM;
43294859Sjhb		goto done;
43375893Sjhb	}
43487218Srwatson	if (uap->pgid == 0)
4351541Srgrimes		uap->pgid = targp->p_pid;
436117214Scognet	if ((pgrp = pgfind(uap->pgid)) == NULL) {
437117214Scognet		if (uap->pgid == targp->p_pid) {
438117214Scognet			error = enterpgrp(targp, uap->pgid, newpgrp,
439117214Scognet			    NULL);
440117214Scognet			if (error == 0)
441117214Scognet				newpgrp = NULL;
442117214Scognet		} else
443117214Scognet			error = EPERM;
44491140Stanimura	} else {
445117214Scognet		if (pgrp == targp->p_pgrp) {
446117214Scognet			PGRP_UNLOCK(pgrp);
44794859Sjhb			goto done;
44875893Sjhb		}
449117214Scognet		if (pgrp->pg_id != targp->p_pid &&
450117214Scognet		    pgrp->pg_session != curp->p_session) {
45191140Stanimura			PGRP_UNLOCK(pgrp);
452117214Scognet			error = EPERM;
45391140Stanimura			goto done;
45491140Stanimura		}
45591140Stanimura		PGRP_UNLOCK(pgrp);
45691140Stanimura		error = enterthispgrp(targp, pgrp);
45782749Sdillon	}
45891140Stanimuradone:
45994859Sjhb	sx_xunlock(&proctree_lock);
46094859Sjhb	KASSERT((error == 0) || (newpgrp != NULL),
46194859Sjhb	    ("setpgid failed and newpgrp is NULL"));
46295973Stanimura	if (newpgrp != NULL)
46391140Stanimura		FREE(newpgrp, M_PGRP);
46482749Sdillon	return (error);
4651541Srgrimes}
4661541Srgrimes
46724448Speter/*
46824448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
46972093Sasmodai * compatible.  It says that setting the uid/gid to euid/egid is a special
47024448Speter * case of "appropriate privilege".  Once the rules are expanded out, this
47124448Speter * basically means that setuid(nnn) sets all three id's, in all permitted
47224448Speter * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
47324448Speter * does not set the saved id - this is dangerous for traditional BSD
47424448Speter * programs.  For this reason, we *really* do not want to set
47524448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
47624448Speter */
47724448Speter#define POSIX_APPENDIX_B_4_2_2
47824448Speter
47912221Sbde#ifndef _SYS_SYSPROTO_H_
4801541Srgrimesstruct setuid_args {
4811541Srgrimes	uid_t	uid;
4821541Srgrimes};
48312221Sbde#endif
48482749Sdillon/*
48582749Sdillon * MPSAFE
48682749Sdillon */
4871541Srgrimes/* ARGSUSED */
4881549Srgrimesint
48993580Sjhbsetuid(struct thread *td, struct setuid_args *uap)
4901541Srgrimes{
49183366Sjulian	struct proc *p = td->td_proc;
49277183Srwatson	struct ucred *newcred, *oldcred;
49377183Srwatson	uid_t uid;
49498417Salfred	struct uidinfo *uip;
49587218Srwatson	int error;
4961541Srgrimes
49777183Srwatson	uid = uap->uid;
49894619Sjhb	newcred = crget();
49998417Salfred	uip = uifind(uid);
50094619Sjhb	PROC_LOCK(p);
50187219Srwatson	oldcred = p->p_ucred;
50287466Srwatson
50324448Speter	/*
50424448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
50524448Speter	 *
50687218Srwatson	 * Note that setuid(geteuid()) is a special case of
50724448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
50872093Sasmodai	 * to use this clause to be compatible with traditional BSD
50924448Speter	 * semantics.  Basically, it means that "setuid(xx)" sets all
51024448Speter	 * three id's (assuming you have privs).
51124448Speter	 *
51224448Speter	 * Notes on the logic.  We do things in three steps.
51324448Speter	 * 1: We determine if the euid is going to change, and do EPERM
51424448Speter	 *    right away.  We unconditionally change the euid later if this
51524448Speter	 *    test is satisfied, simplifying that part of the logic.
51687218Srwatson	 * 2: We determine if the real and/or saved uids are going to
51724448Speter	 *    change.  Determined by compile options.
51824448Speter	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
51924448Speter	 */
52077183Srwatson	if (uid != oldcred->cr_ruid &&		/* allow setuid(getuid()) */
52117994Sache#ifdef _POSIX_SAVED_IDS
52277183Srwatson	    uid != oldcred->cr_svuid &&		/* allow setuid(saved gid) */
52317994Sache#endif
52424448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
52577183Srwatson	    uid != oldcred->cr_uid &&		/* allow setuid(geteuid()) */
52624448Speter#endif
527132653Scperciva	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) {
52894619Sjhb		PROC_UNLOCK(p);
52998417Salfred		uifree(uip);
53094619Sjhb		crfree(newcred);
53194619Sjhb		return (error);
53294619Sjhb	}
53324448Speter
53498417Salfred	/*
53598417Salfred	 * Copy credentials so other references do not see our changes.
53698417Salfred	 */
53794619Sjhb	crcopy(newcred, oldcred);
53824448Speter#ifdef _POSIX_SAVED_IDS
5391541Srgrimes	/*
54024448Speter	 * Do we have "appropriate privileges" (are we root or uid == euid)
54124448Speter	 * If so, we are changing the real uid and/or saved uid.
5421541Srgrimes	 */
54317994Sache	if (
54424448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
54577183Srwatson	    uid == oldcred->cr_uid ||
54617994Sache#endif
547132653Scperciva	    suser_cred(oldcred, SUSER_ALLOWJAIL) == 0) /* we are using privs */
54817994Sache#endif
54924448Speter	{
55024448Speter		/*
55165495Struckman		 * Set the real uid and transfer proc count to new user.
55224448Speter		 */
55377183Srwatson		if (uid != oldcred->cr_ruid) {
55498417Salfred			change_ruid(newcred, uip);
55565495Struckman			setsugid(p);
55624448Speter		}
55724448Speter		/*
55824448Speter		 * Set saved uid
55924448Speter		 *
56024448Speter		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
56124448Speter		 * the security of seteuid() depends on it.  B.4.2.2 says it
56224448Speter		 * is important that we should do this.
56324448Speter		 */
56477183Srwatson		if (uid != oldcred->cr_svuid) {
56577183Srwatson			change_svuid(newcred, uid);
56631891Ssef			setsugid(p);
56724448Speter		}
5688141Sache	}
56924448Speter
57024448Speter	/*
57124448Speter	 * In all permitted cases, we are changing the euid.
57224448Speter	 */
57377183Srwatson	if (uid != oldcred->cr_uid) {
57498417Salfred		change_euid(newcred, uip);
57531891Ssef		setsugid(p);
57624448Speter	}
57777183Srwatson	p->p_ucred = newcred;
57894619Sjhb	PROC_UNLOCK(p);
57998417Salfred	uifree(uip);
58077183Srwatson	crfree(oldcred);
58194619Sjhb	return (0);
5821541Srgrimes}
5831541Srgrimes
58412221Sbde#ifndef _SYS_SYSPROTO_H_
5851541Srgrimesstruct seteuid_args {
5861541Srgrimes	uid_t	euid;
5871541Srgrimes};
58812221Sbde#endif
58982749Sdillon/*
59082749Sdillon * MPSAFE
59182749Sdillon */
5921541Srgrimes/* ARGSUSED */
5931549Srgrimesint
59493580Sjhbseteuid(struct thread *td, struct seteuid_args *uap)
5951541Srgrimes{
59683366Sjulian	struct proc *p = td->td_proc;
59777183Srwatson	struct ucred *newcred, *oldcred;
59877183Srwatson	uid_t euid;
59998417Salfred	struct uidinfo *euip;
60087218Srwatson	int error;
6011541Srgrimes
6021541Srgrimes	euid = uap->euid;
60394619Sjhb	newcred = crget();
60498417Salfred	euip = uifind(euid);
60594619Sjhb	PROC_LOCK(p);
60677183Srwatson	oldcred = p->p_ucred;
60777183Srwatson	if (euid != oldcred->cr_ruid &&		/* allow seteuid(getuid()) */
60877183Srwatson	    euid != oldcred->cr_svuid &&	/* allow seteuid(saved uid) */
609132653Scperciva	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) {
61094619Sjhb		PROC_UNLOCK(p);
61198417Salfred		uifree(euip);
61294619Sjhb		crfree(newcred);
61394619Sjhb		return (error);
61494619Sjhb	}
6151541Srgrimes	/*
6161541Srgrimes	 * Everything's okay, do it.  Copy credentials so other references do
6171541Srgrimes	 * not see our changes.
6181541Srgrimes	 */
61994619Sjhb	crcopy(newcred, oldcred);
62077183Srwatson	if (oldcred->cr_uid != euid) {
62198417Salfred		change_euid(newcred, euip);
62231891Ssef		setsugid(p);
62324449Speter	}
62477183Srwatson	p->p_ucred = newcred;
62594619Sjhb	PROC_UNLOCK(p);
62698417Salfred	uifree(euip);
62777183Srwatson	crfree(oldcred);
62894619Sjhb	return (0);
6291541Srgrimes}
6301541Srgrimes
63112221Sbde#ifndef _SYS_SYSPROTO_H_
6321541Srgrimesstruct setgid_args {
6331541Srgrimes	gid_t	gid;
6341541Srgrimes};
63512221Sbde#endif
63682749Sdillon/*
63782749Sdillon * MPSAFE
63882749Sdillon */
6391541Srgrimes/* ARGSUSED */
6401549Srgrimesint
64193580Sjhbsetgid(struct thread *td, struct setgid_args *uap)
6421541Srgrimes{
64383366Sjulian	struct proc *p = td->td_proc;
64477183Srwatson	struct ucred *newcred, *oldcred;
64577183Srwatson	gid_t gid;
64687218Srwatson	int error;
6471541Srgrimes
64877183Srwatson	gid = uap->gid;
64994619Sjhb	newcred = crget();
65094619Sjhb	PROC_LOCK(p);
65177183Srwatson	oldcred = p->p_ucred;
65287466Srwatson
65324448Speter	/*
65424448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
65524448Speter	 *
65624448Speter	 * Note that setgid(getegid()) is a special case of
65724448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
65872093Sasmodai	 * to use this clause to be compatible with traditional BSD
65924448Speter	 * semantics.  Basically, it means that "setgid(xx)" sets all
66024448Speter	 * three id's (assuming you have privs).
66124448Speter	 *
66224448Speter	 * For notes on the logic here, see setuid() above.
66324448Speter	 */
66477183Srwatson	if (gid != oldcred->cr_rgid &&		/* allow setgid(getgid()) */
66517994Sache#ifdef _POSIX_SAVED_IDS
66677183Srwatson	    gid != oldcred->cr_svgid &&		/* allow setgid(saved gid) */
66717994Sache#endif
66824448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
66977183Srwatson	    gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */
67024448Speter#endif
671132653Scperciva	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) {
67294619Sjhb		PROC_UNLOCK(p);
67394619Sjhb		crfree(newcred);
67494619Sjhb		return (error);
67594619Sjhb	}
67624448Speter
67794619Sjhb	crcopy(newcred, oldcred);
67817994Sache#ifdef _POSIX_SAVED_IDS
67924448Speter	/*
68024448Speter	 * Do we have "appropriate privileges" (are we root or gid == egid)
68124448Speter	 * If so, we are changing the real uid and saved gid.
68224448Speter	 */
68324448Speter	if (
68424448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
68577183Srwatson	    gid == oldcred->cr_groups[0] ||
68617994Sache#endif
687132653Scperciva	    suser_cred(oldcred, SUSER_ALLOWJAIL) == 0) /* we are using privs */
68824448Speter#endif
68924448Speter	{
69024448Speter		/*
69124448Speter		 * Set real gid
69224448Speter		 */
69377183Srwatson		if (oldcred->cr_rgid != gid) {
69477183Srwatson			change_rgid(newcred, gid);
69531891Ssef			setsugid(p);
69624448Speter		}
69724448Speter		/*
69824448Speter		 * Set saved gid
69924448Speter		 *
70024448Speter		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
70124448Speter		 * the security of setegid() depends on it.  B.4.2.2 says it
70224448Speter		 * is important that we should do this.
70324448Speter		 */
70477183Srwatson		if (oldcred->cr_svgid != gid) {
70577183Srwatson			change_svgid(newcred, gid);
70631891Ssef			setsugid(p);
70724448Speter		}
7088141Sache	}
70924448Speter	/*
71024448Speter	 * In all cases permitted cases, we are changing the egid.
71124448Speter	 * Copy credentials so other references do not see our changes.
71224448Speter	 */
71377183Srwatson	if (oldcred->cr_groups[0] != gid) {
71477183Srwatson		change_egid(newcred, gid);
71531891Ssef		setsugid(p);
71624448Speter	}
71777183Srwatson	p->p_ucred = newcred;
71894619Sjhb	PROC_UNLOCK(p);
71977183Srwatson	crfree(oldcred);
72094619Sjhb	return (0);
7211541Srgrimes}
7221541Srgrimes
72312221Sbde#ifndef _SYS_SYSPROTO_H_
7241541Srgrimesstruct setegid_args {
7251541Srgrimes	gid_t	egid;
7261541Srgrimes};
72712221Sbde#endif
72882749Sdillon/*
72982749Sdillon * MPSAFE
73082749Sdillon */
7311541Srgrimes/* ARGSUSED */
7321549Srgrimesint
73393580Sjhbsetegid(struct thread *td, struct setegid_args *uap)
7341541Srgrimes{
73583366Sjulian	struct proc *p = td->td_proc;
73677183Srwatson	struct ucred *newcred, *oldcred;
73777183Srwatson	gid_t egid;
73887218Srwatson	int error;
7391541Srgrimes
7401541Srgrimes	egid = uap->egid;
74194619Sjhb	newcred = crget();
74294619Sjhb	PROC_LOCK(p);
74377183Srwatson	oldcred = p->p_ucred;
74477183Srwatson	if (egid != oldcred->cr_rgid &&		/* allow setegid(getgid()) */
74577183Srwatson	    egid != oldcred->cr_svgid &&	/* allow setegid(saved gid) */
746132653Scperciva	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) {
74794619Sjhb		PROC_UNLOCK(p);
74894619Sjhb		crfree(newcred);
74994619Sjhb		return (error);
75094619Sjhb	}
75194619Sjhb	crcopy(newcred, oldcred);
75277183Srwatson	if (oldcred->cr_groups[0] != egid) {
75377183Srwatson		change_egid(newcred, egid);
75431891Ssef		setsugid(p);
75524449Speter	}
75677183Srwatson	p->p_ucred = newcred;
75794619Sjhb	PROC_UNLOCK(p);
75877183Srwatson	crfree(oldcred);
75994619Sjhb	return (0);
7601541Srgrimes}
7611541Srgrimes
76212221Sbde#ifndef _SYS_SYSPROTO_H_
7631541Srgrimesstruct setgroups_args {
7641541Srgrimes	u_int	gidsetsize;
7651541Srgrimes	gid_t	*gidset;
7661541Srgrimes};
76712221Sbde#endif
76882749Sdillon/*
76982749Sdillon * MPSAFE
77082749Sdillon */
7711541Srgrimes/* ARGSUSED */
7721549Srgrimesint
77393580Sjhbsetgroups(struct thread *td, struct setgroups_args *uap)
7741541Srgrimes{
77583366Sjulian	struct proc *p = td->td_proc;
77694619Sjhb	struct ucred *newcred, *tempcred, *oldcred;
77777183Srwatson	u_int ngrp;
7781541Srgrimes	int error;
7791541Srgrimes
78087220Srwatson	ngrp = uap->gidsetsize;
78194619Sjhb	if (ngrp > NGROUPS)
78294619Sjhb		return (EINVAL);
78394619Sjhb	tempcred = crget();
78499009Salfred	error = copyin(uap->gidset, tempcred->cr_groups, ngrp * sizeof(gid_t));
78594619Sjhb	if (error != 0) {
78694619Sjhb		crfree(tempcred);
78794619Sjhb		return (error);
78894619Sjhb	}
78994619Sjhb	newcred = crget();
79094619Sjhb	PROC_LOCK(p);
79177183Srwatson	oldcred = p->p_ucred;
792132653Scperciva	error = suser_cred(oldcred, SUSER_ALLOWJAIL);
79394619Sjhb	if (error) {
79494619Sjhb		PROC_UNLOCK(p);
79594619Sjhb		crfree(newcred);
79694619Sjhb		crfree(tempcred);
79794619Sjhb		return (error);
79882749Sdillon	}
79994619Sjhb
80024447Speter	/*
80124447Speter	 * XXX A little bit lazy here.  We could test if anything has
80224447Speter	 * changed before crcopy() and setting P_SUGID.
80324447Speter	 */
80494619Sjhb	crcopy(newcred, oldcred);
80524447Speter	if (ngrp < 1) {
80624447Speter		/*
80724447Speter		 * setgroups(0, NULL) is a legitimate way of clearing the
80824447Speter		 * groups vector on non-BSD systems (which generally do not
80924447Speter		 * have the egid in the groups[0]).  We risk security holes
81024447Speter		 * when running non-BSD software if we do not do the same.
81124447Speter		 */
81277183Srwatson		newcred->cr_ngroups = 1;
81324447Speter	} else {
81494619Sjhb		bcopy(tempcred->cr_groups, newcred->cr_groups,
81594619Sjhb		    ngrp * sizeof(gid_t));
81677183Srwatson		newcred->cr_ngroups = ngrp;
81724447Speter	}
81831891Ssef	setsugid(p);
81977183Srwatson	p->p_ucred = newcred;
82094619Sjhb	PROC_UNLOCK(p);
82194619Sjhb	crfree(tempcred);
82277183Srwatson	crfree(oldcred);
82394619Sjhb	return (0);
8241541Srgrimes}
8251541Srgrimes
82612221Sbde#ifndef _SYS_SYSPROTO_H_
8271541Srgrimesstruct setreuid_args {
8289238Sache	uid_t	ruid;
8299238Sache	uid_t	euid;
8301541Srgrimes};
83112221Sbde#endif
83282749Sdillon/*
83382749Sdillon * MPSAFE
83482749Sdillon */
8351541Srgrimes/* ARGSUSED */
8361549Srgrimesint
83793580Sjhbsetreuid(register struct thread *td, struct setreuid_args *uap)
8381541Srgrimes{
83983366Sjulian	struct proc *p = td->td_proc;
84077183Srwatson	struct ucred *newcred, *oldcred;
84187218Srwatson	uid_t euid, ruid;
84298417Salfred	struct uidinfo *euip, *ruip;
84387218Srwatson	int error;
8441541Srgrimes
84587218Srwatson	euid = uap->euid;
8469238Sache	ruid = uap->ruid;
84794619Sjhb	newcred = crget();
84898417Salfred	euip = uifind(euid);
84998417Salfred	ruip = uifind(ruid);
85094619Sjhb	PROC_LOCK(p);
85177183Srwatson	oldcred = p->p_ucred;
85277183Srwatson	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
85377183Srwatson	      ruid != oldcred->cr_svuid) ||
85477183Srwatson	     (euid != (uid_t)-1 && euid != oldcred->cr_uid &&
85577183Srwatson	      euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) &&
856132653Scperciva	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) {
85794619Sjhb		PROC_UNLOCK(p);
85898417Salfred		uifree(ruip);
85998417Salfred		uifree(euip);
86094619Sjhb		crfree(newcred);
86194619Sjhb		return (error);
86294619Sjhb	}
86394619Sjhb	crcopy(newcred, oldcred);
86477183Srwatson	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
86598417Salfred		change_euid(newcred, euip);
86631891Ssef		setsugid(p);
86724450Speter	}
86877183Srwatson	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
86998417Salfred		change_ruid(newcred, ruip);
87031891Ssef		setsugid(p);
8718135Sache	}
87277183Srwatson	if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) &&
87377183Srwatson	    newcred->cr_svuid != newcred->cr_uid) {
87477183Srwatson		change_svuid(newcred, newcred->cr_uid);
87531891Ssef		setsugid(p);
87624450Speter	}
87777183Srwatson	p->p_ucred = newcred;
87894619Sjhb	PROC_UNLOCK(p);
87998417Salfred	uifree(ruip);
88098417Salfred	uifree(euip);
88177183Srwatson	crfree(oldcred);
88294619Sjhb	return (0);
8831541Srgrimes}
8841541Srgrimes
88512221Sbde#ifndef _SYS_SYSPROTO_H_
8861541Srgrimesstruct setregid_args {
8879238Sache	gid_t	rgid;
8889238Sache	gid_t	egid;
8891541Srgrimes};
89012221Sbde#endif
89182749Sdillon/*
89282749Sdillon * MPSAFE
89382749Sdillon */
8941541Srgrimes/* ARGSUSED */
8951549Srgrimesint
89693580Sjhbsetregid(register struct thread *td, struct setregid_args *uap)
8971541Srgrimes{
89883366Sjulian	struct proc *p = td->td_proc;
89977183Srwatson	struct ucred *newcred, *oldcred;
90087218Srwatson	gid_t egid, rgid;
90187218Srwatson	int error;
9021541Srgrimes
90387218Srwatson	egid = uap->egid;
9049238Sache	rgid = uap->rgid;
90594619Sjhb	newcred = crget();
90694619Sjhb	PROC_LOCK(p);
90777183Srwatson	oldcred = p->p_ucred;
90877183Srwatson	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
90977183Srwatson	    rgid != oldcred->cr_svgid) ||
91077183Srwatson	     (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] &&
91177183Srwatson	     egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) &&
912132653Scperciva	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) {
91394619Sjhb		PROC_UNLOCK(p);
91494619Sjhb		crfree(newcred);
91594619Sjhb		return (error);
91694619Sjhb	}
91794619Sjhb
91894619Sjhb	crcopy(newcred, oldcred);
91977183Srwatson	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
92077183Srwatson		change_egid(newcred, egid);
92131891Ssef		setsugid(p);
92224450Speter	}
92377183Srwatson	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
92477183Srwatson		change_rgid(newcred, rgid);
92531891Ssef		setsugid(p);
92624450Speter	}
92777183Srwatson	if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) &&
92877183Srwatson	    newcred->cr_svgid != newcred->cr_groups[0]) {
92977183Srwatson		change_svgid(newcred, newcred->cr_groups[0]);
93031891Ssef		setsugid(p);
93124450Speter	}
93277812Sru	p->p_ucred = newcred;
93394619Sjhb	PROC_UNLOCK(p);
93477812Sru	crfree(oldcred);
93594619Sjhb	return (0);
9361541Srgrimes}
9371541Srgrimes
93856115Speter/*
93956115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the
94056115Speter * saved uid is explicit.
94156115Speter */
94256115Speter
94324453Speter#ifndef _SYS_SYSPROTO_H_
94456115Speterstruct setresuid_args {
94556115Speter	uid_t	ruid;
94656115Speter	uid_t	euid;
94756115Speter	uid_t	suid;
94856115Speter};
94956115Speter#endif
95082749Sdillon/*
95182749Sdillon * MPSAFE
95282749Sdillon */
95356115Speter/* ARGSUSED */
95456115Speterint
95593580Sjhbsetresuid(register struct thread *td, struct setresuid_args *uap)
95656115Speter{
95783366Sjulian	struct proc *p = td->td_proc;
95877183Srwatson	struct ucred *newcred, *oldcred;
95987218Srwatson	uid_t euid, ruid, suid;
96098417Salfred	struct uidinfo *euip, *ruip;
96156115Speter	int error;
96256115Speter
96387218Srwatson	euid = uap->euid;
96456115Speter	ruid = uap->ruid;
96556115Speter	suid = uap->suid;
96694619Sjhb	newcred = crget();
96798417Salfred	euip = uifind(euid);
96898417Salfred	ruip = uifind(ruid);
96994619Sjhb	PROC_LOCK(p);
97077183Srwatson	oldcred = p->p_ucred;
97177183Srwatson	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
97277183Srwatson	     ruid != oldcred->cr_svuid &&
97377183Srwatson	      ruid != oldcred->cr_uid) ||
97477183Srwatson	     (euid != (uid_t)-1 && euid != oldcred->cr_ruid &&
97577183Srwatson	    euid != oldcred->cr_svuid &&
97677183Srwatson	      euid != oldcred->cr_uid) ||
97777183Srwatson	     (suid != (uid_t)-1 && suid != oldcred->cr_ruid &&
97877183Srwatson	    suid != oldcred->cr_svuid &&
97977183Srwatson	      suid != oldcred->cr_uid)) &&
980132653Scperciva	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) {
98194619Sjhb		PROC_UNLOCK(p);
98298417Salfred		uifree(ruip);
98398417Salfred		uifree(euip);
98494619Sjhb		crfree(newcred);
98594619Sjhb		return (error);
98694619Sjhb	}
98794619Sjhb
98894619Sjhb	crcopy(newcred, oldcred);
98977183Srwatson	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
99098417Salfred		change_euid(newcred, euip);
99156115Speter		setsugid(p);
99256115Speter	}
99377183Srwatson	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
99498417Salfred		change_ruid(newcred, ruip);
99556115Speter		setsugid(p);
99656115Speter	}
99777183Srwatson	if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) {
99877183Srwatson		change_svuid(newcred, suid);
99956115Speter		setsugid(p);
100056115Speter	}
100177183Srwatson	p->p_ucred = newcred;
100294619Sjhb	PROC_UNLOCK(p);
100398417Salfred	uifree(ruip);
100498417Salfred	uifree(euip);
100577183Srwatson	crfree(oldcred);
100694619Sjhb	return (0);
100756115Speter}
100856115Speter
100956115Speter/*
101056115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the
101156115Speter * saved gid is explicit.
101256115Speter */
101356115Speter
101456115Speter#ifndef _SYS_SYSPROTO_H_
101556115Speterstruct setresgid_args {
101656115Speter	gid_t	rgid;
101756115Speter	gid_t	egid;
101856115Speter	gid_t	sgid;
101956115Speter};
102056115Speter#endif
102187466Srwatson/*
102282749Sdillon * MPSAFE
102382749Sdillon */
102456115Speter/* ARGSUSED */
102556115Speterint
102693580Sjhbsetresgid(register struct thread *td, struct setresgid_args *uap)
102756115Speter{
102883366Sjulian	struct proc *p = td->td_proc;
102977183Srwatson	struct ucred *newcred, *oldcred;
103087218Srwatson	gid_t egid, rgid, sgid;
103156115Speter	int error;
103256115Speter
103387218Srwatson	egid = uap->egid;
103456115Speter	rgid = uap->rgid;
103556115Speter	sgid = uap->sgid;
103694619Sjhb	newcred = crget();
103794619Sjhb	PROC_LOCK(p);
103877183Srwatson	oldcred = p->p_ucred;
103977183Srwatson	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
104077183Srwatson	      rgid != oldcred->cr_svgid &&
104177183Srwatson	      rgid != oldcred->cr_groups[0]) ||
104277183Srwatson	     (egid != (gid_t)-1 && egid != oldcred->cr_rgid &&
104377183Srwatson	      egid != oldcred->cr_svgid &&
104477183Srwatson	      egid != oldcred->cr_groups[0]) ||
104577183Srwatson	     (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid &&
104677183Srwatson	      sgid != oldcred->cr_svgid &&
104777183Srwatson	      sgid != oldcred->cr_groups[0])) &&
1048132653Scperciva	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) {
104994619Sjhb		PROC_UNLOCK(p);
105094619Sjhb		crfree(newcred);
105194619Sjhb		return (error);
105294619Sjhb	}
105394619Sjhb
105494619Sjhb	crcopy(newcred, oldcred);
105577183Srwatson	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
105677183Srwatson		change_egid(newcred, egid);
105756115Speter		setsugid(p);
105856115Speter	}
105977183Srwatson	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
106077183Srwatson		change_rgid(newcred, rgid);
106156115Speter		setsugid(p);
106256115Speter	}
106377183Srwatson	if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) {
106477183Srwatson		change_svgid(newcred, sgid);
106556115Speter		setsugid(p);
106656115Speter	}
106777183Srwatson	p->p_ucred = newcred;
106894619Sjhb	PROC_UNLOCK(p);
106977183Srwatson	crfree(oldcred);
107094619Sjhb	return (0);
107156115Speter}
107256115Speter
107356115Speter#ifndef _SYS_SYSPROTO_H_
107456115Speterstruct getresuid_args {
107556115Speter	uid_t	*ruid;
107656115Speter	uid_t	*euid;
107756115Speter	uid_t	*suid;
107856115Speter};
107956115Speter#endif
108082749Sdillon/*
108182749Sdillon * MPSAFE
108282749Sdillon */
108356115Speter/* ARGSUSED */
108456115Speterint
108593580Sjhbgetresuid(register struct thread *td, struct getresuid_args *uap)
108656115Speter{
108782749Sdillon	struct ucred *cred;
108856115Speter	int error1 = 0, error2 = 0, error3 = 0;
108956115Speter
109093264Sdillon	cred = td->td_ucred;
109156115Speter	if (uap->ruid)
109299009Salfred		error1 = copyout(&cred->cr_ruid,
109399009Salfred		    uap->ruid, sizeof(cred->cr_ruid));
109456115Speter	if (uap->euid)
109599009Salfred		error2 = copyout(&cred->cr_uid,
109699009Salfred		    uap->euid, sizeof(cred->cr_uid));
109756115Speter	if (uap->suid)
109899009Salfred		error3 = copyout(&cred->cr_svuid,
109999009Salfred		    uap->suid, sizeof(cred->cr_svuid));
110087218Srwatson	return (error1 ? error1 : error2 ? error2 : error3);
110156115Speter}
110256115Speter
110356115Speter#ifndef _SYS_SYSPROTO_H_
110456115Speterstruct getresgid_args {
110556115Speter	gid_t	*rgid;
110656115Speter	gid_t	*egid;
110756115Speter	gid_t	*sgid;
110856115Speter};
110956115Speter#endif
111082749Sdillon/*
111182749Sdillon * MPSAFE
111282749Sdillon */
111356115Speter/* ARGSUSED */
111456115Speterint
111593580Sjhbgetresgid(register struct thread *td, struct getresgid_args *uap)
111656115Speter{
111782749Sdillon	struct ucred *cred;
111856115Speter	int error1 = 0, error2 = 0, error3 = 0;
111956115Speter
112093264Sdillon	cred = td->td_ucred;
112156115Speter	if (uap->rgid)
112299009Salfred		error1 = copyout(&cred->cr_rgid,
112399009Salfred		    uap->rgid, sizeof(cred->cr_rgid));
112456115Speter	if (uap->egid)
112599009Salfred		error2 = copyout(&cred->cr_groups[0],
112699009Salfred		    uap->egid, sizeof(cred->cr_groups[0]));
112756115Speter	if (uap->sgid)
112899009Salfred		error3 = copyout(&cred->cr_svgid,
112999009Salfred		    uap->sgid, sizeof(cred->cr_svgid));
113087218Srwatson	return (error1 ? error1 : error2 ? error2 : error3);
113156115Speter}
113256115Speter
113356115Speter#ifndef _SYS_SYSPROTO_H_
113424453Speterstruct issetugid_args {
113524453Speter	int dummy;
113624453Speter};
113724453Speter#endif
113887218Srwatson/*
1139116121Sjhb * MPSAFE
114087218Srwatson */
114124453Speter/* ARGSUSED */
114224453Speterint
114393580Sjhbissetugid(register struct thread *td, struct issetugid_args *uap)
114424453Speter{
114583366Sjulian	struct proc *p = td->td_proc;
114683366Sjulian
114724453Speter	/*
114824453Speter	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
114924453Speter	 * we use P_SUGID because we consider changing the owners as
115024453Speter	 * "tainting" as well.
115124453Speter	 * This is significant for procs that start as root and "become"
115224453Speter	 * a user without an exec - programs cannot know *everything*
115324453Speter	 * that libc *might* have put in their data segment.
115424453Speter	 */
115591140Stanimura	PROC_LOCK(p);
115683366Sjulian	td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
115791140Stanimura	PROC_UNLOCK(p);
115824453Speter	return (0);
115924453Speter}
116024453Speter
116182749Sdillon/*
116282749Sdillon * MPSAFE
116382749Sdillon */
116475426Srwatsonint
116593580Sjhb__setugid(struct thread *td, struct __setugid_args *uap)
116675426Srwatson{
116782749Sdillon#ifdef REGRESSION
116894619Sjhb	struct proc *p;
116975426Srwatson
117094619Sjhb	p = td->td_proc;
117175426Srwatson	switch (uap->flag) {
117275426Srwatson	case 0:
117394619Sjhb		PROC_LOCK(p);
117494619Sjhb		p->p_flag &= ~P_SUGID;
117594619Sjhb		PROC_UNLOCK(p);
117694619Sjhb		return (0);
117775426Srwatson	case 1:
117894619Sjhb		PROC_LOCK(p);
117994619Sjhb		p->p_flag |= P_SUGID;
118094619Sjhb		PROC_UNLOCK(p);
118194619Sjhb		return (0);
118275426Srwatson	default:
118394619Sjhb		return (EINVAL);
118475426Srwatson	}
118575426Srwatson#else /* !REGRESSION */
118687218Srwatson
118775426Srwatson	return (ENOSYS);
118887218Srwatson#endif /* REGRESSION */
118975426Srwatson}
119075426Srwatson
11911541Srgrimes/*
11921541Srgrimes * Check if gid is a member of the group set.
119393264Sdillon *
119493264Sdillon * MPSAFE (cred must be held)
11951541Srgrimes */
11961549Srgrimesint
119793580Sjhbgroupmember(gid_t gid, struct ucred *cred)
11981541Srgrimes{
11991541Srgrimes	register gid_t *gp;
12001541Srgrimes	gid_t *egp;
12011541Srgrimes
12021541Srgrimes	egp = &(cred->cr_groups[cred->cr_ngroups]);
12031541Srgrimes	for (gp = cred->cr_groups; gp < egp; gp++)
12041541Srgrimes		if (*gp == gid)
12051541Srgrimes			return (1);
12061541Srgrimes	return (0);
12071541Srgrimes}
12081541Srgrimes
120982424Srwatson/*
121089414Sarr * `suser_enabled' (which can be set by the security.suser_enabled
121182466Srwatson * sysctl) determines whether the system 'super-user' policy is in effect.
121282466Srwatson * If it is nonzero, an effective uid of 0 connotes special privilege,
121382466Srwatson * overriding many mandatory and discretionary protections.  If it is zero,
121482466Srwatson * uid 0 is offered no special privilege in the kernel security policy.
121582466Srwatson * Setting it to zero may seriously impact the functionality of many
121682466Srwatson * existing userland programs, and should not be done without careful
121782466Srwatson * consideration of the consequences.
121882424Srwatson */
121982693Srwatsonint	suser_enabled = 1;
122089414SarrSYSCTL_INT(_security_bsd, OID_AUTO, suser_enabled, CTLFLAG_RW,
122182693Srwatson    &suser_enabled, 0, "processes with uid 0 have privilege");
122289414SarrTUNABLE_INT("security.bsd.suser_enabled", &suser_enabled);
122361287Srwatson
12241541Srgrimes/*
122582466Srwatson * Test whether the specified credentials imply "super-user" privilege.
1226132255Scperciva * Return 0 or EPERM.
12271541Srgrimes */
12281549Srgrimesint
122993593Sjhbsuser_cred(struct ucred *cred, int flag)
123046112Sphk{
123187218Srwatson
123282693Srwatson	if (!suser_enabled)
123361282Srwatson		return (EPERM);
1234132255Scperciva	if (((flag & SUSER_RUID) ? cred->cr_ruid : cred->cr_uid) != 0)
123546155Sphk		return (EPERM);
1236132653Scperciva	if (jailed(cred) && !(flag & SUSER_ALLOWJAIL))
123746155Sphk		return (EPERM);
123846155Sphk	return (0);
12391541Srgrimes}
12401541Srgrimes
124183639Srwatson/*
124293593Sjhb * Shortcut to hide contents of struct td and struct proc from the
124393593Sjhb * caller, promoting binary compatibility.
124493593Sjhb */
124593593Sjhbint
124693593Sjhbsuser(struct thread *td)
124793593Sjhb{
124893593Sjhb
1249132548Srwatson#ifdef INVARIANTS
1250132548Srwatson	if (td != curthread) {
1251132548Srwatson		printf("suser: thread %p (%d %s) != curthread %p (%d %s)\n",
1252132548Srwatson		    td, td->td_proc->p_pid, td->td_proc->p_comm,
1253132548Srwatson		    curthread, curthread->td_proc->p_pid,
1254132548Srwatson		    curthread->td_proc->p_comm);
1255132548Srwatson#ifdef KDB
1256132548Srwatson		kdb_backtrace();
1257132548Srwatson#endif
1258132548Srwatson	}
1259132548Srwatson#endif
126093593Sjhb	return (suser_cred(td->td_ucred, 0));
126193593Sjhb}
126293593Sjhb
126393593Sjhb/*
126487218Srwatson * Test the active securelevel against a given level.  securelevel_gt()
126587218Srwatson * implements (securelevel > level).  securelevel_ge() implements
126687218Srwatson * (securelevel >= level).  Note that the logic is inverted -- these
126787218Srwatson * functions return EPERM on "success" and 0 on "failure".
126883639Srwatson *
126993264Sdillon * MPSAFE
127083639Srwatson */
127183639Srwatsonint
127283639Srwatsonsecurelevel_gt(struct ucred *cr, int level)
127383639Srwatson{
127487218Srwatson	int active_securelevel;
127583639Srwatson
127687218Srwatson	active_securelevel = securelevel;
127793732Sjhb	KASSERT(cr != NULL, ("securelevel_gt: null cr"));
127887275Srwatson	if (cr->cr_prison != NULL) {
127987275Srwatson		mtx_lock(&cr->cr_prison->pr_mtx);
128087218Srwatson		active_securelevel = imax(cr->cr_prison->pr_securelevel,
128187218Srwatson		    active_securelevel);
128287275Srwatson		mtx_unlock(&cr->cr_prison->pr_mtx);
128387275Srwatson	}
128487218Srwatson	return (active_securelevel > level ? EPERM : 0);
128583639Srwatson}
128683639Srwatson
128783639Srwatsonint
128883639Srwatsonsecurelevel_ge(struct ucred *cr, int level)
128983639Srwatson{
129087218Srwatson	int active_securelevel;
129183639Srwatson
129287218Srwatson	active_securelevel = securelevel;
129393732Sjhb	KASSERT(cr != NULL, ("securelevel_ge: null cr"));
129487275Srwatson	if (cr->cr_prison != NULL) {
129587275Srwatson		mtx_lock(&cr->cr_prison->pr_mtx);
129687218Srwatson		active_securelevel = imax(cr->cr_prison->pr_securelevel,
129787218Srwatson		    active_securelevel);
129887275Srwatson		mtx_unlock(&cr->cr_prison->pr_mtx);
129987275Srwatson	}
130087218Srwatson	return (active_securelevel >= level ? EPERM : 0);
130183639Srwatson}
130283639Srwatson
130384736Srwatson/*
130487144Srwatson * 'see_other_uids' determines whether or not visibility of processes
130587218Srwatson * and sockets with credentials holding different real uids is possible
130687138Srwatson * using a variety of system MIBs.
130787218Srwatson * XXX: data declarations should be together near the beginning of the file.
130884736Srwatson */
130987144Srwatsonstatic int	see_other_uids = 1;
131089414SarrSYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW,
131187218Srwatson    &see_other_uids, 0,
131284736Srwatson    "Unprivileged processes may see subjects/objects with different real uid");
131384736Srwatson
131482466Srwatson/*-
131592923Srwatson * Determine if u1 "can see" the subject specified by u2, according to the
131692923Srwatson * 'see_other_uids' policy.
131792923Srwatson * Returns: 0 for permitted, ESRCH otherwise
131892923Srwatson * Locks: none
131992923Srwatson * References: *u1 and *u2 must not change during the call
132092923Srwatson *             u1 may equal u2, in which case only one reference is required
132192923Srwatson */
132292923Srwatsonstatic int
132392923Srwatsoncr_seeotheruids(struct ucred *u1, struct ucred *u2)
132492923Srwatson{
132592923Srwatson
132692923Srwatson	if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) {
1327132653Scperciva		if (suser_cred(u1, SUSER_ALLOWJAIL) != 0)
132892923Srwatson			return (ESRCH);
132992923Srwatson	}
133092923Srwatson	return (0);
133192923Srwatson}
133292923Srwatson
1333122869Srwatson/*
1334122869Srwatson * 'see_other_gids' determines whether or not visibility of processes
1335122869Srwatson * and sockets with credentials holding different real gids is possible
1336122869Srwatson * using a variety of system MIBs.
1337122869Srwatson * XXX: data declarations should be together near the beginning of the file.
1338122869Srwatson */
1339122869Srwatsonstatic int	see_other_gids = 1;
1340122869SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, see_other_gids, CTLFLAG_RW,
1341122869Srwatson    &see_other_gids, 0,
1342122869Srwatson    "Unprivileged processes may see subjects/objects with different real gid");
1343122869Srwatson
1344122869Srwatson/*
1345122869Srwatson * Determine if u1 can "see" the subject specified by u2, according to the
1346122869Srwatson * 'see_other_gids' policy.
1347122869Srwatson * Returns: 0 for permitted, ESRCH otherwise
1348122869Srwatson * Locks: none
1349122869Srwatson * References: *u1 and *u2 must not change during the call
1350122869Srwatson *             u1 may equal u2, in which case only one reference is required
1351122869Srwatson */
1352122869Srwatsonstatic int
1353122869Srwatsoncr_seeothergids(struct ucred *u1, struct ucred *u2)
1354122869Srwatson{
1355122869Srwatson	int i, match;
1356122869Srwatson
1357122869Srwatson	if (!see_other_gids) {
1358122869Srwatson		match = 0;
1359122869Srwatson		for (i = 0; i < u1->cr_ngroups; i++) {
1360122869Srwatson			if (groupmember(u1->cr_groups[i], u2))
1361122869Srwatson				match = 1;
1362122869Srwatson			if (match)
1363122869Srwatson				break;
1364122869Srwatson		}
1365122869Srwatson		if (!match) {
1366132653Scperciva			if (suser_cred(u1, SUSER_ALLOWJAIL) != 0)
1367122869Srwatson				return (ESRCH);
1368122869Srwatson		}
1369122869Srwatson	}
1370122869Srwatson	return (0);
1371122869Srwatson}
1372122869Srwatson
137392923Srwatson/*-
137482466Srwatson * Determine if u1 "can see" the subject specified by u2.
137574956Srwatson * Returns: 0 for permitted, an errno value otherwise
137674956Srwatson * Locks: none
137787218Srwatson * References: *u1 and *u2 must not change during the call
137874956Srwatson *             u1 may equal u2, in which case only one reference is required
137974956Srwatson */
138074956Srwatsonint
138183742Srwatsoncr_cansee(struct ucred *u1, struct ucred *u2)
138265237Srwatson{
138372786Srwatson	int error;
138453518Sphk
138574956Srwatson	if ((error = prison_check(u1, u2)))
138672786Srwatson		return (error);
1387101003Srwatson#ifdef MAC
1388101003Srwatson	if ((error = mac_check_cred_visible(u1, u2)))
1389101003Srwatson		return (error);
1390101003Srwatson#endif
139192923Srwatson	if ((error = cr_seeotheruids(u1, u2)))
139292923Srwatson		return (error);
1393122869Srwatson	if ((error = cr_seeothergids(u1, u2)))
1394122869Srwatson		return (error);
139565237Srwatson	return (0);
139665237Srwatson}
139765237Srwatson
139882466Srwatson/*-
139996886Sjhb * Determine if td "can see" the subject specified by p.
140082424Srwatson * Returns: 0 for permitted, an errno value otherwise
140196886Sjhb * Locks: Sufficient locks to protect p->p_ucred must be held.  td really
140296886Sjhb *        should be curthread.
140396886Sjhb * References: td and p must be valid for the lifetime of the call
140482424Srwatson */
140579335Srwatsonint
140696886Sjhbp_cansee(struct thread *td, struct proc *p)
140774956Srwatson{
140874956Srwatson
140983742Srwatson	/* Wrap cr_cansee() for all functionality. */
141096886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
141196886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
141296886Sjhb	return (cr_cansee(td->td_ucred, p->p_ucred));
141374956Srwatson}
141474956Srwatson
1415120052Srwatson/*
1416120052Srwatson * 'conservative_signals' prevents the delivery of a broad class of
1417120052Srwatson * signals by unprivileged processes to processes that have changed their
1418120052Srwatson * credentials since the last invocation of execve().  This can prevent
1419120052Srwatson * the leakage of cached information or retained privileges as a result
1420120052Srwatson * of a common class of signal-related vulnerabilities.  However, this
1421120052Srwatson * may interfere with some applications that expect to be able to
1422120052Srwatson * deliver these signals to peer processes after having given up
1423120052Srwatson * privilege.
1424120052Srwatson */
1425120052Srwatsonstatic int	conservative_signals = 1;
1426120052SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, conservative_signals, CTLFLAG_RW,
1427120052Srwatson    &conservative_signals, 0, "Unprivileged processes prevented from "
1428120052Srwatson    "sending certain signals to processes whose credentials have changed");
142982466Srwatson/*-
143088943Srwatson * Determine whether cred may deliver the specified signal to proc.
143188943Srwatson * Returns: 0 for permitted, an errno value otherwise.
143288943Srwatson * Locks: A lock must be held for proc.
143388943Srwatson * References: cred and proc must be valid for the lifetime of the call.
143475437Srwatson */
143575437Srwatsonint
143688943Srwatsoncr_cansignal(struct ucred *cred, struct proc *proc, int signum)
143753518Sphk{
143882466Srwatson	int error;
143984826Sjhb
144096886Sjhb	PROC_LOCK_ASSERT(proc, MA_OWNED);
144175437Srwatson	/*
144288943Srwatson	 * Jail semantics limit the scope of signalling to proc in the
144388943Srwatson	 * same jail as cred, if cred is in jail.
144475437Srwatson	 */
144588943Srwatson	error = prison_check(cred, proc->p_ucred);
144688943Srwatson	if (error)
144772786Srwatson		return (error);
1448101003Srwatson#ifdef MAC
1449101003Srwatson	if ((error = mac_check_proc_signal(cred, proc, signum)))
1450101003Srwatson		return (error);
1451101003Srwatson#endif
1452122869Srwatson	if ((error = cr_seeotheruids(cred, proc->p_ucred)))
145392923Srwatson		return (error);
1454122869Srwatson	if ((error = cr_seeothergids(cred, proc->p_ucred)))
1455122869Srwatson		return (error);
145665237Srwatson
145765237Srwatson	/*
145882424Srwatson	 * UNIX signal semantics depend on the status of the P_SUGID
145982424Srwatson	 * bit on the target process.  If the bit is set, then additional
146082424Srwatson	 * restrictions are placed on the set of available signals.
146175437Srwatson	 */
1462120052Srwatson	if (conservative_signals && (proc->p_flag & P_SUGID)) {
146375437Srwatson		switch (signum) {
146475437Srwatson		case 0:
146575437Srwatson		case SIGKILL:
146675437Srwatson		case SIGINT:
146775437Srwatson		case SIGTERM:
1468120052Srwatson		case SIGALRM:
146975437Srwatson		case SIGSTOP:
147075437Srwatson		case SIGTTIN:
147175437Srwatson		case SIGTTOU:
147275437Srwatson		case SIGTSTP:
147375437Srwatson		case SIGHUP:
147475437Srwatson		case SIGUSR1:
147575437Srwatson		case SIGUSR2:
147682466Srwatson			/*
147782466Srwatson			 * Generally, permit job and terminal control
147882466Srwatson			 * signals.
147982466Srwatson			 */
148075437Srwatson			break;
148175437Srwatson		default:
148288943Srwatson			/* Not permitted without privilege. */
1483132653Scperciva			error = suser_cred(cred, SUSER_ALLOWJAIL);
148475437Srwatson			if (error)
148575437Srwatson				return (error);
148675437Srwatson		}
148765237Srwatson	}
148865237Srwatson
148975480Srwatson	/*
149082424Srwatson	 * Generally, the target credential's ruid or svuid must match the
149175480Srwatson	 * subject credential's ruid or euid.
149275480Srwatson	 */
149388943Srwatson	if (cred->cr_ruid != proc->p_ucred->cr_ruid &&
149488943Srwatson	    cred->cr_ruid != proc->p_ucred->cr_svuid &&
149588943Srwatson	    cred->cr_uid != proc->p_ucred->cr_ruid &&
149688943Srwatson	    cred->cr_uid != proc->p_ucred->cr_svuid) {
149788943Srwatson		/* Not permitted without privilege. */
1498132653Scperciva		error = suser_cred(cred, SUSER_ALLOWJAIL);
149975480Srwatson		if (error)
150075480Srwatson			return (error);
150175480Srwatson	}
150275480Srwatson
150387218Srwatson	return (0);
150453518Sphk}
150553518Sphk
150688943Srwatson
150782466Srwatson/*-
150896886Sjhb * Determine whether td may deliver the specified signal to p.
150988943Srwatson * Returns: 0 for permitted, an errno value otherwise
151096886Sjhb * Locks: Sufficient locks to protect various components of td and p
151196886Sjhb *        must be held.  td must be curthread, and a lock must be
151296886Sjhb *        held for p.
151396886Sjhb * References: td and p must be valid for the lifetime of the call
151488943Srwatson */
151588943Srwatsonint
151696886Sjhbp_cansignal(struct thread *td, struct proc *p, int signum)
151788943Srwatson{
151888943Srwatson
151996886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
152096886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
152196886Sjhb	if (td->td_proc == p)
152288943Srwatson		return (0);
152388943Srwatson
152488943Srwatson	/*
152588943Srwatson	 * UNIX signalling semantics require that processes in the same
152688943Srwatson	 * session always be able to deliver SIGCONT to one another,
152788943Srwatson	 * overriding the remaining protections.
152888943Srwatson	 */
152996886Sjhb	/* XXX: This will require an additional lock of some sort. */
153096886Sjhb	if (signum == SIGCONT && td->td_proc->p_session == p->p_session)
153188943Srwatson		return (0);
153288943Srwatson
153396886Sjhb	return (cr_cansignal(td->td_ucred, p, signum));
153488943Srwatson}
153588943Srwatson
153688943Srwatson/*-
153796886Sjhb * Determine whether td may reschedule p.
153882466Srwatson * Returns: 0 for permitted, an errno value otherwise
153996886Sjhb * Locks: Sufficient locks to protect various components of td and p
154096886Sjhb *        must be held.  td must be curthread, and a lock must
154196886Sjhb *        be held for p.
154296886Sjhb * References: td and p must be valid for the lifetime of the call
154382424Srwatson */
154479335Srwatsonint
154596886Sjhbp_cansched(struct thread *td, struct proc *p)
154665237Srwatson{
154772786Srwatson	int error;
154865237Srwatson
154996886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
155096886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
155196886Sjhb	if (td->td_proc == p)
155265237Srwatson		return (0);
155396886Sjhb	if ((error = prison_check(td->td_ucred, p->p_ucred)))
155472786Srwatson		return (error);
1555101003Srwatson#ifdef MAC
1556101003Srwatson	if ((error = mac_check_proc_sched(td->td_ucred, p)))
1557101003Srwatson		return (error);
1558101003Srwatson#endif
155996886Sjhb	if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred)))
156092923Srwatson		return (error);
1561122869Srwatson	if ((error = cr_seeothergids(td->td_ucred, p->p_ucred)))
1562122869Srwatson		return (error);
156396886Sjhb	if (td->td_ucred->cr_ruid == p->p_ucred->cr_ruid)
156465237Srwatson		return (0);
156596886Sjhb	if (td->td_ucred->cr_uid == p->p_ucred->cr_ruid)
156665237Srwatson		return (0);
1567132653Scperciva	if (suser_cred(td->td_ucred, SUSER_ALLOWJAIL) == 0)
156865237Srwatson		return (0);
156965237Srwatson
157065237Srwatson#ifdef CAPABILITIES
1571132653Scperciva	if (!cap_check(NULL, td, CAP_SYS_NICE, SUSER_ALLOWJAIL))
157265237Srwatson		return (0);
157365237Srwatson#endif
157465237Srwatson
157565237Srwatson	return (EPERM);
157665237Srwatson}
157765237Srwatson
157882424Srwatson/*
157987280Srwatson * The 'unprivileged_proc_debug' flag may be used to disable a variety of
158087280Srwatson * unprivileged inter-process debugging services, including some procfs
158187280Srwatson * functionality, ptrace(), and ktrace().  In the past, inter-process
158287280Srwatson * debugging has been involved in a variety of security problems, and sites
158387280Srwatson * not requiring the service might choose to disable it when hardening
158487280Srwatson * systems.
158582424Srwatson *
158682424Srwatson * XXX: Should modifying and reading this variable require locking?
158787218Srwatson * XXX: data declarations should be together near the beginning of the file.
158882424Srwatson */
158987144Srwatsonstatic int	unprivileged_proc_debug = 1;
159089414SarrSYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW,
159187218Srwatson    &unprivileged_proc_debug, 0,
159280735Srwatson    "Unprivileged processes may use process debugging facilities");
159380735Srwatson
159482466Srwatson/*-
159596886Sjhb * Determine whether td may debug p.
159682466Srwatson * Returns: 0 for permitted, an errno value otherwise
159796886Sjhb * Locks: Sufficient locks to protect various components of td and p
159896886Sjhb *        must be held.  td must be curthread, and a lock must
159996886Sjhb *        be held for p.
160096886Sjhb * References: td and p must be valid for the lifetime of the call
160182424Srwatson */
160279335Srwatsonint
160396886Sjhbp_candebug(struct thread *td, struct proc *p)
160465237Srwatson{
160587218Srwatson	int credentialchanged, error, grpsubset, i, uidsubset;
160665237Srwatson
160796886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
160896886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
160987144Srwatson	if (!unprivileged_proc_debug) {
1610132653Scperciva		error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL);
161184727Srwatson		if (error)
161284727Srwatson			return (error);
161384727Srwatson	}
161496886Sjhb	if (td->td_proc == p)
161584636Sdes		return (0);
161696886Sjhb	if ((error = prison_check(td->td_ucred, p->p_ucred)))
161772786Srwatson		return (error);
1618101003Srwatson#ifdef MAC
1619101003Srwatson	if ((error = mac_check_proc_debug(td->td_ucred, p)))
1620101003Srwatson		return (error);
1621101003Srwatson#endif
162296886Sjhb	if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred)))
162392923Srwatson		return (error);
1624122869Srwatson	if ((error = cr_seeothergids(td->td_ucred, p->p_ucred)))
1625122869Srwatson		return (error);
162665237Srwatson
162782466Srwatson	/*
162896886Sjhb	 * Is p's group set a subset of td's effective group set?  This
162996886Sjhb	 * includes p's egid, group access list, rgid, and svgid.
163082466Srwatson	 */
163185895Srwatson	grpsubset = 1;
163296886Sjhb	for (i = 0; i < p->p_ucred->cr_ngroups; i++) {
163396886Sjhb		if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) {
163485895Srwatson			grpsubset = 0;
163585895Srwatson			break;
163685895Srwatson		}
163785895Srwatson	}
163885895Srwatson	grpsubset = grpsubset &&
163996886Sjhb	    groupmember(p->p_ucred->cr_rgid, td->td_ucred) &&
164096886Sjhb	    groupmember(p->p_ucred->cr_svgid, td->td_ucred);
164185895Srwatson
164285895Srwatson	/*
164396886Sjhb	 * Are the uids present in p's credential equal to td's
164496886Sjhb	 * effective uid?  This includes p's euid, svuid, and ruid.
164585895Srwatson	 */
164696886Sjhb	uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid &&
164796886Sjhb	    td->td_ucred->cr_uid == p->p_ucred->cr_svuid &&
164896886Sjhb	    td->td_ucred->cr_uid == p->p_ucred->cr_ruid);
164985895Srwatson
165085895Srwatson	/*
165185895Srwatson	 * Has the credential of the process changed since the last exec()?
165285895Srwatson	 */
165396886Sjhb	credentialchanged = (p->p_flag & P_SUGID);
165485895Srwatson
165585895Srwatson	/*
165696886Sjhb	 * If p's gids aren't a subset, or the uids aren't a subset,
165785895Srwatson	 * or the credential has changed, require appropriate privilege
165896886Sjhb	 * for td to debug p.  For POSIX.1e capabilities, this will
165985895Srwatson	 * require CAP_SYS_PTRACE.
166085895Srwatson	 */
166185895Srwatson	if (!grpsubset || !uidsubset || credentialchanged) {
1662132653Scperciva		error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL);
166384727Srwatson		if (error)
166465237Srwatson			return (error);
166582466Srwatson	}
166665237Srwatson
166787218Srwatson	/* Can't trace init when securelevel > 0. */
166896886Sjhb	if (p == initproc) {
166996886Sjhb		error = securelevel_gt(td->td_ucred, 0);
167083639Srwatson		if (error)
167183639Srwatson			return (error);
167283639Srwatson	}
167365237Srwatson
167485880Srwatson	/*
167585880Srwatson	 * Can't trace a process that's currently exec'ing.
167685880Srwatson	 * XXX: Note, this is not a security policy decision, it's a
167785880Srwatson	 * basic correctness/functionality decision.  Therefore, this check
167885880Srwatson	 * should be moved to the caller's of p_candebug().
167985880Srwatson	 */
168096886Sjhb	if ((p->p_flag & P_INEXEC) != 0)
168185598Sdes		return (EAGAIN);
168287466Srwatson
168365237Srwatson	return (0);
168465237Srwatson}
168565237Srwatson
168692976Srwatson/*-
168792976Srwatson * Determine whether the subject represented by cred can "see" a socket.
168892976Srwatson * Returns: 0 for permitted, ENOENT otherwise.
168992976Srwatson */
169092976Srwatsonint
169192976Srwatsoncr_canseesocket(struct ucred *cred, struct socket *so)
169292976Srwatson{
169392976Srwatson	int error;
169492976Srwatson
169592976Srwatson	error = prison_check(cred, so->so_cred);
169692976Srwatson	if (error)
169792976Srwatson		return (ENOENT);
1698101003Srwatson#ifdef MAC
1699130398Srwatson	SOCK_LOCK(so);
1700101003Srwatson	error = mac_check_socket_visible(cred, so);
1701130398Srwatson	SOCK_UNLOCK(so);
1702101003Srwatson	if (error)
1703101003Srwatson		return (error);
1704101003Srwatson#endif
170592976Srwatson	if (cr_seeotheruids(cred, so->so_cred))
170692976Srwatson		return (ENOENT);
1707122869Srwatson	if (cr_seeothergids(cred, so->so_cred))
1708122869Srwatson		return (ENOENT);
170992976Srwatson
171092976Srwatson	return (0);
171192976Srwatson}
171292976Srwatson
171353518Sphk/*
17141541Srgrimes * Allocate a zeroed cred structure.
1715116406Srwatson * MPSAFE
17161541Srgrimes */
17171541Srgrimesstruct ucred *
171893580Sjhbcrget(void)
17191541Srgrimes{
17201541Srgrimes	register struct ucred *cr;
17211541Srgrimes
1722111119Simp	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK | M_ZERO);
17231541Srgrimes	cr->cr_ref = 1;
1724117494Struckman	cr->cr_mtxp = mtx_pool_find(mtxpool_sleep, cr);
1725101001Srwatson#ifdef MAC
1726101001Srwatson	mac_init_cred(cr);
1727101001Srwatson#endif
17281541Srgrimes	return (cr);
17291541Srgrimes}
17301541Srgrimes
17311541Srgrimes/*
173282466Srwatson * Claim another reference to a ucred structure.
1733116406Srwatson * MPSAFE
173469401Salfred */
173584827Sjhbstruct ucred *
173693580Sjhbcrhold(struct ucred *cr)
173769401Salfred{
173869401Salfred
173990756Sdillon	mtx_lock(cr->cr_mtxp);
174069401Salfred	cr->cr_ref++;
174190756Sdillon	mtx_unlock(cr->cr_mtxp);
174284827Sjhb	return (cr);
174369401Salfred}
174469401Salfred
174569401Salfred/*
17461541Srgrimes * Free a cred structure.
17471541Srgrimes * Throws away space when ref count gets to 0.
1748116406Srwatson * MPSAFE
17491541Srgrimes */
17501549Srgrimesvoid
175193580Sjhbcrfree(struct ucred *cr)
17521541Srgrimes{
175390756Sdillon	struct mtx *mtxp = cr->cr_mtxp;
175469239Salfred
175590756Sdillon	mtx_lock(mtxp);
175675632Salfred	KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref));
175765495Struckman	if (--cr->cr_ref == 0) {
1758124884Srwatson		mtx_unlock(mtxp);
175965495Struckman		/*
176065495Struckman		 * Some callers of crget(), such as nfs_statfs(),
176165495Struckman		 * allocate a temporary credential, but don't
176265495Struckman		 * allocate a uidinfo structure.
176365495Struckman		 */
176465495Struckman		if (cr->cr_uidinfo != NULL)
176565495Struckman			uifree(cr->cr_uidinfo);
176677277Srwatson		if (cr->cr_ruidinfo != NULL)
176777277Srwatson			uifree(cr->cr_ruidinfo);
176872786Srwatson		/*
176972786Srwatson		 * Free a prison, if any.
177072786Srwatson		 */
177172786Srwatson		if (jailed(cr))
177272786Srwatson			prison_free(cr->cr_prison);
1773101001Srwatson#ifdef MAC
1774101001Srwatson		mac_destroy_cred(cr);
1775101001Srwatson#endif
177699009Salfred		FREE(cr, M_CRED);
177790756Sdillon	} else {
177890756Sdillon		mtx_unlock(mtxp);
177990756Sdillon	}
17801541Srgrimes}
17811541Srgrimes
17821541Srgrimes/*
178384827Sjhb * Check to see if this ucred is shared.
1784116406Srwatson * MPSAFE
17851541Srgrimes */
178684827Sjhbint
178793580Sjhbcrshared(struct ucred *cr)
17881541Srgrimes{
178984827Sjhb	int shared;
17901541Srgrimes
179190756Sdillon	mtx_lock(cr->cr_mtxp);
179284827Sjhb	shared = (cr->cr_ref > 1);
179390756Sdillon	mtx_unlock(cr->cr_mtxp);
179484827Sjhb	return (shared);
17951541Srgrimes}
17961541Srgrimes
17971541Srgrimes/*
179884827Sjhb * Copy a ucred's contents from a template.  Does not block.
1799116406Srwatson * MPSAFE
180084827Sjhb */
180184827Sjhbvoid
180293580Sjhbcrcopy(struct ucred *dest, struct ucred *src)
180384827Sjhb{
180484827Sjhb
180584827Sjhb	KASSERT(crshared(dest) == 0, ("crcopy of shared ucred"));
180684827Sjhb	bcopy(&src->cr_startcopy, &dest->cr_startcopy,
180787218Srwatson	    (unsigned)((caddr_t)&src->cr_endcopy -
180884827Sjhb		(caddr_t)&src->cr_startcopy));
180984827Sjhb	uihold(dest->cr_uidinfo);
181084827Sjhb	uihold(dest->cr_ruidinfo);
181184827Sjhb	if (jailed(dest))
181284827Sjhb		prison_hold(dest->cr_prison);
1813101001Srwatson#ifdef MAC
1814123173Srwatson	mac_copy_cred(src, dest);
1815101001Srwatson#endif
181684827Sjhb}
181784827Sjhb
181884827Sjhb/*
18191541Srgrimes * Dup cred struct to a new held one.
1820116406Srwatson * MPSAFE
18211541Srgrimes */
18221541Srgrimesstruct ucred *
182393580Sjhbcrdup(struct ucred *cr)
18241541Srgrimes{
18251541Srgrimes	struct ucred *newcr;
18261541Srgrimes
182784827Sjhb	newcr = crget();
182884827Sjhb	crcopy(newcr, cr);
18291541Srgrimes	return (newcr);
18301541Srgrimes}
18311541Srgrimes
18321541Srgrimes/*
183391354Sdd * Fill in a struct xucred based on a struct ucred.
1834116406Srwatson * MPSAFE
183591354Sdd */
183691354Sddvoid
183793580Sjhbcru2x(struct ucred *cr, struct xucred *xcr)
183891354Sdd{
183991354Sdd
184091354Sdd	bzero(xcr, sizeof(*xcr));
184191354Sdd	xcr->cr_version = XUCRED_VERSION;
184291354Sdd	xcr->cr_uid = cr->cr_uid;
184391354Sdd	xcr->cr_ngroups = cr->cr_ngroups;
184491354Sdd	bcopy(cr->cr_groups, xcr->cr_groups, sizeof(cr->cr_groups));
184591354Sdd}
184691354Sdd
184791354Sdd/*
184890748Sjulian * small routine to swap a thread's current ucred for the correct one
184990748Sjulian * taken from the process.
1850116406Srwatson * MPSAFE
185190748Sjulian */
185290748Sjulianvoid
185390748Sjuliancred_update_thread(struct thread *td)
185490748Sjulian{
185590748Sjulian	struct proc *p;
185691405Sjhb	struct ucred *cred;
185790748Sjulian
185890748Sjulian	p = td->td_proc;
185991405Sjhb	cred = td->td_ucred;
186090748Sjulian	PROC_LOCK(p);
186190748Sjulian	td->td_ucred = crhold(p->p_ucred);
186290748Sjulian	PROC_UNLOCK(p);
186391405Sjhb	if (cred != NULL)
186491405Sjhb		crfree(cred);
186590748Sjulian}
186690748Sjulian
186790748Sjulian/*
18681541Srgrimes * Get login name, if available.
18691541Srgrimes */
187012221Sbde#ifndef _SYS_SYSPROTO_H_
18711541Srgrimesstruct getlogin_args {
18721541Srgrimes	char	*namebuf;
18731541Srgrimes	u_int	namelen;
18741541Srgrimes};
187512221Sbde#endif
187682749Sdillon/*
187782749Sdillon * MPSAFE
187882749Sdillon */
18791541Srgrimes/* ARGSUSED */
18801549Srgrimesint
188193580Sjhbgetlogin(struct thread *td, struct getlogin_args *uap)
18821541Srgrimes{
188382749Sdillon	int error;
188491140Stanimura	char login[MAXLOGNAME];
188583366Sjulian	struct proc *p = td->td_proc;
18861541Srgrimes
188723358Sache	if (uap->namelen > MAXLOGNAME)
188823359Sache		uap->namelen = MAXLOGNAME;
188991140Stanimura	PROC_LOCK(p);
189091140Stanimura	SESS_LOCK(p->p_session);
189191140Stanimura	bcopy(p->p_session->s_login, login, uap->namelen);
189291140Stanimura	SESS_UNLOCK(p->p_session);
189391140Stanimura	PROC_UNLOCK(p);
189499009Salfred	error = copyout(login, uap->namebuf, uap->namelen);
189582749Sdillon	return(error);
18961541Srgrimes}
18971541Srgrimes
18981541Srgrimes/*
18991541Srgrimes * Set login name.
19001541Srgrimes */
190112221Sbde#ifndef _SYS_SYSPROTO_H_
19021541Srgrimesstruct setlogin_args {
19031541Srgrimes	char	*namebuf;
19041541Srgrimes};
190512221Sbde#endif
190682749Sdillon/*
190782749Sdillon * MPSAFE
190882749Sdillon */
19091541Srgrimes/* ARGSUSED */
19101549Srgrimesint
191193580Sjhbsetlogin(struct thread *td, struct setlogin_args *uap)
19121541Srgrimes{
191383366Sjulian	struct proc *p = td->td_proc;
19141541Srgrimes	int error;
191523330Sache	char logintmp[MAXLOGNAME];
19161541Srgrimes
1917132653Scperciva	error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL);
191894619Sjhb	if (error)
191994619Sjhb		return (error);
192099009Salfred	error = copyinstr(uap->namebuf, logintmp, sizeof(logintmp), NULL);
192187218Srwatson	if (error == ENAMETOOLONG)
19221541Srgrimes		error = EINVAL;
192391140Stanimura	else if (!error) {
192491140Stanimura		PROC_LOCK(p);
192591140Stanimura		SESS_LOCK(p->p_session);
192691140Stanimura		(void) memcpy(p->p_session->s_login, logintmp,
192723330Sache		    sizeof(logintmp));
192891140Stanimura		SESS_UNLOCK(p->p_session);
192991140Stanimura		PROC_UNLOCK(p);
193091140Stanimura	}
19311541Srgrimes	return (error);
19321541Srgrimes}
193331891Ssef
193431891Ssefvoid
193593580Sjhbsetsugid(struct proc *p)
193631891Ssef{
193798403Salfred
193898403Salfred	PROC_LOCK_ASSERT(p, MA_OWNED);
193931891Ssef	p->p_flag |= P_SUGID;
194055707Ssef	if (!(p->p_pfsflags & PF_ISUGID))
194131891Ssef		p->p_stops = 0;
194231891Ssef}
194365495Struckman
194482466Srwatson/*-
194582466Srwatson * Change a process's effective uid.
194677183Srwatson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified.
194777183Srwatson * References: newcred must be an exclusive credential reference for the
194877183Srwatson *             duration of the call.
194965495Struckman */
195065495Struckmanvoid
195198417Salfredchange_euid(struct ucred *newcred, struct uidinfo *euip)
195265495Struckman{
195365495Struckman
195498417Salfred	newcred->cr_uid = euip->ui_uid;
195598417Salfred	uihold(euip);
195677183Srwatson	uifree(newcred->cr_uidinfo);
195798417Salfred	newcred->cr_uidinfo = euip;
195865495Struckman}
195965495Struckman
196082466Srwatson/*-
196182466Srwatson * Change a process's effective gid.
196277183Srwatson * Side effects: newcred->cr_gid will be modified.
196377183Srwatson * References: newcred must be an exclusive credential reference for the
196477183Srwatson *             duration of the call.
196565495Struckman */
196667629Sgallatinvoid
196793580Sjhbchange_egid(struct ucred *newcred, gid_t egid)
196865495Struckman{
196965495Struckman
197077183Srwatson	newcred->cr_groups[0] = egid;
197165495Struckman}
197277183Srwatson
197382466Srwatson/*-
197482466Srwatson * Change a process's real uid.
197577183Srwatson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo
197677183Srwatson *               will be updated, and the old and new cr_ruidinfo proc
197777183Srwatson *               counts will be updated.
197877183Srwatson * References: newcred must be an exclusive credential reference for the
197977183Srwatson *             duration of the call.
198077183Srwatson */
198177183Srwatsonvoid
198298417Salfredchange_ruid(struct ucred *newcred, struct uidinfo *ruip)
198377183Srwatson{
198477183Srwatson
198577183Srwatson	(void)chgproccnt(newcred->cr_ruidinfo, -1, 0);
198698417Salfred	newcred->cr_ruid = ruip->ui_uid;
198798417Salfred	uihold(ruip);
198877183Srwatson	uifree(newcred->cr_ruidinfo);
198998417Salfred	newcred->cr_ruidinfo = ruip;
199077183Srwatson	(void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
199177183Srwatson}
199277183Srwatson
199382466Srwatson/*-
199482466Srwatson * Change a process's real gid.
199577183Srwatson * Side effects: newcred->cr_rgid will be updated.
199677183Srwatson * References: newcred must be an exclusive credential reference for the
199777183Srwatson *             duration of the call.
199877183Srwatson */
199977183Srwatsonvoid
200093580Sjhbchange_rgid(struct ucred *newcred, gid_t rgid)
200177183Srwatson{
200277183Srwatson
200377183Srwatson	newcred->cr_rgid = rgid;
200477183Srwatson}
200577183Srwatson
200682466Srwatson/*-
200782466Srwatson * Change a process's saved uid.
200877183Srwatson * Side effects: newcred->cr_svuid will be updated.
200977183Srwatson * References: newcred must be an exclusive credential reference for the
201077183Srwatson *             duration of the call.
201177183Srwatson */
201277183Srwatsonvoid
201393580Sjhbchange_svuid(struct ucred *newcred, uid_t svuid)
201477183Srwatson{
201577183Srwatson
201677183Srwatson	newcred->cr_svuid = svuid;
201777183Srwatson}
201877183Srwatson
201982466Srwatson/*-
202082466Srwatson * Change a process's saved gid.
202177183Srwatson * Side effects: newcred->cr_svgid will be updated.
202277183Srwatson * References: newcred must be an exclusive credential reference for the
202377183Srwatson *             duration of the call.
202477183Srwatson */
202577183Srwatsonvoid
202693580Sjhbchange_svgid(struct ucred *newcred, gid_t svgid)
202777183Srwatson{
202877183Srwatson
202977183Srwatson	newcred->cr_svgid = svgid;
203077183Srwatson}
2031