1139804Simp/*-
21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
3165897Srwatson *	The Regents of the University of California.
41541Srgrimes * (c) UNIX System Laboratories, Inc.
5165897Srwatson * Copyright (c) 2000-2001 Robert N. M. Watson.
6165897Srwatson * All rights reserved.
7165897Srwatson *
81541Srgrimes * All or some portions of this file are derived from material licensed
91541Srgrimes * to the University of California by American Telephone and Telegraph
101541Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with
111541Srgrimes * the permission of UNIX System Laboratories, Inc.
121541Srgrimes *
131541Srgrimes * Redistribution and use in source and binary forms, with or without
141541Srgrimes * modification, are permitted provided that the following conditions
151541Srgrimes * are met:
161541Srgrimes * 1. Redistributions of source code must retain the above copyright
171541Srgrimes *    notice, this list of conditions and the following disclaimer.
181541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
191541Srgrimes *    notice, this list of conditions and the following disclaimer in the
201541Srgrimes *    documentation and/or other materials provided with the distribution.
211541Srgrimes * 4. Neither the name of the University nor the names of its contributors
221541Srgrimes *    may be used to endorse or promote products derived from this software
231541Srgrimes *    without specific prior written permission.
241541Srgrimes *
251541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
261541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
271541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
281541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
291541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
301541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
311541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
321541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
331541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
341541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
351541Srgrimes * SUCH DAMAGE.
361541Srgrimes *
371541Srgrimes *	@(#)kern_prot.c	8.6 (Berkeley) 1/21/94
381541Srgrimes */
391541Srgrimes
401541Srgrimes/*
411541Srgrimes * System calls related to processes and protection
421541Srgrimes */
431541Srgrimes
44116182Sobrien#include <sys/cdefs.h>
45116182Sobrien__FBSDID("$FreeBSD: stable/11/sys/kern/kern_prot.c 335536 2018-06-22 09:18:38Z avg $");
46116182Sobrien
4731778Seivind#include "opt_compat.h"
48183982Sbz#include "opt_inet.h"
49183982Sbz#include "opt_inet6.h"
5031778Seivind
511541Srgrimes#include <sys/param.h>
5276166Smarkm#include <sys/systm.h>
531541Srgrimes#include <sys/acct.h>
54132548Srwatson#include <sys/kdb.h>
5541059Speter#include <sys/kernel.h>
5670317Sjake#include <sys/lock.h>
57219304Strasz#include <sys/loginclass.h>
5891140Stanimura#include <sys/malloc.h>
5976166Smarkm#include <sys/mutex.h>
60150634Sjhb#include <sys/refcount.h>
6191140Stanimura#include <sys/sx.h>
62164032Srwatson#include <sys/priv.h>
631541Srgrimes#include <sys/proc.h>
6476166Smarkm#include <sys/sysproto.h>
6587218Srwatson#include <sys/jail.h>
6631891Ssef#include <sys/pioctl.h>
67220212Strasz#include <sys/racct.h>
68335536Savg#include <sys/rctl.h>
6965495Struckman#include <sys/resourcevar.h>
7092976Srwatson#include <sys/socket.h>
7192976Srwatson#include <sys/socketvar.h>
72160139Sjhb#include <sys/syscallsubr.h>
7361287Srwatson#include <sys/sysctl.h>
741541Srgrimes
75219028Snetchild#ifdef REGRESSION
76219028SnetchildFEATURE(regression,
77229818Shrs    "Kernel support for interfaces necessary for regression testing (SECURITY RISK!)");
78219028Snetchild#endif
79219028Snetchild
80183982Sbz#if defined(INET) || defined(INET6)
81183982Sbz#include <netinet/in.h>
82183982Sbz#include <netinet/in_pcb.h>
83183982Sbz#endif
84183982Sbz
85155370Swsalamon#include <security/audit/audit.h>
86163606Srwatson#include <security/mac/mac_framework.h>
87155370Swsalamon
8830354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials");
8930354Sphk
90162383SrwatsonSYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0, "BSD security policy");
9187138Srwatson
92194498Sbrooksstatic void crsetgroups_locked(struct ucred *cr, int ngrp,
93194498Sbrooks    gid_t *groups);
94194498Sbrooks
9512221Sbde#ifndef _SYS_SYSPROTO_H_
9611332Sswallacestruct getpid_args {
971541Srgrimes	int	dummy;
981541Srgrimes};
9912221Sbde#endif
1001541Srgrimes/* ARGSUSED */
1011549Srgrimesint
102225617Skmacysys_getpid(struct thread *td, struct getpid_args *uap)
1031541Srgrimes{
10483366Sjulian	struct proc *p = td->td_proc;
1051541Srgrimes
10683366Sjulian	td->td_retval[0] = p->p_pid;
107130344Sphk#if defined(COMPAT_43)
108270444Smjg	td->td_retval[1] = kern_getppid(td);
1091541Srgrimes#endif
1101541Srgrimes	return (0);
1111541Srgrimes}
1121541Srgrimes
11312221Sbde#ifndef _SYS_SYSPROTO_H_
11411332Sswallacestruct getppid_args {
11511332Sswallace        int     dummy;
11611332Sswallace};
11712221Sbde#endif
1181541Srgrimes/* ARGSUSED */
1191549Srgrimesint
120225617Skmacysys_getppid(struct thread *td, struct getppid_args *uap)
1211541Srgrimes{
122270444Smjg
123270444Smjg	td->td_retval[0] = kern_getppid(td);
124270444Smjg	return (0);
125270444Smjg}
126270444Smjg
127270444Smjgint
128270444Smjgkern_getppid(struct thread *td)
129270444Smjg{
13083366Sjulian	struct proc *p = td->td_proc;
131270444Smjg	struct proc *pp;
132270444Smjg	int ppid;
1331541Srgrimes
13474728Sjhb	PROC_LOCK(p);
135270444Smjg	if (!(p->p_flag & P_TRACED)) {
136270444Smjg		ppid = p->p_pptr->p_pid;
137270444Smjg		PROC_UNLOCK(p);
138270444Smjg	} else {
139270444Smjg		PROC_UNLOCK(p);
140270444Smjg		sx_slock(&proctree_lock);
141270444Smjg		pp = proc_realparent(p);
142270444Smjg		ppid = pp->p_pid;
143270444Smjg		sx_sunlock(&proctree_lock);
144270444Smjg	}
145270444Smjg
146270444Smjg	return (ppid);
1471541Srgrimes}
1481541Srgrimes
14987466Srwatson/*
15087218Srwatson * Get process group ID; note that POSIX getpgrp takes no parameter.
15158717Sdillon */
15212221Sbde#ifndef _SYS_SYSPROTO_H_
15311332Sswallacestruct getpgrp_args {
15411332Sswallace        int     dummy;
15511332Sswallace};
15612221Sbde#endif
1571549Srgrimesint
158225617Skmacysys_getpgrp(struct thread *td, struct getpgrp_args *uap)
1591541Srgrimes{
16083366Sjulian	struct proc *p = td->td_proc;
1611541Srgrimes
16291140Stanimura	PROC_LOCK(p);
16383366Sjulian	td->td_retval[0] = p->p_pgrp->pg_id;
16491140Stanimura	PROC_UNLOCK(p);
1651541Srgrimes	return (0);
1661541Srgrimes}
1671541Srgrimes
168298819Spfg/* Get an arbitrary pid's process group id */
16912221Sbde#ifndef _SYS_SYSPROTO_H_
17028401Speterstruct getpgid_args {
17128401Speter	pid_t	pid;
17228401Speter};
17328401Speter#endif
17428401Speterint
175225617Skmacysys_getpgid(struct thread *td, struct getpgid_args *uap)
17628401Speter{
177114031Sjhb	struct proc *p;
17892985Sjhb	int error;
17941726Struckman
18091140Stanimura	if (uap->pid == 0) {
181114031Sjhb		p = td->td_proc;
18291140Stanimura		PROC_LOCK(p);
183114031Sjhb	} else {
184114031Sjhb		p = pfind(uap->pid);
185114031Sjhb		if (p == NULL)
186114031Sjhb			return (ESRCH);
187114031Sjhb		error = p_cansee(td, p);
188114031Sjhb		if (error) {
189114031Sjhb			PROC_UNLOCK(p);
190114031Sjhb			return (error);
191114031Sjhb		}
19275893Sjhb	}
193114031Sjhb	td->td_retval[0] = p->p_pgrp->pg_id;
194114031Sjhb	PROC_UNLOCK(p);
195114031Sjhb	return (0);
19628401Speter}
19728401Speter
19828401Speter/*
199298819Spfg * Get an arbitrary pid's session id.
20028401Speter */
20128401Speter#ifndef _SYS_SYSPROTO_H_
20228401Speterstruct getsid_args {
20328401Speter	pid_t	pid;
20428401Speter};
20528401Speter#endif
20628401Speterint
207225617Skmacysys_getsid(struct thread *td, struct getsid_args *uap)
20828401Speter{
209114031Sjhb	struct proc *p;
21087218Srwatson	int error;
21141726Struckman
21291140Stanimura	if (uap->pid == 0) {
213114031Sjhb		p = td->td_proc;
21491140Stanimura		PROC_LOCK(p);
215114031Sjhb	} else {
216114031Sjhb		p = pfind(uap->pid);
217114031Sjhb		if (p == NULL)
218114031Sjhb			return (ESRCH);
219114031Sjhb		error = p_cansee(td, p);
220114031Sjhb		if (error) {
221114031Sjhb			PROC_UNLOCK(p);
222114031Sjhb			return (error);
223114031Sjhb		}
22475893Sjhb	}
225114031Sjhb	td->td_retval[0] = p->p_session->s_sid;
226114031Sjhb	PROC_UNLOCK(p);
227114031Sjhb	return (0);
22828401Speter}
22928401Speter
23028401Speter#ifndef _SYS_SYSPROTO_H_
23111332Sswallacestruct getuid_args {
23211332Sswallace        int     dummy;
23311332Sswallace};
23412221Sbde#endif
2351541Srgrimes/* ARGSUSED */
2361549Srgrimesint
237225617Skmacysys_getuid(struct thread *td, struct getuid_args *uap)
2381541Srgrimes{
2391541Srgrimes
24092987Sjhb	td->td_retval[0] = td->td_ucred->cr_ruid;
241130344Sphk#if defined(COMPAT_43)
24292987Sjhb	td->td_retval[1] = td->td_ucred->cr_uid;
2431541Srgrimes#endif
2441541Srgrimes	return (0);
2451541Srgrimes}
2461541Srgrimes
24712221Sbde#ifndef _SYS_SYSPROTO_H_
24811332Sswallacestruct geteuid_args {
24911332Sswallace        int     dummy;
25011332Sswallace};
25112221Sbde#endif
2521541Srgrimes/* ARGSUSED */
2531549Srgrimesint
254225617Skmacysys_geteuid(struct thread *td, struct geteuid_args *uap)
2551541Srgrimes{
25692987Sjhb
25792987Sjhb	td->td_retval[0] = td->td_ucred->cr_uid;
2581541Srgrimes	return (0);
2591541Srgrimes}
2601541Srgrimes
26112221Sbde#ifndef _SYS_SYSPROTO_H_
26211332Sswallacestruct getgid_args {
26311332Sswallace        int     dummy;
26411332Sswallace};
26512221Sbde#endif
2661541Srgrimes/* ARGSUSED */
2671549Srgrimesint
268225617Skmacysys_getgid(struct thread *td, struct getgid_args *uap)
2691541Srgrimes{
2701541Srgrimes
27192987Sjhb	td->td_retval[0] = td->td_ucred->cr_rgid;
272130344Sphk#if defined(COMPAT_43)
27392987Sjhb	td->td_retval[1] = td->td_ucred->cr_groups[0];
2741541Srgrimes#endif
2751541Srgrimes	return (0);
2761541Srgrimes}
2771541Srgrimes
2781541Srgrimes/*
2791541Srgrimes * Get effective group ID.  The "egid" is groups[0], and could be obtained
2801541Srgrimes * via getgroups.  This syscall exists because it is somewhat painful to do
2811541Srgrimes * correctly in a library function.
2821541Srgrimes */
28312221Sbde#ifndef _SYS_SYSPROTO_H_
28411332Sswallacestruct getegid_args {
28511332Sswallace        int     dummy;
28611332Sswallace};
28712221Sbde#endif
2881541Srgrimes/* ARGSUSED */
2891549Srgrimesint
290225617Skmacysys_getegid(struct thread *td, struct getegid_args *uap)
2911541Srgrimes{
2921541Srgrimes
29392987Sjhb	td->td_retval[0] = td->td_ucred->cr_groups[0];
2941541Srgrimes	return (0);
2951541Srgrimes}
2961541Srgrimes
29712221Sbde#ifndef _SYS_SYSPROTO_H_
2981541Srgrimesstruct getgroups_args {
2991541Srgrimes	u_int	gidsetsize;
3001541Srgrimes	gid_t	*gidset;
3011541Srgrimes};
30212221Sbde#endif
3031549Srgrimesint
304331643Sdimsys_getgroups(struct thread *td, struct getgroups_args *uap)
3051541Srgrimes{
306273436Smjg	struct ucred *cred;
30777183Srwatson	u_int ngrp;
30887218Srwatson	int error;
3091541Srgrimes
310273436Smjg	cred = td->td_ucred;
311273436Smjg	ngrp = cred->cr_ngroups;
312273436Smjg
313273436Smjg	if (uap->gidsetsize == 0) {
314273436Smjg		error = 0;
315194498Sbrooks		goto out;
316273436Smjg	}
317273436Smjg	if (uap->gidsetsize < ngrp)
318273436Smjg		return (EINVAL);
319273436Smjg
320273436Smjg	error = copyout(cred->cr_groups, uap->gidset, ngrp * sizeof(gid_t));
321194498Sbrooksout:
322273436Smjg	td->td_retval[0] = ngrp;
323160139Sjhb	return (error);
324160139Sjhb}
325160139Sjhb
32612221Sbde#ifndef _SYS_SYSPROTO_H_
32712207Sbdestruct setsid_args {
32811332Sswallace        int     dummy;
32911332Sswallace};
33012221Sbde#endif
3311541Srgrimes/* ARGSUSED */
3321549Srgrimesint
333331643Sdimsys_setsid(struct thread *td, struct setsid_args *uap)
3341541Srgrimes{
33591140Stanimura	struct pgrp *pgrp;
33682749Sdillon	int error;
33783366Sjulian	struct proc *p = td->td_proc;
33891140Stanimura	struct pgrp *newpgrp;
33991140Stanimura	struct session *newsess;
3401541Srgrimes
34191140Stanimura	error = 0;
34291140Stanimura	pgrp = NULL;
34391140Stanimura
344184205Sdes	newpgrp = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
345184205Sdes	newsess = malloc(sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO);
34691140Stanimura
34794859Sjhb	sx_xlock(&proctree_lock);
34891140Stanimura
34991140Stanimura	if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) {
35091140Stanimura		if (pgrp != NULL)
35191140Stanimura			PGRP_UNLOCK(pgrp);
35282749Sdillon		error = EPERM;
35391140Stanimura	} else {
35491140Stanimura		(void)enterpgrp(p, p->p_pid, newpgrp, newsess);
35583366Sjulian		td->td_retval[0] = p->p_pid;
35694859Sjhb		newpgrp = NULL;
35794859Sjhb		newsess = NULL;
3581541Srgrimes	}
35991140Stanimura
36094859Sjhb	sx_xunlock(&proctree_lock);
36191140Stanimura
36295973Stanimura	if (newpgrp != NULL)
363184205Sdes		free(newpgrp, M_PGRP);
36495973Stanimura	if (newsess != NULL)
365184205Sdes		free(newsess, M_SESSION);
36691140Stanimura
36794859Sjhb	return (error);
3681541Srgrimes}
3691541Srgrimes
3701541Srgrimes/*
3711541Srgrimes * set process group (setpgid/old setpgrp)
3721541Srgrimes *
3731541Srgrimes * caller does setpgid(targpid, targpgid)
3741541Srgrimes *
3751541Srgrimes * pid must be caller or child of caller (ESRCH)
3761541Srgrimes * if a child
3771541Srgrimes *	pid must be in same session (EPERM)
3781541Srgrimes *	pid can't have done an exec (EACCES)
3791541Srgrimes * if pgid != pid
3801541Srgrimes * 	there must exist some pid in same session having pgid (EPERM)
3811541Srgrimes * pid must not be session leader (EPERM)
3821541Srgrimes */
38312221Sbde#ifndef _SYS_SYSPROTO_H_
3841541Srgrimesstruct setpgid_args {
38587218Srwatson	int	pid;		/* target process id */
38687218Srwatson	int	pgid;		/* target pgrp id */
3871541Srgrimes};
38812221Sbde#endif
3891541Srgrimes/* ARGSUSED */
3901549Srgrimesint
391331643Sdimsys_setpgid(struct thread *td, struct setpgid_args *uap)
3921541Srgrimes{
39383366Sjulian	struct proc *curp = td->td_proc;
394331643Sdim	struct proc *targp;	/* target process */
395331643Sdim	struct pgrp *pgrp;	/* target pgrp */
39675448Srwatson	int error;
39791140Stanimura	struct pgrp *newpgrp;
3981541Srgrimes
39920677Sbde	if (uap->pgid < 0)
40020677Sbde		return (EINVAL);
40191140Stanimura
40291140Stanimura	error = 0;
40391140Stanimura
404184205Sdes	newpgrp = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
40591140Stanimura
40694859Sjhb	sx_xlock(&proctree_lock);
4071541Srgrimes	if (uap->pid != 0 && uap->pid != curp->p_pid) {
40891140Stanimura		if ((targp = pfind(uap->pid)) == NULL) {
40982749Sdillon			error = ESRCH;
41094859Sjhb			goto done;
41175893Sjhb		}
41291140Stanimura		if (!inferior(targp)) {
41391140Stanimura			PROC_UNLOCK(targp);
41491371Stanimura			error = ESRCH;
41594859Sjhb			goto done;
41691140Stanimura		}
417132568Srwatson		if ((error = p_cansee(td, targp))) {
41875893Sjhb			PROC_UNLOCK(targp);
41994859Sjhb			goto done;
42075893Sjhb		}
42175893Sjhb		if (targp->p_pgrp == NULL ||
42275893Sjhb		    targp->p_session != curp->p_session) {
42375893Sjhb			PROC_UNLOCK(targp);
42482749Sdillon			error = EPERM;
42594859Sjhb			goto done;
42675893Sjhb		}
42775893Sjhb		if (targp->p_flag & P_EXEC) {
42875893Sjhb			PROC_UNLOCK(targp);
42982749Sdillon			error = EACCES;
43094859Sjhb			goto done;
43175893Sjhb		}
43291140Stanimura		PROC_UNLOCK(targp);
43391140Stanimura	} else
4341541Srgrimes		targp = curp;
43575893Sjhb	if (SESS_LEADER(targp)) {
43682749Sdillon		error = EPERM;
43794859Sjhb		goto done;
43875893Sjhb	}
43987218Srwatson	if (uap->pgid == 0)
4401541Srgrimes		uap->pgid = targp->p_pid;
441117214Scognet	if ((pgrp = pgfind(uap->pgid)) == NULL) {
442117214Scognet		if (uap->pgid == targp->p_pid) {
443117214Scognet			error = enterpgrp(targp, uap->pgid, newpgrp,
444117214Scognet			    NULL);
445117214Scognet			if (error == 0)
446117214Scognet				newpgrp = NULL;
447117214Scognet		} else
448117214Scognet			error = EPERM;
44991140Stanimura	} else {
450117214Scognet		if (pgrp == targp->p_pgrp) {
451117214Scognet			PGRP_UNLOCK(pgrp);
45294859Sjhb			goto done;
45375893Sjhb		}
454117214Scognet		if (pgrp->pg_id != targp->p_pid &&
455117214Scognet		    pgrp->pg_session != curp->p_session) {
45691140Stanimura			PGRP_UNLOCK(pgrp);
457117214Scognet			error = EPERM;
45891140Stanimura			goto done;
45991140Stanimura		}
46091140Stanimura		PGRP_UNLOCK(pgrp);
46191140Stanimura		error = enterthispgrp(targp, pgrp);
46282749Sdillon	}
46391140Stanimuradone:
46494859Sjhb	sx_xunlock(&proctree_lock);
46594859Sjhb	KASSERT((error == 0) || (newpgrp != NULL),
46694859Sjhb	    ("setpgid failed and newpgrp is NULL"));
46795973Stanimura	if (newpgrp != NULL)
468184205Sdes		free(newpgrp, M_PGRP);
46982749Sdillon	return (error);
4701541Srgrimes}
4711541Srgrimes
47224448Speter/*
47324448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
47472093Sasmodai * compatible.  It says that setting the uid/gid to euid/egid is a special
47524448Speter * case of "appropriate privilege".  Once the rules are expanded out, this
47624448Speter * basically means that setuid(nnn) sets all three id's, in all permitted
47724448Speter * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
47824448Speter * does not set the saved id - this is dangerous for traditional BSD
47924448Speter * programs.  For this reason, we *really* do not want to set
48024448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
48124448Speter */
48224448Speter#define POSIX_APPENDIX_B_4_2_2
48324448Speter
48412221Sbde#ifndef _SYS_SYSPROTO_H_
4851541Srgrimesstruct setuid_args {
4861541Srgrimes	uid_t	uid;
4871541Srgrimes};
48812221Sbde#endif
4891541Srgrimes/* ARGSUSED */
4901549Srgrimesint
491225617Skmacysys_setuid(struct thread *td, struct setuid_args *uap)
4921541Srgrimes{
49383366Sjulian	struct proc *p = td->td_proc;
49477183Srwatson	struct ucred *newcred, *oldcred;
49577183Srwatson	uid_t uid;
49698417Salfred	struct uidinfo *uip;
49787218Srwatson	int error;
4981541Srgrimes
49977183Srwatson	uid = uap->uid;
500195104Srwatson	AUDIT_ARG_UID(uid);
50194619Sjhb	newcred = crget();
50298417Salfred	uip = uifind(uid);
50394619Sjhb	PROC_LOCK(p);
504194498Sbrooks	/*
505194498Sbrooks	 * Copy credentials so other references do not see our changes.
506194498Sbrooks	 */
507194498Sbrooks	oldcred = crcopysafe(p, newcred);
50887466Srwatson
509145147Srwatson#ifdef MAC
510189529Srwatson	error = mac_cred_check_setuid(oldcred, uid);
511145147Srwatson	if (error)
512145147Srwatson		goto fail;
513145147Srwatson#endif
514145147Srwatson
51524448Speter	/*
51624448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
51724448Speter	 *
51887218Srwatson	 * Note that setuid(geteuid()) is a special case of
51924448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
52072093Sasmodai	 * to use this clause to be compatible with traditional BSD
52124448Speter	 * semantics.  Basically, it means that "setuid(xx)" sets all
52224448Speter	 * three id's (assuming you have privs).
52324448Speter	 *
52424448Speter	 * Notes on the logic.  We do things in three steps.
52524448Speter	 * 1: We determine if the euid is going to change, and do EPERM
52624448Speter	 *    right away.  We unconditionally change the euid later if this
52724448Speter	 *    test is satisfied, simplifying that part of the logic.
52887218Srwatson	 * 2: We determine if the real and/or saved uids are going to
52924448Speter	 *    change.  Determined by compile options.
53024448Speter	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
53124448Speter	 */
53277183Srwatson	if (uid != oldcred->cr_ruid &&		/* allow setuid(getuid()) */
53317994Sache#ifdef _POSIX_SAVED_IDS
53477183Srwatson	    uid != oldcred->cr_svuid &&		/* allow setuid(saved gid) */
53517994Sache#endif
53624448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
53777183Srwatson	    uid != oldcred->cr_uid &&		/* allow setuid(geteuid()) */
53824448Speter#endif
539170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETUID, 0)) != 0)
540145147Srwatson		goto fail;
54124448Speter
54224448Speter#ifdef _POSIX_SAVED_IDS
5431541Srgrimes	/*
54424448Speter	 * Do we have "appropriate privileges" (are we root or uid == euid)
54524448Speter	 * If so, we are changing the real uid and/or saved uid.
5461541Srgrimes	 */
54717994Sache	if (
54824448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
54977183Srwatson	    uid == oldcred->cr_uid ||
55017994Sache#endif
551164032Srwatson	    /* We are using privs. */
552170587Srwatson	    priv_check_cred(oldcred, PRIV_CRED_SETUID, 0) == 0)
55317994Sache#endif
55424448Speter	{
55524448Speter		/*
55665495Struckman		 * Set the real uid and transfer proc count to new user.
55724448Speter		 */
55877183Srwatson		if (uid != oldcred->cr_ruid) {
55998417Salfred			change_ruid(newcred, uip);
56065495Struckman			setsugid(p);
56124448Speter		}
56224448Speter		/*
56324448Speter		 * Set saved uid
56424448Speter		 *
56524448Speter		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
56624448Speter		 * the security of seteuid() depends on it.  B.4.2.2 says it
56724448Speter		 * is important that we should do this.
56824448Speter		 */
56977183Srwatson		if (uid != oldcred->cr_svuid) {
57077183Srwatson			change_svuid(newcred, uid);
57131891Ssef			setsugid(p);
57224448Speter		}
5738141Sache	}
57424448Speter
57524448Speter	/*
57624448Speter	 * In all permitted cases, we are changing the euid.
57724448Speter	 */
57877183Srwatson	if (uid != oldcred->cr_uid) {
57998417Salfred		change_euid(newcred, uip);
58031891Ssef		setsugid(p);
58124448Speter	}
582280130Smjg	proc_set_cred(p, newcred);
583220212Strasz#ifdef RACCT
584220212Strasz	racct_proc_ucred_changed(p, oldcred, newcred);
585335536Savg	crhold(newcred);
586220212Strasz#endif
587335536Savg	PROC_UNLOCK(p);
588335536Savg#ifdef RCTL
589335536Savg	rctl_proc_ucred_changed(p, newcred);
590335536Savg	crfree(newcred);
591335536Savg#endif
59298417Salfred	uifree(uip);
59377183Srwatson	crfree(oldcred);
59494619Sjhb	return (0);
595145147Srwatson
596145147Srwatsonfail:
597145147Srwatson	PROC_UNLOCK(p);
598145147Srwatson	uifree(uip);
599145147Srwatson	crfree(newcred);
600145147Srwatson	return (error);
6011541Srgrimes}
6021541Srgrimes
60312221Sbde#ifndef _SYS_SYSPROTO_H_
6041541Srgrimesstruct seteuid_args {
6051541Srgrimes	uid_t	euid;
6061541Srgrimes};
60712221Sbde#endif
6081541Srgrimes/* ARGSUSED */
6091549Srgrimesint
610225617Skmacysys_seteuid(struct thread *td, struct seteuid_args *uap)
6111541Srgrimes{
61283366Sjulian	struct proc *p = td->td_proc;
61377183Srwatson	struct ucred *newcred, *oldcred;
61477183Srwatson	uid_t euid;
61598417Salfred	struct uidinfo *euip;
61687218Srwatson	int error;
6171541Srgrimes
6181541Srgrimes	euid = uap->euid;
619195104Srwatson	AUDIT_ARG_EUID(euid);
62094619Sjhb	newcred = crget();
62198417Salfred	euip = uifind(euid);
62294619Sjhb	PROC_LOCK(p);
623194498Sbrooks	/*
624194498Sbrooks	 * Copy credentials so other references do not see our changes.
625194498Sbrooks	 */
626194498Sbrooks	oldcred = crcopysafe(p, newcred);
627145147Srwatson
628145147Srwatson#ifdef MAC
629189529Srwatson	error = mac_cred_check_seteuid(oldcred, euid);
630145147Srwatson	if (error)
631145147Srwatson		goto fail;
632145147Srwatson#endif
633145147Srwatson
63477183Srwatson	if (euid != oldcred->cr_ruid &&		/* allow seteuid(getuid()) */
63577183Srwatson	    euid != oldcred->cr_svuid &&	/* allow seteuid(saved uid) */
636170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETEUID, 0)) != 0)
637145147Srwatson		goto fail;
638145147Srwatson
6391541Srgrimes	/*
640194498Sbrooks	 * Everything's okay, do it.
6411541Srgrimes	 */
64277183Srwatson	if (oldcred->cr_uid != euid) {
64398417Salfred		change_euid(newcred, euip);
64431891Ssef		setsugid(p);
64524449Speter	}
646280130Smjg	proc_set_cred(p, newcred);
64794619Sjhb	PROC_UNLOCK(p);
64898417Salfred	uifree(euip);
64977183Srwatson	crfree(oldcred);
65094619Sjhb	return (0);
651145147Srwatson
652145147Srwatsonfail:
653145147Srwatson	PROC_UNLOCK(p);
654145147Srwatson	uifree(euip);
655145147Srwatson	crfree(newcred);
656145147Srwatson	return (error);
6571541Srgrimes}
6581541Srgrimes
65912221Sbde#ifndef _SYS_SYSPROTO_H_
6601541Srgrimesstruct setgid_args {
6611541Srgrimes	gid_t	gid;
6621541Srgrimes};
66312221Sbde#endif
6641541Srgrimes/* ARGSUSED */
6651549Srgrimesint
666225617Skmacysys_setgid(struct thread *td, struct setgid_args *uap)
6671541Srgrimes{
66883366Sjulian	struct proc *p = td->td_proc;
66977183Srwatson	struct ucred *newcred, *oldcred;
67077183Srwatson	gid_t gid;
67187218Srwatson	int error;
6721541Srgrimes
67377183Srwatson	gid = uap->gid;
674195104Srwatson	AUDIT_ARG_GID(gid);
67594619Sjhb	newcred = crget();
67694619Sjhb	PROC_LOCK(p);
677194498Sbrooks	oldcred = crcopysafe(p, newcred);
67887466Srwatson
679145147Srwatson#ifdef MAC
680189529Srwatson	error = mac_cred_check_setgid(oldcred, gid);
681145147Srwatson	if (error)
682145147Srwatson		goto fail;
683145147Srwatson#endif
684145147Srwatson
68524448Speter	/*
68624448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
68724448Speter	 *
68824448Speter	 * Note that setgid(getegid()) is a special case of
68924448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
69072093Sasmodai	 * to use this clause to be compatible with traditional BSD
69124448Speter	 * semantics.  Basically, it means that "setgid(xx)" sets all
69224448Speter	 * three id's (assuming you have privs).
69324448Speter	 *
69424448Speter	 * For notes on the logic here, see setuid() above.
69524448Speter	 */
69677183Srwatson	if (gid != oldcred->cr_rgid &&		/* allow setgid(getgid()) */
69717994Sache#ifdef _POSIX_SAVED_IDS
69877183Srwatson	    gid != oldcred->cr_svgid &&		/* allow setgid(saved gid) */
69917994Sache#endif
70024448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
70177183Srwatson	    gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */
70224448Speter#endif
703170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETGID, 0)) != 0)
704145147Srwatson		goto fail;
70524448Speter
70617994Sache#ifdef _POSIX_SAVED_IDS
70724448Speter	/*
70824448Speter	 * Do we have "appropriate privileges" (are we root or gid == egid)
70924448Speter	 * If so, we are changing the real uid and saved gid.
71024448Speter	 */
71124448Speter	if (
71224448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
71377183Srwatson	    gid == oldcred->cr_groups[0] ||
71417994Sache#endif
715164032Srwatson	    /* We are using privs. */
716170587Srwatson	    priv_check_cred(oldcred, PRIV_CRED_SETGID, 0) == 0)
71724448Speter#endif
71824448Speter	{
71924448Speter		/*
72024448Speter		 * Set real gid
72124448Speter		 */
72277183Srwatson		if (oldcred->cr_rgid != gid) {
72377183Srwatson			change_rgid(newcred, gid);
72431891Ssef			setsugid(p);
72524448Speter		}
72624448Speter		/*
72724448Speter		 * Set saved gid
72824448Speter		 *
72924448Speter		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
73024448Speter		 * the security of setegid() depends on it.  B.4.2.2 says it
73124448Speter		 * is important that we should do this.
73224448Speter		 */
73377183Srwatson		if (oldcred->cr_svgid != gid) {
73477183Srwatson			change_svgid(newcred, gid);
73531891Ssef			setsugid(p);
73624448Speter		}
7378141Sache	}
73824448Speter	/*
73924448Speter	 * In all cases permitted cases, we are changing the egid.
74024448Speter	 * Copy credentials so other references do not see our changes.
74124448Speter	 */
74277183Srwatson	if (oldcred->cr_groups[0] != gid) {
74377183Srwatson		change_egid(newcred, gid);
74431891Ssef		setsugid(p);
74524448Speter	}
746280130Smjg	proc_set_cred(p, newcred);
74794619Sjhb	PROC_UNLOCK(p);
74877183Srwatson	crfree(oldcred);
74994619Sjhb	return (0);
750145147Srwatson
751145147Srwatsonfail:
752145147Srwatson	PROC_UNLOCK(p);
753145147Srwatson	crfree(newcred);
754145147Srwatson	return (error);
7551541Srgrimes}
7561541Srgrimes
75712221Sbde#ifndef _SYS_SYSPROTO_H_
7581541Srgrimesstruct setegid_args {
7591541Srgrimes	gid_t	egid;
7601541Srgrimes};
76112221Sbde#endif
7621541Srgrimes/* ARGSUSED */
7631549Srgrimesint
764225617Skmacysys_setegid(struct thread *td, struct setegid_args *uap)
7651541Srgrimes{
76683366Sjulian	struct proc *p = td->td_proc;
76777183Srwatson	struct ucred *newcred, *oldcred;
76877183Srwatson	gid_t egid;
76987218Srwatson	int error;
7701541Srgrimes
7711541Srgrimes	egid = uap->egid;
772195104Srwatson	AUDIT_ARG_EGID(egid);
77394619Sjhb	newcred = crget();
77494619Sjhb	PROC_LOCK(p);
775194498Sbrooks	oldcred = crcopysafe(p, newcred);
776145147Srwatson
777145147Srwatson#ifdef MAC
778189529Srwatson	error = mac_cred_check_setegid(oldcred, egid);
779145147Srwatson	if (error)
780145147Srwatson		goto fail;
781145147Srwatson#endif
782145147Srwatson
78377183Srwatson	if (egid != oldcred->cr_rgid &&		/* allow setegid(getgid()) */
78477183Srwatson	    egid != oldcred->cr_svgid &&	/* allow setegid(saved gid) */
785170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETEGID, 0)) != 0)
786145147Srwatson		goto fail;
787145147Srwatson
78877183Srwatson	if (oldcred->cr_groups[0] != egid) {
78977183Srwatson		change_egid(newcred, egid);
79031891Ssef		setsugid(p);
79124449Speter	}
792280130Smjg	proc_set_cred(p, newcred);
79394619Sjhb	PROC_UNLOCK(p);
79477183Srwatson	crfree(oldcred);
79594619Sjhb	return (0);
796145147Srwatson
797145147Srwatsonfail:
798145147Srwatson	PROC_UNLOCK(p);
799145147Srwatson	crfree(newcred);
800145147Srwatson	return (error);
8011541Srgrimes}
8021541Srgrimes
80312221Sbde#ifndef _SYS_SYSPROTO_H_
8041541Srgrimesstruct setgroups_args {
8051541Srgrimes	u_int	gidsetsize;
8061541Srgrimes	gid_t	*gidset;
8071541Srgrimes};
80812221Sbde#endif
8091541Srgrimes/* ARGSUSED */
8101549Srgrimesint
811225617Skmacysys_setgroups(struct thread *td, struct setgroups_args *uap)
8121541Srgrimes{
813273684Smjg	gid_t smallgroups[XU_NGROUPS];
814273685Smjg	gid_t *groups;
815273684Smjg	u_int gidsetsize;
816160139Sjhb	int error;
817160139Sjhb
818273684Smjg	gidsetsize = uap->gidsetsize;
819273684Smjg	if (gidsetsize > ngroups_max + 1)
820160139Sjhb		return (EINVAL);
821273685Smjg
822273684Smjg	if (gidsetsize > XU_NGROUPS)
823273684Smjg		groups = malloc(gidsetsize * sizeof(gid_t), M_TEMP, M_WAITOK);
824273684Smjg	else
825273684Smjg		groups = smallgroups;
826273685Smjg
827273684Smjg	error = copyin(uap->gidset, groups, gidsetsize * sizeof(gid_t));
828273685Smjg	if (error == 0)
829273685Smjg		error = kern_setgroups(td, gidsetsize, groups);
830273685Smjg
831273684Smjg	if (gidsetsize > XU_NGROUPS)
832273684Smjg		free(groups, M_TEMP);
833194498Sbrooks	return (error);
834160139Sjhb}
835160139Sjhb
836160139Sjhbint
837160139Sjhbkern_setgroups(struct thread *td, u_int ngrp, gid_t *groups)
838160139Sjhb{
83983366Sjulian	struct proc *p = td->td_proc;
840160139Sjhb	struct ucred *newcred, *oldcred;
8411541Srgrimes	int error;
8421541Srgrimes
843273691Smjg	MPASS(ngrp <= ngroups_max + 1);
844195104Srwatson	AUDIT_ARG_GROUPSET(groups, ngrp);
84594619Sjhb	newcred = crget();
846194498Sbrooks	crextend(newcred, ngrp);
84794619Sjhb	PROC_LOCK(p);
848194498Sbrooks	oldcred = crcopysafe(p, newcred);
849145147Srwatson
850145147Srwatson#ifdef MAC
851189529Srwatson	error = mac_cred_check_setgroups(oldcred, ngrp, groups);
852145147Srwatson	if (error)
853145147Srwatson		goto fail;
854145147Srwatson#endif
855145147Srwatson
856170587Srwatson	error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0);
857145147Srwatson	if (error)
858145147Srwatson		goto fail;
859145147Srwatson
860273685Smjg	if (ngrp == 0) {
86124447Speter		/*
86224447Speter		 * setgroups(0, NULL) is a legitimate way of clearing the
86324447Speter		 * groups vector on non-BSD systems (which generally do not
86424447Speter		 * have the egid in the groups[0]).  We risk security holes
86524447Speter		 * when running non-BSD software if we do not do the same.
86624447Speter		 */
86777183Srwatson		newcred->cr_ngroups = 1;
86824447Speter	} else {
869194498Sbrooks		crsetgroups_locked(newcred, ngrp, groups);
87024447Speter	}
87131891Ssef	setsugid(p);
872280130Smjg	proc_set_cred(p, newcred);
87394619Sjhb	PROC_UNLOCK(p);
87477183Srwatson	crfree(oldcred);
87594619Sjhb	return (0);
876145147Srwatson
877145147Srwatsonfail:
878145147Srwatson	PROC_UNLOCK(p);
879145147Srwatson	crfree(newcred);
880145147Srwatson	return (error);
8811541Srgrimes}
8821541Srgrimes
88312221Sbde#ifndef _SYS_SYSPROTO_H_
8841541Srgrimesstruct setreuid_args {
8859238Sache	uid_t	ruid;
8869238Sache	uid_t	euid;
8871541Srgrimes};
88812221Sbde#endif
8891541Srgrimes/* ARGSUSED */
8901549Srgrimesint
891331643Sdimsys_setreuid(struct thread *td, struct setreuid_args *uap)
8921541Srgrimes{
89383366Sjulian	struct proc *p = td->td_proc;
89477183Srwatson	struct ucred *newcred, *oldcred;
89587218Srwatson	uid_t euid, ruid;
89698417Salfred	struct uidinfo *euip, *ruip;
89787218Srwatson	int error;
8981541Srgrimes
89987218Srwatson	euid = uap->euid;
9009238Sache	ruid = uap->ruid;
901195104Srwatson	AUDIT_ARG_EUID(euid);
902195104Srwatson	AUDIT_ARG_RUID(ruid);
90394619Sjhb	newcred = crget();
90498417Salfred	euip = uifind(euid);
90598417Salfred	ruip = uifind(ruid);
90694619Sjhb	PROC_LOCK(p);
907194498Sbrooks	oldcred = crcopysafe(p, newcred);
908145147Srwatson
909145147Srwatson#ifdef MAC
910189529Srwatson	error = mac_cred_check_setreuid(oldcred, ruid, euid);
911145147Srwatson	if (error)
912145147Srwatson		goto fail;
913145147Srwatson#endif
914145147Srwatson
91577183Srwatson	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
91677183Srwatson	      ruid != oldcred->cr_svuid) ||
91777183Srwatson	     (euid != (uid_t)-1 && euid != oldcred->cr_uid &&
91877183Srwatson	      euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) &&
919170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETREUID, 0)) != 0)
920145147Srwatson		goto fail;
921145147Srwatson
92277183Srwatson	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
92398417Salfred		change_euid(newcred, euip);
92431891Ssef		setsugid(p);
92524450Speter	}
92677183Srwatson	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
92798417Salfred		change_ruid(newcred, ruip);
92831891Ssef		setsugid(p);
9298135Sache	}
93077183Srwatson	if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) &&
93177183Srwatson	    newcred->cr_svuid != newcred->cr_uid) {
93277183Srwatson		change_svuid(newcred, newcred->cr_uid);
93331891Ssef		setsugid(p);
93424450Speter	}
935280130Smjg	proc_set_cred(p, newcred);
936220212Strasz#ifdef RACCT
937220212Strasz	racct_proc_ucred_changed(p, oldcred, newcred);
938335536Savg	crhold(newcred);
939220212Strasz#endif
940335536Savg	PROC_UNLOCK(p);
941335536Savg#ifdef RCTL
942335536Savg	rctl_proc_ucred_changed(p, newcred);
943335536Savg	crfree(newcred);
944335536Savg#endif
94598417Salfred	uifree(ruip);
94698417Salfred	uifree(euip);
94777183Srwatson	crfree(oldcred);
94894619Sjhb	return (0);
949145147Srwatson
950145147Srwatsonfail:
951145147Srwatson	PROC_UNLOCK(p);
952145147Srwatson	uifree(ruip);
953145147Srwatson	uifree(euip);
954145147Srwatson	crfree(newcred);
955145147Srwatson	return (error);
9561541Srgrimes}
9571541Srgrimes
95812221Sbde#ifndef _SYS_SYSPROTO_H_
9591541Srgrimesstruct setregid_args {
9609238Sache	gid_t	rgid;
9619238Sache	gid_t	egid;
9621541Srgrimes};
96312221Sbde#endif
9641541Srgrimes/* ARGSUSED */
9651549Srgrimesint
966331643Sdimsys_setregid(struct thread *td, struct setregid_args *uap)
9671541Srgrimes{
96883366Sjulian	struct proc *p = td->td_proc;
96977183Srwatson	struct ucred *newcred, *oldcred;
97087218Srwatson	gid_t egid, rgid;
97187218Srwatson	int error;
9721541Srgrimes
97387218Srwatson	egid = uap->egid;
9749238Sache	rgid = uap->rgid;
975195104Srwatson	AUDIT_ARG_EGID(egid);
976195104Srwatson	AUDIT_ARG_RGID(rgid);
97794619Sjhb	newcred = crget();
97894619Sjhb	PROC_LOCK(p);
979194498Sbrooks	oldcred = crcopysafe(p, newcred);
980145147Srwatson
981145147Srwatson#ifdef MAC
982189529Srwatson	error = mac_cred_check_setregid(oldcred, rgid, egid);
983145147Srwatson	if (error)
984145147Srwatson		goto fail;
985145147Srwatson#endif
986145147Srwatson
98777183Srwatson	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
98877183Srwatson	    rgid != oldcred->cr_svgid) ||
98977183Srwatson	     (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] &&
99077183Srwatson	     egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) &&
991170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETREGID, 0)) != 0)
992145147Srwatson		goto fail;
99394619Sjhb
99477183Srwatson	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
99577183Srwatson		change_egid(newcred, egid);
99631891Ssef		setsugid(p);
99724450Speter	}
99877183Srwatson	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
99977183Srwatson		change_rgid(newcred, rgid);
100031891Ssef		setsugid(p);
100124450Speter	}
100277183Srwatson	if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) &&
100377183Srwatson	    newcred->cr_svgid != newcred->cr_groups[0]) {
100477183Srwatson		change_svgid(newcred, newcred->cr_groups[0]);
100531891Ssef		setsugid(p);
100624450Speter	}
1007280130Smjg	proc_set_cred(p, newcred);
100894619Sjhb	PROC_UNLOCK(p);
100977812Sru	crfree(oldcred);
101094619Sjhb	return (0);
1011145147Srwatson
1012145147Srwatsonfail:
1013145147Srwatson	PROC_UNLOCK(p);
1014145147Srwatson	crfree(newcred);
1015145147Srwatson	return (error);
10161541Srgrimes}
10171541Srgrimes
101856115Speter/*
1019167232Srwatson * setresuid(ruid, euid, suid) is like setreuid except control over the saved
1020167232Srwatson * uid is explicit.
102156115Speter */
102224453Speter#ifndef _SYS_SYSPROTO_H_
102356115Speterstruct setresuid_args {
102456115Speter	uid_t	ruid;
102556115Speter	uid_t	euid;
102656115Speter	uid_t	suid;
102756115Speter};
102856115Speter#endif
102956115Speter/* ARGSUSED */
103056115Speterint
1031331643Sdimsys_setresuid(struct thread *td, struct setresuid_args *uap)
103256115Speter{
103383366Sjulian	struct proc *p = td->td_proc;
103477183Srwatson	struct ucred *newcred, *oldcred;
103587218Srwatson	uid_t euid, ruid, suid;
103698417Salfred	struct uidinfo *euip, *ruip;
103756115Speter	int error;
103856115Speter
103987218Srwatson	euid = uap->euid;
104056115Speter	ruid = uap->ruid;
104156115Speter	suid = uap->suid;
1042195104Srwatson	AUDIT_ARG_EUID(euid);
1043195104Srwatson	AUDIT_ARG_RUID(ruid);
1044195104Srwatson	AUDIT_ARG_SUID(suid);
104594619Sjhb	newcred = crget();
104698417Salfred	euip = uifind(euid);
104798417Salfred	ruip = uifind(ruid);
104894619Sjhb	PROC_LOCK(p);
1049194498Sbrooks	oldcred = crcopysafe(p, newcred);
1050145147Srwatson
1051145147Srwatson#ifdef MAC
1052189529Srwatson	error = mac_cred_check_setresuid(oldcred, ruid, euid, suid);
1053145147Srwatson	if (error)
1054145147Srwatson		goto fail;
1055145147Srwatson#endif
1056145147Srwatson
105777183Srwatson	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
105877183Srwatson	     ruid != oldcred->cr_svuid &&
105977183Srwatson	      ruid != oldcred->cr_uid) ||
106077183Srwatson	     (euid != (uid_t)-1 && euid != oldcred->cr_ruid &&
106177183Srwatson	    euid != oldcred->cr_svuid &&
106277183Srwatson	      euid != oldcred->cr_uid) ||
106377183Srwatson	     (suid != (uid_t)-1 && suid != oldcred->cr_ruid &&
106477183Srwatson	    suid != oldcred->cr_svuid &&
106577183Srwatson	      suid != oldcred->cr_uid)) &&
1066170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETRESUID, 0)) != 0)
1067145147Srwatson		goto fail;
106894619Sjhb
106977183Srwatson	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
107098417Salfred		change_euid(newcred, euip);
107156115Speter		setsugid(p);
107256115Speter	}
107377183Srwatson	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
107498417Salfred		change_ruid(newcred, ruip);
107556115Speter		setsugid(p);
107656115Speter	}
107777183Srwatson	if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) {
107877183Srwatson		change_svuid(newcred, suid);
107956115Speter		setsugid(p);
108056115Speter	}
1081280130Smjg	proc_set_cred(p, newcred);
1082220212Strasz#ifdef RACCT
1083220212Strasz	racct_proc_ucred_changed(p, oldcred, newcred);
1084335536Savg	crhold(newcred);
1085220212Strasz#endif
1086335536Savg	PROC_UNLOCK(p);
1087335536Savg#ifdef RCTL
1088335536Savg	rctl_proc_ucred_changed(p, newcred);
1089335536Savg	crfree(newcred);
1090335536Savg#endif
109198417Salfred	uifree(ruip);
109298417Salfred	uifree(euip);
109377183Srwatson	crfree(oldcred);
109494619Sjhb	return (0);
1095145147Srwatson
1096145147Srwatsonfail:
1097145147Srwatson	PROC_UNLOCK(p);
1098145147Srwatson	uifree(ruip);
1099145147Srwatson	uifree(euip);
1100145147Srwatson	crfree(newcred);
1101145147Srwatson	return (error);
1102145147Srwatson
110356115Speter}
110456115Speter
110556115Speter/*
1106167232Srwatson * setresgid(rgid, egid, sgid) is like setregid except control over the saved
1107167232Srwatson * gid is explicit.
110856115Speter */
110956115Speter#ifndef _SYS_SYSPROTO_H_
111056115Speterstruct setresgid_args {
111156115Speter	gid_t	rgid;
111256115Speter	gid_t	egid;
111356115Speter	gid_t	sgid;
111456115Speter};
111556115Speter#endif
111656115Speter/* ARGSUSED */
111756115Speterint
1118331643Sdimsys_setresgid(struct thread *td, struct setresgid_args *uap)
111956115Speter{
112083366Sjulian	struct proc *p = td->td_proc;
112177183Srwatson	struct ucred *newcred, *oldcred;
112287218Srwatson	gid_t egid, rgid, sgid;
112356115Speter	int error;
112456115Speter
112587218Srwatson	egid = uap->egid;
112656115Speter	rgid = uap->rgid;
112756115Speter	sgid = uap->sgid;
1128195104Srwatson	AUDIT_ARG_EGID(egid);
1129195104Srwatson	AUDIT_ARG_RGID(rgid);
1130195104Srwatson	AUDIT_ARG_SGID(sgid);
113194619Sjhb	newcred = crget();
113294619Sjhb	PROC_LOCK(p);
1133194498Sbrooks	oldcred = crcopysafe(p, newcred);
1134145147Srwatson
1135145147Srwatson#ifdef MAC
1136189529Srwatson	error = mac_cred_check_setresgid(oldcred, rgid, egid, sgid);
1137145147Srwatson	if (error)
1138145147Srwatson		goto fail;
1139145147Srwatson#endif
1140145147Srwatson
114177183Srwatson	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
114277183Srwatson	      rgid != oldcred->cr_svgid &&
114377183Srwatson	      rgid != oldcred->cr_groups[0]) ||
114477183Srwatson	     (egid != (gid_t)-1 && egid != oldcred->cr_rgid &&
114577183Srwatson	      egid != oldcred->cr_svgid &&
114677183Srwatson	      egid != oldcred->cr_groups[0]) ||
114777183Srwatson	     (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid &&
114877183Srwatson	      sgid != oldcred->cr_svgid &&
114977183Srwatson	      sgid != oldcred->cr_groups[0])) &&
1150170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETRESGID, 0)) != 0)
1151145147Srwatson		goto fail;
115294619Sjhb
115377183Srwatson	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
115477183Srwatson		change_egid(newcred, egid);
115556115Speter		setsugid(p);
115656115Speter	}
115777183Srwatson	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
115877183Srwatson		change_rgid(newcred, rgid);
115956115Speter		setsugid(p);
116056115Speter	}
116177183Srwatson	if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) {
116277183Srwatson		change_svgid(newcred, sgid);
116356115Speter		setsugid(p);
116456115Speter	}
1165280130Smjg	proc_set_cred(p, newcred);
116694619Sjhb	PROC_UNLOCK(p);
116777183Srwatson	crfree(oldcred);
116894619Sjhb	return (0);
1169145147Srwatson
1170145147Srwatsonfail:
1171145147Srwatson	PROC_UNLOCK(p);
1172145147Srwatson	crfree(newcred);
1173145147Srwatson	return (error);
117456115Speter}
117556115Speter
117656115Speter#ifndef _SYS_SYSPROTO_H_
117756115Speterstruct getresuid_args {
117856115Speter	uid_t	*ruid;
117956115Speter	uid_t	*euid;
118056115Speter	uid_t	*suid;
118156115Speter};
118256115Speter#endif
118356115Speter/* ARGSUSED */
118456115Speterint
1185331643Sdimsys_getresuid(struct thread *td, struct getresuid_args *uap)
118656115Speter{
118782749Sdillon	struct ucred *cred;
118856115Speter	int error1 = 0, error2 = 0, error3 = 0;
118956115Speter
119093264Sdillon	cred = td->td_ucred;
119156115Speter	if (uap->ruid)
119299009Salfred		error1 = copyout(&cred->cr_ruid,
119399009Salfred		    uap->ruid, sizeof(cred->cr_ruid));
119456115Speter	if (uap->euid)
119599009Salfred		error2 = copyout(&cred->cr_uid,
119699009Salfred		    uap->euid, sizeof(cred->cr_uid));
119756115Speter	if (uap->suid)
119899009Salfred		error3 = copyout(&cred->cr_svuid,
119999009Salfred		    uap->suid, sizeof(cred->cr_svuid));
120087218Srwatson	return (error1 ? error1 : error2 ? error2 : error3);
120156115Speter}
120256115Speter
120356115Speter#ifndef _SYS_SYSPROTO_H_
120456115Speterstruct getresgid_args {
120556115Speter	gid_t	*rgid;
120656115Speter	gid_t	*egid;
120756115Speter	gid_t	*sgid;
120856115Speter};
120956115Speter#endif
121056115Speter/* ARGSUSED */
121156115Speterint
1212331643Sdimsys_getresgid(struct thread *td, struct getresgid_args *uap)
121356115Speter{
121482749Sdillon	struct ucred *cred;
121556115Speter	int error1 = 0, error2 = 0, error3 = 0;
121656115Speter
121793264Sdillon	cred = td->td_ucred;
121856115Speter	if (uap->rgid)
121999009Salfred		error1 = copyout(&cred->cr_rgid,
122099009Salfred		    uap->rgid, sizeof(cred->cr_rgid));
122156115Speter	if (uap->egid)
122299009Salfred		error2 = copyout(&cred->cr_groups[0],
122399009Salfred		    uap->egid, sizeof(cred->cr_groups[0]));
122456115Speter	if (uap->sgid)
122599009Salfred		error3 = copyout(&cred->cr_svgid,
122699009Salfred		    uap->sgid, sizeof(cred->cr_svgid));
122787218Srwatson	return (error1 ? error1 : error2 ? error2 : error3);
122856115Speter}
122956115Speter
123056115Speter#ifndef _SYS_SYSPROTO_H_
123124453Speterstruct issetugid_args {
123224453Speter	int dummy;
123324453Speter};
123424453Speter#endif
123524453Speter/* ARGSUSED */
123624453Speterint
1237331643Sdimsys_issetugid(struct thread *td, struct issetugid_args *uap)
123824453Speter{
123983366Sjulian	struct proc *p = td->td_proc;
124083366Sjulian
124124453Speter	/*
124224453Speter	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
124324453Speter	 * we use P_SUGID because we consider changing the owners as
124424453Speter	 * "tainting" as well.
124524453Speter	 * This is significant for procs that start as root and "become"
124624453Speter	 * a user without an exec - programs cannot know *everything*
124724453Speter	 * that libc *might* have put in their data segment.
124824453Speter	 */
124983366Sjulian	td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
125024453Speter	return (0);
125124453Speter}
125224453Speter
125375426Srwatsonint
1254225617Skmacysys___setugid(struct thread *td, struct __setugid_args *uap)
125575426Srwatson{
125682749Sdillon#ifdef REGRESSION
125794619Sjhb	struct proc *p;
125875426Srwatson
125994619Sjhb	p = td->td_proc;
126075426Srwatson	switch (uap->flag) {
126175426Srwatson	case 0:
126294619Sjhb		PROC_LOCK(p);
126394619Sjhb		p->p_flag &= ~P_SUGID;
126494619Sjhb		PROC_UNLOCK(p);
126594619Sjhb		return (0);
126675426Srwatson	case 1:
126794619Sjhb		PROC_LOCK(p);
126894619Sjhb		p->p_flag |= P_SUGID;
126994619Sjhb		PROC_UNLOCK(p);
127094619Sjhb		return (0);
127175426Srwatson	default:
127294619Sjhb		return (EINVAL);
127375426Srwatson	}
127475426Srwatson#else /* !REGRESSION */
127587218Srwatson
127675426Srwatson	return (ENOSYS);
127787218Srwatson#endif /* REGRESSION */
127875426Srwatson}
127975426Srwatson
12801541Srgrimes/*
12811541Srgrimes * Check if gid is a member of the group set.
12821541Srgrimes */
12831549Srgrimesint
128493580Sjhbgroupmember(gid_t gid, struct ucred *cred)
12851541Srgrimes{
1286194556Sbrooks	int l;
1287194556Sbrooks	int h;
1288194556Sbrooks	int m;
12891541Srgrimes
1290194556Sbrooks	if (cred->cr_groups[0] == gid)
1291194556Sbrooks		return(1);
1292194556Sbrooks
1293194556Sbrooks	/*
1294194556Sbrooks	 * If gid was not our primary group, perform a binary search
1295194556Sbrooks	 * of the supplemental groups.  This is possible because we
1296194556Sbrooks	 * sort the groups in crsetgroups().
1297194556Sbrooks	 */
1298194556Sbrooks	l = 1;
1299194556Sbrooks	h = cred->cr_ngroups;
1300194556Sbrooks	while (l < h) {
1301194556Sbrooks		m = l + ((h - l) / 2);
1302194556Sbrooks		if (cred->cr_groups[m] < gid)
1303194556Sbrooks			l = m + 1;
1304194556Sbrooks		else
1305194556Sbrooks			h = m;
1306194556Sbrooks	}
1307194556Sbrooks	if ((l < cred->cr_ngroups) && (cred->cr_groups[l] == gid))
1308194556Sbrooks		return (1);
1309194556Sbrooks
13101541Srgrimes	return (0);
13111541Srgrimes}
13121541Srgrimes
131382424Srwatson/*
131487218Srwatson * Test the active securelevel against a given level.  securelevel_gt()
131587218Srwatson * implements (securelevel > level).  securelevel_ge() implements
131687218Srwatson * (securelevel >= level).  Note that the logic is inverted -- these
131787218Srwatson * functions return EPERM on "success" and 0 on "failure".
131883639Srwatson *
1319192895Sjamie * Due to care taken when setting the securelevel, we know that no jail will
1320192895Sjamie * be less secure that its parent (or the physical system), so it is sufficient
1321192895Sjamie * to test the current jail only.
1322192895Sjamie *
1323164032Srwatson * XXXRW: Possibly since this has to do with privilege, it should move to
1324164032Srwatson * kern_priv.c.
132583639Srwatson */
132683639Srwatsonint
132783639Srwatsonsecurelevel_gt(struct ucred *cr, int level)
132883639Srwatson{
132983639Srwatson
1330192895Sjamie	return (cr->cr_prison->pr_securelevel > level ? EPERM : 0);
133183639Srwatson}
133283639Srwatson
133383639Srwatsonint
133483639Srwatsonsecurelevel_ge(struct ucred *cr, int level)
133583639Srwatson{
133683639Srwatson
1337192895Sjamie	return (cr->cr_prison->pr_securelevel >= level ? EPERM : 0);
133883639Srwatson}
133983639Srwatson
134084736Srwatson/*
134187144Srwatson * 'see_other_uids' determines whether or not visibility of processes
134287218Srwatson * and sockets with credentials holding different real uids is possible
134387138Srwatson * using a variety of system MIBs.
134487218Srwatson * XXX: data declarations should be together near the beginning of the file.
134584736Srwatson */
134687144Srwatsonstatic int	see_other_uids = 1;
134789414SarrSYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW,
134887218Srwatson    &see_other_uids, 0,
134984736Srwatson    "Unprivileged processes may see subjects/objects with different real uid");
135084736Srwatson
1351210226Strasz/*-
135292923Srwatson * Determine if u1 "can see" the subject specified by u2, according to the
135392923Srwatson * 'see_other_uids' policy.
135492923Srwatson * Returns: 0 for permitted, ESRCH otherwise
135592923Srwatson * Locks: none
135692923Srwatson * References: *u1 and *u2 must not change during the call
135792923Srwatson *             u1 may equal u2, in which case only one reference is required
135892923Srwatson */
135992923Srwatsonstatic int
136092923Srwatsoncr_seeotheruids(struct ucred *u1, struct ucred *u2)
136192923Srwatson{
136292923Srwatson
136392923Srwatson	if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) {
1364170587Srwatson		if (priv_check_cred(u1, PRIV_SEEOTHERUIDS, 0) != 0)
136592923Srwatson			return (ESRCH);
136692923Srwatson	}
136792923Srwatson	return (0);
136892923Srwatson}
136992923Srwatson
1370122869Srwatson/*
1371122869Srwatson * 'see_other_gids' determines whether or not visibility of processes
1372122869Srwatson * and sockets with credentials holding different real gids is possible
1373122869Srwatson * using a variety of system MIBs.
1374122869Srwatson * XXX: data declarations should be together near the beginning of the file.
1375122869Srwatson */
1376122869Srwatsonstatic int	see_other_gids = 1;
1377122869SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, see_other_gids, CTLFLAG_RW,
1378122869Srwatson    &see_other_gids, 0,
1379122869Srwatson    "Unprivileged processes may see subjects/objects with different real gid");
1380122869Srwatson
1381122869Srwatson/*
1382122869Srwatson * Determine if u1 can "see" the subject specified by u2, according to the
1383122869Srwatson * 'see_other_gids' policy.
1384122869Srwatson * Returns: 0 for permitted, ESRCH otherwise
1385122869Srwatson * Locks: none
1386122869Srwatson * References: *u1 and *u2 must not change during the call
1387122869Srwatson *             u1 may equal u2, in which case only one reference is required
1388122869Srwatson */
1389122869Srwatsonstatic int
1390122869Srwatsoncr_seeothergids(struct ucred *u1, struct ucred *u2)
1391122869Srwatson{
1392122869Srwatson	int i, match;
1393122869Srwatson
1394122869Srwatson	if (!see_other_gids) {
1395122869Srwatson		match = 0;
1396122869Srwatson		for (i = 0; i < u1->cr_ngroups; i++) {
1397122869Srwatson			if (groupmember(u1->cr_groups[i], u2))
1398122869Srwatson				match = 1;
1399122869Srwatson			if (match)
1400122869Srwatson				break;
1401122869Srwatson		}
1402122869Srwatson		if (!match) {
1403170587Srwatson			if (priv_check_cred(u1, PRIV_SEEOTHERGIDS, 0) != 0)
1404122869Srwatson				return (ESRCH);
1405122869Srwatson		}
1406122869Srwatson	}
1407122869Srwatson	return (0);
1408122869Srwatson}
1409122869Srwatson
1410210226Strasz/*-
141182466Srwatson * Determine if u1 "can see" the subject specified by u2.
141274956Srwatson * Returns: 0 for permitted, an errno value otherwise
141374956Srwatson * Locks: none
141487218Srwatson * References: *u1 and *u2 must not change during the call
141574956Srwatson *             u1 may equal u2, in which case only one reference is required
141674956Srwatson */
141774956Srwatsonint
141883742Srwatsoncr_cansee(struct ucred *u1, struct ucred *u2)
141965237Srwatson{
142072786Srwatson	int error;
142153518Sphk
142274956Srwatson	if ((error = prison_check(u1, u2)))
142372786Srwatson		return (error);
1424101003Srwatson#ifdef MAC
1425172930Srwatson	if ((error = mac_cred_check_visible(u1, u2)))
1426101003Srwatson		return (error);
1427101003Srwatson#endif
142892923Srwatson	if ((error = cr_seeotheruids(u1, u2)))
142992923Srwatson		return (error);
1430122869Srwatson	if ((error = cr_seeothergids(u1, u2)))
1431122869Srwatson		return (error);
143265237Srwatson	return (0);
143365237Srwatson}
143465237Srwatson
1435210226Strasz/*-
143696886Sjhb * Determine if td "can see" the subject specified by p.
143782424Srwatson * Returns: 0 for permitted, an errno value otherwise
143896886Sjhb * Locks: Sufficient locks to protect p->p_ucred must be held.  td really
143996886Sjhb *        should be curthread.
144096886Sjhb * References: td and p must be valid for the lifetime of the call
144182424Srwatson */
144279335Srwatsonint
144396886Sjhbp_cansee(struct thread *td, struct proc *p)
144474956Srwatson{
144574956Srwatson
144683742Srwatson	/* Wrap cr_cansee() for all functionality. */
144796886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
144896886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
144996886Sjhb	return (cr_cansee(td->td_ucred, p->p_ucred));
145074956Srwatson}
145174956Srwatson
1452120052Srwatson/*
1453120052Srwatson * 'conservative_signals' prevents the delivery of a broad class of
1454120052Srwatson * signals by unprivileged processes to processes that have changed their
1455120052Srwatson * credentials since the last invocation of execve().  This can prevent
1456120052Srwatson * the leakage of cached information or retained privileges as a result
1457120052Srwatson * of a common class of signal-related vulnerabilities.  However, this
1458120052Srwatson * may interfere with some applications that expect to be able to
1459120052Srwatson * deliver these signals to peer processes after having given up
1460120052Srwatson * privilege.
1461120052Srwatson */
1462120052Srwatsonstatic int	conservative_signals = 1;
1463120052SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, conservative_signals, CTLFLAG_RW,
1464120052Srwatson    &conservative_signals, 0, "Unprivileged processes prevented from "
1465120052Srwatson    "sending certain signals to processes whose credentials have changed");
1466210226Strasz/*-
146788943Srwatson * Determine whether cred may deliver the specified signal to proc.
146888943Srwatson * Returns: 0 for permitted, an errno value otherwise.
146988943Srwatson * Locks: A lock must be held for proc.
147088943Srwatson * References: cred and proc must be valid for the lifetime of the call.
147175437Srwatson */
147275437Srwatsonint
1473141815Ssobomaxcr_cansignal(struct ucred *cred, struct proc *proc, int signum)
147453518Sphk{
147582466Srwatson	int error;
147684826Sjhb
147796886Sjhb	PROC_LOCK_ASSERT(proc, MA_OWNED);
147875437Srwatson	/*
147988943Srwatson	 * Jail semantics limit the scope of signalling to proc in the
148088943Srwatson	 * same jail as cred, if cred is in jail.
148175437Srwatson	 */
148288943Srwatson	error = prison_check(cred, proc->p_ucred);
148388943Srwatson	if (error)
148472786Srwatson		return (error);
1485101003Srwatson#ifdef MAC
1486172930Srwatson	if ((error = mac_proc_check_signal(cred, proc, signum)))
1487101003Srwatson		return (error);
1488101003Srwatson#endif
1489122869Srwatson	if ((error = cr_seeotheruids(cred, proc->p_ucred)))
149092923Srwatson		return (error);
1491122869Srwatson	if ((error = cr_seeothergids(cred, proc->p_ucred)))
1492122869Srwatson		return (error);
149365237Srwatson
149465237Srwatson	/*
149582424Srwatson	 * UNIX signal semantics depend on the status of the P_SUGID
149682424Srwatson	 * bit on the target process.  If the bit is set, then additional
149782424Srwatson	 * restrictions are placed on the set of available signals.
149875437Srwatson	 */
1499141815Ssobomax	if (conservative_signals && (proc->p_flag & P_SUGID)) {
150075437Srwatson		switch (signum) {
150175437Srwatson		case 0:
150275437Srwatson		case SIGKILL:
150375437Srwatson		case SIGINT:
150475437Srwatson		case SIGTERM:
1505120052Srwatson		case SIGALRM:
150675437Srwatson		case SIGSTOP:
150775437Srwatson		case SIGTTIN:
150875437Srwatson		case SIGTTOU:
150975437Srwatson		case SIGTSTP:
151075437Srwatson		case SIGHUP:
151175437Srwatson		case SIGUSR1:
151275437Srwatson		case SIGUSR2:
151382466Srwatson			/*
151482466Srwatson			 * Generally, permit job and terminal control
151582466Srwatson			 * signals.
151682466Srwatson			 */
151775437Srwatson			break;
151875437Srwatson		default:
151988943Srwatson			/* Not permitted without privilege. */
1520170587Srwatson			error = priv_check_cred(cred, PRIV_SIGNAL_SUGID, 0);
152175437Srwatson			if (error)
152275437Srwatson				return (error);
152375437Srwatson		}
152465237Srwatson	}
152565237Srwatson
152675480Srwatson	/*
152782424Srwatson	 * Generally, the target credential's ruid or svuid must match the
152875480Srwatson	 * subject credential's ruid or euid.
152975480Srwatson	 */
153088943Srwatson	if (cred->cr_ruid != proc->p_ucred->cr_ruid &&
153188943Srwatson	    cred->cr_ruid != proc->p_ucred->cr_svuid &&
153288943Srwatson	    cred->cr_uid != proc->p_ucred->cr_ruid &&
153388943Srwatson	    cred->cr_uid != proc->p_ucred->cr_svuid) {
1534170587Srwatson		error = priv_check_cred(cred, PRIV_SIGNAL_DIFFCRED, 0);
153575480Srwatson		if (error)
153675480Srwatson			return (error);
153775480Srwatson	}
153875480Srwatson
153987218Srwatson	return (0);
154053518Sphk}
154153518Sphk
1542210226Strasz/*-
154396886Sjhb * Determine whether td may deliver the specified signal to p.
154488943Srwatson * Returns: 0 for permitted, an errno value otherwise
154596886Sjhb * Locks: Sufficient locks to protect various components of td and p
154696886Sjhb *        must be held.  td must be curthread, and a lock must be
154796886Sjhb *        held for p.
154896886Sjhb * References: td and p must be valid for the lifetime of the call
154988943Srwatson */
155088943Srwatsonint
1551141815Ssobomaxp_cansignal(struct thread *td, struct proc *p, int signum)
155288943Srwatson{
155388943Srwatson
155496886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
155596886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
155696886Sjhb	if (td->td_proc == p)
155788943Srwatson		return (0);
155888943Srwatson
155988943Srwatson	/*
156088943Srwatson	 * UNIX signalling semantics require that processes in the same
156188943Srwatson	 * session always be able to deliver SIGCONT to one another,
156288943Srwatson	 * overriding the remaining protections.
156388943Srwatson	 */
156496886Sjhb	/* XXX: This will require an additional lock of some sort. */
156596886Sjhb	if (signum == SIGCONT && td->td_proc->p_session == p->p_session)
156688943Srwatson		return (0);
1567143108Ssobomax	/*
1568143800Ssobomax	 * Some compat layers use SIGTHR and higher signals for
1569143800Ssobomax	 * communication between different kernel threads of the same
1570143800Ssobomax	 * process, so that they expect that it's always possible to
1571143800Ssobomax	 * deliver them, even for suid applications where cr_cansignal() can
1572143108Ssobomax	 * deny such ability for security consideration.  It should be
1573143108Ssobomax	 * pretty safe to do since the only way to create two processes
1574143108Ssobomax	 * with the same p_leader is via rfork(2).
1575143108Ssobomax	 */
1576143805Ssobomax	if (td->td_proc->p_leader != NULL && signum >= SIGTHR &&
1577143805Ssobomax	    signum < SIGTHR + 4 && td->td_proc->p_leader == p->p_leader)
1578143108Ssobomax		return (0);
157988943Srwatson
1580141815Ssobomax	return (cr_cansignal(td->td_ucred, p, signum));
158188943Srwatson}
158288943Srwatson
1583210226Strasz/*-
158496886Sjhb * Determine whether td may reschedule p.
158582466Srwatson * Returns: 0 for permitted, an errno value otherwise
158696886Sjhb * Locks: Sufficient locks to protect various components of td and p
158796886Sjhb *        must be held.  td must be curthread, and a lock must
158896886Sjhb *        be held for p.
158996886Sjhb * References: td and p must be valid for the lifetime of the call
159082424Srwatson */
159179335Srwatsonint
159296886Sjhbp_cansched(struct thread *td, struct proc *p)
159365237Srwatson{
159472786Srwatson	int error;
159565237Srwatson
159696886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
159796886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
159896886Sjhb	if (td->td_proc == p)
159965237Srwatson		return (0);
160096886Sjhb	if ((error = prison_check(td->td_ucred, p->p_ucred)))
160172786Srwatson		return (error);
1602101003Srwatson#ifdef MAC
1603172930Srwatson	if ((error = mac_proc_check_sched(td->td_ucred, p)))
1604101003Srwatson		return (error);
1605101003Srwatson#endif
160696886Sjhb	if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred)))
160792923Srwatson		return (error);
1608122869Srwatson	if ((error = cr_seeothergids(td->td_ucred, p->p_ucred)))
1609122869Srwatson		return (error);
1610164032Srwatson	if (td->td_ucred->cr_ruid != p->p_ucred->cr_ruid &&
1611164032Srwatson	    td->td_ucred->cr_uid != p->p_ucred->cr_ruid) {
1612170587Srwatson		error = priv_check(td, PRIV_SCHED_DIFFCRED);
1613164032Srwatson		if (error)
1614164032Srwatson			return (error);
1615164032Srwatson	}
1616164032Srwatson	return (0);
161765237Srwatson}
161865237Srwatson
161982424Srwatson/*
162087280Srwatson * The 'unprivileged_proc_debug' flag may be used to disable a variety of
162187280Srwatson * unprivileged inter-process debugging services, including some procfs
162287280Srwatson * functionality, ptrace(), and ktrace().  In the past, inter-process
162387280Srwatson * debugging has been involved in a variety of security problems, and sites
162487280Srwatson * not requiring the service might choose to disable it when hardening
162587280Srwatson * systems.
162682424Srwatson *
162782424Srwatson * XXX: Should modifying and reading this variable require locking?
162887218Srwatson * XXX: data declarations should be together near the beginning of the file.
162982424Srwatson */
163087144Srwatsonstatic int	unprivileged_proc_debug = 1;
163189414SarrSYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW,
163287218Srwatson    &unprivileged_proc_debug, 0,
163380735Srwatson    "Unprivileged processes may use process debugging facilities");
163480735Srwatson
1635210226Strasz/*-
163696886Sjhb * Determine whether td may debug p.
163782466Srwatson * Returns: 0 for permitted, an errno value otherwise
163896886Sjhb * Locks: Sufficient locks to protect various components of td and p
163996886Sjhb *        must be held.  td must be curthread, and a lock must
164096886Sjhb *        be held for p.
164196886Sjhb * References: td and p must be valid for the lifetime of the call
164282424Srwatson */
164379335Srwatsonint
164496886Sjhbp_candebug(struct thread *td, struct proc *p)
164565237Srwatson{
164687218Srwatson	int credentialchanged, error, grpsubset, i, uidsubset;
164765237Srwatson
164896886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
164996886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
165087144Srwatson	if (!unprivileged_proc_debug) {
1651170587Srwatson		error = priv_check(td, PRIV_DEBUG_UNPRIV);
165284727Srwatson		if (error)
165384727Srwatson			return (error);
165484727Srwatson	}
165596886Sjhb	if (td->td_proc == p)
165684636Sdes		return (0);
165796886Sjhb	if ((error = prison_check(td->td_ucred, p->p_ucred)))
165872786Srwatson		return (error);
1659101003Srwatson#ifdef MAC
1660172930Srwatson	if ((error = mac_proc_check_debug(td->td_ucred, p)))
1661101003Srwatson		return (error);
1662101003Srwatson#endif
166396886Sjhb	if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred)))
166492923Srwatson		return (error);
1665122869Srwatson	if ((error = cr_seeothergids(td->td_ucred, p->p_ucred)))
1666122869Srwatson		return (error);
166765237Srwatson
166882466Srwatson	/*
166996886Sjhb	 * Is p's group set a subset of td's effective group set?  This
167096886Sjhb	 * includes p's egid, group access list, rgid, and svgid.
167182466Srwatson	 */
167285895Srwatson	grpsubset = 1;
167396886Sjhb	for (i = 0; i < p->p_ucred->cr_ngroups; i++) {
167496886Sjhb		if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) {
167585895Srwatson			grpsubset = 0;
167685895Srwatson			break;
167785895Srwatson		}
167885895Srwatson	}
167985895Srwatson	grpsubset = grpsubset &&
168096886Sjhb	    groupmember(p->p_ucred->cr_rgid, td->td_ucred) &&
168196886Sjhb	    groupmember(p->p_ucred->cr_svgid, td->td_ucred);
168285895Srwatson
168385895Srwatson	/*
168496886Sjhb	 * Are the uids present in p's credential equal to td's
168596886Sjhb	 * effective uid?  This includes p's euid, svuid, and ruid.
168685895Srwatson	 */
168796886Sjhb	uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid &&
168896886Sjhb	    td->td_ucred->cr_uid == p->p_ucred->cr_svuid &&
168996886Sjhb	    td->td_ucred->cr_uid == p->p_ucred->cr_ruid);
169085895Srwatson
169185895Srwatson	/*
169285895Srwatson	 * Has the credential of the process changed since the last exec()?
169385895Srwatson	 */
169496886Sjhb	credentialchanged = (p->p_flag & P_SUGID);
169585895Srwatson
169685895Srwatson	/*
169796886Sjhb	 * If p's gids aren't a subset, or the uids aren't a subset,
169885895Srwatson	 * or the credential has changed, require appropriate privilege
1699164032Srwatson	 * for td to debug p.
170085895Srwatson	 */
1701164032Srwatson	if (!grpsubset || !uidsubset) {
1702170587Srwatson		error = priv_check(td, PRIV_DEBUG_DIFFCRED);
170384727Srwatson		if (error)
170465237Srwatson			return (error);
170582466Srwatson	}
170665237Srwatson
1707164032Srwatson	if (credentialchanged) {
1708170587Srwatson		error = priv_check(td, PRIV_DEBUG_SUGID);
1709164032Srwatson		if (error)
1710164032Srwatson			return (error);
1711164032Srwatson	}
1712164032Srwatson
171387218Srwatson	/* Can't trace init when securelevel > 0. */
171496886Sjhb	if (p == initproc) {
171596886Sjhb		error = securelevel_gt(td->td_ucred, 0);
171683639Srwatson		if (error)
171783639Srwatson			return (error);
171883639Srwatson	}
171965237Srwatson
172085880Srwatson	/*
172185880Srwatson	 * Can't trace a process that's currently exec'ing.
1722164032Srwatson	 *
172385880Srwatson	 * XXX: Note, this is not a security policy decision, it's a
172485880Srwatson	 * basic correctness/functionality decision.  Therefore, this check
172585880Srwatson	 * should be moved to the caller's of p_candebug().
172685880Srwatson	 */
172796886Sjhb	if ((p->p_flag & P_INEXEC) != 0)
1728185983Skib		return (EBUSY);
172987466Srwatson
1730277322Skib	/* Denied explicitely */
1731277322Skib	if ((p->p_flag2 & P2_NOTRACE) != 0) {
1732277322Skib		error = priv_check(td, PRIV_DEBUG_DENIED);
1733277322Skib		if (error != 0)
1734277322Skib			return (error);
1735277322Skib	}
1736277322Skib
173765237Srwatson	return (0);
173865237Srwatson}
173965237Srwatson
1740210226Strasz/*-
174192976Srwatson * Determine whether the subject represented by cred can "see" a socket.
174292976Srwatson * Returns: 0 for permitted, ENOENT otherwise.
174392976Srwatson */
174492976Srwatsonint
174592976Srwatsoncr_canseesocket(struct ucred *cred, struct socket *so)
174692976Srwatson{
174792976Srwatson	int error;
174892976Srwatson
174992976Srwatson	error = prison_check(cred, so->so_cred);
175092976Srwatson	if (error)
175192976Srwatson		return (ENOENT);
1752101003Srwatson#ifdef MAC
1753172930Srwatson	error = mac_socket_check_visible(cred, so);
1754101003Srwatson	if (error)
1755101003Srwatson		return (error);
1756101003Srwatson#endif
175792976Srwatson	if (cr_seeotheruids(cred, so->so_cred))
175892976Srwatson		return (ENOENT);
1759122869Srwatson	if (cr_seeothergids(cred, so->so_cred))
1760122869Srwatson		return (ENOENT);
176192976Srwatson
176292976Srwatson	return (0);
176392976Srwatson}
176492976Srwatson
1765183982Sbz#if defined(INET) || defined(INET6)
1766210226Strasz/*-
1767183982Sbz * Determine whether the subject represented by cred can "see" a socket.
1768183982Sbz * Returns: 0 for permitted, ENOENT otherwise.
1769183982Sbz */
1770183982Sbzint
1771183982Sbzcr_canseeinpcb(struct ucred *cred, struct inpcb *inp)
1772183982Sbz{
1773183982Sbz	int error;
1774183982Sbz
1775183982Sbz	error = prison_check(cred, inp->inp_cred);
1776183982Sbz	if (error)
1777183982Sbz		return (ENOENT);
1778183982Sbz#ifdef MAC
1779183982Sbz	INP_LOCK_ASSERT(inp);
1780183982Sbz	error = mac_inpcb_check_visible(cred, inp);
1781183982Sbz	if (error)
1782183982Sbz		return (error);
1783183982Sbz#endif
1784183982Sbz	if (cr_seeotheruids(cred, inp->inp_cred))
1785183982Sbz		return (ENOENT);
1786183982Sbz	if (cr_seeothergids(cred, inp->inp_cred))
1787183982Sbz		return (ENOENT);
1788183982Sbz
1789183982Sbz	return (0);
1790183982Sbz}
1791183982Sbz#endif
1792183982Sbz
1793210226Strasz/*-
1794145234Srwatson * Determine whether td can wait for the exit of p.
1795145234Srwatson * Returns: 0 for permitted, an errno value otherwise
1796145234Srwatson * Locks: Sufficient locks to protect various components of td and p
1797145234Srwatson *        must be held.  td must be curthread, and a lock must
1798145234Srwatson *        be held for p.
1799145234Srwatson * References: td and p must be valid for the lifetime of the call
1800145234Srwatson
1801145234Srwatson */
1802145234Srwatsonint
1803145234Srwatsonp_canwait(struct thread *td, struct proc *p)
1804145234Srwatson{
1805145234Srwatson	int error;
1806145234Srwatson
1807145234Srwatson	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1808145234Srwatson	PROC_LOCK_ASSERT(p, MA_OWNED);
1809195741Sjamie	if ((error = prison_check(td->td_ucred, p->p_ucred)))
1810145234Srwatson		return (error);
1811145234Srwatson#ifdef MAC
1812172930Srwatson	if ((error = mac_proc_check_wait(td->td_ucred, p)))
1813145234Srwatson		return (error);
1814145234Srwatson#endif
1815145234Srwatson#if 0
1816145234Srwatson	/* XXXMAC: This could have odd effects on some shells. */
1817145234Srwatson	if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred)))
1818145234Srwatson		return (error);
1819145234Srwatson#endif
1820145234Srwatson
1821145234Srwatson	return (0);
1822145234Srwatson}
1823145234Srwatson
182453518Sphk/*
18251541Srgrimes * Allocate a zeroed cred structure.
18261541Srgrimes */
18271541Srgrimesstruct ucred *
182893580Sjhbcrget(void)
18291541Srgrimes{
1830331643Sdim	struct ucred *cr;
18311541Srgrimes
1832184205Sdes	cr = malloc(sizeof(*cr), M_CRED, M_WAITOK | M_ZERO);
1833150634Sjhb	refcount_init(&cr->cr_ref, 1);
1834170407Srwatson#ifdef AUDIT
1835170407Srwatson	audit_cred_init(cr);
1836170407Srwatson#endif
1837101001Srwatson#ifdef MAC
1838172930Srwatson	mac_cred_init(cr);
1839101001Srwatson#endif
1840274122Smjg	cr->cr_groups = cr->cr_smallgroups;
1841274122Smjg	cr->cr_agroups =
1842274122Smjg	    sizeof(cr->cr_smallgroups) / sizeof(cr->cr_smallgroups[0]);
18431541Srgrimes	return (cr);
18441541Srgrimes}
18451541Srgrimes
18461541Srgrimes/*
184782466Srwatson * Claim another reference to a ucred structure.
184869401Salfred */
184984827Sjhbstruct ucred *
185093580Sjhbcrhold(struct ucred *cr)
185169401Salfred{
185269401Salfred
1853150634Sjhb	refcount_acquire(&cr->cr_ref);
185484827Sjhb	return (cr);
185569401Salfred}
185669401Salfred
185769401Salfred/*
1858167211Srwatson * Free a cred structure.  Throws away space when ref count gets to 0.
18591541Srgrimes */
18601549Srgrimesvoid
186193580Sjhbcrfree(struct ucred *cr)
18621541Srgrimes{
186369239Salfred
186475632Salfred	KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref));
1865150634Sjhb	KASSERT(cr->cr_ref != 0xdeadc0de, ("dangling reference to ucred"));
1866150634Sjhb	if (refcount_release(&cr->cr_ref)) {
186765495Struckman		/*
186865495Struckman		 * Some callers of crget(), such as nfs_statfs(),
186965495Struckman		 * allocate a temporary credential, but don't
187065495Struckman		 * allocate a uidinfo structure.
187165495Struckman		 */
187265495Struckman		if (cr->cr_uidinfo != NULL)
187365495Struckman			uifree(cr->cr_uidinfo);
187477277Srwatson		if (cr->cr_ruidinfo != NULL)
187577277Srwatson			uifree(cr->cr_ruidinfo);
187672786Srwatson		/*
187772786Srwatson		 * Free a prison, if any.
187872786Srwatson		 */
1879192895Sjamie		if (cr->cr_prison != NULL)
188072786Srwatson			prison_free(cr->cr_prison);
1881219304Strasz		if (cr->cr_loginclass != NULL)
1882219304Strasz			loginclass_free(cr->cr_loginclass);
1883170407Srwatson#ifdef AUDIT
1884170407Srwatson		audit_cred_destroy(cr);
1885170407Srwatson#endif
1886101001Srwatson#ifdef MAC
1887172930Srwatson		mac_cred_destroy(cr);
1888101001Srwatson#endif
1889274122Smjg		if (cr->cr_groups != cr->cr_smallgroups)
1890274122Smjg			free(cr->cr_groups, M_CRED);
1891184205Sdes		free(cr, M_CRED);
189290756Sdillon	}
18931541Srgrimes}
18941541Srgrimes
18951541Srgrimes/*
189684827Sjhb * Copy a ucred's contents from a template.  Does not block.
189784827Sjhb */
189884827Sjhbvoid
189993580Sjhbcrcopy(struct ucred *dest, struct ucred *src)
190084827Sjhb{
190184827Sjhb
1902272546Smjg	KASSERT(dest->cr_ref == 1, ("crcopy of shared ucred"));
190384827Sjhb	bcopy(&src->cr_startcopy, &dest->cr_startcopy,
190487218Srwatson	    (unsigned)((caddr_t)&src->cr_endcopy -
190584827Sjhb		(caddr_t)&src->cr_startcopy));
1906194498Sbrooks	crsetgroups(dest, src->cr_ngroups, src->cr_groups);
190784827Sjhb	uihold(dest->cr_uidinfo);
190884827Sjhb	uihold(dest->cr_ruidinfo);
1909192895Sjamie	prison_hold(dest->cr_prison);
1910219304Strasz	loginclass_hold(dest->cr_loginclass);
1911170407Srwatson#ifdef AUDIT
1912170407Srwatson	audit_cred_copy(src, dest);
1913170407Srwatson#endif
1914101001Srwatson#ifdef MAC
1915172930Srwatson	mac_cred_copy(src, dest);
1916101001Srwatson#endif
191784827Sjhb}
191884827Sjhb
191984827Sjhb/*
19201541Srgrimes * Dup cred struct to a new held one.
19211541Srgrimes */
19221541Srgrimesstruct ucred *
192393580Sjhbcrdup(struct ucred *cr)
19241541Srgrimes{
19251541Srgrimes	struct ucred *newcr;
19261541Srgrimes
192784827Sjhb	newcr = crget();
192884827Sjhb	crcopy(newcr, cr);
19291541Srgrimes	return (newcr);
19301541Srgrimes}
19311541Srgrimes
19321541Srgrimes/*
193391354Sdd * Fill in a struct xucred based on a struct ucred.
193491354Sdd */
193591354Sddvoid
193693580Sjhbcru2x(struct ucred *cr, struct xucred *xcr)
193791354Sdd{
1938194498Sbrooks	int ngroups;
193991354Sdd
194091354Sdd	bzero(xcr, sizeof(*xcr));
194191354Sdd	xcr->cr_version = XUCRED_VERSION;
194291354Sdd	xcr->cr_uid = cr->cr_uid;
1943194498Sbrooks
1944194498Sbrooks	ngroups = MIN(cr->cr_ngroups, XU_NGROUPS);
1945194498Sbrooks	xcr->cr_ngroups = ngroups;
1946194498Sbrooks	bcopy(cr->cr_groups, xcr->cr_groups,
1947194498Sbrooks	    ngroups * sizeof(*cr->cr_groups));
194891354Sdd}
194991354Sdd
195091354Sdd/*
1951280331Smjg * Set initial process credentials.
1952280331Smjg * Callers are responsible for providing the reference for provided credentials.
1953280331Smjg */
1954280331Smjgvoid
1955280331Smjgproc_set_cred_init(struct proc *p, struct ucred *newcred)
1956280331Smjg{
1957280331Smjg
1958280331Smjg	p->p_ucred = newcred;
1959280331Smjg}
1960280331Smjg
1961280331Smjg/*
1962280130Smjg * Change process credentials.
1963280331Smjg * Callers are responsible for providing the reference for passed credentials
1964280130Smjg * and for freeing old ones.
1965280130Smjg *
1966280130Smjg * Process has to be locked except when it does not have credentials (as it
1967280130Smjg * should not be visible just yet) or when newcred is NULL (as this can be
1968280130Smjg * only used when the process is about to be freed, at which point it should
1969280130Smjg * not be visible anymore).
1970280130Smjg */
1971194498Sbrooksstruct ucred *
1972280130Smjgproc_set_cred(struct proc *p, struct ucred *newcred)
1973280130Smjg{
1974280130Smjg	struct ucred *oldcred;
1975280130Smjg
1976280331Smjg	MPASS(p->p_ucred != NULL);
1977280130Smjg	if (newcred == NULL)
1978280130Smjg		MPASS(p->p_state == PRS_ZOMBIE);
1979280331Smjg	else
1980280130Smjg		PROC_LOCK_ASSERT(p, MA_OWNED);
1981280130Smjg
1982280130Smjg	oldcred = p->p_ucred;
1983280130Smjg	p->p_ucred = newcred;
1984284214Smjg	if (newcred != NULL)
1985284214Smjg		PROC_UPDATE_COW(p);
1986280130Smjg	return (oldcred);
1987280130Smjg}
1988280130Smjg
1989280130Smjgstruct ucred *
1990194498Sbrookscrcopysafe(struct proc *p, struct ucred *cr)
1991194498Sbrooks{
1992194498Sbrooks	struct ucred *oldcred;
1993194498Sbrooks	int groups;
1994194498Sbrooks
1995194498Sbrooks	PROC_LOCK_ASSERT(p, MA_OWNED);
1996194498Sbrooks
1997194498Sbrooks	oldcred = p->p_ucred;
1998194498Sbrooks	while (cr->cr_agroups < oldcred->cr_agroups) {
1999194498Sbrooks		groups = oldcred->cr_agroups;
2000194498Sbrooks		PROC_UNLOCK(p);
2001194498Sbrooks		crextend(cr, groups);
2002194498Sbrooks		PROC_LOCK(p);
2003194498Sbrooks		oldcred = p->p_ucred;
2004194498Sbrooks	}
2005194498Sbrooks	crcopy(cr, oldcred);
2006194498Sbrooks
2007194498Sbrooks	return (oldcred);
2008194498Sbrooks}
2009194498Sbrooks
201090748Sjulian/*
2011194498Sbrooks * Extend the passed in credential to hold n items.
2012194498Sbrooks */
2013293909Sglebiusvoid
2014194498Sbrookscrextend(struct ucred *cr, int n)
2015194498Sbrooks{
2016194498Sbrooks	int cnt;
2017194498Sbrooks
2018194498Sbrooks	/* Truncate? */
2019194498Sbrooks	if (n <= cr->cr_agroups)
2020194498Sbrooks		return;
2021194498Sbrooks
2022194498Sbrooks	/*
2023194498Sbrooks	 * We extend by 2 each time since we're using a power of two
2024194498Sbrooks	 * allocator until we need enough groups to fill a page.
2025194498Sbrooks	 * Once we're allocating multiple pages, only allocate as many
2026194498Sbrooks	 * as we actually need.  The case of processes needing a
2027194498Sbrooks	 * non-power of two number of pages seems more likely than
2028194498Sbrooks	 * a real world process that adds thousands of groups one at a
2029194498Sbrooks	 * time.
2030194498Sbrooks	 */
2031194498Sbrooks	if ( n < PAGE_SIZE / sizeof(gid_t) ) {
2032194498Sbrooks		if (cr->cr_agroups == 0)
2033194498Sbrooks			cnt = MINALLOCSIZE / sizeof(gid_t);
2034194498Sbrooks		else
2035194498Sbrooks			cnt = cr->cr_agroups * 2;
2036194498Sbrooks
2037194498Sbrooks		while (cnt < n)
2038194498Sbrooks			cnt *= 2;
2039194498Sbrooks	} else
2040194498Sbrooks		cnt = roundup2(n, PAGE_SIZE / sizeof(gid_t));
2041194498Sbrooks
2042194498Sbrooks	/* Free the old array. */
2043274122Smjg	if (cr->cr_groups != cr->cr_smallgroups)
2044194498Sbrooks		free(cr->cr_groups, M_CRED);
2045194498Sbrooks
2046194498Sbrooks	cr->cr_groups = malloc(cnt * sizeof(gid_t), M_CRED, M_WAITOK | M_ZERO);
2047194498Sbrooks	cr->cr_agroups = cnt;
2048194498Sbrooks}
2049194498Sbrooks
2050194498Sbrooks/*
2051194556Sbrooks * Copy groups in to a credential, preserving any necessary invariants.
2052194556Sbrooks * Currently this includes the sorting of all supplemental gids.
2053194556Sbrooks * crextend() must have been called before hand to ensure sufficient
2054194556Sbrooks * space is available.
2055194498Sbrooks */
2056194498Sbrooksstatic void
2057194498Sbrookscrsetgroups_locked(struct ucred *cr, int ngrp, gid_t *groups)
2058194498Sbrooks{
2059194556Sbrooks	int i;
2060194556Sbrooks	int j;
2061194556Sbrooks	gid_t g;
2062194498Sbrooks
2063194498Sbrooks	KASSERT(cr->cr_agroups >= ngrp, ("cr_ngroups is too small"));
2064194498Sbrooks
2065194498Sbrooks	bcopy(groups, cr->cr_groups, ngrp * sizeof(gid_t));
2066194498Sbrooks	cr->cr_ngroups = ngrp;
2067194556Sbrooks
2068194556Sbrooks	/*
2069194556Sbrooks	 * Sort all groups except cr_groups[0] to allow groupmember to
2070194556Sbrooks	 * perform a binary search.
2071194556Sbrooks	 *
2072194556Sbrooks	 * XXX: If large numbers of groups become common this should
2073194556Sbrooks	 * be replaced with shell sort like linux uses or possibly
2074194556Sbrooks	 * heap sort.
2075194556Sbrooks	 */
2076194556Sbrooks	for (i = 2; i < ngrp; i++) {
2077194556Sbrooks		g = cr->cr_groups[i];
2078194556Sbrooks		for (j = i-1; j >= 1 && g < cr->cr_groups[j]; j--)
2079194556Sbrooks			cr->cr_groups[j + 1] = cr->cr_groups[j];
2080194556Sbrooks		cr->cr_groups[j + 1] = g;
2081194556Sbrooks	}
2082194498Sbrooks}
2083194498Sbrooks
2084194498Sbrooks/*
2085194498Sbrooks * Copy groups in to a credential after expanding it if required.
2086202143Sbrooks * Truncate the list to (ngroups_max + 1) if it is too large.
2087194498Sbrooks */
2088194498Sbrooksvoid
2089194498Sbrookscrsetgroups(struct ucred *cr, int ngrp, gid_t *groups)
2090194498Sbrooks{
2091194498Sbrooks
2092202143Sbrooks	if (ngrp > ngroups_max + 1)
2093202143Sbrooks		ngrp = ngroups_max + 1;
2094194498Sbrooks
2095194498Sbrooks	crextend(cr, ngrp);
2096194498Sbrooks	crsetgroups_locked(cr, ngrp, groups);
2097194498Sbrooks}
2098194498Sbrooks
2099194498Sbrooks/*
21001541Srgrimes * Get login name, if available.
21011541Srgrimes */
210212221Sbde#ifndef _SYS_SYSPROTO_H_
21031541Srgrimesstruct getlogin_args {
21041541Srgrimes	char	*namebuf;
21051541Srgrimes	u_int	namelen;
21061541Srgrimes};
210712221Sbde#endif
21081541Srgrimes/* ARGSUSED */
21091549Srgrimesint
2110225617Skmacysys_getlogin(struct thread *td, struct getlogin_args *uap)
21111541Srgrimes{
211291140Stanimura	char login[MAXLOGNAME];
211383366Sjulian	struct proc *p = td->td_proc;
2114274106Sdes	size_t len;
21151541Srgrimes
211623358Sache	if (uap->namelen > MAXLOGNAME)
211723359Sache		uap->namelen = MAXLOGNAME;
211891140Stanimura	PROC_LOCK(p);
211991140Stanimura	SESS_LOCK(p->p_session);
2120274106Sdes	len = strlcpy(login, p->p_session->s_login, uap->namelen) + 1;
212191140Stanimura	SESS_UNLOCK(p->p_session);
212291140Stanimura	PROC_UNLOCK(p);
2123274106Sdes	if (len > uap->namelen)
2124243021Sbapt		return (ERANGE);
2125274106Sdes	return (copyout(login, uap->namebuf, len));
21261541Srgrimes}
21271541Srgrimes
21281541Srgrimes/*
21291541Srgrimes * Set login name.
21301541Srgrimes */
213112221Sbde#ifndef _SYS_SYSPROTO_H_
21321541Srgrimesstruct setlogin_args {
21331541Srgrimes	char	*namebuf;
21341541Srgrimes};
213512221Sbde#endif
21361541Srgrimes/* ARGSUSED */
21371549Srgrimesint
2138225617Skmacysys_setlogin(struct thread *td, struct setlogin_args *uap)
21391541Srgrimes{
214083366Sjulian	struct proc *p = td->td_proc;
21411541Srgrimes	int error;
214223330Sache	char logintmp[MAXLOGNAME];
21431541Srgrimes
2144274106Sdes	CTASSERT(sizeof(p->p_session->s_login) >= sizeof(logintmp));
2145274106Sdes
2146170587Srwatson	error = priv_check(td, PRIV_PROC_SETLOGIN);
214794619Sjhb	if (error)
214894619Sjhb		return (error);
214999009Salfred	error = copyinstr(uap->namebuf, logintmp, sizeof(logintmp), NULL);
2150274106Sdes	if (error != 0) {
2151274106Sdes		if (error == ENAMETOOLONG)
2152274106Sdes			error = EINVAL;
2153274106Sdes		return (error);
215491140Stanimura	}
2155274106Sdes	PROC_LOCK(p);
2156274106Sdes	SESS_LOCK(p->p_session);
2157274106Sdes	strcpy(p->p_session->s_login, logintmp);
2158274106Sdes	SESS_UNLOCK(p->p_session);
2159274106Sdes	PROC_UNLOCK(p);
2160274106Sdes	return (0);
21611541Srgrimes}
216231891Ssef
216331891Ssefvoid
216493580Sjhbsetsugid(struct proc *p)
216531891Ssef{
216698403Salfred
216798403Salfred	PROC_LOCK_ASSERT(p, MA_OWNED);
216831891Ssef	p->p_flag |= P_SUGID;
216955707Ssef	if (!(p->p_pfsflags & PF_ISUGID))
217031891Ssef		p->p_stops = 0;
217131891Ssef}
217265495Struckman
2173210226Strasz/*-
217482466Srwatson * Change a process's effective uid.
217577183Srwatson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified.
217677183Srwatson * References: newcred must be an exclusive credential reference for the
217777183Srwatson *             duration of the call.
217865495Struckman */
217965495Struckmanvoid
218098417Salfredchange_euid(struct ucred *newcred, struct uidinfo *euip)
218165495Struckman{
218265495Struckman
218398417Salfred	newcred->cr_uid = euip->ui_uid;
218498417Salfred	uihold(euip);
218577183Srwatson	uifree(newcred->cr_uidinfo);
218698417Salfred	newcred->cr_uidinfo = euip;
218765495Struckman}
218865495Struckman
2189210226Strasz/*-
219082466Srwatson * Change a process's effective gid.
219177183Srwatson * Side effects: newcred->cr_gid will be modified.
219277183Srwatson * References: newcred must be an exclusive credential reference for the
219377183Srwatson *             duration of the call.
219465495Struckman */
219567629Sgallatinvoid
219693580Sjhbchange_egid(struct ucred *newcred, gid_t egid)
219765495Struckman{
219865495Struckman
219977183Srwatson	newcred->cr_groups[0] = egid;
220065495Struckman}
220177183Srwatson
2202210226Strasz/*-
220382466Srwatson * Change a process's real uid.
220477183Srwatson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo
220577183Srwatson *               will be updated, and the old and new cr_ruidinfo proc
220677183Srwatson *               counts will be updated.
220777183Srwatson * References: newcred must be an exclusive credential reference for the
220877183Srwatson *             duration of the call.
220977183Srwatson */
221077183Srwatsonvoid
221198417Salfredchange_ruid(struct ucred *newcred, struct uidinfo *ruip)
221277183Srwatson{
221377183Srwatson
221477183Srwatson	(void)chgproccnt(newcred->cr_ruidinfo, -1, 0);
221598417Salfred	newcred->cr_ruid = ruip->ui_uid;
221698417Salfred	uihold(ruip);
221777183Srwatson	uifree(newcred->cr_ruidinfo);
221898417Salfred	newcred->cr_ruidinfo = ruip;
221977183Srwatson	(void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
222077183Srwatson}
222177183Srwatson
2222210226Strasz/*-
222382466Srwatson * Change a process's real gid.
222477183Srwatson * Side effects: newcred->cr_rgid will be updated.
222577183Srwatson * References: newcred must be an exclusive credential reference for the
222677183Srwatson *             duration of the call.
222777183Srwatson */
222877183Srwatsonvoid
222993580Sjhbchange_rgid(struct ucred *newcred, gid_t rgid)
223077183Srwatson{
223177183Srwatson
223277183Srwatson	newcred->cr_rgid = rgid;
223377183Srwatson}
223477183Srwatson
2235210226Strasz/*-
223682466Srwatson * Change a process's saved uid.
223777183Srwatson * Side effects: newcred->cr_svuid will be updated.
223877183Srwatson * References: newcred must be an exclusive credential reference for the
223977183Srwatson *             duration of the call.
224077183Srwatson */
224177183Srwatsonvoid
224293580Sjhbchange_svuid(struct ucred *newcred, uid_t svuid)
224377183Srwatson{
224477183Srwatson
224577183Srwatson	newcred->cr_svuid = svuid;
224677183Srwatson}
224777183Srwatson
2248210226Strasz/*-
224982466Srwatson * Change a process's saved gid.
225077183Srwatson * Side effects: newcred->cr_svgid will be updated.
225177183Srwatson * References: newcred must be an exclusive credential reference for the
225277183Srwatson *             duration of the call.
225377183Srwatson */
225477183Srwatsonvoid
225593580Sjhbchange_svgid(struct ucred *newcred, gid_t svgid)
225677183Srwatson{
225777183Srwatson
225877183Srwatson	newcred->cr_svgid = svgid;
225977183Srwatson}
2260