xref: /freebsd/sys/kern/kern_prot.c (revision 634675067867090e538b08e62ff9b14d3ffae5a3)
19454b2d8SWarner Losh /*-
251369649SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni  *
4df8bae1dSRodney W. Grimes  * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
5ef08c420SRobert Watson  *	The Regents of the University of California.
6df8bae1dSRodney W. Grimes  * (c) UNIX System Laboratories, Inc.
7ef08c420SRobert Watson  * Copyright (c) 2000-2001 Robert N. M. Watson.
8ef08c420SRobert Watson  * All rights reserved.
9ef08c420SRobert Watson  *
10df8bae1dSRodney W. Grimes  * All or some portions of this file are derived from material licensed
11df8bae1dSRodney W. Grimes  * to the University of California by American Telephone and Telegraph
12df8bae1dSRodney W. Grimes  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
13df8bae1dSRodney W. Grimes  * the permission of UNIX System Laboratories, Inc.
14df8bae1dSRodney W. Grimes  *
15df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
16df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
17df8bae1dSRodney W. Grimes  * are met:
18df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
19df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
20df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
21df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
22df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
2369a28758SEd Maste  * 3. Neither the name of the University nor the names of its contributors
24df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
25df8bae1dSRodney W. Grimes  *    without specific prior written permission.
26df8bae1dSRodney W. Grimes  *
27df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
38df8bae1dSRodney W. Grimes  */
39df8bae1dSRodney W. Grimes 
40df8bae1dSRodney W. Grimes /*
41df8bae1dSRodney W. Grimes  * System calls related to processes and protection
42df8bae1dSRodney W. Grimes  */
43df8bae1dSRodney W. Grimes 
44677b542eSDavid E. O'Brien #include <sys/cdefs.h>
45f08ef6c5SBjoern A. Zeeb #include "opt_inet.h"
46f08ef6c5SBjoern A. Zeeb #include "opt_inet6.h"
475591b823SEivind Eklund 
48df8bae1dSRodney W. Grimes #include <sys/param.h>
49df8bae1dSRodney W. Grimes #include <sys/systm.h>
50fb919e4dSMark Murray #include <sys/acct.h>
51df04411aSRobert Watson #include <sys/kdb.h>
521c5bb3eaSPeter Wemm #include <sys/kernel.h>
5337260547SOlivier Certner #include <sys/libkern.h>
5498f03f90SJake Burkholder #include <sys/lock.h>
552bfc50bcSEdward Tomasz Napierala #include <sys/loginclass.h>
56f9d0d524SRobert Watson #include <sys/malloc.h>
57fb919e4dSMark Murray #include <sys/mutex.h>
58fe6db727SKonstantin Belousov #include <sys/ptrace.h>
597e9e371fSJohn Baldwin #include <sys/refcount.h>
605b29d6e9SJohn Baldwin #include <sys/sx.h>
61800c9408SRobert Watson #include <sys/priv.h>
62f591779bSSeigo Tanimura #include <sys/proc.h>
6331d1b816SDmitry Chagin #ifdef COMPAT_43
647e097daaSKonstantin Belousov #include <sys/sysent.h>
6531d1b816SDmitry Chagin #endif
66fb919e4dSMark Murray #include <sys/sysproto.h>
67eb725b4eSRobert Watson #include <sys/jail.h>
68e4dcb704SEdward Tomasz Napierala #include <sys/racct.h>
69f87beb93SAndriy Gapon #include <sys/rctl.h>
70f535380cSDon Lewis #include <sys/resourcevar.h>
7129dc1288SRobert Watson #include <sys/socket.h>
7229dc1288SRobert Watson #include <sys/socketvar.h>
733cb83e71SJohn Baldwin #include <sys/syscallsubr.h>
74579f4eb4SRobert Watson #include <sys/sysctl.h>
75df8bae1dSRodney W. Grimes 
766bb132baSBrooks Davis #include <vm/uma.h>
776bb132baSBrooks Davis 
78de5b1952SAlexander Leidinger #ifdef REGRESSION
79de5b1952SAlexander Leidinger FEATURE(regression,
80ca54e1aeSHiroki Sato     "Kernel support for interfaces necessary for regression testing (SECURITY RISK!)");
81de5b1952SAlexander Leidinger #endif
82de5b1952SAlexander Leidinger 
832f8a46d5SWayne Salamon #include <security/audit/audit.h>
84aed55708SRobert Watson #include <security/mac/mac_framework.h>
852f8a46d5SWayne Salamon 
86a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_CRED, "cred", "credentials");
87a1c995b6SPoul-Henning Kamp 
887029da5cSPawel Biernacki SYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
897029da5cSPawel Biernacki     "BSD security policy");
9048713bdcSRobert Watson 
91f34a2f56SMateusz Guzik static void crfree_final(struct ucred *cr);
926d2efbb3SOlivier Certner 
936d2efbb3SOlivier Certner static inline void
946d2efbb3SOlivier Certner groups_check_positive_len(int ngrp)
956d2efbb3SOlivier Certner {
966d2efbb3SOlivier Certner 	MPASS2(ngrp >= 0, "negative number of groups");
976d2efbb3SOlivier Certner 	MPASS2(ngrp != 0, "at least one group expected (effective GID)");
986d2efbb3SOlivier Certner }
996d2efbb3SOlivier Certner static inline void
1006d2efbb3SOlivier Certner groups_check_max_len(int ngrp)
1016d2efbb3SOlivier Certner {
1026d2efbb3SOlivier Certner 	MPASS2(ngrp <= ngroups_max + 1, "too many groups");
1036d2efbb3SOlivier Certner }
1046d2efbb3SOlivier Certner 
1056d2efbb3SOlivier Certner static void groups_normalize(int *ngrp, gid_t *groups);
1066d2efbb3SOlivier Certner static void crsetgroups_internal(struct ucred *cr, int ngrp,
1076d2efbb3SOlivier Certner     const gid_t *groups);
108838d9858SBrooks Davis 
10991e9d669SOlivier Certner static int cr_canseeotheruids(struct ucred *u1, struct ucred *u2);
11091e9d669SOlivier Certner static int cr_canseeothergids(struct ucred *u1, struct ucred *u2);
11191e9d669SOlivier Certner static int cr_canseejailproc(struct ucred *u1, struct ucred *u2);
11291e9d669SOlivier Certner 
113d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
114ad7507e2SSteven Wallace struct getpid_args {
115df8bae1dSRodney W. Grimes 	int	dummy;
116df8bae1dSRodney W. Grimes };
117d2d3e875SBruce Evans #endif
118df8bae1dSRodney W. Grimes /* ARGSUSED */
11926f9a767SRodney W. Grimes int
1208451d0ddSKip Macy sys_getpid(struct thread *td, struct getpid_args *uap)
121df8bae1dSRodney W. Grimes {
122b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
123df8bae1dSRodney W. Grimes 
124b40ce416SJulian Elischer 	td->td_retval[0] = p->p_pid;
1251930e303SPoul-Henning Kamp #if defined(COMPAT_43)
1267e097daaSKonstantin Belousov 	if (SV_PROC_FLAG(p, SV_AOUT))
127abd386baSMateusz Guzik 		td->td_retval[1] = kern_getppid(td);
128df8bae1dSRodney W. Grimes #endif
129df8bae1dSRodney W. Grimes 	return (0);
130df8bae1dSRodney W. Grimes }
131df8bae1dSRodney W. Grimes 
132d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
133ad7507e2SSteven Wallace struct getppid_args {
134ad7507e2SSteven Wallace         int     dummy;
135ad7507e2SSteven Wallace };
136d2d3e875SBruce Evans #endif
137df8bae1dSRodney W. Grimes /* ARGSUSED */
13826f9a767SRodney W. Grimes int
1398451d0ddSKip Macy sys_getppid(struct thread *td, struct getppid_args *uap)
140df8bae1dSRodney W. Grimes {
141abd386baSMateusz Guzik 
142abd386baSMateusz Guzik 	td->td_retval[0] = kern_getppid(td);
143abd386baSMateusz Guzik 	return (0);
144abd386baSMateusz Guzik }
145abd386baSMateusz Guzik 
146abd386baSMateusz Guzik int
147abd386baSMateusz Guzik kern_getppid(struct thread *td)
148abd386baSMateusz Guzik {
149b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
150df8bae1dSRodney W. Grimes 
1512c054ce9SMateusz Guzik 	return (p->p_oppid);
152df8bae1dSRodney W. Grimes }
153df8bae1dSRodney W. Grimes 
15436e9f877SMatthew Dillon /*
155eb725b4eSRobert Watson  * Get process group ID; note that POSIX getpgrp takes no parameter.
15636e9f877SMatthew Dillon  */
157d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
158ad7507e2SSteven Wallace struct getpgrp_args {
159ad7507e2SSteven Wallace         int     dummy;
160ad7507e2SSteven Wallace };
161d2d3e875SBruce Evans #endif
16226f9a767SRodney W. Grimes int
1638451d0ddSKip Macy sys_getpgrp(struct thread *td, struct getpgrp_args *uap)
164df8bae1dSRodney W. Grimes {
165b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
166df8bae1dSRodney W. Grimes 
167f591779bSSeigo Tanimura 	PROC_LOCK(p);
168b40ce416SJulian Elischer 	td->td_retval[0] = p->p_pgrp->pg_id;
169f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
170df8bae1dSRodney W. Grimes 	return (0);
171df8bae1dSRodney W. Grimes }
172df8bae1dSRodney W. Grimes 
173e3043798SPedro F. Giffuni /* Get an arbitrary pid's process group id */
1741a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1751a5018a0SPeter Wemm struct getpgid_args {
1761a5018a0SPeter Wemm 	pid_t	pid;
1771a5018a0SPeter Wemm };
1781a5018a0SPeter Wemm #endif
1791a5018a0SPeter Wemm int
1808451d0ddSKip Macy sys_getpgid(struct thread *td, struct getpgid_args *uap)
1811a5018a0SPeter Wemm {
182a70a2b74SJohn Baldwin 	struct proc *p;
183f2ae7368SJohn Baldwin 	int error;
18465de0c7aSDon Lewis 
185f591779bSSeigo Tanimura 	if (uap->pid == 0) {
186a70a2b74SJohn Baldwin 		p = td->td_proc;
187f591779bSSeigo Tanimura 		PROC_LOCK(p);
188a70a2b74SJohn Baldwin 	} else {
189a70a2b74SJohn Baldwin 		p = pfind(uap->pid);
190a70a2b74SJohn Baldwin 		if (p == NULL)
191a70a2b74SJohn Baldwin 			return (ESRCH);
192a70a2b74SJohn Baldwin 		error = p_cansee(td, p);
193a70a2b74SJohn Baldwin 		if (error) {
194a70a2b74SJohn Baldwin 			PROC_UNLOCK(p);
195a70a2b74SJohn Baldwin 			return (error);
196a70a2b74SJohn Baldwin 		}
197a70a2b74SJohn Baldwin 	}
198b40ce416SJulian Elischer 	td->td_retval[0] = p->p_pgrp->pg_id;
199f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
200a70a2b74SJohn Baldwin 	return (0);
2011a5018a0SPeter Wemm }
2021a5018a0SPeter Wemm 
2031a5018a0SPeter Wemm /*
204e3043798SPedro F. Giffuni  * Get an arbitrary pid's session id.
2051a5018a0SPeter Wemm  */
2061a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_
2071a5018a0SPeter Wemm struct getsid_args {
2081a5018a0SPeter Wemm 	pid_t	pid;
2091a5018a0SPeter Wemm };
2101a5018a0SPeter Wemm #endif
2111a5018a0SPeter Wemm int
2128451d0ddSKip Macy sys_getsid(struct thread *td, struct getsid_args *uap)
2131a5018a0SPeter Wemm {
214be2cfdbcSEdward Tomasz Napierala 
215be2cfdbcSEdward Tomasz Napierala 	return (kern_getsid(td, uap->pid));
216be2cfdbcSEdward Tomasz Napierala }
217be2cfdbcSEdward Tomasz Napierala 
218be2cfdbcSEdward Tomasz Napierala int
219be2cfdbcSEdward Tomasz Napierala kern_getsid(struct thread *td, pid_t pid)
220be2cfdbcSEdward Tomasz Napierala {
221a70a2b74SJohn Baldwin 	struct proc *p;
222eb725b4eSRobert Watson 	int error;
22365de0c7aSDon Lewis 
224be2cfdbcSEdward Tomasz Napierala 	if (pid == 0) {
225a70a2b74SJohn Baldwin 		p = td->td_proc;
226f591779bSSeigo Tanimura 		PROC_LOCK(p);
227a70a2b74SJohn Baldwin 	} else {
228be2cfdbcSEdward Tomasz Napierala 		p = pfind(pid);
229a70a2b74SJohn Baldwin 		if (p == NULL)
230a70a2b74SJohn Baldwin 			return (ESRCH);
231a70a2b74SJohn Baldwin 		error = p_cansee(td, p);
232a70a2b74SJohn Baldwin 		if (error) {
233a70a2b74SJohn Baldwin 			PROC_UNLOCK(p);
234a70a2b74SJohn Baldwin 			return (error);
235a70a2b74SJohn Baldwin 		}
236a70a2b74SJohn Baldwin 	}
237b40ce416SJulian Elischer 	td->td_retval[0] = p->p_session->s_sid;
238f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
239a70a2b74SJohn Baldwin 	return (0);
2401a5018a0SPeter Wemm }
2411a5018a0SPeter Wemm 
242d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
243ad7507e2SSteven Wallace struct getuid_args {
244ad7507e2SSteven Wallace         int     dummy;
245ad7507e2SSteven Wallace };
246d2d3e875SBruce Evans #endif
247df8bae1dSRodney W. Grimes /* ARGSUSED */
24826f9a767SRodney W. Grimes int
2498451d0ddSKip Macy sys_getuid(struct thread *td, struct getuid_args *uap)
250df8bae1dSRodney W. Grimes {
251df8bae1dSRodney W. Grimes 
252d846883bSJohn Baldwin 	td->td_retval[0] = td->td_ucred->cr_ruid;
2531930e303SPoul-Henning Kamp #if defined(COMPAT_43)
254d846883bSJohn Baldwin 	td->td_retval[1] = td->td_ucred->cr_uid;
255df8bae1dSRodney W. Grimes #endif
256df8bae1dSRodney W. Grimes 	return (0);
257df8bae1dSRodney W. Grimes }
258df8bae1dSRodney W. Grimes 
259d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
260ad7507e2SSteven Wallace struct geteuid_args {
261ad7507e2SSteven Wallace         int     dummy;
262ad7507e2SSteven Wallace };
263d2d3e875SBruce Evans #endif
264df8bae1dSRodney W. Grimes /* ARGSUSED */
26526f9a767SRodney W. Grimes int
2668451d0ddSKip Macy sys_geteuid(struct thread *td, struct geteuid_args *uap)
267df8bae1dSRodney W. Grimes {
268d846883bSJohn Baldwin 
269d846883bSJohn Baldwin 	td->td_retval[0] = td->td_ucred->cr_uid;
270df8bae1dSRodney W. Grimes 	return (0);
271df8bae1dSRodney W. Grimes }
272df8bae1dSRodney W. Grimes 
273d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
274ad7507e2SSteven Wallace struct getgid_args {
275ad7507e2SSteven Wallace         int     dummy;
276ad7507e2SSteven Wallace };
277d2d3e875SBruce Evans #endif
278df8bae1dSRodney W. Grimes /* ARGSUSED */
27926f9a767SRodney W. Grimes int
2808451d0ddSKip Macy sys_getgid(struct thread *td, struct getgid_args *uap)
281df8bae1dSRodney W. Grimes {
282df8bae1dSRodney W. Grimes 
283d846883bSJohn Baldwin 	td->td_retval[0] = td->td_ucred->cr_rgid;
2841930e303SPoul-Henning Kamp #if defined(COMPAT_43)
285d846883bSJohn Baldwin 	td->td_retval[1] = td->td_ucred->cr_groups[0];
286df8bae1dSRodney W. Grimes #endif
287df8bae1dSRodney W. Grimes 	return (0);
288df8bae1dSRodney W. Grimes }
289df8bae1dSRodney W. Grimes 
290df8bae1dSRodney W. Grimes /*
291df8bae1dSRodney W. Grimes  * Get effective group ID.  The "egid" is groups[0], and could be obtained
292df8bae1dSRodney W. Grimes  * via getgroups.  This syscall exists because it is somewhat painful to do
293df8bae1dSRodney W. Grimes  * correctly in a library function.
294df8bae1dSRodney W. Grimes  */
295d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
296ad7507e2SSteven Wallace struct getegid_args {
297ad7507e2SSteven Wallace         int     dummy;
298ad7507e2SSteven Wallace };
299d2d3e875SBruce Evans #endif
300df8bae1dSRodney W. Grimes /* ARGSUSED */
30126f9a767SRodney W. Grimes int
3028451d0ddSKip Macy sys_getegid(struct thread *td, struct getegid_args *uap)
303df8bae1dSRodney W. Grimes {
304df8bae1dSRodney W. Grimes 
305d846883bSJohn Baldwin 	td->td_retval[0] = td->td_ucred->cr_groups[0];
306df8bae1dSRodney W. Grimes 	return (0);
307df8bae1dSRodney W. Grimes }
308df8bae1dSRodney W. Grimes 
309d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
310df8bae1dSRodney W. Grimes struct getgroups_args {
3114bc2174aSMoritz Buhl 	int	gidsetsize;
312df8bae1dSRodney W. Grimes 	gid_t	*gidset;
313df8bae1dSRodney W. Grimes };
314d2d3e875SBruce Evans #endif
31526f9a767SRodney W. Grimes int
3163e85b721SEd Maste sys_getgroups(struct thread *td, struct getgroups_args *uap)
317df8bae1dSRodney W. Grimes {
31807b384cbSMateusz Guzik 	struct ucred *cred;
3194bc2174aSMoritz Buhl 	int ngrp, error;
320df8bae1dSRodney W. Grimes 
3213cb83e71SJohn Baldwin 	cred = td->td_ucred;
32207b384cbSMateusz Guzik 	ngrp = cred->cr_ngroups;
32307b384cbSMateusz Guzik 
32407b384cbSMateusz Guzik 	if (uap->gidsetsize == 0) {
32507b384cbSMateusz Guzik 		error = 0;
32607b384cbSMateusz Guzik 		goto out;
3273cb83e71SJohn Baldwin 	}
32807b384cbSMateusz Guzik 	if (uap->gidsetsize < ngrp)
3293cb83e71SJohn Baldwin 		return (EINVAL);
33007b384cbSMateusz Guzik 
33107b384cbSMateusz Guzik 	error = copyout(cred->cr_groups, uap->gidset, ngrp * sizeof(gid_t));
33207b384cbSMateusz Guzik out:
33307b384cbSMateusz Guzik 	td->td_retval[0] = ngrp;
33407b384cbSMateusz Guzik 	return (error);
3353cb83e71SJohn Baldwin }
3363cb83e71SJohn Baldwin 
337d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
33882970b81SBruce Evans struct setsid_args {
339ad7507e2SSteven Wallace         int     dummy;
340ad7507e2SSteven Wallace };
341d2d3e875SBruce Evans #endif
342df8bae1dSRodney W. Grimes /* ARGSUSED */
34326f9a767SRodney W. Grimes int
3443e85b721SEd Maste sys_setsid(struct thread *td, struct setsid_args *uap)
345df8bae1dSRodney W. Grimes {
346f591779bSSeigo Tanimura 	struct pgrp *pgrp;
347835a82eeSMatthew Dillon 	int error;
348b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
349f591779bSSeigo Tanimura 	struct pgrp *newpgrp;
350f591779bSSeigo Tanimura 	struct session *newsess;
351f591779bSSeigo Tanimura 
352f591779bSSeigo Tanimura 	pgrp = NULL;
353df8bae1dSRodney W. Grimes 
354ef739c73SKonstantin Belousov 	newpgrp = uma_zalloc(pgrp_zone, M_WAITOK);
3551ede983cSDag-Erling Smørgrav 	newsess = malloc(sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO);
356f591779bSSeigo Tanimura 
3573360b485SKonstantin Belousov again:
3583360b485SKonstantin Belousov 	error = 0;
359c8b1829dSJohn Baldwin 	sx_xlock(&proctree_lock);
360f591779bSSeigo Tanimura 
361f591779bSSeigo Tanimura 	if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) {
362f591779bSSeigo Tanimura 		if (pgrp != NULL)
363f591779bSSeigo Tanimura 			PGRP_UNLOCK(pgrp);
364835a82eeSMatthew Dillon 		error = EPERM;
365f591779bSSeigo Tanimura 	} else {
3663360b485SKonstantin Belousov 		error = enterpgrp(p, p->p_pid, newpgrp, newsess);
3677a70f17aSKonstantin Belousov 		if (error == ERESTART)
3683360b485SKonstantin Belousov 			goto again;
3693360b485SKonstantin Belousov 		MPASS(error == 0);
370b40ce416SJulian Elischer 		td->td_retval[0] = p->p_pid;
371c8b1829dSJohn Baldwin 		newpgrp = NULL;
372c8b1829dSJohn Baldwin 		newsess = NULL;
373df8bae1dSRodney W. Grimes 	}
374f591779bSSeigo Tanimura 
375c8b1829dSJohn Baldwin 	sx_xunlock(&proctree_lock);
376f591779bSSeigo Tanimura 
377ef739c73SKonstantin Belousov 	uma_zfree(pgrp_zone, newpgrp);
3781ede983cSDag-Erling Smørgrav 	free(newsess, M_SESSION);
3791c2451c2SSeigo Tanimura 
380c8b1829dSJohn Baldwin 	return (error);
381df8bae1dSRodney W. Grimes }
382df8bae1dSRodney W. Grimes 
383df8bae1dSRodney W. Grimes /*
384df8bae1dSRodney W. Grimes  * set process group (setpgid/old setpgrp)
385df8bae1dSRodney W. Grimes  *
386df8bae1dSRodney W. Grimes  * caller does setpgid(targpid, targpgid)
387df8bae1dSRodney W. Grimes  *
388df8bae1dSRodney W. Grimes  * pid must be caller or child of caller (ESRCH)
389df8bae1dSRodney W. Grimes  * if a child
390df8bae1dSRodney W. Grimes  *	pid must be in same session (EPERM)
391df8bae1dSRodney W. Grimes  *	pid can't have done an exec (EACCES)
392df8bae1dSRodney W. Grimes  * if pgid != pid
393df8bae1dSRodney W. Grimes  * 	there must exist some pid in same session having pgid (EPERM)
394df8bae1dSRodney W. Grimes  * pid must not be session leader (EPERM)
395df8bae1dSRodney W. Grimes  */
396d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
397df8bae1dSRodney W. Grimes struct setpgid_args {
398df8bae1dSRodney W. Grimes 	int	pid;		/* target process id */
399df8bae1dSRodney W. Grimes 	int	pgid;		/* target pgrp id */
400df8bae1dSRodney W. Grimes };
401d2d3e875SBruce Evans #endif
402df8bae1dSRodney W. Grimes /* ARGSUSED */
40326f9a767SRodney W. Grimes int
4043e85b721SEd Maste sys_setpgid(struct thread *td, struct setpgid_args *uap)
405df8bae1dSRodney W. Grimes {
406b40ce416SJulian Elischer 	struct proc *curp = td->td_proc;
4073e85b721SEd Maste 	struct proc *targp;	/* target process */
4083e85b721SEd Maste 	struct pgrp *pgrp;	/* target pgrp */
409eb9e5c1dSRobert Watson 	int error;
410f591779bSSeigo Tanimura 	struct pgrp *newpgrp;
411df8bae1dSRodney W. Grimes 
41278f64bccSBruce Evans 	if (uap->pgid < 0)
41378f64bccSBruce Evans 		return (EINVAL);
414f591779bSSeigo Tanimura 
415ef739c73SKonstantin Belousov 	newpgrp = uma_zalloc(pgrp_zone, M_WAITOK);
416f591779bSSeigo Tanimura 
4173360b485SKonstantin Belousov again:
4183360b485SKonstantin Belousov 	error = 0;
4193360b485SKonstantin Belousov 
420c8b1829dSJohn Baldwin 	sx_xlock(&proctree_lock);
421df8bae1dSRodney W. Grimes 	if (uap->pid != 0 && uap->pid != curp->p_pid) {
422f591779bSSeigo Tanimura 		if ((targp = pfind(uap->pid)) == NULL) {
423835a82eeSMatthew Dillon 			error = ESRCH;
424c8b1829dSJohn Baldwin 			goto done;
42533a9ed9dSJohn Baldwin 		}
426f591779bSSeigo Tanimura 		if (!inferior(targp)) {
427f591779bSSeigo Tanimura 			PROC_UNLOCK(targp);
4282f932587SSeigo Tanimura 			error = ESRCH;
429c8b1829dSJohn Baldwin 			goto done;
430f591779bSSeigo Tanimura 		}
43171a057bcSRobert Watson 		if ((error = p_cansee(td, targp))) {
43233a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
433c8b1829dSJohn Baldwin 			goto done;
43433a9ed9dSJohn Baldwin 		}
43533a9ed9dSJohn Baldwin 		if (targp->p_pgrp == NULL ||
43633a9ed9dSJohn Baldwin 		    targp->p_session != curp->p_session) {
43733a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
438835a82eeSMatthew Dillon 			error = EPERM;
439c8b1829dSJohn Baldwin 			goto done;
44033a9ed9dSJohn Baldwin 		}
44133a9ed9dSJohn Baldwin 		if (targp->p_flag & P_EXEC) {
44233a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
443835a82eeSMatthew Dillon 			error = EACCES;
444c8b1829dSJohn Baldwin 			goto done;
44533a9ed9dSJohn Baldwin 		}
44633a9ed9dSJohn Baldwin 		PROC_UNLOCK(targp);
447f591779bSSeigo Tanimura 	} else
448f591779bSSeigo Tanimura 		targp = curp;
449f591779bSSeigo Tanimura 	if (SESS_LEADER(targp)) {
450835a82eeSMatthew Dillon 		error = EPERM;
451c8b1829dSJohn Baldwin 		goto done;
45233a9ed9dSJohn Baldwin 	}
453eb725b4eSRobert Watson 	if (uap->pgid == 0)
454df8bae1dSRodney W. Grimes 		uap->pgid = targp->p_pid;
455a10d5f02SOlivier Houchard 	if ((pgrp = pgfind(uap->pgid)) == NULL) {
456f591779bSSeigo Tanimura 		if (uap->pgid == targp->p_pid) {
457a10d5f02SOlivier Houchard 			error = enterpgrp(targp, uap->pgid, newpgrp,
458a10d5f02SOlivier Houchard 			    NULL);
459f591779bSSeigo Tanimura 			if (error == 0)
460f591779bSSeigo Tanimura 				newpgrp = NULL;
461a10d5f02SOlivier Houchard 		} else
462835a82eeSMatthew Dillon 			error = EPERM;
463a10d5f02SOlivier Houchard 	} else {
464f591779bSSeigo Tanimura 		if (pgrp == targp->p_pgrp) {
465f591779bSSeigo Tanimura 			PGRP_UNLOCK(pgrp);
466f591779bSSeigo Tanimura 			goto done;
46733a9ed9dSJohn Baldwin 		}
468a10d5f02SOlivier Houchard 		if (pgrp->pg_id != targp->p_pid &&
469a10d5f02SOlivier Houchard 		    pgrp->pg_session != curp->p_session) {
470a10d5f02SOlivier Houchard 			PGRP_UNLOCK(pgrp);
471a10d5f02SOlivier Houchard 			error = EPERM;
472a10d5f02SOlivier Houchard 			goto done;
473a10d5f02SOlivier Houchard 		}
474f591779bSSeigo Tanimura 		PGRP_UNLOCK(pgrp);
475f591779bSSeigo Tanimura 		error = enterthispgrp(targp, pgrp);
476f591779bSSeigo Tanimura 	}
477f591779bSSeigo Tanimura done:
478ed84cb59SKonstantin Belousov 	KASSERT(error == 0 || newpgrp != NULL,
479c8b1829dSJohn Baldwin 	    ("setpgid failed and newpgrp is NULL"));
4803360b485SKonstantin Belousov 	if (error == ERESTART)
4813360b485SKonstantin Belousov 		goto again;
4827a70f17aSKonstantin Belousov 	sx_xunlock(&proctree_lock);
483ef739c73SKonstantin Belousov 	uma_zfree(pgrp_zone, newpgrp);
484835a82eeSMatthew Dillon 	return (error);
485df8bae1dSRodney W. Grimes }
486df8bae1dSRodney W. Grimes 
487a08f4bf6SPeter Wemm /*
488a08f4bf6SPeter Wemm  * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
4892fa72ea7SJeroen Ruigrok van der Werven  * compatible.  It says that setting the uid/gid to euid/egid is a special
490a08f4bf6SPeter Wemm  * case of "appropriate privilege".  Once the rules are expanded out, this
491a08f4bf6SPeter Wemm  * basically means that setuid(nnn) sets all three id's, in all permitted
492a08f4bf6SPeter Wemm  * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
493a08f4bf6SPeter Wemm  * does not set the saved id - this is dangerous for traditional BSD
494a08f4bf6SPeter Wemm  * programs.  For this reason, we *really* do not want to set
495a08f4bf6SPeter Wemm  * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
496a08f4bf6SPeter Wemm  */
497a08f4bf6SPeter Wemm #define POSIX_APPENDIX_B_4_2_2
498a08f4bf6SPeter Wemm 
499d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
500df8bae1dSRodney W. Grimes struct setuid_args {
501df8bae1dSRodney W. Grimes 	uid_t	uid;
502df8bae1dSRodney W. Grimes };
503d2d3e875SBruce Evans #endif
504df8bae1dSRodney W. Grimes /* ARGSUSED */
50526f9a767SRodney W. Grimes int
5068451d0ddSKip Macy sys_setuid(struct thread *td, struct setuid_args *uap)
507df8bae1dSRodney W. Grimes {
508b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
509b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
510b1fc0ec1SRobert Watson 	uid_t uid;
5111419eacbSAlfred Perlstein 	struct uidinfo *uip;
512eb725b4eSRobert Watson 	int error;
513df8bae1dSRodney W. Grimes 
51407f3485dSJohn Baldwin 	uid = uap->uid;
51514961ba7SRobert Watson 	AUDIT_ARG_UID(uid);
51607f3485dSJohn Baldwin 	newcred = crget();
5171419eacbSAlfred Perlstein 	uip = uifind(uid);
51807f3485dSJohn Baldwin 	PROC_LOCK(p);
519838d9858SBrooks Davis 	/*
520838d9858SBrooks Davis 	 * Copy credentials so other references do not see our changes.
521838d9858SBrooks Davis 	 */
522838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
5235a92ee3cSRobert Watson 
524030a28b3SRobert Watson #ifdef MAC
5256f6174a7SRobert Watson 	error = mac_cred_check_setuid(oldcred, uid);
526030a28b3SRobert Watson 	if (error)
527030a28b3SRobert Watson 		goto fail;
528030a28b3SRobert Watson #endif
529030a28b3SRobert Watson 
530a08f4bf6SPeter Wemm 	/*
531a08f4bf6SPeter Wemm 	 * See if we have "permission" by POSIX 1003.1 rules.
532a08f4bf6SPeter Wemm 	 *
533a08f4bf6SPeter Wemm 	 * Note that setuid(geteuid()) is a special case of
534a08f4bf6SPeter Wemm 	 * "appropriate privileges" in appendix B.4.2.2.  We need
5352fa72ea7SJeroen Ruigrok van der Werven 	 * to use this clause to be compatible with traditional BSD
536a08f4bf6SPeter Wemm 	 * semantics.  Basically, it means that "setuid(xx)" sets all
537a08f4bf6SPeter Wemm 	 * three id's (assuming you have privs).
538a08f4bf6SPeter Wemm 	 *
539a08f4bf6SPeter Wemm 	 * Notes on the logic.  We do things in three steps.
540a08f4bf6SPeter Wemm 	 * 1: We determine if the euid is going to change, and do EPERM
541a08f4bf6SPeter Wemm 	 *    right away.  We unconditionally change the euid later if this
542a08f4bf6SPeter Wemm 	 *    test is satisfied, simplifying that part of the logic.
543eb725b4eSRobert Watson 	 * 2: We determine if the real and/or saved uids are going to
544a08f4bf6SPeter Wemm 	 *    change.  Determined by compile options.
545a08f4bf6SPeter Wemm 	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
546a08f4bf6SPeter Wemm 	 */
547b1fc0ec1SRobert Watson 	if (uid != oldcred->cr_ruid &&		/* allow setuid(getuid()) */
5483f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS
549b1fc0ec1SRobert Watson 	    uid != oldcred->cr_svuid &&		/* allow setuid(saved gid) */
550a08f4bf6SPeter Wemm #endif
551a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
552b1fc0ec1SRobert Watson 	    uid != oldcred->cr_uid &&		/* allow setuid(geteuid()) */
5533f246666SAndrey A. Chernov #endif
554cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETUID)) != 0)
555030a28b3SRobert Watson 		goto fail;
556a08f4bf6SPeter Wemm 
557a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS
558df8bae1dSRodney W. Grimes 	/*
559a08f4bf6SPeter Wemm 	 * Do we have "appropriate privileges" (are we root or uid == euid)
560a08f4bf6SPeter Wemm 	 * If so, we are changing the real uid and/or saved uid.
561df8bae1dSRodney W. Grimes 	 */
5623f246666SAndrey A. Chernov 	if (
563a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
564b1fc0ec1SRobert Watson 	    uid == oldcred->cr_uid ||
5653f246666SAndrey A. Chernov #endif
566800c9408SRobert Watson 	    /* We are using privs. */
567cc426dd3SMateusz Guzik 	    priv_check_cred(oldcred, PRIV_CRED_SETUID) == 0)
568a08f4bf6SPeter Wemm #endif
569a08f4bf6SPeter Wemm 	{
570a08f4bf6SPeter Wemm 		/*
571f535380cSDon Lewis 		 * Set the real uid and transfer proc count to new user.
572a08f4bf6SPeter Wemm 		 */
573b1fc0ec1SRobert Watson 		if (uid != oldcred->cr_ruid) {
5741419eacbSAlfred Perlstein 			change_ruid(newcred, uip);
575f535380cSDon Lewis 			setsugid(p);
576d3cdb93dSAndrey A. Chernov 		}
577a08f4bf6SPeter Wemm 		/*
578a08f4bf6SPeter Wemm 		 * Set saved uid
579a08f4bf6SPeter Wemm 		 *
580a08f4bf6SPeter Wemm 		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
581a08f4bf6SPeter Wemm 		 * the security of seteuid() depends on it.  B.4.2.2 says it
582a08f4bf6SPeter Wemm 		 * is important that we should do this.
583a08f4bf6SPeter Wemm 		 */
584b1fc0ec1SRobert Watson 		if (uid != oldcred->cr_svuid) {
585b1fc0ec1SRobert Watson 			change_svuid(newcred, uid);
586d5f81602SSean Eric Fagan 			setsugid(p);
587a08f4bf6SPeter Wemm 		}
588a08f4bf6SPeter Wemm 	}
589a08f4bf6SPeter Wemm 
590a08f4bf6SPeter Wemm 	/*
591a08f4bf6SPeter Wemm 	 * In all permitted cases, we are changing the euid.
592a08f4bf6SPeter Wemm 	 */
593b1fc0ec1SRobert Watson 	if (uid != oldcred->cr_uid) {
5941419eacbSAlfred Perlstein 		change_euid(newcred, uip);
595d5f81602SSean Eric Fagan 		setsugid(p);
596a08f4bf6SPeter Wemm 	}
597daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
598e4dcb704SEdward Tomasz Napierala #ifdef RACCT
599e4dcb704SEdward Tomasz Napierala 	racct_proc_ucred_changed(p, oldcred, newcred);
600f87beb93SAndriy Gapon 	crhold(newcred);
601f87beb93SAndriy Gapon #endif
602f87beb93SAndriy Gapon 	PROC_UNLOCK(p);
603f87beb93SAndriy Gapon #ifdef RCTL
604f87beb93SAndriy Gapon 	rctl_proc_ucred_changed(p, newcred);
605f87beb93SAndriy Gapon 	crfree(newcred);
606e4dcb704SEdward Tomasz Napierala #endif
6071419eacbSAlfred Perlstein 	uifree(uip);
608b1fc0ec1SRobert Watson 	crfree(oldcred);
60907f3485dSJohn Baldwin 	return (0);
610030a28b3SRobert Watson 
611030a28b3SRobert Watson fail:
612030a28b3SRobert Watson 	PROC_UNLOCK(p);
613030a28b3SRobert Watson 	uifree(uip);
614030a28b3SRobert Watson 	crfree(newcred);
615030a28b3SRobert Watson 	return (error);
616df8bae1dSRodney W. Grimes }
617df8bae1dSRodney W. Grimes 
618d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
619df8bae1dSRodney W. Grimes struct seteuid_args {
620df8bae1dSRodney W. Grimes 	uid_t	euid;
621df8bae1dSRodney W. Grimes };
622d2d3e875SBruce Evans #endif
623df8bae1dSRodney W. Grimes /* ARGSUSED */
62426f9a767SRodney W. Grimes int
6258451d0ddSKip Macy sys_seteuid(struct thread *td, struct seteuid_args *uap)
626df8bae1dSRodney W. Grimes {
627b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
628b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
629b1fc0ec1SRobert Watson 	uid_t euid;
6301419eacbSAlfred Perlstein 	struct uidinfo *euip;
631eb725b4eSRobert Watson 	int error;
632df8bae1dSRodney W. Grimes 
633df8bae1dSRodney W. Grimes 	euid = uap->euid;
63414961ba7SRobert Watson 	AUDIT_ARG_EUID(euid);
63507f3485dSJohn Baldwin 	newcred = crget();
6361419eacbSAlfred Perlstein 	euip = uifind(euid);
63707f3485dSJohn Baldwin 	PROC_LOCK(p);
638838d9858SBrooks Davis 	/*
639838d9858SBrooks Davis 	 * Copy credentials so other references do not see our changes.
640838d9858SBrooks Davis 	 */
641838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
642030a28b3SRobert Watson 
643030a28b3SRobert Watson #ifdef MAC
6446f6174a7SRobert Watson 	error = mac_cred_check_seteuid(oldcred, euid);
645030a28b3SRobert Watson 	if (error)
646030a28b3SRobert Watson 		goto fail;
647030a28b3SRobert Watson #endif
648030a28b3SRobert Watson 
649b1fc0ec1SRobert Watson 	if (euid != oldcred->cr_ruid &&		/* allow seteuid(getuid()) */
650b1fc0ec1SRobert Watson 	    euid != oldcred->cr_svuid &&	/* allow seteuid(saved uid) */
651cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETEUID)) != 0)
652030a28b3SRobert Watson 		goto fail;
653030a28b3SRobert Watson 
654df8bae1dSRodney W. Grimes 	/*
655838d9858SBrooks Davis 	 * Everything's okay, do it.
656df8bae1dSRodney W. Grimes 	 */
657b1fc0ec1SRobert Watson 	if (oldcred->cr_uid != euid) {
6581419eacbSAlfred Perlstein 		change_euid(newcred, euip);
659d5f81602SSean Eric Fagan 		setsugid(p);
660229a15f0SPeter Wemm 	}
661daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
66207f3485dSJohn Baldwin 	PROC_UNLOCK(p);
6631419eacbSAlfred Perlstein 	uifree(euip);
664b1fc0ec1SRobert Watson 	crfree(oldcred);
66507f3485dSJohn Baldwin 	return (0);
666030a28b3SRobert Watson 
667030a28b3SRobert Watson fail:
668030a28b3SRobert Watson 	PROC_UNLOCK(p);
669030a28b3SRobert Watson 	uifree(euip);
670030a28b3SRobert Watson 	crfree(newcred);
671030a28b3SRobert Watson 	return (error);
672df8bae1dSRodney W. Grimes }
673df8bae1dSRodney W. Grimes 
674d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
675df8bae1dSRodney W. Grimes struct setgid_args {
676df8bae1dSRodney W. Grimes 	gid_t	gid;
677df8bae1dSRodney W. Grimes };
678d2d3e875SBruce Evans #endif
679df8bae1dSRodney W. Grimes /* ARGSUSED */
68026f9a767SRodney W. Grimes int
6818451d0ddSKip Macy sys_setgid(struct thread *td, struct setgid_args *uap)
682df8bae1dSRodney W. Grimes {
683b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
684b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
685b1fc0ec1SRobert Watson 	gid_t gid;
686eb725b4eSRobert Watson 	int error;
687df8bae1dSRodney W. Grimes 
688b1fc0ec1SRobert Watson 	gid = uap->gid;
68914961ba7SRobert Watson 	AUDIT_ARG_GID(gid);
69007f3485dSJohn Baldwin 	newcred = crget();
69107f3485dSJohn Baldwin 	PROC_LOCK(p);
692838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
6935a92ee3cSRobert Watson 
694030a28b3SRobert Watson #ifdef MAC
6956f6174a7SRobert Watson 	error = mac_cred_check_setgid(oldcred, gid);
696030a28b3SRobert Watson 	if (error)
697030a28b3SRobert Watson 		goto fail;
698030a28b3SRobert Watson #endif
699030a28b3SRobert Watson 
700a08f4bf6SPeter Wemm 	/*
701a08f4bf6SPeter Wemm 	 * See if we have "permission" by POSIX 1003.1 rules.
702a08f4bf6SPeter Wemm 	 *
703a08f4bf6SPeter Wemm 	 * Note that setgid(getegid()) is a special case of
704a08f4bf6SPeter Wemm 	 * "appropriate privileges" in appendix B.4.2.2.  We need
7052fa72ea7SJeroen Ruigrok van der Werven 	 * to use this clause to be compatible with traditional BSD
706a08f4bf6SPeter Wemm 	 * semantics.  Basically, it means that "setgid(xx)" sets all
707a08f4bf6SPeter Wemm 	 * three id's (assuming you have privs).
708a08f4bf6SPeter Wemm 	 *
709a08f4bf6SPeter Wemm 	 * For notes on the logic here, see setuid() above.
710a08f4bf6SPeter Wemm 	 */
711b1fc0ec1SRobert Watson 	if (gid != oldcred->cr_rgid &&		/* allow setgid(getgid()) */
7123f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS
713b1fc0ec1SRobert Watson 	    gid != oldcred->cr_svgid &&		/* allow setgid(saved gid) */
714a08f4bf6SPeter Wemm #endif
715a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
716b1fc0ec1SRobert Watson 	    gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */
7173f246666SAndrey A. Chernov #endif
718cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETGID)) != 0)
719030a28b3SRobert Watson 		goto fail;
720a08f4bf6SPeter Wemm 
721a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS
722a08f4bf6SPeter Wemm 	/*
723a08f4bf6SPeter Wemm 	 * Do we have "appropriate privileges" (are we root or gid == egid)
724a08f4bf6SPeter Wemm 	 * If so, we are changing the real uid and saved gid.
725a08f4bf6SPeter Wemm 	 */
726a08f4bf6SPeter Wemm 	if (
727a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
728b1fc0ec1SRobert Watson 	    gid == oldcred->cr_groups[0] ||
729a08f4bf6SPeter Wemm #endif
730800c9408SRobert Watson 	    /* We are using privs. */
731cc426dd3SMateusz Guzik 	    priv_check_cred(oldcred, PRIV_CRED_SETGID) == 0)
732a08f4bf6SPeter Wemm #endif
733a08f4bf6SPeter Wemm 	{
734a08f4bf6SPeter Wemm 		/*
735a08f4bf6SPeter Wemm 		 * Set real gid
736a08f4bf6SPeter Wemm 		 */
737b1fc0ec1SRobert Watson 		if (oldcred->cr_rgid != gid) {
738b1fc0ec1SRobert Watson 			change_rgid(newcred, gid);
739d5f81602SSean Eric Fagan 			setsugid(p);
740a08f4bf6SPeter Wemm 		}
741a08f4bf6SPeter Wemm 		/*
742a08f4bf6SPeter Wemm 		 * Set saved gid
743a08f4bf6SPeter Wemm 		 *
744a08f4bf6SPeter Wemm 		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
745a08f4bf6SPeter Wemm 		 * the security of setegid() depends on it.  B.4.2.2 says it
746a08f4bf6SPeter Wemm 		 * is important that we should do this.
747a08f4bf6SPeter Wemm 		 */
748b1fc0ec1SRobert Watson 		if (oldcred->cr_svgid != gid) {
749b1fc0ec1SRobert Watson 			change_svgid(newcred, gid);
750d5f81602SSean Eric Fagan 			setsugid(p);
751a08f4bf6SPeter Wemm 		}
752a08f4bf6SPeter Wemm 	}
753a08f4bf6SPeter Wemm 	/*
754a08f4bf6SPeter Wemm 	 * In all cases permitted cases, we are changing the egid.
755a08f4bf6SPeter Wemm 	 * Copy credentials so other references do not see our changes.
756a08f4bf6SPeter Wemm 	 */
757b1fc0ec1SRobert Watson 	if (oldcred->cr_groups[0] != gid) {
758b1fc0ec1SRobert Watson 		change_egid(newcred, gid);
759d5f81602SSean Eric Fagan 		setsugid(p);
760a08f4bf6SPeter Wemm 	}
761daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
76207f3485dSJohn Baldwin 	PROC_UNLOCK(p);
763b1fc0ec1SRobert Watson 	crfree(oldcred);
76407f3485dSJohn Baldwin 	return (0);
765030a28b3SRobert Watson 
766030a28b3SRobert Watson fail:
767030a28b3SRobert Watson 	PROC_UNLOCK(p);
768030a28b3SRobert Watson 	crfree(newcred);
769030a28b3SRobert Watson 	return (error);
770df8bae1dSRodney W. Grimes }
771df8bae1dSRodney W. Grimes 
772d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
773df8bae1dSRodney W. Grimes struct setegid_args {
774df8bae1dSRodney W. Grimes 	gid_t	egid;
775df8bae1dSRodney W. Grimes };
776d2d3e875SBruce Evans #endif
777df8bae1dSRodney W. Grimes /* ARGSUSED */
77826f9a767SRodney W. Grimes int
7798451d0ddSKip Macy sys_setegid(struct thread *td, struct setegid_args *uap)
780df8bae1dSRodney W. Grimes {
781b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
782b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
783b1fc0ec1SRobert Watson 	gid_t egid;
784eb725b4eSRobert Watson 	int error;
785df8bae1dSRodney W. Grimes 
786df8bae1dSRodney W. Grimes 	egid = uap->egid;
78714961ba7SRobert Watson 	AUDIT_ARG_EGID(egid);
78807f3485dSJohn Baldwin 	newcred = crget();
78907f3485dSJohn Baldwin 	PROC_LOCK(p);
790838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
791030a28b3SRobert Watson 
792030a28b3SRobert Watson #ifdef MAC
7936f6174a7SRobert Watson 	error = mac_cred_check_setegid(oldcred, egid);
794030a28b3SRobert Watson 	if (error)
795030a28b3SRobert Watson 		goto fail;
796030a28b3SRobert Watson #endif
797030a28b3SRobert Watson 
798b1fc0ec1SRobert Watson 	if (egid != oldcred->cr_rgid &&		/* allow setegid(getgid()) */
799b1fc0ec1SRobert Watson 	    egid != oldcred->cr_svgid &&	/* allow setegid(saved gid) */
800cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETEGID)) != 0)
801030a28b3SRobert Watson 		goto fail;
802030a28b3SRobert Watson 
803b1fc0ec1SRobert Watson 	if (oldcred->cr_groups[0] != egid) {
804b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
805d5f81602SSean Eric Fagan 		setsugid(p);
806229a15f0SPeter Wemm 	}
807daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
80807f3485dSJohn Baldwin 	PROC_UNLOCK(p);
809b1fc0ec1SRobert Watson 	crfree(oldcred);
81007f3485dSJohn Baldwin 	return (0);
811030a28b3SRobert Watson 
812030a28b3SRobert Watson fail:
813030a28b3SRobert Watson 	PROC_UNLOCK(p);
814030a28b3SRobert Watson 	crfree(newcred);
815030a28b3SRobert Watson 	return (error);
816df8bae1dSRodney W. Grimes }
817df8bae1dSRodney W. Grimes 
818d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
819df8bae1dSRodney W. Grimes struct setgroups_args {
8204bc2174aSMoritz Buhl 	int	gidsetsize;
821df8bae1dSRodney W. Grimes 	gid_t	*gidset;
822df8bae1dSRodney W. Grimes };
823d2d3e875SBruce Evans #endif
824df8bae1dSRodney W. Grimes /* ARGSUSED */
82526f9a767SRodney W. Grimes int
8268451d0ddSKip Macy sys_setgroups(struct thread *td, struct setgroups_args *uap)
827df8bae1dSRodney W. Grimes {
828664b9fcbSOlivier Certner 	gid_t smallgroups[CRED_SMALLGROUPS_NB];
8297e9a456aSMateusz Guzik 	gid_t *groups;
8304bc2174aSMoritz Buhl 	int gidsetsize, error;
831df8bae1dSRodney W. Grimes 
832abd39811SOlivier Certner 	/*
833abd39811SOlivier Certner 	 * Sanity check size now to avoid passing too big a value to copyin(),
834abd39811SOlivier Certner 	 * even if kern_setgroups() will do it again.
835abd39811SOlivier Certner 	 *
836abd39811SOlivier Certner 	 * Ideally, the 'gidsetsize' argument should have been a 'u_int' (and it
837abd39811SOlivier Certner 	 * was, in this implementation, for a long time), but POSIX standardized
838abd39811SOlivier Certner 	 * getgroups() to take an 'int' and it would be quite entrapping to have
839abd39811SOlivier Certner 	 * setgroups() differ.
840abd39811SOlivier Certner 	 */
84192b064f4SMateusz Guzik 	gidsetsize = uap->gidsetsize;
8424bc2174aSMoritz Buhl 	if (gidsetsize > ngroups_max + 1 || gidsetsize < 0)
8433cb83e71SJohn Baldwin 		return (EINVAL);
8447e9a456aSMateusz Guzik 
845664b9fcbSOlivier Certner 	if (gidsetsize > CRED_SMALLGROUPS_NB)
84692b064f4SMateusz Guzik 		groups = malloc(gidsetsize * sizeof(gid_t), M_TEMP, M_WAITOK);
84792b064f4SMateusz Guzik 	else
84892b064f4SMateusz Guzik 		groups = smallgroups;
8497e9a456aSMateusz Guzik 
85092b064f4SMateusz Guzik 	error = copyin(uap->gidset, groups, gidsetsize * sizeof(gid_t));
8517e9a456aSMateusz Guzik 	if (error == 0)
8526d2efbb3SOlivier Certner 		error = kern_setgroups(td, &gidsetsize, groups);
8537e9a456aSMateusz Guzik 
8546d2efbb3SOlivier Certner 	if (groups != smallgroups)
855838d9858SBrooks Davis 		free(groups, M_TEMP);
8563cb83e71SJohn Baldwin 	return (error);
8573cb83e71SJohn Baldwin }
8583cb83e71SJohn Baldwin 
85937260547SOlivier Certner static int
86037260547SOlivier Certner gidp_cmp(const void *p1, const void *p2)
86137260547SOlivier Certner {
86237260547SOlivier Certner 	const gid_t g1 = *(const gid_t *)p1;
86337260547SOlivier Certner 	const gid_t g2 = *(const gid_t *)p2;
86437260547SOlivier Certner 
86537260547SOlivier Certner 	return ((g1 > g2) - (g1 < g2));
86637260547SOlivier Certner }
86737260547SOlivier Certner 
8686d2efbb3SOlivier Certner /*
8696d2efbb3SOlivier Certner  * CAUTION: This function normalizes 'groups', possibly also changing the value
8706d2efbb3SOlivier Certner  * of '*ngrpp' as a consequence.
8716d2efbb3SOlivier Certner  */
8723cb83e71SJohn Baldwin int
8736d2efbb3SOlivier Certner kern_setgroups(struct thread *td, int *ngrpp, gid_t *groups)
8743cb83e71SJohn Baldwin {
8753cb83e71SJohn Baldwin 	struct proc *p = td->td_proc;
8763cb83e71SJohn Baldwin 	struct ucred *newcred, *oldcred;
8776d2efbb3SOlivier Certner 	int ngrp, error;
8783cb83e71SJohn Baldwin 
8796d2efbb3SOlivier Certner 	ngrp = *ngrpp;
880abd39811SOlivier Certner 	/* Sanity check size. */
881abd39811SOlivier Certner 	if (ngrp < 0 || ngrp > ngroups_max + 1)
882abd39811SOlivier Certner 		return (EINVAL);
883abd39811SOlivier Certner 
88414961ba7SRobert Watson 	AUDIT_ARG_GROUPSET(groups, ngrp);
8856d2efbb3SOlivier Certner 	if (ngrp != 0) {
8866d2efbb3SOlivier Certner 		/* We allow and treat 0 specially below. */
8876d2efbb3SOlivier Certner 		groups_normalize(ngrpp, groups);
8886d2efbb3SOlivier Certner 		ngrp = *ngrpp;
8896d2efbb3SOlivier Certner 	}
89007f3485dSJohn Baldwin 	newcred = crget();
891838d9858SBrooks Davis 	crextend(newcred, ngrp);
89207f3485dSJohn Baldwin 	PROC_LOCK(p);
893838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
894030a28b3SRobert Watson 
895030a28b3SRobert Watson #ifdef MAC
8966d2efbb3SOlivier Certner 	error = ngrp == 0 ?
8976d2efbb3SOlivier Certner 	    /* If 'ngrp' is 0, we'll keep just the current effective GID. */
8986d2efbb3SOlivier Certner 	    mac_cred_check_setgroups(oldcred, 1, oldcred->cr_groups) :
8996d2efbb3SOlivier Certner 	    mac_cred_check_setgroups(oldcred, ngrp, groups);
900030a28b3SRobert Watson 	if (error)
901030a28b3SRobert Watson 		goto fail;
902030a28b3SRobert Watson #endif
903030a28b3SRobert Watson 
904cc426dd3SMateusz Guzik 	error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS);
905030a28b3SRobert Watson 	if (error)
906030a28b3SRobert Watson 		goto fail;
90707f3485dSJohn Baldwin 
9087e9a456aSMateusz Guzik 	if (ngrp == 0) {
9098a5d815aSPeter Wemm 		/*
9108a5d815aSPeter Wemm 		 * setgroups(0, NULL) is a legitimate way of clearing the
9118a5d815aSPeter Wemm 		 * groups vector on non-BSD systems (which generally do not
9128a5d815aSPeter Wemm 		 * have the egid in the groups[0]).  We risk security holes
9138a5d815aSPeter Wemm 		 * when running non-BSD software if we do not do the same.
9148a5d815aSPeter Wemm 		 */
915b1fc0ec1SRobert Watson 		newcred->cr_ngroups = 1;
9166d2efbb3SOlivier Certner 	} else
9176d2efbb3SOlivier Certner 		crsetgroups_internal(newcred, ngrp, groups);
9186d2efbb3SOlivier Certner 
919d5f81602SSean Eric Fagan 	setsugid(p);
920daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
92107f3485dSJohn Baldwin 	PROC_UNLOCK(p);
922b1fc0ec1SRobert Watson 	crfree(oldcred);
92307f3485dSJohn Baldwin 	return (0);
924030a28b3SRobert Watson 
925030a28b3SRobert Watson fail:
926030a28b3SRobert Watson 	PROC_UNLOCK(p);
927030a28b3SRobert Watson 	crfree(newcred);
928030a28b3SRobert Watson 	return (error);
929df8bae1dSRodney W. Grimes }
930df8bae1dSRodney W. Grimes 
931d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
932df8bae1dSRodney W. Grimes struct setreuid_args {
93300999cd6SAndrey A. Chernov 	uid_t	ruid;
93400999cd6SAndrey A. Chernov 	uid_t	euid;
935df8bae1dSRodney W. Grimes };
936d2d3e875SBruce Evans #endif
937df8bae1dSRodney W. Grimes /* ARGSUSED */
93826f9a767SRodney W. Grimes int
9393e85b721SEd Maste sys_setreuid(struct thread *td, struct setreuid_args *uap)
940df8bae1dSRodney W. Grimes {
941b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
942b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
943eb725b4eSRobert Watson 	uid_t euid, ruid;
9441419eacbSAlfred Perlstein 	struct uidinfo *euip, *ruip;
945eb725b4eSRobert Watson 	int error;
946df8bae1dSRodney W. Grimes 
94700999cd6SAndrey A. Chernov 	euid = uap->euid;
948eb725b4eSRobert Watson 	ruid = uap->ruid;
94914961ba7SRobert Watson 	AUDIT_ARG_EUID(euid);
95014961ba7SRobert Watson 	AUDIT_ARG_RUID(ruid);
95107f3485dSJohn Baldwin 	newcred = crget();
9521419eacbSAlfred Perlstein 	euip = uifind(euid);
9531419eacbSAlfred Perlstein 	ruip = uifind(ruid);
95407f3485dSJohn Baldwin 	PROC_LOCK(p);
955838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
956030a28b3SRobert Watson 
957030a28b3SRobert Watson #ifdef MAC
9586f6174a7SRobert Watson 	error = mac_cred_check_setreuid(oldcred, ruid, euid);
959030a28b3SRobert Watson 	if (error)
960030a28b3SRobert Watson 		goto fail;
961030a28b3SRobert Watson #endif
962030a28b3SRobert Watson 
963b1fc0ec1SRobert Watson 	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
964b1fc0ec1SRobert Watson 	      ruid != oldcred->cr_svuid) ||
965b1fc0ec1SRobert Watson 	     (euid != (uid_t)-1 && euid != oldcred->cr_uid &&
966b1fc0ec1SRobert Watson 	      euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) &&
967cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETREUID)) != 0)
968030a28b3SRobert Watson 		goto fail;
969030a28b3SRobert Watson 
970b1fc0ec1SRobert Watson 	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
9711419eacbSAlfred Perlstein 		change_euid(newcred, euip);
972d5f81602SSean Eric Fagan 		setsugid(p);
973a89a5370SPeter Wemm 	}
974b1fc0ec1SRobert Watson 	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
9751419eacbSAlfred Perlstein 		change_ruid(newcred, ruip);
976d5f81602SSean Eric Fagan 		setsugid(p);
97700999cd6SAndrey A. Chernov 	}
978b1fc0ec1SRobert Watson 	if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) &&
979b1fc0ec1SRobert Watson 	    newcred->cr_svuid != newcred->cr_uid) {
980b1fc0ec1SRobert Watson 		change_svuid(newcred, newcred->cr_uid);
981d5f81602SSean Eric Fagan 		setsugid(p);
982a89a5370SPeter Wemm 	}
983daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
984e4dcb704SEdward Tomasz Napierala #ifdef RACCT
985e4dcb704SEdward Tomasz Napierala 	racct_proc_ucred_changed(p, oldcred, newcred);
986f87beb93SAndriy Gapon 	crhold(newcred);
987f87beb93SAndriy Gapon #endif
988f87beb93SAndriy Gapon 	PROC_UNLOCK(p);
989f87beb93SAndriy Gapon #ifdef RCTL
990f87beb93SAndriy Gapon 	rctl_proc_ucred_changed(p, newcred);
991f87beb93SAndriy Gapon 	crfree(newcred);
992e4dcb704SEdward Tomasz Napierala #endif
9931419eacbSAlfred Perlstein 	uifree(ruip);
9941419eacbSAlfred Perlstein 	uifree(euip);
995b1fc0ec1SRobert Watson 	crfree(oldcred);
99607f3485dSJohn Baldwin 	return (0);
997030a28b3SRobert Watson 
998030a28b3SRobert Watson fail:
999030a28b3SRobert Watson 	PROC_UNLOCK(p);
1000030a28b3SRobert Watson 	uifree(ruip);
1001030a28b3SRobert Watson 	uifree(euip);
1002030a28b3SRobert Watson 	crfree(newcred);
1003030a28b3SRobert Watson 	return (error);
1004df8bae1dSRodney W. Grimes }
1005df8bae1dSRodney W. Grimes 
1006d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
1007df8bae1dSRodney W. Grimes struct setregid_args {
100800999cd6SAndrey A. Chernov 	gid_t	rgid;
100900999cd6SAndrey A. Chernov 	gid_t	egid;
1010df8bae1dSRodney W. Grimes };
1011d2d3e875SBruce Evans #endif
1012df8bae1dSRodney W. Grimes /* ARGSUSED */
101326f9a767SRodney W. Grimes int
10143e85b721SEd Maste sys_setregid(struct thread *td, struct setregid_args *uap)
1015df8bae1dSRodney W. Grimes {
1016b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1017b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
1018eb725b4eSRobert Watson 	gid_t egid, rgid;
1019eb725b4eSRobert Watson 	int error;
1020df8bae1dSRodney W. Grimes 
102100999cd6SAndrey A. Chernov 	egid = uap->egid;
1022eb725b4eSRobert Watson 	rgid = uap->rgid;
102314961ba7SRobert Watson 	AUDIT_ARG_EGID(egid);
102414961ba7SRobert Watson 	AUDIT_ARG_RGID(rgid);
102507f3485dSJohn Baldwin 	newcred = crget();
102607f3485dSJohn Baldwin 	PROC_LOCK(p);
1027838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
1028030a28b3SRobert Watson 
1029030a28b3SRobert Watson #ifdef MAC
10306f6174a7SRobert Watson 	error = mac_cred_check_setregid(oldcred, rgid, egid);
1031030a28b3SRobert Watson 	if (error)
1032030a28b3SRobert Watson 		goto fail;
1033030a28b3SRobert Watson #endif
1034030a28b3SRobert Watson 
1035b1fc0ec1SRobert Watson 	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
1036b1fc0ec1SRobert Watson 	    rgid != oldcred->cr_svgid) ||
1037b1fc0ec1SRobert Watson 	     (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] &&
1038b1fc0ec1SRobert Watson 	     egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) &&
1039cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETREGID)) != 0)
1040030a28b3SRobert Watson 		goto fail;
104107f3485dSJohn Baldwin 
1042b1fc0ec1SRobert Watson 	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
1043b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
1044d5f81602SSean Eric Fagan 		setsugid(p);
1045a89a5370SPeter Wemm 	}
1046b1fc0ec1SRobert Watson 	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
1047b1fc0ec1SRobert Watson 		change_rgid(newcred, rgid);
1048d5f81602SSean Eric Fagan 		setsugid(p);
1049a89a5370SPeter Wemm 	}
1050b1fc0ec1SRobert Watson 	if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) &&
1051b1fc0ec1SRobert Watson 	    newcred->cr_svgid != newcred->cr_groups[0]) {
1052b1fc0ec1SRobert Watson 		change_svgid(newcred, newcred->cr_groups[0]);
1053d5f81602SSean Eric Fagan 		setsugid(p);
1054a89a5370SPeter Wemm 	}
1055daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
105607f3485dSJohn Baldwin 	PROC_UNLOCK(p);
10574589be70SRuslan Ermilov 	crfree(oldcred);
105807f3485dSJohn Baldwin 	return (0);
1059030a28b3SRobert Watson 
1060030a28b3SRobert Watson fail:
1061030a28b3SRobert Watson 	PROC_UNLOCK(p);
1062030a28b3SRobert Watson 	crfree(newcred);
1063030a28b3SRobert Watson 	return (error);
1064df8bae1dSRodney W. Grimes }
1065df8bae1dSRodney W. Grimes 
10668ccd6334SPeter Wemm /*
1067873fbcd7SRobert Watson  * setresuid(ruid, euid, suid) is like setreuid except control over the saved
1068873fbcd7SRobert Watson  * uid is explicit.
10698ccd6334SPeter Wemm  */
10708ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
10718ccd6334SPeter Wemm struct setresuid_args {
10728ccd6334SPeter Wemm 	uid_t	ruid;
10738ccd6334SPeter Wemm 	uid_t	euid;
10748ccd6334SPeter Wemm 	uid_t	suid;
10758ccd6334SPeter Wemm };
10768ccd6334SPeter Wemm #endif
10778ccd6334SPeter Wemm /* ARGSUSED */
10788ccd6334SPeter Wemm int
10793e85b721SEd Maste sys_setresuid(struct thread *td, struct setresuid_args *uap)
10808ccd6334SPeter Wemm {
1081b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1082b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
1083eb725b4eSRobert Watson 	uid_t euid, ruid, suid;
10841419eacbSAlfred Perlstein 	struct uidinfo *euip, *ruip;
10858ccd6334SPeter Wemm 	int error;
10868ccd6334SPeter Wemm 
10878ccd6334SPeter Wemm 	euid = uap->euid;
1088eb725b4eSRobert Watson 	ruid = uap->ruid;
10898ccd6334SPeter Wemm 	suid = uap->suid;
109014961ba7SRobert Watson 	AUDIT_ARG_EUID(euid);
109114961ba7SRobert Watson 	AUDIT_ARG_RUID(ruid);
109214961ba7SRobert Watson 	AUDIT_ARG_SUID(suid);
109307f3485dSJohn Baldwin 	newcred = crget();
10941419eacbSAlfred Perlstein 	euip = uifind(euid);
10951419eacbSAlfred Perlstein 	ruip = uifind(ruid);
109607f3485dSJohn Baldwin 	PROC_LOCK(p);
1097838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
1098030a28b3SRobert Watson 
1099030a28b3SRobert Watson #ifdef MAC
11006f6174a7SRobert Watson 	error = mac_cred_check_setresuid(oldcred, ruid, euid, suid);
1101030a28b3SRobert Watson 	if (error)
1102030a28b3SRobert Watson 		goto fail;
1103030a28b3SRobert Watson #endif
1104030a28b3SRobert Watson 
1105b1fc0ec1SRobert Watson 	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
1106b1fc0ec1SRobert Watson 	     ruid != oldcred->cr_svuid &&
1107b1fc0ec1SRobert Watson 	      ruid != oldcred->cr_uid) ||
1108b1fc0ec1SRobert Watson 	     (euid != (uid_t)-1 && euid != oldcred->cr_ruid &&
1109b1fc0ec1SRobert Watson 	    euid != oldcred->cr_svuid &&
1110b1fc0ec1SRobert Watson 	      euid != oldcred->cr_uid) ||
1111b1fc0ec1SRobert Watson 	     (suid != (uid_t)-1 && suid != oldcred->cr_ruid &&
1112b1fc0ec1SRobert Watson 	    suid != oldcred->cr_svuid &&
1113b1fc0ec1SRobert Watson 	      suid != oldcred->cr_uid)) &&
1114cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETRESUID)) != 0)
1115030a28b3SRobert Watson 		goto fail;
111607f3485dSJohn Baldwin 
1117b1fc0ec1SRobert Watson 	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
11181419eacbSAlfred Perlstein 		change_euid(newcred, euip);
11198ccd6334SPeter Wemm 		setsugid(p);
11208ccd6334SPeter Wemm 	}
1121b1fc0ec1SRobert Watson 	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
11221419eacbSAlfred Perlstein 		change_ruid(newcred, ruip);
11238ccd6334SPeter Wemm 		setsugid(p);
11248ccd6334SPeter Wemm 	}
1125b1fc0ec1SRobert Watson 	if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) {
1126b1fc0ec1SRobert Watson 		change_svuid(newcred, suid);
11278ccd6334SPeter Wemm 		setsugid(p);
11288ccd6334SPeter Wemm 	}
1129daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
1130e4dcb704SEdward Tomasz Napierala #ifdef RACCT
1131e4dcb704SEdward Tomasz Napierala 	racct_proc_ucred_changed(p, oldcred, newcred);
1132f87beb93SAndriy Gapon 	crhold(newcred);
1133f87beb93SAndriy Gapon #endif
1134f87beb93SAndriy Gapon 	PROC_UNLOCK(p);
1135f87beb93SAndriy Gapon #ifdef RCTL
1136f87beb93SAndriy Gapon 	rctl_proc_ucred_changed(p, newcred);
1137f87beb93SAndriy Gapon 	crfree(newcred);
1138e4dcb704SEdward Tomasz Napierala #endif
11391419eacbSAlfred Perlstein 	uifree(ruip);
11401419eacbSAlfred Perlstein 	uifree(euip);
1141b1fc0ec1SRobert Watson 	crfree(oldcred);
114207f3485dSJohn Baldwin 	return (0);
1143030a28b3SRobert Watson 
1144030a28b3SRobert Watson fail:
1145030a28b3SRobert Watson 	PROC_UNLOCK(p);
1146030a28b3SRobert Watson 	uifree(ruip);
1147030a28b3SRobert Watson 	uifree(euip);
1148030a28b3SRobert Watson 	crfree(newcred);
1149030a28b3SRobert Watson 	return (error);
1150030a28b3SRobert Watson 
11518ccd6334SPeter Wemm }
11528ccd6334SPeter Wemm 
11538ccd6334SPeter Wemm /*
1154873fbcd7SRobert Watson  * setresgid(rgid, egid, sgid) is like setregid except control over the saved
1155873fbcd7SRobert Watson  * gid is explicit.
11568ccd6334SPeter Wemm  */
11578ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
11588ccd6334SPeter Wemm struct setresgid_args {
11598ccd6334SPeter Wemm 	gid_t	rgid;
11608ccd6334SPeter Wemm 	gid_t	egid;
11618ccd6334SPeter Wemm 	gid_t	sgid;
11628ccd6334SPeter Wemm };
11638ccd6334SPeter Wemm #endif
11648ccd6334SPeter Wemm /* ARGSUSED */
11658ccd6334SPeter Wemm int
11663e85b721SEd Maste sys_setresgid(struct thread *td, struct setresgid_args *uap)
11678ccd6334SPeter Wemm {
1168b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1169b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
1170eb725b4eSRobert Watson 	gid_t egid, rgid, sgid;
11718ccd6334SPeter Wemm 	int error;
11728ccd6334SPeter Wemm 
11738ccd6334SPeter Wemm 	egid = uap->egid;
1174eb725b4eSRobert Watson 	rgid = uap->rgid;
11758ccd6334SPeter Wemm 	sgid = uap->sgid;
117614961ba7SRobert Watson 	AUDIT_ARG_EGID(egid);
117714961ba7SRobert Watson 	AUDIT_ARG_RGID(rgid);
117814961ba7SRobert Watson 	AUDIT_ARG_SGID(sgid);
117907f3485dSJohn Baldwin 	newcred = crget();
118007f3485dSJohn Baldwin 	PROC_LOCK(p);
1181838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
1182030a28b3SRobert Watson 
1183030a28b3SRobert Watson #ifdef MAC
11846f6174a7SRobert Watson 	error = mac_cred_check_setresgid(oldcred, rgid, egid, sgid);
1185030a28b3SRobert Watson 	if (error)
1186030a28b3SRobert Watson 		goto fail;
1187030a28b3SRobert Watson #endif
1188030a28b3SRobert Watson 
1189b1fc0ec1SRobert Watson 	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
1190b1fc0ec1SRobert Watson 	      rgid != oldcred->cr_svgid &&
1191b1fc0ec1SRobert Watson 	      rgid != oldcred->cr_groups[0]) ||
1192b1fc0ec1SRobert Watson 	     (egid != (gid_t)-1 && egid != oldcred->cr_rgid &&
1193b1fc0ec1SRobert Watson 	      egid != oldcred->cr_svgid &&
1194b1fc0ec1SRobert Watson 	      egid != oldcred->cr_groups[0]) ||
1195b1fc0ec1SRobert Watson 	     (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid &&
1196b1fc0ec1SRobert Watson 	      sgid != oldcred->cr_svgid &&
1197b1fc0ec1SRobert Watson 	      sgid != oldcred->cr_groups[0])) &&
1198cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETRESGID)) != 0)
1199030a28b3SRobert Watson 		goto fail;
120007f3485dSJohn Baldwin 
1201b1fc0ec1SRobert Watson 	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
1202b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
12038ccd6334SPeter Wemm 		setsugid(p);
12048ccd6334SPeter Wemm 	}
1205b1fc0ec1SRobert Watson 	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
1206b1fc0ec1SRobert Watson 		change_rgid(newcred, rgid);
12078ccd6334SPeter Wemm 		setsugid(p);
12088ccd6334SPeter Wemm 	}
1209b1fc0ec1SRobert Watson 	if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) {
1210b1fc0ec1SRobert Watson 		change_svgid(newcred, sgid);
12118ccd6334SPeter Wemm 		setsugid(p);
12128ccd6334SPeter Wemm 	}
1213daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
121407f3485dSJohn Baldwin 	PROC_UNLOCK(p);
1215b1fc0ec1SRobert Watson 	crfree(oldcred);
121607f3485dSJohn Baldwin 	return (0);
1217030a28b3SRobert Watson 
1218030a28b3SRobert Watson fail:
1219030a28b3SRobert Watson 	PROC_UNLOCK(p);
1220030a28b3SRobert Watson 	crfree(newcred);
1221030a28b3SRobert Watson 	return (error);
12228ccd6334SPeter Wemm }
12238ccd6334SPeter Wemm 
12248ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
12258ccd6334SPeter Wemm struct getresuid_args {
12268ccd6334SPeter Wemm 	uid_t	*ruid;
12278ccd6334SPeter Wemm 	uid_t	*euid;
12288ccd6334SPeter Wemm 	uid_t	*suid;
12298ccd6334SPeter Wemm };
12308ccd6334SPeter Wemm #endif
12318ccd6334SPeter Wemm /* ARGSUSED */
12328ccd6334SPeter Wemm int
12333e85b721SEd Maste sys_getresuid(struct thread *td, struct getresuid_args *uap)
12348ccd6334SPeter Wemm {
1235835a82eeSMatthew Dillon 	struct ucred *cred;
12368ccd6334SPeter Wemm 	int error1 = 0, error2 = 0, error3 = 0;
12378ccd6334SPeter Wemm 
1238d74ac681SMatthew Dillon 	cred = td->td_ucred;
12398ccd6334SPeter Wemm 	if (uap->ruid)
12407f05b035SAlfred Perlstein 		error1 = copyout(&cred->cr_ruid,
12417f05b035SAlfred Perlstein 		    uap->ruid, sizeof(cred->cr_ruid));
12428ccd6334SPeter Wemm 	if (uap->euid)
12437f05b035SAlfred Perlstein 		error2 = copyout(&cred->cr_uid,
12447f05b035SAlfred Perlstein 		    uap->euid, sizeof(cred->cr_uid));
12458ccd6334SPeter Wemm 	if (uap->suid)
12467f05b035SAlfred Perlstein 		error3 = copyout(&cred->cr_svuid,
12477f05b035SAlfred Perlstein 		    uap->suid, sizeof(cred->cr_svuid));
1248eb725b4eSRobert Watson 	return (error1 ? error1 : error2 ? error2 : error3);
12498ccd6334SPeter Wemm }
12508ccd6334SPeter Wemm 
12518ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
12528ccd6334SPeter Wemm struct getresgid_args {
12538ccd6334SPeter Wemm 	gid_t	*rgid;
12548ccd6334SPeter Wemm 	gid_t	*egid;
12558ccd6334SPeter Wemm 	gid_t	*sgid;
12568ccd6334SPeter Wemm };
12578ccd6334SPeter Wemm #endif
12588ccd6334SPeter Wemm /* ARGSUSED */
12598ccd6334SPeter Wemm int
12603e85b721SEd Maste sys_getresgid(struct thread *td, struct getresgid_args *uap)
12618ccd6334SPeter Wemm {
1262835a82eeSMatthew Dillon 	struct ucred *cred;
12638ccd6334SPeter Wemm 	int error1 = 0, error2 = 0, error3 = 0;
12648ccd6334SPeter Wemm 
1265d74ac681SMatthew Dillon 	cred = td->td_ucred;
12668ccd6334SPeter Wemm 	if (uap->rgid)
12677f05b035SAlfred Perlstein 		error1 = copyout(&cred->cr_rgid,
12687f05b035SAlfred Perlstein 		    uap->rgid, sizeof(cred->cr_rgid));
12698ccd6334SPeter Wemm 	if (uap->egid)
12707f05b035SAlfred Perlstein 		error2 = copyout(&cred->cr_groups[0],
12717f05b035SAlfred Perlstein 		    uap->egid, sizeof(cred->cr_groups[0]));
12728ccd6334SPeter Wemm 	if (uap->sgid)
12737f05b035SAlfred Perlstein 		error3 = copyout(&cred->cr_svgid,
12747f05b035SAlfred Perlstein 		    uap->sgid, sizeof(cred->cr_svgid));
1275eb725b4eSRobert Watson 	return (error1 ? error1 : error2 ? error2 : error3);
12768ccd6334SPeter Wemm }
12778ccd6334SPeter Wemm 
1278b67cbc65SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1279b67cbc65SPeter Wemm struct issetugid_args {
1280b67cbc65SPeter Wemm 	int dummy;
1281b67cbc65SPeter Wemm };
1282b67cbc65SPeter Wemm #endif
1283b67cbc65SPeter Wemm /* ARGSUSED */
1284b67cbc65SPeter Wemm int
12853e85b721SEd Maste sys_issetugid(struct thread *td, struct issetugid_args *uap)
1286b67cbc65SPeter Wemm {
1287b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1288b40ce416SJulian Elischer 
1289b67cbc65SPeter Wemm 	/*
1290b67cbc65SPeter Wemm 	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
1291b67cbc65SPeter Wemm 	 * we use P_SUGID because we consider changing the owners as
1292b67cbc65SPeter Wemm 	 * "tainting" as well.
1293b67cbc65SPeter Wemm 	 * This is significant for procs that start as root and "become"
1294b67cbc65SPeter Wemm 	 * a user without an exec - programs cannot know *everything*
1295b67cbc65SPeter Wemm 	 * that libc *might* have put in their data segment.
1296b67cbc65SPeter Wemm 	 */
1297b40ce416SJulian Elischer 	td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
1298b67cbc65SPeter Wemm 	return (0);
1299b67cbc65SPeter Wemm }
1300b67cbc65SPeter Wemm 
1301130d0157SRobert Watson int
13028451d0ddSKip Macy sys___setugid(struct thread *td, struct __setugid_args *uap)
1303130d0157SRobert Watson {
1304130d0157SRobert Watson #ifdef REGRESSION
130507f3485dSJohn Baldwin 	struct proc *p;
1306835a82eeSMatthew Dillon 
130707f3485dSJohn Baldwin 	p = td->td_proc;
1308130d0157SRobert Watson 	switch (uap->flag) {
1309130d0157SRobert Watson 	case 0:
131007f3485dSJohn Baldwin 		PROC_LOCK(p);
131107f3485dSJohn Baldwin 		p->p_flag &= ~P_SUGID;
131207f3485dSJohn Baldwin 		PROC_UNLOCK(p);
131307f3485dSJohn Baldwin 		return (0);
131407f3485dSJohn Baldwin 	case 1:
131507f3485dSJohn Baldwin 		PROC_LOCK(p);
131607f3485dSJohn Baldwin 		p->p_flag |= P_SUGID;
131707f3485dSJohn Baldwin 		PROC_UNLOCK(p);
131807f3485dSJohn Baldwin 		return (0);
131907f3485dSJohn Baldwin 	default:
132007f3485dSJohn Baldwin 		return (EINVAL);
132107f3485dSJohn Baldwin 	}
1322130d0157SRobert Watson #else /* !REGRESSION */
1323eb725b4eSRobert Watson 
1324130d0157SRobert Watson 	return (ENOSYS);
1325eb725b4eSRobert Watson #endif /* REGRESSION */
1326130d0157SRobert Watson }
1327130d0157SRobert Watson 
13286d2efbb3SOlivier Certner #ifdef INVARIANTS
13296d2efbb3SOlivier Certner static void
13306d2efbb3SOlivier Certner groups_check_normalized(int ngrp, const gid_t *groups)
13316d2efbb3SOlivier Certner {
13326d2efbb3SOlivier Certner 	gid_t prev_g;
13336d2efbb3SOlivier Certner 
13346d2efbb3SOlivier Certner 	groups_check_positive_len(ngrp);
13356d2efbb3SOlivier Certner 	groups_check_max_len(ngrp);
13366d2efbb3SOlivier Certner 
13376d2efbb3SOlivier Certner 	if (ngrp == 1)
13386d2efbb3SOlivier Certner 		return;
13396d2efbb3SOlivier Certner 
13406d2efbb3SOlivier Certner 	prev_g = groups[1];
13416d2efbb3SOlivier Certner 	for (int i = 2; i < ngrp; ++i) {
13426d2efbb3SOlivier Certner 		const gid_t g = groups[i];
13436d2efbb3SOlivier Certner 
13446d2efbb3SOlivier Certner 		if (prev_g >= g)
13456d2efbb3SOlivier Certner 			panic("%s: groups[%d] (%u) >= groups[%d] (%u)",
13466d2efbb3SOlivier Certner 			    __func__, i - 1, prev_g, i, g);
13476d2efbb3SOlivier Certner 		prev_g = g;
13486d2efbb3SOlivier Certner 	}
13496d2efbb3SOlivier Certner }
13506d2efbb3SOlivier Certner #else
13516d2efbb3SOlivier Certner #define groups_check_normalized(...)
13526d2efbb3SOlivier Certner #endif
13536d2efbb3SOlivier Certner 
1354df8bae1dSRodney W. Grimes /*
1355b725f232SOlivier Certner  * Returns whether gid designates a supplementary group in cred.
1356df8bae1dSRodney W. Grimes  */
135763695442SOlivier Certner bool
13582e031fd0SOlivier Certner group_is_supplementary(const gid_t gid, const struct ucred *const cred)
1359df8bae1dSRodney W. Grimes {
13607f92e578SBrooks Davis 
1361*63467506SOlivier Certner 	groups_check_normalized(cred->cr_ngroups, cred->cr_groups);
1362*63467506SOlivier Certner 
13637f92e578SBrooks Davis 	/*
13642e031fd0SOlivier Certner 	 * Perform a binary search of the supplementary groups.  This is
13652e031fd0SOlivier Certner 	 * possible because we sort the groups in crsetgroups().
13667f92e578SBrooks Davis 	 */
136737260547SOlivier Certner 	return (bsearch(&gid, cred->cr_groups + 1, cred->cr_ngroups - 1,
136837260547SOlivier Certner 	    sizeof(gid), gidp_cmp) != NULL);
1369b725f232SOlivier Certner }
1370b725f232SOlivier Certner 
1371b725f232SOlivier Certner /*
1372b725f232SOlivier Certner  * Check if gid is a member of the (effective) group set (i.e., effective and
1373b725f232SOlivier Certner  * supplementary groups).
1374b725f232SOlivier Certner  */
1375ffd3ef8eSOlivier Certner bool
1376b15110fbSOlivier Certner groupmember(gid_t gid, const struct ucred *cred)
1377b725f232SOlivier Certner {
1378b725f232SOlivier Certner 
1379caa309c8SRick Macklem 	/*
1380caa309c8SRick Macklem 	 * The nfsd server can use a credential with zero groups in it
1381caa309c8SRick Macklem 	 * when certain mapped export credentials are specified via exports(5).
1382caa309c8SRick Macklem 	 */
1383caa309c8SRick Macklem 	if (cred->cr_ngroups == 0)
1384caa309c8SRick Macklem 		return (false);
1385caa309c8SRick Macklem 
1386*63467506SOlivier Certner 	groups_check_positive_len(cred->cr_ngroups);
1387*63467506SOlivier Certner 
1388ffd3ef8eSOlivier Certner 	if (gid == cred->cr_groups[0])
1389ffd3ef8eSOlivier Certner 		return (true);
13907f92e578SBrooks Davis 
13912e031fd0SOlivier Certner 	return (group_is_supplementary(gid, cred));
1392df8bae1dSRodney W. Grimes }
1393df8bae1dSRodney W. Grimes 
13943b243b72SRobert Watson /*
13952a2bfa6aSOlivier Certner  * Check if gid is a member of the real group set (i.e., real and supplementary
13962a2bfa6aSOlivier Certner  * groups).
13972a2bfa6aSOlivier Certner  */
1398ffd3ef8eSOlivier Certner bool
1399b15110fbSOlivier Certner realgroupmember(gid_t gid, const struct ucred *cred)
14002a2bfa6aSOlivier Certner {
1401*63467506SOlivier Certner 	/*
1402*63467506SOlivier Certner 	 * Although the equality test on 'cr_rgid' below doesn't access
1403*63467506SOlivier Certner 	 * 'cr_groups', we check for the latter's length here as we assume that,
1404*63467506SOlivier Certner 	 * if 'cr_ngroups' is 0, the passed 'struct ucred' is invalid, and
1405*63467506SOlivier Certner 	 * 'cr_rgid' may not have been filled.
1406*63467506SOlivier Certner 	 */
1407*63467506SOlivier Certner 	groups_check_positive_len(cred->cr_ngroups);
1408*63467506SOlivier Certner 
14092a2bfa6aSOlivier Certner 	if (gid == cred->cr_rgid)
1410ffd3ef8eSOlivier Certner 		return (true);
14112a2bfa6aSOlivier Certner 
14122e031fd0SOlivier Certner 	return (group_is_supplementary(gid, cred));
14132a2bfa6aSOlivier Certner }
14142a2bfa6aSOlivier Certner 
14152a2bfa6aSOlivier Certner /*
1416eb725b4eSRobert Watson  * Test the active securelevel against a given level.  securelevel_gt()
1417eb725b4eSRobert Watson  * implements (securelevel > level).  securelevel_ge() implements
1418eb725b4eSRobert Watson  * (securelevel >= level).  Note that the logic is inverted -- these
1419eb725b4eSRobert Watson  * functions return EPERM on "success" and 0 on "failure".
14203ca719f1SRobert Watson  *
14210304c731SJamie Gritton  * Due to care taken when setting the securelevel, we know that no jail will
14220304c731SJamie Gritton  * be less secure that its parent (or the physical system), so it is sufficient
14230304c731SJamie Gritton  * to test the current jail only.
14240304c731SJamie Gritton  *
1425800c9408SRobert Watson  * XXXRW: Possibly since this has to do with privilege, it should move to
1426800c9408SRobert Watson  * kern_priv.c.
14273ca719f1SRobert Watson  */
14283ca719f1SRobert Watson int
14293ca719f1SRobert Watson securelevel_gt(struct ucred *cr, int level)
14303ca719f1SRobert Watson {
14313ca719f1SRobert Watson 
14320304c731SJamie Gritton 	return (cr->cr_prison->pr_securelevel > level ? EPERM : 0);
14333ca719f1SRobert Watson }
14343ca719f1SRobert Watson 
14353ca719f1SRobert Watson int
14363ca719f1SRobert Watson securelevel_ge(struct ucred *cr, int level)
14373ca719f1SRobert Watson {
14383ca719f1SRobert Watson 
14390304c731SJamie Gritton 	return (cr->cr_prison->pr_securelevel >= level ? EPERM : 0);
14403ca719f1SRobert Watson }
14413ca719f1SRobert Watson 
14428a7d8cc6SRobert Watson /*
1443e409590dSRobert Watson  * 'see_other_uids' determines whether or not visibility of processes
1444eb725b4eSRobert Watson  * and sockets with credentials holding different real uids is possible
144548713bdcSRobert Watson  * using a variety of system MIBs.
1446eb725b4eSRobert Watson  * XXX: data declarations should be together near the beginning of the file.
14478a7d8cc6SRobert Watson  */
1448e409590dSRobert Watson static int	see_other_uids = 1;
1449d0615c64SAndrew R. Reiter SYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW,
1450eb725b4eSRobert Watson     &see_other_uids, 0,
14518a7d8cc6SRobert Watson     "Unprivileged processes may see subjects/objects with different real uid");
14528a7d8cc6SRobert Watson 
14531a996ed1SEdward Tomasz Napierala /*-
14541b350b45SRobert Watson  * Determine if u1 "can see" the subject specified by u2, according to the
14551b350b45SRobert Watson  * 'see_other_uids' policy.
14561b350b45SRobert Watson  * Returns: 0 for permitted, ESRCH otherwise
14571b350b45SRobert Watson  * Locks: none
14581b350b45SRobert Watson  * References: *u1 and *u2 must not change during the call
14591b350b45SRobert Watson  *             u1 may equal u2, in which case only one reference is required
14601b350b45SRobert Watson  */
146191e9d669SOlivier Certner static int
14624ac21b4fSStephen J. Kiernan cr_canseeotheruids(struct ucred *u1, struct ucred *u2)
14631b350b45SRobert Watson {
14641b350b45SRobert Watson 
14651b350b45SRobert Watson 	if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) {
1466cc426dd3SMateusz Guzik 		if (priv_check_cred(u1, PRIV_SEEOTHERUIDS) != 0)
14671b350b45SRobert Watson 			return (ESRCH);
14681b350b45SRobert Watson 	}
14691b350b45SRobert Watson 	return (0);
14701b350b45SRobert Watson }
14711b350b45SRobert Watson 
147264d19c2eSRobert Watson /*
147364d19c2eSRobert Watson  * 'see_other_gids' determines whether or not visibility of processes
147464d19c2eSRobert Watson  * and sockets with credentials holding different real gids is possible
147564d19c2eSRobert Watson  * using a variety of system MIBs.
147664d19c2eSRobert Watson  * XXX: data declarations should be together near the beginning of the file.
147764d19c2eSRobert Watson  */
147864d19c2eSRobert Watson static int	see_other_gids = 1;
147964d19c2eSRobert Watson SYSCTL_INT(_security_bsd, OID_AUTO, see_other_gids, CTLFLAG_RW,
148064d19c2eSRobert Watson     &see_other_gids, 0,
148164d19c2eSRobert Watson     "Unprivileged processes may see subjects/objects with different real gid");
148264d19c2eSRobert Watson 
148364d19c2eSRobert Watson /*
148464d19c2eSRobert Watson  * Determine if u1 can "see" the subject specified by u2, according to the
148564d19c2eSRobert Watson  * 'see_other_gids' policy.
148664d19c2eSRobert Watson  * Returns: 0 for permitted, ESRCH otherwise
148764d19c2eSRobert Watson  * Locks: none
148864d19c2eSRobert Watson  * References: *u1 and *u2 must not change during the call
148964d19c2eSRobert Watson  *             u1 may equal u2, in which case only one reference is required
149064d19c2eSRobert Watson  */
149191e9d669SOlivier Certner static int
14924ac21b4fSStephen J. Kiernan cr_canseeothergids(struct ucred *u1, struct ucred *u2)
149364d19c2eSRobert Watson {
149464d19c2eSRobert Watson 	if (!see_other_gids) {
149591658080SOlivier Certner 		if (realgroupmember(u1->cr_rgid, u2))
149691658080SOlivier Certner 			return (0);
149791658080SOlivier Certner 
149891658080SOlivier Certner 		for (int i = 1; i < u1->cr_ngroups; i++)
149991658080SOlivier Certner 			if (realgroupmember(u1->cr_groups[i], u2))
150091658080SOlivier Certner 				return (0);
150191658080SOlivier Certner 
1502cc426dd3SMateusz Guzik 		if (priv_check_cred(u1, PRIV_SEEOTHERGIDS) != 0)
150364d19c2eSRobert Watson 			return (ESRCH);
150464d19c2eSRobert Watson 	}
150591658080SOlivier Certner 
150664d19c2eSRobert Watson 	return (0);
150764d19c2eSRobert Watson }
150864d19c2eSRobert Watson 
1509a4aaba3bSSteve Wills /*
1510a4aaba3bSSteve Wills  * 'see_jail_proc' determines whether or not visibility of processes and
1511a4aaba3bSSteve Wills  * sockets with credentials holding different jail ids is possible using a
1512a4aaba3bSSteve Wills  * variety of system MIBs.
1513a4aaba3bSSteve Wills  *
1514a4aaba3bSSteve Wills  * XXX: data declarations should be together near the beginning of the file.
1515a4aaba3bSSteve Wills  */
1516a4aaba3bSSteve Wills 
1517a4aaba3bSSteve Wills static int	see_jail_proc = 1;
1518a4aaba3bSSteve Wills SYSCTL_INT(_security_bsd, OID_AUTO, see_jail_proc, CTLFLAG_RW,
1519a4aaba3bSSteve Wills     &see_jail_proc, 0,
1520a4aaba3bSSteve Wills     "Unprivileged processes may see subjects/objects with different jail ids");
1521a4aaba3bSSteve Wills 
1522a4aaba3bSSteve Wills /*-
1523a4aaba3bSSteve Wills  * Determine if u1 "can see" the subject specified by u2, according to the
1524a4aaba3bSSteve Wills  * 'see_jail_proc' policy.
1525a4aaba3bSSteve Wills  * Returns: 0 for permitted, ESRCH otherwise
1526a4aaba3bSSteve Wills  * Locks: none
1527a4aaba3bSSteve Wills  * References: *u1 and *u2 must not change during the call
1528a4aaba3bSSteve Wills  *             u1 may equal u2, in which case only one reference is required
1529a4aaba3bSSteve Wills  */
153091e9d669SOlivier Certner static int
1531a4aaba3bSSteve Wills cr_canseejailproc(struct ucred *u1, struct ucred *u2)
1532a4aaba3bSSteve Wills {
15337974ca1cSOlivier Certner 	if (see_jail_proc || /* Policy deactivated. */
15347974ca1cSOlivier Certner 	    u1->cr_prison == u2->cr_prison || /* Same jail. */
15357974ca1cSOlivier Certner 	    priv_check_cred(u1, PRIV_SEEJAILPROC) == 0) /* Privileged. */
1536a4aaba3bSSteve Wills 		return (0);
15377974ca1cSOlivier Certner 
15387974ca1cSOlivier Certner 	return (ESRCH);
1539a4aaba3bSSteve Wills }
1540a4aaba3bSSteve Wills 
1541e4a7b4f9SOlivier Certner /*
1542e4a7b4f9SOlivier Certner  * Helper for cr_cansee*() functions to abide by system-wide security.bsd.see_*
1543e4a7b4f9SOlivier Certner  * policies.  Determines if u1 "can see" u2 according to these policies.
1544e4a7b4f9SOlivier Certner  * Returns: 0 for permitted, ESRCH otherwise
1545e4a7b4f9SOlivier Certner  */
1546e4a7b4f9SOlivier Certner int
1547e4a7b4f9SOlivier Certner cr_bsd_visible(struct ucred *u1, struct ucred *u2)
1548e4a7b4f9SOlivier Certner {
1549e4a7b4f9SOlivier Certner 	int error;
1550e4a7b4f9SOlivier Certner 
1551a1e37bebSOlivier Certner 	error = cr_canseeotheruids(u1, u2);
1552a1e37bebSOlivier Certner 	if (error != 0)
1553e4a7b4f9SOlivier Certner 		return (error);
1554a1e37bebSOlivier Certner 	error = cr_canseeothergids(u1, u2);
1555a1e37bebSOlivier Certner 	if (error != 0)
1556e4a7b4f9SOlivier Certner 		return (error);
1557a1e37bebSOlivier Certner 	error = cr_canseejailproc(u1, u2);
1558a1e37bebSOlivier Certner 	if (error != 0)
1559e4a7b4f9SOlivier Certner 		return (error);
1560e4a7b4f9SOlivier Certner 	return (0);
1561e4a7b4f9SOlivier Certner }
1562e4a7b4f9SOlivier Certner 
15631a996ed1SEdward Tomasz Napierala /*-
15647fd6a959SRobert Watson  * Determine if u1 "can see" the subject specified by u2.
1565ed639720SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1566ed639720SRobert Watson  * Locks: none
1567eb725b4eSRobert Watson  * References: *u1 and *u2 must not change during the call
1568ed639720SRobert Watson  *             u1 may equal u2, in which case only one reference is required
1569ed639720SRobert Watson  */
1570ed639720SRobert Watson int
157194088977SRobert Watson cr_cansee(struct ucred *u1, struct ucred *u2)
1572a9e0361bSPoul-Henning Kamp {
157391421ba2SRobert Watson 	int error;
1574a9e0361bSPoul-Henning Kamp 
1575ed639720SRobert Watson 	if ((error = prison_check(u1, u2)))
157691421ba2SRobert Watson 		return (error);
15778a1d977dSRobert Watson #ifdef MAC
157830d239bcSRobert Watson 	if ((error = mac_cred_check_visible(u1, u2)))
15798a1d977dSRobert Watson 		return (error);
15808a1d977dSRobert Watson #endif
15815817169bSOlivier Certner 	if ((error = cr_bsd_visible(u1, u2)))
1582a4aaba3bSSteve Wills 		return (error);
1583387d2c03SRobert Watson 	return (0);
1584387d2c03SRobert Watson }
1585387d2c03SRobert Watson 
15861a996ed1SEdward Tomasz Napierala /*-
1587f44d9e24SJohn Baldwin  * Determine if td "can see" the subject specified by p.
15883b243b72SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1589f44d9e24SJohn Baldwin  * Locks: Sufficient locks to protect p->p_ucred must be held.  td really
1590f44d9e24SJohn Baldwin  *        should be curthread.
1591f44d9e24SJohn Baldwin  * References: td and p must be valid for the lifetime of the call
15923b243b72SRobert Watson  */
1593a0f75161SRobert Watson int
1594f44d9e24SJohn Baldwin p_cansee(struct thread *td, struct proc *p)
1595ed639720SRobert Watson {
159694088977SRobert Watson 	/* Wrap cr_cansee() for all functionality. */
1597f44d9e24SJohn Baldwin 	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1598f44d9e24SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
159955a0aa21SKonstantin Belousov 
160055a0aa21SKonstantin Belousov 	if (td->td_proc == p)
160155a0aa21SKonstantin Belousov 		return (0);
1602f44d9e24SJohn Baldwin 	return (cr_cansee(td->td_ucred, p->p_ucred));
1603ed639720SRobert Watson }
1604ed639720SRobert Watson 
160562c45ef4SRobert Watson /*
160662c45ef4SRobert Watson  * 'conservative_signals' prevents the delivery of a broad class of
160762c45ef4SRobert Watson  * signals by unprivileged processes to processes that have changed their
160862c45ef4SRobert Watson  * credentials since the last invocation of execve().  This can prevent
160962c45ef4SRobert Watson  * the leakage of cached information or retained privileges as a result
161062c45ef4SRobert Watson  * of a common class of signal-related vulnerabilities.  However, this
161162c45ef4SRobert Watson  * may interfere with some applications that expect to be able to
161262c45ef4SRobert Watson  * deliver these signals to peer processes after having given up
161362c45ef4SRobert Watson  * privilege.
161462c45ef4SRobert Watson  */
161562c45ef4SRobert Watson static int	conservative_signals = 1;
161662c45ef4SRobert Watson SYSCTL_INT(_security_bsd, OID_AUTO, conservative_signals, CTLFLAG_RW,
161762c45ef4SRobert Watson     &conservative_signals, 0, "Unprivileged processes prevented from "
161862c45ef4SRobert Watson     "sending certain signals to processes whose credentials have changed");
16191a996ed1SEdward Tomasz Napierala /*-
1620c83f8015SRobert Watson  * Determine whether cred may deliver the specified signal to proc.
1621c83f8015SRobert Watson  * Returns: 0 for permitted, an errno value otherwise.
1622c83f8015SRobert Watson  * Locks: A lock must be held for proc.
1623c83f8015SRobert Watson  * References: cred and proc must be valid for the lifetime of the call.
16244c5eb9c3SRobert Watson  */
16254c5eb9c3SRobert Watson int
16261a88a252SMaxim Sobolev cr_cansignal(struct ucred *cred, struct proc *proc, int signum)
1627387d2c03SRobert Watson {
162891421ba2SRobert Watson 	int error;
1629387d2c03SRobert Watson 
1630f44d9e24SJohn Baldwin 	PROC_LOCK_ASSERT(proc, MA_OWNED);
16314c5eb9c3SRobert Watson 	/*
1632c83f8015SRobert Watson 	 * Jail semantics limit the scope of signalling to proc in the
1633c83f8015SRobert Watson 	 * same jail as cred, if cred is in jail.
16344c5eb9c3SRobert Watson 	 */
1635c83f8015SRobert Watson 	error = prison_check(cred, proc->p_ucred);
1636c83f8015SRobert Watson 	if (error)
163791421ba2SRobert Watson 		return (error);
16388a1d977dSRobert Watson #ifdef MAC
163930d239bcSRobert Watson 	if ((error = mac_proc_check_signal(cred, proc, signum)))
16408a1d977dSRobert Watson 		return (error);
16418a1d977dSRobert Watson #endif
16425817169bSOlivier Certner 	if ((error = cr_bsd_visible(cred, proc->p_ucred)))
16431b350b45SRobert Watson 		return (error);
1644387d2c03SRobert Watson 
1645387d2c03SRobert Watson 	/*
16463b243b72SRobert Watson 	 * UNIX signal semantics depend on the status of the P_SUGID
16473b243b72SRobert Watson 	 * bit on the target process.  If the bit is set, then additional
16483b243b72SRobert Watson 	 * restrictions are placed on the set of available signals.
16494c5eb9c3SRobert Watson 	 */
16501a88a252SMaxim Sobolev 	if (conservative_signals && (proc->p_flag & P_SUGID)) {
16514c5eb9c3SRobert Watson 		switch (signum) {
16524c5eb9c3SRobert Watson 		case 0:
16534c5eb9c3SRobert Watson 		case SIGKILL:
16544c5eb9c3SRobert Watson 		case SIGINT:
16554c5eb9c3SRobert Watson 		case SIGTERM:
165662c45ef4SRobert Watson 		case SIGALRM:
16574c5eb9c3SRobert Watson 		case SIGSTOP:
16584c5eb9c3SRobert Watson 		case SIGTTIN:
16594c5eb9c3SRobert Watson 		case SIGTTOU:
16604c5eb9c3SRobert Watson 		case SIGTSTP:
16614c5eb9c3SRobert Watson 		case SIGHUP:
16624c5eb9c3SRobert Watson 		case SIGUSR1:
16634c5eb9c3SRobert Watson 		case SIGUSR2:
16647fd6a959SRobert Watson 			/*
16657fd6a959SRobert Watson 			 * Generally, permit job and terminal control
16667fd6a959SRobert Watson 			 * signals.
16677fd6a959SRobert Watson 			 */
16684c5eb9c3SRobert Watson 			break;
16694c5eb9c3SRobert Watson 		default:
1670c83f8015SRobert Watson 			/* Not permitted without privilege. */
1671cc426dd3SMateusz Guzik 			error = priv_check_cred(cred, PRIV_SIGNAL_SUGID);
16724c5eb9c3SRobert Watson 			if (error)
16734c5eb9c3SRobert Watson 				return (error);
16744c5eb9c3SRobert Watson 		}
1675e9e7ff5bSRobert Watson 	}
1676e9e7ff5bSRobert Watson 
16774c5eb9c3SRobert Watson 	/*
16783b243b72SRobert Watson 	 * Generally, the target credential's ruid or svuid must match the
1679e9e7ff5bSRobert Watson 	 * subject credential's ruid or euid.
16804c5eb9c3SRobert Watson 	 */
1681c83f8015SRobert Watson 	if (cred->cr_ruid != proc->p_ucred->cr_ruid &&
1682c83f8015SRobert Watson 	    cred->cr_ruid != proc->p_ucred->cr_svuid &&
1683c83f8015SRobert Watson 	    cred->cr_uid != proc->p_ucred->cr_ruid &&
1684c83f8015SRobert Watson 	    cred->cr_uid != proc->p_ucred->cr_svuid) {
1685cc426dd3SMateusz Guzik 		error = priv_check_cred(cred, PRIV_SIGNAL_DIFFCRED);
16864c5eb9c3SRobert Watson 		if (error)
16874c5eb9c3SRobert Watson 			return (error);
16884c5eb9c3SRobert Watson 	}
1689387d2c03SRobert Watson 
1690387d2c03SRobert Watson 	return (0);
1691387d2c03SRobert Watson }
1692a9e0361bSPoul-Henning Kamp 
16931a996ed1SEdward Tomasz Napierala /*-
1694f44d9e24SJohn Baldwin  * Determine whether td may deliver the specified signal to p.
1695c83f8015SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1696f44d9e24SJohn Baldwin  * Locks: Sufficient locks to protect various components of td and p
1697f44d9e24SJohn Baldwin  *        must be held.  td must be curthread, and a lock must be
1698f44d9e24SJohn Baldwin  *        held for p.
1699f44d9e24SJohn Baldwin  * References: td and p must be valid for the lifetime of the call
1700c83f8015SRobert Watson  */
1701c83f8015SRobert Watson int
17021a88a252SMaxim Sobolev p_cansignal(struct thread *td, struct proc *p, int signum)
1703c83f8015SRobert Watson {
1704c83f8015SRobert Watson 
1705f44d9e24SJohn Baldwin 	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1706f44d9e24SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
1707f44d9e24SJohn Baldwin 	if (td->td_proc == p)
1708c83f8015SRobert Watson 		return (0);
1709c83f8015SRobert Watson 
1710c83f8015SRobert Watson 	/*
1711c83f8015SRobert Watson 	 * UNIX signalling semantics require that processes in the same
1712c83f8015SRobert Watson 	 * session always be able to deliver SIGCONT to one another,
1713c83f8015SRobert Watson 	 * overriding the remaining protections.
1714c83f8015SRobert Watson 	 */
1715f44d9e24SJohn Baldwin 	/* XXX: This will require an additional lock of some sort. */
1716f44d9e24SJohn Baldwin 	if (signum == SIGCONT && td->td_proc->p_session == p->p_session)
1717c83f8015SRobert Watson 		return (0);
17184b178336SMaxim Sobolev 	/*
1719f9cd63d4SMaxim Sobolev 	 * Some compat layers use SIGTHR and higher signals for
1720f9cd63d4SMaxim Sobolev 	 * communication between different kernel threads of the same
1721f9cd63d4SMaxim Sobolev 	 * process, so that they expect that it's always possible to
1722f9cd63d4SMaxim Sobolev 	 * deliver them, even for suid applications where cr_cansignal() can
17234b178336SMaxim Sobolev 	 * deny such ability for security consideration.  It should be
17244b178336SMaxim Sobolev 	 * pretty safe to do since the only way to create two processes
17254b178336SMaxim Sobolev 	 * with the same p_leader is via rfork(2).
17264b178336SMaxim Sobolev 	 */
17272322a0a7SMaxim Sobolev 	if (td->td_proc->p_leader != NULL && signum >= SIGTHR &&
17282322a0a7SMaxim Sobolev 	    signum < SIGTHR + 4 && td->td_proc->p_leader == p->p_leader)
17294b178336SMaxim Sobolev 		return (0);
1730c83f8015SRobert Watson 
17311a88a252SMaxim Sobolev 	return (cr_cansignal(td->td_ucred, p, signum));
1732c83f8015SRobert Watson }
1733c83f8015SRobert Watson 
17341a996ed1SEdward Tomasz Napierala /*-
1735f44d9e24SJohn Baldwin  * Determine whether td may reschedule p.
17367fd6a959SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1737f44d9e24SJohn Baldwin  * Locks: Sufficient locks to protect various components of td and p
1738f44d9e24SJohn Baldwin  *        must be held.  td must be curthread, and a lock must
1739f44d9e24SJohn Baldwin  *        be held for p.
1740f44d9e24SJohn Baldwin  * References: td and p must be valid for the lifetime of the call
17413b243b72SRobert Watson  */
1742a0f75161SRobert Watson int
1743f44d9e24SJohn Baldwin p_cansched(struct thread *td, struct proc *p)
1744387d2c03SRobert Watson {
174591421ba2SRobert Watson 	int error;
1746387d2c03SRobert Watson 
1747f44d9e24SJohn Baldwin 	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1748f44d9e24SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
1749f44d9e24SJohn Baldwin 	if (td->td_proc == p)
1750387d2c03SRobert Watson 		return (0);
1751f44d9e24SJohn Baldwin 	if ((error = prison_check(td->td_ucred, p->p_ucred)))
175291421ba2SRobert Watson 		return (error);
17538a1d977dSRobert Watson #ifdef MAC
175430d239bcSRobert Watson 	if ((error = mac_proc_check_sched(td->td_ucred, p)))
17558a1d977dSRobert Watson 		return (error);
17568a1d977dSRobert Watson #endif
17575817169bSOlivier Certner 	if ((error = cr_bsd_visible(td->td_ucred, p->p_ucred)))
17581b350b45SRobert Watson 		return (error);
17595817169bSOlivier Certner 
1760800c9408SRobert Watson 	if (td->td_ucred->cr_ruid != p->p_ucred->cr_ruid &&
1761800c9408SRobert Watson 	    td->td_ucred->cr_uid != p->p_ucred->cr_ruid) {
176232f9753cSRobert Watson 		error = priv_check(td, PRIV_SCHED_DIFFCRED);
1763800c9408SRobert Watson 		if (error)
1764800c9408SRobert Watson 			return (error);
1765800c9408SRobert Watson 	}
1766387d2c03SRobert Watson 	return (0);
1767387d2c03SRobert Watson }
1768387d2c03SRobert Watson 
17693b243b72SRobert Watson /*
1770b3079544SJamie Gritton  * Handle getting or setting the prison's unprivileged_proc_debug
1771b3079544SJamie Gritton  * value.
1772b3079544SJamie Gritton  */
1773b3079544SJamie Gritton static int
1774b3079544SJamie Gritton sysctl_unprivileged_proc_debug(SYSCTL_HANDLER_ARGS)
1775b3079544SJamie Gritton {
1776b3079544SJamie Gritton 	int error, val;
1777b3079544SJamie Gritton 
17780fe74ae6SJamie Gritton 	val = prison_allow(req->td->td_ucred, PR_ALLOW_UNPRIV_DEBUG);
1779b3079544SJamie Gritton 	error = sysctl_handle_int(oidp, &val, 0, req);
1780b3079544SJamie Gritton 	if (error != 0 || req->newptr == NULL)
1781b3079544SJamie Gritton 		return (error);
17820fe74ae6SJamie Gritton 	if (val != 0 && val != 1)
17830fe74ae6SJamie Gritton 		return (EINVAL);
17840fe74ae6SJamie Gritton 	prison_set_allow(req->td->td_ucred, PR_ALLOW_UNPRIV_DEBUG, val);
17850fe74ae6SJamie Gritton 	return (0);
1786b3079544SJamie Gritton }
1787b3079544SJamie Gritton 
1788b3079544SJamie Gritton /*
17895d476e73SRobert Watson  * The 'unprivileged_proc_debug' flag may be used to disable a variety of
17905d476e73SRobert Watson  * unprivileged inter-process debugging services, including some procfs
17915d476e73SRobert Watson  * functionality, ptrace(), and ktrace().  In the past, inter-process
17925d476e73SRobert Watson  * debugging has been involved in a variety of security problems, and sites
17935d476e73SRobert Watson  * not requiring the service might choose to disable it when hardening
17945d476e73SRobert Watson  * systems.
17953b243b72SRobert Watson  */
1796b3079544SJamie Gritton SYSCTL_PROC(_security_bsd, OID_AUTO, unprivileged_proc_debug,
17977029da5cSPawel Biernacki     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_SECURE |
17987029da5cSPawel Biernacki     CTLFLAG_MPSAFE, 0, 0, sysctl_unprivileged_proc_debug, "I",
17990ef5652eSRobert Watson     "Unprivileged processes may use process debugging facilities");
18000ef5652eSRobert Watson 
18011a996ed1SEdward Tomasz Napierala /*-
1802f44d9e24SJohn Baldwin  * Determine whether td may debug p.
18037fd6a959SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1804f44d9e24SJohn Baldwin  * Locks: Sufficient locks to protect various components of td and p
1805f44d9e24SJohn Baldwin  *        must be held.  td must be curthread, and a lock must
1806f44d9e24SJohn Baldwin  *        be held for p.
1807f44d9e24SJohn Baldwin  * References: td and p must be valid for the lifetime of the call
18083b243b72SRobert Watson  */
1809a0f75161SRobert Watson int
1810f44d9e24SJohn Baldwin p_candebug(struct thread *td, struct proc *p)
1811387d2c03SRobert Watson {
1812c54d240eSPawel Jakub Dawidek 	int error, grpsubset, i, uidsubset;
1813387d2c03SRobert Watson 
1814f44d9e24SJohn Baldwin 	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1815f44d9e24SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
1816f44d9e24SJohn Baldwin 	if (td->td_proc == p)
181723fad5b6SDag-Erling Smørgrav 		return (0);
181855a0aa21SKonstantin Belousov 	if ((error = priv_check(td, PRIV_DEBUG_UNPRIV)))
181955a0aa21SKonstantin Belousov 		return (error);
1820f44d9e24SJohn Baldwin 	if ((error = prison_check(td->td_ucred, p->p_ucred)))
182191421ba2SRobert Watson 		return (error);
18228a1d977dSRobert Watson #ifdef MAC
182330d239bcSRobert Watson 	if ((error = mac_proc_check_debug(td->td_ucred, p)))
18248a1d977dSRobert Watson 		return (error);
18258a1d977dSRobert Watson #endif
18265817169bSOlivier Certner 	if ((error = cr_bsd_visible(td->td_ucred, p->p_ucred)))
182764d19c2eSRobert Watson 		return (error);
1828387d2c03SRobert Watson 
18297fd6a959SRobert Watson 	/*
1830f44d9e24SJohn Baldwin 	 * Is p's group set a subset of td's effective group set?  This
1831f44d9e24SJohn Baldwin 	 * includes p's egid, group access list, rgid, and svgid.
18327fd6a959SRobert Watson 	 */
1833db42a33dSRobert Watson 	grpsubset = 1;
1834f44d9e24SJohn Baldwin 	for (i = 0; i < p->p_ucred->cr_ngroups; i++) {
1835f44d9e24SJohn Baldwin 		if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) {
1836db42a33dSRobert Watson 			grpsubset = 0;
1837db42a33dSRobert Watson 			break;
1838db42a33dSRobert Watson 		}
1839db42a33dSRobert Watson 	}
1840db42a33dSRobert Watson 	grpsubset = grpsubset &&
1841f44d9e24SJohn Baldwin 	    groupmember(p->p_ucred->cr_rgid, td->td_ucred) &&
1842f44d9e24SJohn Baldwin 	    groupmember(p->p_ucred->cr_svgid, td->td_ucred);
1843db42a33dSRobert Watson 
1844db42a33dSRobert Watson 	/*
1845f44d9e24SJohn Baldwin 	 * Are the uids present in p's credential equal to td's
1846f44d9e24SJohn Baldwin 	 * effective uid?  This includes p's euid, svuid, and ruid.
1847db42a33dSRobert Watson 	 */
1848f44d9e24SJohn Baldwin 	uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid &&
1849f44d9e24SJohn Baldwin 	    td->td_ucred->cr_uid == p->p_ucred->cr_svuid &&
1850f44d9e24SJohn Baldwin 	    td->td_ucred->cr_uid == p->p_ucred->cr_ruid);
1851db42a33dSRobert Watson 
1852db42a33dSRobert Watson 	/*
1853f44d9e24SJohn Baldwin 	 * If p's gids aren't a subset, or the uids aren't a subset,
1854db42a33dSRobert Watson 	 * or the credential has changed, require appropriate privilege
1855800c9408SRobert Watson 	 * for td to debug p.
1856db42a33dSRobert Watson 	 */
1857800c9408SRobert Watson 	if (!grpsubset || !uidsubset) {
185832f9753cSRobert Watson 		error = priv_check(td, PRIV_DEBUG_DIFFCRED);
1859800c9408SRobert Watson 		if (error)
1860800c9408SRobert Watson 			return (error);
1861800c9408SRobert Watson 	}
1862800c9408SRobert Watson 
1863c54d240eSPawel Jakub Dawidek 	/*
1864c54d240eSPawel Jakub Dawidek 	 * Has the credential of the process changed since the last exec()?
1865c54d240eSPawel Jakub Dawidek 	 */
1866c54d240eSPawel Jakub Dawidek 	if ((p->p_flag & P_SUGID) != 0) {
186732f9753cSRobert Watson 		error = priv_check(td, PRIV_DEBUG_SUGID);
186832d18604SRobert Watson 		if (error)
1869387d2c03SRobert Watson 			return (error);
18707fd6a959SRobert Watson 	}
1871387d2c03SRobert Watson 
1872eb725b4eSRobert Watson 	/* Can't trace init when securelevel > 0. */
1873f44d9e24SJohn Baldwin 	if (p == initproc) {
1874f44d9e24SJohn Baldwin 		error = securelevel_gt(td->td_ucred, 0);
18753ca719f1SRobert Watson 		if (error)
18763ca719f1SRobert Watson 			return (error);
18773ca719f1SRobert Watson 	}
1878387d2c03SRobert Watson 
18795fab7614SRobert Watson 	/*
18805fab7614SRobert Watson 	 * Can't trace a process that's currently exec'ing.
1881800c9408SRobert Watson 	 *
18825fab7614SRobert Watson 	 * XXX: Note, this is not a security policy decision, it's a
18835fab7614SRobert Watson 	 * basic correctness/functionality decision.  Therefore, this check
18845fab7614SRobert Watson 	 * should be moved to the caller's of p_candebug().
18855fab7614SRobert Watson 	 */
1886f44d9e24SJohn Baldwin 	if ((p->p_flag & P_INEXEC) != 0)
1887af80b2c9SKonstantin Belousov 		return (EBUSY);
18889ca45e81SDag-Erling Smørgrav 
1889768f9b8bSGordon Bergling 	/* Denied explicitly */
1890677258f7SKonstantin Belousov 	if ((p->p_flag2 & P2_NOTRACE) != 0) {
1891677258f7SKonstantin Belousov 		error = priv_check(td, PRIV_DEBUG_DENIED);
1892677258f7SKonstantin Belousov 		if (error != 0)
1893677258f7SKonstantin Belousov 			return (error);
1894677258f7SKonstantin Belousov 	}
1895677258f7SKonstantin Belousov 
1896387d2c03SRobert Watson 	return (0);
1897387d2c03SRobert Watson }
1898387d2c03SRobert Watson 
18991a996ed1SEdward Tomasz Napierala /*-
190029dc1288SRobert Watson  * Determine whether the subject represented by cred can "see" a socket.
190129dc1288SRobert Watson  * Returns: 0 for permitted, ENOENT otherwise.
190229dc1288SRobert Watson  */
190329dc1288SRobert Watson int
190429dc1288SRobert Watson cr_canseesocket(struct ucred *cred, struct socket *so)
190529dc1288SRobert Watson {
190629dc1288SRobert Watson 	int error;
190729dc1288SRobert Watson 
190829dc1288SRobert Watson 	error = prison_check(cred, so->so_cred);
190929dc1288SRobert Watson 	if (error)
191029dc1288SRobert Watson 		return (ENOENT);
19118a1d977dSRobert Watson #ifdef MAC
191230d239bcSRobert Watson 	error = mac_socket_check_visible(cred, so);
19138a1d977dSRobert Watson 	if (error)
19148a1d977dSRobert Watson 		return (error);
19158a1d977dSRobert Watson #endif
19165817169bSOlivier Certner 	if (cr_bsd_visible(cred, so->so_cred))
191764d19c2eSRobert Watson 		return (ENOENT);
191829dc1288SRobert Watson 
191929dc1288SRobert Watson 	return (0);
192029dc1288SRobert Watson }
192129dc1288SRobert Watson 
19221a996ed1SEdward Tomasz Napierala /*-
1923babe9a2bSRobert Watson  * Determine whether td can wait for the exit of p.
1924babe9a2bSRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1925babe9a2bSRobert Watson  * Locks: Sufficient locks to protect various components of td and p
1926babe9a2bSRobert Watson  *        must be held.  td must be curthread, and a lock must
1927babe9a2bSRobert Watson  *        be held for p.
1928babe9a2bSRobert Watson  * References: td and p must be valid for the lifetime of the call
1929babe9a2bSRobert Watson 
1930babe9a2bSRobert Watson  */
1931babe9a2bSRobert Watson int
1932babe9a2bSRobert Watson p_canwait(struct thread *td, struct proc *p)
1933babe9a2bSRobert Watson {
1934babe9a2bSRobert Watson 	int error;
1935babe9a2bSRobert Watson 
1936babe9a2bSRobert Watson 	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1937babe9a2bSRobert Watson 	PROC_LOCK_ASSERT(p, MA_OWNED);
19387afcbc18SJamie Gritton 	if ((error = prison_check(td->td_ucred, p->p_ucred)))
1939babe9a2bSRobert Watson 		return (error);
1940babe9a2bSRobert Watson #ifdef MAC
194130d239bcSRobert Watson 	if ((error = mac_proc_check_wait(td->td_ucred, p)))
1942babe9a2bSRobert Watson 		return (error);
1943babe9a2bSRobert Watson #endif
1944babe9a2bSRobert Watson #if 0
1945babe9a2bSRobert Watson 	/* XXXMAC: This could have odd effects on some shells. */
19465817169bSOlivier Certner 	if ((error = cr_bsd_visible(td->td_ucred, p->p_ucred)))
1947babe9a2bSRobert Watson 		return (error);
1948babe9a2bSRobert Watson #endif
1949babe9a2bSRobert Watson 
1950babe9a2bSRobert Watson 	return (0);
1951babe9a2bSRobert Watson }
1952babe9a2bSRobert Watson 
1953a9e0361bSPoul-Henning Kamp /*
19541724c563SMateusz Guzik  * Credential management.
19551724c563SMateusz Guzik  *
19561724c563SMateusz Guzik  * struct ucred objects are rarely allocated but gain and lose references all
19571724c563SMateusz Guzik  * the time (e.g., on struct file alloc/dealloc) turning refcount updates into
19581724c563SMateusz Guzik  * a significant source of cache-line ping ponging. Common cases are worked
19591724c563SMateusz Guzik  * around by modifying thread-local counter instead if the cred to operate on
19601724c563SMateusz Guzik  * matches td_realucred.
19611724c563SMateusz Guzik  *
19621724c563SMateusz Guzik  * The counter is split into 2 parts:
19631724c563SMateusz Guzik  * - cr_users -- total count of all struct proc and struct thread objects
19641724c563SMateusz Guzik  *   which have given cred in p_ucred and td_ucred respectively
19651724c563SMateusz Guzik  * - cr_ref -- the actual ref count, only valid if cr_users == 0
19661724c563SMateusz Guzik  *
19671724c563SMateusz Guzik  * If users == 0 then cr_ref behaves similarly to refcount(9), in particular if
19681724c563SMateusz Guzik  * the count reaches 0 the object is freeable.
19691724c563SMateusz Guzik  * If users > 0 and curthread->td_realucred == cred, then updates are performed
19701724c563SMateusz Guzik  * against td_ucredref.
19711724c563SMateusz Guzik  * In other cases updates are performed against cr_ref.
19721724c563SMateusz Guzik  *
19731724c563SMateusz Guzik  * Changing td_realucred into something else decrements cr_users and transfers
19741724c563SMateusz Guzik  * accumulated updates.
19751724c563SMateusz Guzik  */
19761724c563SMateusz Guzik struct ucred *
19771724c563SMateusz Guzik crcowget(struct ucred *cr)
19781724c563SMateusz Guzik {
19791724c563SMateusz Guzik 
19801724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
19811724c563SMateusz Guzik 	KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
19821724c563SMateusz Guzik 	    __func__, cr->cr_users, cr));
19831724c563SMateusz Guzik 	cr->cr_users++;
19841724c563SMateusz Guzik 	cr->cr_ref++;
19851724c563SMateusz Guzik 	mtx_unlock(&cr->cr_mtx);
19861724c563SMateusz Guzik 	return (cr);
19871724c563SMateusz Guzik }
19881724c563SMateusz Guzik 
19891724c563SMateusz Guzik static struct ucred *
19901724c563SMateusz Guzik crunuse(struct thread *td)
19911724c563SMateusz Guzik {
19921724c563SMateusz Guzik 	struct ucred *cr, *crold;
19931724c563SMateusz Guzik 
1994936c24faSMateusz Guzik 	MPASS(td->td_realucred == td->td_ucred);
1995936c24faSMateusz Guzik 	cr = td->td_realucred;
19961724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
19971724c563SMateusz Guzik 	cr->cr_ref += td->td_ucredref;
19981724c563SMateusz Guzik 	td->td_ucredref = 0;
19991724c563SMateusz Guzik 	KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
20001724c563SMateusz Guzik 	    __func__, cr->cr_users, cr));
20011724c563SMateusz Guzik 	cr->cr_users--;
20021724c563SMateusz Guzik 	if (cr->cr_users == 0) {
200337337709SMateusz Guzik 		KASSERT(cr->cr_ref > 0, ("%s: ref %ld not > 0 on cred %p",
20041724c563SMateusz Guzik 		    __func__, cr->cr_ref, cr));
20051724c563SMateusz Guzik 		crold = cr;
20061724c563SMateusz Guzik 	} else {
20071724c563SMateusz Guzik 		cr->cr_ref--;
20081724c563SMateusz Guzik 		crold = NULL;
20091724c563SMateusz Guzik 	}
20101724c563SMateusz Guzik 	mtx_unlock(&cr->cr_mtx);
2011936c24faSMateusz Guzik 	td->td_realucred = NULL;
20121724c563SMateusz Guzik 	return (crold);
20131724c563SMateusz Guzik }
20141724c563SMateusz Guzik 
2015f34a2f56SMateusz Guzik static void
2016f34a2f56SMateusz Guzik crunusebatch(struct ucred *cr, int users, int ref)
2017f34a2f56SMateusz Guzik {
2018f34a2f56SMateusz Guzik 
2019f34a2f56SMateusz Guzik 	KASSERT(users > 0, ("%s: passed users %d not > 0 ; cred %p",
2020f34a2f56SMateusz Guzik 	    __func__, users, cr));
2021f34a2f56SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
2022f34a2f56SMateusz Guzik 	KASSERT(cr->cr_users >= users, ("%s: users %d not > %d on cred %p",
2023f34a2f56SMateusz Guzik 	    __func__, cr->cr_users, users, cr));
2024f34a2f56SMateusz Guzik 	cr->cr_users -= users;
2025f34a2f56SMateusz Guzik 	cr->cr_ref += ref;
2026f34a2f56SMateusz Guzik 	cr->cr_ref -= users;
2027f34a2f56SMateusz Guzik 	if (cr->cr_users > 0) {
2028f34a2f56SMateusz Guzik 		mtx_unlock(&cr->cr_mtx);
2029f34a2f56SMateusz Guzik 		return;
2030f34a2f56SMateusz Guzik 	}
203137337709SMateusz Guzik 	KASSERT(cr->cr_ref >= 0, ("%s: ref %ld not >= 0 on cred %p",
2032f34a2f56SMateusz Guzik 	    __func__, cr->cr_ref, cr));
2033f34a2f56SMateusz Guzik 	if (cr->cr_ref > 0) {
2034f34a2f56SMateusz Guzik 		mtx_unlock(&cr->cr_mtx);
2035f34a2f56SMateusz Guzik 		return;
2036f34a2f56SMateusz Guzik 	}
2037f34a2f56SMateusz Guzik 	crfree_final(cr);
2038f34a2f56SMateusz Guzik }
2039f34a2f56SMateusz Guzik 
20401724c563SMateusz Guzik void
20411724c563SMateusz Guzik crcowfree(struct thread *td)
20421724c563SMateusz Guzik {
20431724c563SMateusz Guzik 	struct ucred *cr;
20441724c563SMateusz Guzik 
20451724c563SMateusz Guzik 	cr = crunuse(td);
20461724c563SMateusz Guzik 	if (cr != NULL)
20471724c563SMateusz Guzik 		crfree(cr);
20481724c563SMateusz Guzik }
20491724c563SMateusz Guzik 
20501724c563SMateusz Guzik struct ucred *
20511724c563SMateusz Guzik crcowsync(void)
20521724c563SMateusz Guzik {
20531724c563SMateusz Guzik 	struct thread *td;
20541724c563SMateusz Guzik 	struct proc *p;
20551724c563SMateusz Guzik 	struct ucred *crnew, *crold;
20561724c563SMateusz Guzik 
20571724c563SMateusz Guzik 	td = curthread;
20581724c563SMateusz Guzik 	p = td->td_proc;
20591724c563SMateusz Guzik 	PROC_LOCK_ASSERT(p, MA_OWNED);
20601724c563SMateusz Guzik 
20611724c563SMateusz Guzik 	MPASS(td->td_realucred == td->td_ucred);
20621724c563SMateusz Guzik 	if (td->td_realucred == p->p_ucred)
20631724c563SMateusz Guzik 		return (NULL);
20641724c563SMateusz Guzik 
20651724c563SMateusz Guzik 	crnew = crcowget(p->p_ucred);
20661724c563SMateusz Guzik 	crold = crunuse(td);
20671724c563SMateusz Guzik 	td->td_realucred = crnew;
20681724c563SMateusz Guzik 	td->td_ucred = td->td_realucred;
20691724c563SMateusz Guzik 	return (crold);
20701724c563SMateusz Guzik }
20711724c563SMateusz Guzik 
20721724c563SMateusz Guzik /*
2073f34a2f56SMateusz Guzik  * Batching.
2074f34a2f56SMateusz Guzik  */
2075f34a2f56SMateusz Guzik void
2076f34a2f56SMateusz Guzik credbatch_add(struct credbatch *crb, struct thread *td)
2077f34a2f56SMateusz Guzik {
2078f34a2f56SMateusz Guzik 	struct ucred *cr;
2079f34a2f56SMateusz Guzik 
2080f34a2f56SMateusz Guzik 	MPASS(td->td_realucred != NULL);
2081f34a2f56SMateusz Guzik 	MPASS(td->td_realucred == td->td_ucred);
2082fa2528acSAlex Richardson 	MPASS(TD_GET_STATE(td) == TDS_INACTIVE);
2083f34a2f56SMateusz Guzik 	cr = td->td_realucred;
2084f34a2f56SMateusz Guzik 	KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
2085f34a2f56SMateusz Guzik 	    __func__, cr->cr_users, cr));
2086f34a2f56SMateusz Guzik 	if (crb->cred != cr) {
2087f34a2f56SMateusz Guzik 		if (crb->users > 0) {
2088f34a2f56SMateusz Guzik 			MPASS(crb->cred != NULL);
2089f34a2f56SMateusz Guzik 			crunusebatch(crb->cred, crb->users, crb->ref);
2090f34a2f56SMateusz Guzik 			crb->users = 0;
2091f34a2f56SMateusz Guzik 			crb->ref = 0;
2092f34a2f56SMateusz Guzik 		}
2093f34a2f56SMateusz Guzik 	}
2094f34a2f56SMateusz Guzik 	crb->cred = cr;
2095f34a2f56SMateusz Guzik 	crb->users++;
2096f34a2f56SMateusz Guzik 	crb->ref += td->td_ucredref;
2097f34a2f56SMateusz Guzik 	td->td_ucredref = 0;
2098f34a2f56SMateusz Guzik 	td->td_realucred = NULL;
2099f34a2f56SMateusz Guzik }
2100f34a2f56SMateusz Guzik 
2101f34a2f56SMateusz Guzik void
2102f34a2f56SMateusz Guzik credbatch_final(struct credbatch *crb)
2103f34a2f56SMateusz Guzik {
2104f34a2f56SMateusz Guzik 
2105f34a2f56SMateusz Guzik 	MPASS(crb->cred != NULL);
2106f34a2f56SMateusz Guzik 	MPASS(crb->users > 0);
2107f34a2f56SMateusz Guzik 	crunusebatch(crb->cred, crb->users, crb->ref);
2108f34a2f56SMateusz Guzik }
2109f34a2f56SMateusz Guzik 
2110f34a2f56SMateusz Guzik /*
2111df8bae1dSRodney W. Grimes  * Allocate a zeroed cred structure.
2112df8bae1dSRodney W. Grimes  */
2113df8bae1dSRodney W. Grimes struct ucred *
21144c44ad8eSJohn Baldwin crget(void)
2115df8bae1dSRodney W. Grimes {
21163e85b721SEd Maste 	struct ucred *cr;
2117df8bae1dSRodney W. Grimes 
21181ede983cSDag-Erling Smørgrav 	cr = malloc(sizeof(*cr), M_CRED, M_WAITOK | M_ZERO);
21191724c563SMateusz Guzik 	mtx_init(&cr->cr_mtx, "cred", NULL, MTX_DEF);
21201724c563SMateusz Guzik 	cr->cr_ref = 1;
2121faef5371SRobert Watson #ifdef AUDIT
2122faef5371SRobert Watson 	audit_cred_init(cr);
2123faef5371SRobert Watson #endif
212440244964SRobert Watson #ifdef MAC
212530d239bcSRobert Watson 	mac_cred_init(cr);
212640244964SRobert Watson #endif
2127a99500a9SMateusz Guzik 	cr->cr_groups = cr->cr_smallgroups;
2128a99500a9SMateusz Guzik 	cr->cr_agroups =
2129a99500a9SMateusz Guzik 	    sizeof(cr->cr_smallgroups) / sizeof(cr->cr_smallgroups[0]);
2130df8bae1dSRodney W. Grimes 	return (cr);
2131df8bae1dSRodney W. Grimes }
2132df8bae1dSRodney W. Grimes 
2133df8bae1dSRodney W. Grimes /*
21347fd6a959SRobert Watson  * Claim another reference to a ucred structure.
21355c3f70d7SAlfred Perlstein  */
2136bd78ceceSJohn Baldwin struct ucred *
21374c44ad8eSJohn Baldwin crhold(struct ucred *cr)
21385c3f70d7SAlfred Perlstein {
21391724c563SMateusz Guzik 	struct thread *td;
21405c3f70d7SAlfred Perlstein 
21411724c563SMateusz Guzik 	td = curthread;
21421724c563SMateusz Guzik 	if (__predict_true(td->td_realucred == cr)) {
21431724c563SMateusz Guzik 		KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
21441724c563SMateusz Guzik 		    __func__, cr->cr_users, cr));
21451724c563SMateusz Guzik 		td->td_ucredref++;
21461724c563SMateusz Guzik 		return (cr);
21471724c563SMateusz Guzik 	}
21481724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
21491724c563SMateusz Guzik 	cr->cr_ref++;
21501724c563SMateusz Guzik 	mtx_unlock(&cr->cr_mtx);
2151bd78ceceSJohn Baldwin 	return (cr);
21525c3f70d7SAlfred Perlstein }
21535c3f70d7SAlfred Perlstein 
21545c3f70d7SAlfred Perlstein /*
21550c14ff0eSRobert Watson  * Free a cred structure.  Throws away space when ref count gets to 0.
2156df8bae1dSRodney W. Grimes  */
215726f9a767SRodney W. Grimes void
21584c44ad8eSJohn Baldwin crfree(struct ucred *cr)
2159df8bae1dSRodney W. Grimes {
21601724c563SMateusz Guzik 	struct thread *td;
21611e5d626aSAlfred Perlstein 
21621724c563SMateusz Guzik 	td = curthread;
2163a2de789eSMateusz Guzik 	if (__predict_true(td->td_realucred == cr)) {
21641724c563SMateusz Guzik 		KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
21651724c563SMateusz Guzik 		    __func__, cr->cr_users, cr));
21661724c563SMateusz Guzik 		td->td_ucredref--;
21671724c563SMateusz Guzik 		return;
21681724c563SMateusz Guzik 	}
21691724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
21701724c563SMateusz Guzik 	KASSERT(cr->cr_users >= 0, ("%s: users %d not >= 0 on cred %p",
21711724c563SMateusz Guzik 	    __func__, cr->cr_users, cr));
21721724c563SMateusz Guzik 	cr->cr_ref--;
21731724c563SMateusz Guzik 	if (cr->cr_users > 0) {
21741724c563SMateusz Guzik 		mtx_unlock(&cr->cr_mtx);
21751724c563SMateusz Guzik 		return;
21761724c563SMateusz Guzik 	}
217737337709SMateusz Guzik 	KASSERT(cr->cr_ref >= 0, ("%s: ref %ld not >= 0 on cred %p",
21781724c563SMateusz Guzik 	    __func__, cr->cr_ref, cr));
21791724c563SMateusz Guzik 	if (cr->cr_ref > 0) {
21801724c563SMateusz Guzik 		mtx_unlock(&cr->cr_mtx);
21811724c563SMateusz Guzik 		return;
21821724c563SMateusz Guzik 	}
2183f34a2f56SMateusz Guzik 	crfree_final(cr);
2184f34a2f56SMateusz Guzik }
2185f34a2f56SMateusz Guzik 
2186f34a2f56SMateusz Guzik static void
2187f34a2f56SMateusz Guzik crfree_final(struct ucred *cr)
2188f34a2f56SMateusz Guzik {
2189f34a2f56SMateusz Guzik 
2190f34a2f56SMateusz Guzik 	KASSERT(cr->cr_users == 0, ("%s: users %d not == 0 on cred %p",
2191f34a2f56SMateusz Guzik 	    __func__, cr->cr_users, cr));
219237337709SMateusz Guzik 	KASSERT(cr->cr_ref == 0, ("%s: ref %ld not == 0 on cred %p",
2193f34a2f56SMateusz Guzik 	    __func__, cr->cr_ref, cr));
21942f5b0b48SMateusz Guzik 
2195f535380cSDon Lewis 	/*
21961724c563SMateusz Guzik 	 * Some callers of crget(), such as nfs_statfs(), allocate a temporary
21971724c563SMateusz Guzik 	 * credential, but don't allocate a uidinfo structure.
2198f535380cSDon Lewis 	 */
2199f535380cSDon Lewis 	if (cr->cr_uidinfo != NULL)
2200f535380cSDon Lewis 		uifree(cr->cr_uidinfo);
2201823c224eSRobert Watson 	if (cr->cr_ruidinfo != NULL)
2202823c224eSRobert Watson 		uifree(cr->cr_ruidinfo);
22030304c731SJamie Gritton 	if (cr->cr_prison != NULL)
220491421ba2SRobert Watson 		prison_free(cr->cr_prison);
22052bfc50bcSEdward Tomasz Napierala 	if (cr->cr_loginclass != NULL)
22062bfc50bcSEdward Tomasz Napierala 		loginclass_free(cr->cr_loginclass);
2207faef5371SRobert Watson #ifdef AUDIT
2208faef5371SRobert Watson 	audit_cred_destroy(cr);
2209faef5371SRobert Watson #endif
221040244964SRobert Watson #ifdef MAC
221130d239bcSRobert Watson 	mac_cred_destroy(cr);
221240244964SRobert Watson #endif
22131724c563SMateusz Guzik 	mtx_destroy(&cr->cr_mtx);
2214a99500a9SMateusz Guzik 	if (cr->cr_groups != cr->cr_smallgroups)
2215838d9858SBrooks Davis 		free(cr->cr_groups, M_CRED);
22161ede983cSDag-Erling Smørgrav 	free(cr, M_CRED);
2217e1bca29fSMatthew Dillon }
2218df8bae1dSRodney W. Grimes 
2219df8bae1dSRodney W. Grimes /*
2220bd78ceceSJohn Baldwin  * Copy a ucred's contents from a template.  Does not block.
2221bd78ceceSJohn Baldwin  */
2222bd78ceceSJohn Baldwin void
22234c44ad8eSJohn Baldwin crcopy(struct ucred *dest, struct ucred *src)
2224bd78ceceSJohn Baldwin {
2225bd78ceceSJohn Baldwin 
2226bd78ceceSJohn Baldwin 	bcopy(&src->cr_startcopy, &dest->cr_startcopy,
2227bd78ceceSJohn Baldwin 	    (unsigned)((caddr_t)&src->cr_endcopy -
2228bd78ceceSJohn Baldwin 		(caddr_t)&src->cr_startcopy));
222937337709SMateusz Guzik 	dest->cr_flags = src->cr_flags;
2230838d9858SBrooks Davis 	crsetgroups(dest, src->cr_ngroups, src->cr_groups);
2231bd78ceceSJohn Baldwin 	uihold(dest->cr_uidinfo);
2232bd78ceceSJohn Baldwin 	uihold(dest->cr_ruidinfo);
2233bd78ceceSJohn Baldwin 	prison_hold(dest->cr_prison);
22342bfc50bcSEdward Tomasz Napierala 	loginclass_hold(dest->cr_loginclass);
2235faef5371SRobert Watson #ifdef AUDIT
2236faef5371SRobert Watson 	audit_cred_copy(src, dest);
2237faef5371SRobert Watson #endif
223840244964SRobert Watson #ifdef MAC
223930d239bcSRobert Watson 	mac_cred_copy(src, dest);
224040244964SRobert Watson #endif
2241df8bae1dSRodney W. Grimes }
2242df8bae1dSRodney W. Grimes 
2243df8bae1dSRodney W. Grimes /*
2244df8bae1dSRodney W. Grimes  * Dup cred struct to a new held one.
2245df8bae1dSRodney W. Grimes  */
2246df8bae1dSRodney W. Grimes struct ucred *
22474c44ad8eSJohn Baldwin crdup(struct ucred *cr)
2248df8bae1dSRodney W. Grimes {
2249df8bae1dSRodney W. Grimes 	struct ucred *newcr;
2250df8bae1dSRodney W. Grimes 
2251bd78ceceSJohn Baldwin 	newcr = crget();
2252bd78ceceSJohn Baldwin 	crcopy(newcr, cr);
2253df8bae1dSRodney W. Grimes 	return (newcr);
2254df8bae1dSRodney W. Grimes }
2255df8bae1dSRodney W. Grimes 
2256df8bae1dSRodney W. Grimes /*
225776183f34SDima Dorfman  * Fill in a struct xucred based on a struct ucred.
225876183f34SDima Dorfman  */
225976183f34SDima Dorfman void
22604c44ad8eSJohn Baldwin cru2x(struct ucred *cr, struct xucred *xcr)
226176183f34SDima Dorfman {
2262838d9858SBrooks Davis 	int ngroups;
226376183f34SDima Dorfman 
226476183f34SDima Dorfman 	bzero(xcr, sizeof(*xcr));
226576183f34SDima Dorfman 	xcr->cr_version = XUCRED_VERSION;
226676183f34SDima Dorfman 	xcr->cr_uid = cr->cr_uid;
2267838d9858SBrooks Davis 
2268838d9858SBrooks Davis 	ngroups = MIN(cr->cr_ngroups, XU_NGROUPS);
2269838d9858SBrooks Davis 	xcr->cr_ngroups = ngroups;
2270838d9858SBrooks Davis 	bcopy(cr->cr_groups, xcr->cr_groups,
2271838d9858SBrooks Davis 	    ngroups * sizeof(*cr->cr_groups));
227276183f34SDima Dorfman }
227376183f34SDima Dorfman 
2274c8124e20SDmitry Chagin void
2275c5afec6eSDmitry Chagin cru2xt(struct thread *td, struct xucred *xcr)
2276c5afec6eSDmitry Chagin {
2277c5afec6eSDmitry Chagin 
2278c5afec6eSDmitry Chagin 	cru2x(td->td_ucred, xcr);
2279c5afec6eSDmitry Chagin 	xcr->cr_pid = td->td_proc->p_pid;
2280c5afec6eSDmitry Chagin }
2281c5afec6eSDmitry Chagin 
228276183f34SDima Dorfman /*
2283daf63fd2SMateusz Guzik  * Change process credentials.
2284ffb34484SMateusz Guzik  * Callers are responsible for providing the reference for passed credentials
2285daf63fd2SMateusz Guzik  * and for freeing old ones.
2286daf63fd2SMateusz Guzik  *
2287daf63fd2SMateusz Guzik  * Process has to be locked except when it does not have credentials (as it
2288daf63fd2SMateusz Guzik  * should not be visible just yet) or when newcred is NULL (as this can be
2289daf63fd2SMateusz Guzik  * only used when the process is about to be freed, at which point it should
2290daf63fd2SMateusz Guzik  * not be visible anymore).
2291daf63fd2SMateusz Guzik  */
22926f836483SMateusz Guzik void
2293daf63fd2SMateusz Guzik proc_set_cred(struct proc *p, struct ucred *newcred)
2294daf63fd2SMateusz Guzik {
22951724c563SMateusz Guzik 	struct ucred *cr;
2296daf63fd2SMateusz Guzik 
22971724c563SMateusz Guzik 	cr = p->p_ucred;
22981724c563SMateusz Guzik 	MPASS(cr != NULL);
2299daf63fd2SMateusz Guzik 	PROC_LOCK_ASSERT(p, MA_OWNED);
23001724c563SMateusz Guzik 	KASSERT(newcred->cr_users == 0, ("%s: users %d not 0 on cred %p",
23011724c563SMateusz Guzik 	    __func__, newcred->cr_users, newcred));
23021724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
23031724c563SMateusz Guzik 	KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
23041724c563SMateusz Guzik 	    __func__, cr->cr_users, cr));
23051724c563SMateusz Guzik 	cr->cr_users--;
23061724c563SMateusz Guzik 	mtx_unlock(&cr->cr_mtx);
2307daf63fd2SMateusz Guzik 	p->p_ucred = newcred;
23081724c563SMateusz Guzik 	newcred->cr_users = 1;
23094ea6a9a2SMateusz Guzik 	PROC_UPDATE_COW(p);
2310daf63fd2SMateusz Guzik }
2311daf63fd2SMateusz Guzik 
23125a90435cSMateusz Guzik void
23135a90435cSMateusz Guzik proc_unset_cred(struct proc *p)
23145a90435cSMateusz Guzik {
23155a90435cSMateusz Guzik 	struct ucred *cr;
23165a90435cSMateusz Guzik 
23171724c563SMateusz Guzik 	MPASS(p->p_state == PRS_ZOMBIE || p->p_state == PRS_NEW);
23185a90435cSMateusz Guzik 	cr = p->p_ucred;
23195a90435cSMateusz Guzik 	p->p_ucred = NULL;
23201724c563SMateusz Guzik 	KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
23211724c563SMateusz Guzik 	    __func__, cr->cr_users, cr));
23221724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
23231724c563SMateusz Guzik 	cr->cr_users--;
23241724c563SMateusz Guzik 	if (cr->cr_users == 0)
232537337709SMateusz Guzik 		KASSERT(cr->cr_ref > 0, ("%s: ref %ld not > 0 on cred %p",
23261724c563SMateusz Guzik 		    __func__, cr->cr_ref, cr));
23271724c563SMateusz Guzik 	mtx_unlock(&cr->cr_mtx);
23285a90435cSMateusz Guzik 	crfree(cr);
23295a90435cSMateusz Guzik }
23305a90435cSMateusz Guzik 
2331838d9858SBrooks Davis struct ucred *
2332838d9858SBrooks Davis crcopysafe(struct proc *p, struct ucred *cr)
2333838d9858SBrooks Davis {
2334838d9858SBrooks Davis 	struct ucred *oldcred;
2335838d9858SBrooks Davis 	int groups;
2336838d9858SBrooks Davis 
2337838d9858SBrooks Davis 	PROC_LOCK_ASSERT(p, MA_OWNED);
2338838d9858SBrooks Davis 
2339838d9858SBrooks Davis 	oldcred = p->p_ucred;
2340838d9858SBrooks Davis 	while (cr->cr_agroups < oldcred->cr_agroups) {
2341838d9858SBrooks Davis 		groups = oldcred->cr_agroups;
2342838d9858SBrooks Davis 		PROC_UNLOCK(p);
2343838d9858SBrooks Davis 		crextend(cr, groups);
2344838d9858SBrooks Davis 		PROC_LOCK(p);
2345838d9858SBrooks Davis 		oldcred = p->p_ucred;
2346838d9858SBrooks Davis 	}
2347838d9858SBrooks Davis 	crcopy(cr, oldcred);
2348838d9858SBrooks Davis 
2349838d9858SBrooks Davis 	return (oldcred);
2350838d9858SBrooks Davis }
2351838d9858SBrooks Davis 
2352838d9858SBrooks Davis /*
2353838d9858SBrooks Davis  * Extend the passed in credential to hold n items.
2354838d9858SBrooks Davis  */
2355c8358c6eSGleb Smirnoff void
2356838d9858SBrooks Davis crextend(struct ucred *cr, int n)
2357838d9858SBrooks Davis {
2358838d9858SBrooks Davis 	int cnt;
2359838d9858SBrooks Davis 
23606d2efbb3SOlivier Certner 	MPASS2(cr->cr_ref == 1, "'cr_ref' must be 1 (referenced, unshared)");
23616d2efbb3SOlivier Certner 
2362838d9858SBrooks Davis 	/* Truncate? */
2363838d9858SBrooks Davis 	if (n <= cr->cr_agroups)
2364838d9858SBrooks Davis 		return;
2365838d9858SBrooks Davis 
2366838d9858SBrooks Davis 	/*
2367838d9858SBrooks Davis 	 * We extend by 2 each time since we're using a power of two
2368838d9858SBrooks Davis 	 * allocator until we need enough groups to fill a page.
2369838d9858SBrooks Davis 	 * Once we're allocating multiple pages, only allocate as many
2370838d9858SBrooks Davis 	 * as we actually need.  The case of processes needing a
2371838d9858SBrooks Davis 	 * non-power of two number of pages seems more likely than
2372838d9858SBrooks Davis 	 * a real world process that adds thousands of groups one at a
2373838d9858SBrooks Davis 	 * time.
2374838d9858SBrooks Davis 	 */
2375838d9858SBrooks Davis 	if ( n < PAGE_SIZE / sizeof(gid_t) ) {
2376838d9858SBrooks Davis 		if (cr->cr_agroups == 0)
237751871224SRyan Libby 			cnt = MAX(1, MINALLOCSIZE / sizeof(gid_t));
2378838d9858SBrooks Davis 		else
2379838d9858SBrooks Davis 			cnt = cr->cr_agroups * 2;
2380838d9858SBrooks Davis 
2381838d9858SBrooks Davis 		while (cnt < n)
2382838d9858SBrooks Davis 			cnt *= 2;
2383838d9858SBrooks Davis 	} else
2384838d9858SBrooks Davis 		cnt = roundup2(n, PAGE_SIZE / sizeof(gid_t));
2385838d9858SBrooks Davis 
2386838d9858SBrooks Davis 	/* Free the old array. */
2387a99500a9SMateusz Guzik 	if (cr->cr_groups != cr->cr_smallgroups)
2388838d9858SBrooks Davis 		free(cr->cr_groups, M_CRED);
2389838d9858SBrooks Davis 
2390838d9858SBrooks Davis 	cr->cr_groups = malloc(cnt * sizeof(gid_t), M_CRED, M_WAITOK | M_ZERO);
2391838d9858SBrooks Davis 	cr->cr_agroups = cnt;
2392838d9858SBrooks Davis }
2393838d9858SBrooks Davis 
2394838d9858SBrooks Davis /*
23956d2efbb3SOlivier Certner  * Normalizes a set of groups to be applied to a 'struct ucred'.
23966d2efbb3SOlivier Certner  *
23976d2efbb3SOlivier Certner  * The set of groups is an array that must comprise the effective GID as its
23986d2efbb3SOlivier Certner  * first element (so its length cannot be 0).
23996d2efbb3SOlivier Certner  *
24006d2efbb3SOlivier Certner  * Normalization ensures that elements after the first, which stand for the
24016d2efbb3SOlivier Certner  * supplementary groups, are sorted in ascending order and do not contain
24026d2efbb3SOlivier Certner  * duplicates.
2403838d9858SBrooks Davis  */
2404838d9858SBrooks Davis static void
24056d2efbb3SOlivier Certner groups_normalize(int *ngrp, gid_t *groups)
2406838d9858SBrooks Davis {
24076d2efbb3SOlivier Certner 	gid_t prev_g;
24086d2efbb3SOlivier Certner 	int ins_idx;
2409838d9858SBrooks Davis 
24106d2efbb3SOlivier Certner 	groups_check_positive_len(*ngrp);
24116d2efbb3SOlivier Certner 	groups_check_max_len(*ngrp);
24126d2efbb3SOlivier Certner 
24136d2efbb3SOlivier Certner 	if (*ngrp == 1)
24146d2efbb3SOlivier Certner 		return;
24156d2efbb3SOlivier Certner 
24166d2efbb3SOlivier Certner 	qsort(groups + 1, *ngrp - 1, sizeof(*groups), gidp_cmp);
24176d2efbb3SOlivier Certner 
24186d2efbb3SOlivier Certner 	/* Remove duplicates. */
24196d2efbb3SOlivier Certner 	prev_g = groups[1];
24206d2efbb3SOlivier Certner 	ins_idx = 2;
24216d2efbb3SOlivier Certner 	for (int i = 2; i < *ngrp; ++i) {
24226d2efbb3SOlivier Certner 		const gid_t g = groups[i];
24236d2efbb3SOlivier Certner 
24246d2efbb3SOlivier Certner 		if (g != prev_g) {
24256d2efbb3SOlivier Certner 			if (i != ins_idx)
24266d2efbb3SOlivier Certner 				groups[ins_idx] = g;
24276d2efbb3SOlivier Certner 			++ins_idx;
24286d2efbb3SOlivier Certner 			prev_g = g;
24296d2efbb3SOlivier Certner 		}
24306d2efbb3SOlivier Certner 	}
24316d2efbb3SOlivier Certner 	*ngrp = ins_idx;
24326d2efbb3SOlivier Certner 
24336d2efbb3SOlivier Certner 	groups_check_normalized(*ngrp, groups);
24346d2efbb3SOlivier Certner }
24356d2efbb3SOlivier Certner 
24366d2efbb3SOlivier Certner /*
24376d2efbb3SOlivier Certner  * Internal function copying groups into a credential.
24386d2efbb3SOlivier Certner  *
24396d2efbb3SOlivier Certner  * 'ngrp' must be strictly positive.  Either the passed 'groups' array must have
24406d2efbb3SOlivier Certner  * been normalized in advance (see groups_normalize()), else it must be so
24416d2efbb3SOlivier Certner  * before the structure is to be used again.
24426d2efbb3SOlivier Certner  *
24436d2efbb3SOlivier Certner  * This function is suitable to be used under any lock (it doesn't take any lock
24446d2efbb3SOlivier Certner  * itself nor sleep, and in particular doesn't allocate memory).  crextend()
24456d2efbb3SOlivier Certner  * must have been called beforehand to ensure sufficient space is available.
24466d2efbb3SOlivier Certner  * See also crsetgroups(), which handles that.
24476d2efbb3SOlivier Certner  */
24486d2efbb3SOlivier Certner static void
24496d2efbb3SOlivier Certner crsetgroups_internal(struct ucred *cr, int ngrp, const gid_t *groups)
24506d2efbb3SOlivier Certner {
24516d2efbb3SOlivier Certner 
24526d2efbb3SOlivier Certner 	MPASS2(cr->cr_ref == 1, "'cr_ref' must be 1 (referenced, unshared)");
24536d2efbb3SOlivier Certner 	MPASS2(cr->cr_agroups >= ngrp, "'cr_agroups' too small");
24546d2efbb3SOlivier Certner 	groups_check_positive_len(ngrp);
2455838d9858SBrooks Davis 
2456838d9858SBrooks Davis 	bcopy(groups, cr->cr_groups, ngrp * sizeof(gid_t));
2457838d9858SBrooks Davis 	cr->cr_ngroups = ngrp;
2458838d9858SBrooks Davis }
2459838d9858SBrooks Davis 
2460838d9858SBrooks Davis /*
2461838d9858SBrooks Davis  * Copy groups in to a credential after expanding it if required.
24626d2efbb3SOlivier Certner  *
24636d2efbb3SOlivier Certner  * May sleep in order to allocate memory (except if, e.g., crextend() was called
24646d2efbb3SOlivier Certner  * before with 'ngrp' or greater).  Truncates the list to (ngroups_max + 1) if
24656d2efbb3SOlivier Certner  * it is too large.  Array 'groups' doesn't need to be sorted.  'ngrp' must be
24666d2efbb3SOlivier Certner  * strictly positive.
2467838d9858SBrooks Davis  */
2468838d9858SBrooks Davis void
24696d2efbb3SOlivier Certner crsetgroups(struct ucred *cr, int ngrp, const gid_t *groups)
2470838d9858SBrooks Davis {
2471838d9858SBrooks Davis 
2472412f9500SBrooks Davis 	if (ngrp > ngroups_max + 1)
2473412f9500SBrooks Davis 		ngrp = ngroups_max + 1;
2474838d9858SBrooks Davis 	crextend(cr, ngrp);
24756d2efbb3SOlivier Certner 	crsetgroups_internal(cr, ngrp, groups);
24766d2efbb3SOlivier Certner 	groups_normalize(&cr->cr_ngroups, cr->cr_groups);
2477838d9858SBrooks Davis }
2478838d9858SBrooks Davis 
24792eb927e2SJulian Elischer /*
2480df8bae1dSRodney W. Grimes  * Get login name, if available.
2481df8bae1dSRodney W. Grimes  */
2482d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
2483df8bae1dSRodney W. Grimes struct getlogin_args {
2484df8bae1dSRodney W. Grimes 	char	*namebuf;
2485df8bae1dSRodney W. Grimes 	u_int	namelen;
2486df8bae1dSRodney W. Grimes };
2487d2d3e875SBruce Evans #endif
2488df8bae1dSRodney W. Grimes /* ARGSUSED */
248926f9a767SRodney W. Grimes int
24908451d0ddSKip Macy sys_getlogin(struct thread *td, struct getlogin_args *uap)
2491df8bae1dSRodney W. Grimes {
2492f591779bSSeigo Tanimura 	char login[MAXLOGNAME];
2493b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
2494bccb6d5aSDag-Erling Smørgrav 	size_t len;
2495df8bae1dSRodney W. Grimes 
249630cf3ac4SAndrey A. Chernov 	if (uap->namelen > MAXLOGNAME)
249753490b76SAndrey A. Chernov 		uap->namelen = MAXLOGNAME;
2498f591779bSSeigo Tanimura 	PROC_LOCK(p);
2499f591779bSSeigo Tanimura 	SESS_LOCK(p->p_session);
2500bccb6d5aSDag-Erling Smørgrav 	len = strlcpy(login, p->p_session->s_login, uap->namelen) + 1;
2501f591779bSSeigo Tanimura 	SESS_UNLOCK(p->p_session);
2502f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
2503bccb6d5aSDag-Erling Smørgrav 	if (len > uap->namelen)
25046f68699fSBaptiste Daroussin 		return (ERANGE);
2505bccb6d5aSDag-Erling Smørgrav 	return (copyout(login, uap->namebuf, len));
2506df8bae1dSRodney W. Grimes }
2507df8bae1dSRodney W. Grimes 
2508df8bae1dSRodney W. Grimes /*
2509df8bae1dSRodney W. Grimes  * Set login name.
2510df8bae1dSRodney W. Grimes  */
2511d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
2512df8bae1dSRodney W. Grimes struct setlogin_args {
2513df8bae1dSRodney W. Grimes 	char	*namebuf;
2514df8bae1dSRodney W. Grimes };
2515d2d3e875SBruce Evans #endif
2516df8bae1dSRodney W. Grimes /* ARGSUSED */
251726f9a767SRodney W. Grimes int
25188451d0ddSKip Macy sys_setlogin(struct thread *td, struct setlogin_args *uap)
2519df8bae1dSRodney W. Grimes {
2520b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
2521df8bae1dSRodney W. Grimes 	int error;
2522964ca0caSAndrey A. Chernov 	char logintmp[MAXLOGNAME];
2523df8bae1dSRodney W. Grimes 
2524bccb6d5aSDag-Erling Smørgrav 	CTASSERT(sizeof(p->p_session->s_login) >= sizeof(logintmp));
2525bccb6d5aSDag-Erling Smørgrav 
252632f9753cSRobert Watson 	error = priv_check(td, PRIV_PROC_SETLOGIN);
252707f3485dSJohn Baldwin 	if (error)
252807f3485dSJohn Baldwin 		return (error);
25297f05b035SAlfred Perlstein 	error = copyinstr(uap->namebuf, logintmp, sizeof(logintmp), NULL);
2530bccb6d5aSDag-Erling Smørgrav 	if (error != 0) {
2531eb725b4eSRobert Watson 		if (error == ENAMETOOLONG)
2532df8bae1dSRodney W. Grimes 			error = EINVAL;
2533bccb6d5aSDag-Erling Smørgrav 		return (error);
2534bccb6d5aSDag-Erling Smørgrav 	}
253570a98c11SRobert Watson 	AUDIT_ARG_LOGIN(logintmp);
2536f591779bSSeigo Tanimura 	PROC_LOCK(p);
2537f591779bSSeigo Tanimura 	SESS_LOCK(p->p_session);
2538bccb6d5aSDag-Erling Smørgrav 	strcpy(p->p_session->s_login, logintmp);
2539f591779bSSeigo Tanimura 	SESS_UNLOCK(p->p_session);
2540f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
2541bccb6d5aSDag-Erling Smørgrav 	return (0);
2542df8bae1dSRodney W. Grimes }
2543d5f81602SSean Eric Fagan 
2544d5f81602SSean Eric Fagan void
25454c44ad8eSJohn Baldwin setsugid(struct proc *p)
2546d5f81602SSean Eric Fagan {
2547f2102dadSAlfred Perlstein 
2548f2102dadSAlfred Perlstein 	PROC_LOCK_ASSERT(p, MA_OWNED);
2549d5f81602SSean Eric Fagan 	p->p_flag |= P_SUGID;
2550d5f81602SSean Eric Fagan }
2551f535380cSDon Lewis 
25521a996ed1SEdward Tomasz Napierala /*-
25537fd6a959SRobert Watson  * Change a process's effective uid.
2554b1fc0ec1SRobert Watson  * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified.
2555b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2556b1fc0ec1SRobert Watson  *             duration of the call.
2557f535380cSDon Lewis  */
2558f535380cSDon Lewis void
25591419eacbSAlfred Perlstein change_euid(struct ucred *newcred, struct uidinfo *euip)
2560f535380cSDon Lewis {
2561f535380cSDon Lewis 
25621419eacbSAlfred Perlstein 	newcred->cr_uid = euip->ui_uid;
25631419eacbSAlfred Perlstein 	uihold(euip);
2564b1fc0ec1SRobert Watson 	uifree(newcred->cr_uidinfo);
25651419eacbSAlfred Perlstein 	newcred->cr_uidinfo = euip;
2566f535380cSDon Lewis }
2567f535380cSDon Lewis 
25681a996ed1SEdward Tomasz Napierala /*-
25697fd6a959SRobert Watson  * Change a process's effective gid.
2570b1fc0ec1SRobert Watson  * Side effects: newcred->cr_gid will be modified.
2571b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2572b1fc0ec1SRobert Watson  *             duration of the call.
2573f535380cSDon Lewis  */
2574810bfc8eSAndrew Gallatin void
25754c44ad8eSJohn Baldwin change_egid(struct ucred *newcred, gid_t egid)
2576b1fc0ec1SRobert Watson {
2577b1fc0ec1SRobert Watson 
2578b1fc0ec1SRobert Watson 	newcred->cr_groups[0] = egid;
2579b1fc0ec1SRobert Watson }
2580b1fc0ec1SRobert Watson 
25811a996ed1SEdward Tomasz Napierala /*-
25827fd6a959SRobert Watson  * Change a process's real uid.
2583b1fc0ec1SRobert Watson  * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo
2584b1fc0ec1SRobert Watson  *               will be updated, and the old and new cr_ruidinfo proc
2585b1fc0ec1SRobert Watson  *               counts will be updated.
2586b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2587b1fc0ec1SRobert Watson  *             duration of the call.
2588b1fc0ec1SRobert Watson  */
2589b1fc0ec1SRobert Watson void
25901419eacbSAlfred Perlstein change_ruid(struct ucred *newcred, struct uidinfo *ruip)
2591f535380cSDon Lewis {
2592f535380cSDon Lewis 
2593b1fc0ec1SRobert Watson 	(void)chgproccnt(newcred->cr_ruidinfo, -1, 0);
25941419eacbSAlfred Perlstein 	newcred->cr_ruid = ruip->ui_uid;
25951419eacbSAlfred Perlstein 	uihold(ruip);
2596b1fc0ec1SRobert Watson 	uifree(newcred->cr_ruidinfo);
25971419eacbSAlfred Perlstein 	newcred->cr_ruidinfo = ruip;
2598b1fc0ec1SRobert Watson 	(void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
2599b1fc0ec1SRobert Watson }
2600b1fc0ec1SRobert Watson 
26011a996ed1SEdward Tomasz Napierala /*-
26027fd6a959SRobert Watson  * Change a process's real gid.
2603b1fc0ec1SRobert Watson  * Side effects: newcred->cr_rgid will be updated.
2604b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2605b1fc0ec1SRobert Watson  *             duration of the call.
2606b1fc0ec1SRobert Watson  */
2607b1fc0ec1SRobert Watson void
26084c44ad8eSJohn Baldwin change_rgid(struct ucred *newcred, gid_t rgid)
2609b1fc0ec1SRobert Watson {
2610b1fc0ec1SRobert Watson 
2611b1fc0ec1SRobert Watson 	newcred->cr_rgid = rgid;
2612b1fc0ec1SRobert Watson }
2613b1fc0ec1SRobert Watson 
26141a996ed1SEdward Tomasz Napierala /*-
26157fd6a959SRobert Watson  * Change a process's saved uid.
2616b1fc0ec1SRobert Watson  * Side effects: newcred->cr_svuid will be updated.
2617b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2618b1fc0ec1SRobert Watson  *             duration of the call.
2619b1fc0ec1SRobert Watson  */
2620b1fc0ec1SRobert Watson void
26214c44ad8eSJohn Baldwin change_svuid(struct ucred *newcred, uid_t svuid)
2622b1fc0ec1SRobert Watson {
2623b1fc0ec1SRobert Watson 
2624b1fc0ec1SRobert Watson 	newcred->cr_svuid = svuid;
2625b1fc0ec1SRobert Watson }
2626b1fc0ec1SRobert Watson 
26271a996ed1SEdward Tomasz Napierala /*-
26287fd6a959SRobert Watson  * Change a process's saved gid.
2629b1fc0ec1SRobert Watson  * Side effects: newcred->cr_svgid will be updated.
2630b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2631b1fc0ec1SRobert Watson  *             duration of the call.
2632b1fc0ec1SRobert Watson  */
2633b1fc0ec1SRobert Watson void
26344c44ad8eSJohn Baldwin change_svgid(struct ucred *newcred, gid_t svgid)
2635b1fc0ec1SRobert Watson {
2636b1fc0ec1SRobert Watson 
2637b1fc0ec1SRobert Watson 	newcred->cr_svgid = svgid;
2638f535380cSDon Lewis }
2639fe6db727SKonstantin Belousov 
2640fe6db727SKonstantin Belousov bool allow_ptrace = true;
2641fe6db727SKonstantin Belousov SYSCTL_BOOL(_security_bsd, OID_AUTO, allow_ptrace, CTLFLAG_RWTUN,
2642fe6db727SKonstantin Belousov     &allow_ptrace, 0,
2643fe6db727SKonstantin Belousov     "Deny ptrace(2) use by returning ENOSYS");
2644