xref: /freebsd/sys/kern/kern_prot.c (revision a2de789ebb804374bac13ef2931158c364c2774a)
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  *	@(#)kern_prot.c	8.6 (Berkeley) 1/21/94
40df8bae1dSRodney W. Grimes  */
41df8bae1dSRodney W. Grimes 
42df8bae1dSRodney W. Grimes /*
43df8bae1dSRodney W. Grimes  * System calls related to processes and protection
44df8bae1dSRodney W. Grimes  */
45df8bae1dSRodney W. Grimes 
46677b542eSDavid E. O'Brien #include <sys/cdefs.h>
47677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
48677b542eSDavid E. O'Brien 
49f08ef6c5SBjoern A. Zeeb #include "opt_inet.h"
50f08ef6c5SBjoern A. Zeeb #include "opt_inet6.h"
515591b823SEivind Eklund 
52df8bae1dSRodney W. Grimes #include <sys/param.h>
53df8bae1dSRodney W. Grimes #include <sys/systm.h>
54fb919e4dSMark Murray #include <sys/acct.h>
55df04411aSRobert Watson #include <sys/kdb.h>
561c5bb3eaSPeter Wemm #include <sys/kernel.h>
5798f03f90SJake Burkholder #include <sys/lock.h>
582bfc50bcSEdward Tomasz Napierala #include <sys/loginclass.h>
59f9d0d524SRobert Watson #include <sys/malloc.h>
60fb919e4dSMark Murray #include <sys/mutex.h>
617e9e371fSJohn Baldwin #include <sys/refcount.h>
625b29d6e9SJohn Baldwin #include <sys/sx.h>
63800c9408SRobert Watson #include <sys/priv.h>
64f591779bSSeigo Tanimura #include <sys/proc.h>
657e097daaSKonstantin Belousov #include <sys/sysent.h>
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 
76de5b1952SAlexander Leidinger #ifdef REGRESSION
77de5b1952SAlexander Leidinger FEATURE(regression,
78ca54e1aeSHiroki Sato     "Kernel support for interfaces necessary for regression testing (SECURITY RISK!)");
79de5b1952SAlexander Leidinger #endif
80de5b1952SAlexander Leidinger 
812f8a46d5SWayne Salamon #include <security/audit/audit.h>
82aed55708SRobert Watson #include <security/mac/mac_framework.h>
832f8a46d5SWayne Salamon 
84a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_CRED, "cred", "credentials");
85a1c995b6SPoul-Henning Kamp 
867029da5cSPawel Biernacki SYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
877029da5cSPawel Biernacki     "BSD security policy");
8848713bdcSRobert Watson 
89838d9858SBrooks Davis static void crsetgroups_locked(struct ucred *cr, int ngrp,
90838d9858SBrooks Davis     gid_t *groups);
91838d9858SBrooks Davis 
92d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
93ad7507e2SSteven Wallace struct getpid_args {
94df8bae1dSRodney W. Grimes 	int	dummy;
95df8bae1dSRodney W. Grimes };
96d2d3e875SBruce Evans #endif
97df8bae1dSRodney W. Grimes /* ARGSUSED */
9826f9a767SRodney W. Grimes int
998451d0ddSKip Macy sys_getpid(struct thread *td, struct getpid_args *uap)
100df8bae1dSRodney W. Grimes {
101b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
102df8bae1dSRodney W. Grimes 
103b40ce416SJulian Elischer 	td->td_retval[0] = p->p_pid;
1041930e303SPoul-Henning Kamp #if defined(COMPAT_43)
1057e097daaSKonstantin Belousov 	if (SV_PROC_FLAG(p, SV_AOUT))
106abd386baSMateusz Guzik 		td->td_retval[1] = kern_getppid(td);
107df8bae1dSRodney W. Grimes #endif
108df8bae1dSRodney W. Grimes 	return (0);
109df8bae1dSRodney W. Grimes }
110df8bae1dSRodney W. Grimes 
111d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
112ad7507e2SSteven Wallace struct getppid_args {
113ad7507e2SSteven Wallace         int     dummy;
114ad7507e2SSteven Wallace };
115d2d3e875SBruce Evans #endif
116df8bae1dSRodney W. Grimes /* ARGSUSED */
11726f9a767SRodney W. Grimes int
1188451d0ddSKip Macy sys_getppid(struct thread *td, struct getppid_args *uap)
119df8bae1dSRodney W. Grimes {
120abd386baSMateusz Guzik 
121abd386baSMateusz Guzik 	td->td_retval[0] = kern_getppid(td);
122abd386baSMateusz Guzik 	return (0);
123abd386baSMateusz Guzik }
124abd386baSMateusz Guzik 
125abd386baSMateusz Guzik int
126abd386baSMateusz Guzik kern_getppid(struct thread *td)
127abd386baSMateusz Guzik {
128b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
129df8bae1dSRodney W. Grimes 
1302c054ce9SMateusz Guzik 	return (p->p_oppid);
131df8bae1dSRodney W. Grimes }
132df8bae1dSRodney W. Grimes 
13336e9f877SMatthew Dillon /*
134eb725b4eSRobert Watson  * Get process group ID; note that POSIX getpgrp takes no parameter.
13536e9f877SMatthew Dillon  */
136d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
137ad7507e2SSteven Wallace struct getpgrp_args {
138ad7507e2SSteven Wallace         int     dummy;
139ad7507e2SSteven Wallace };
140d2d3e875SBruce Evans #endif
14126f9a767SRodney W. Grimes int
1428451d0ddSKip Macy sys_getpgrp(struct thread *td, struct getpgrp_args *uap)
143df8bae1dSRodney W. Grimes {
144b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
145df8bae1dSRodney W. Grimes 
146f591779bSSeigo Tanimura 	PROC_LOCK(p);
147b40ce416SJulian Elischer 	td->td_retval[0] = p->p_pgrp->pg_id;
148f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
149df8bae1dSRodney W. Grimes 	return (0);
150df8bae1dSRodney W. Grimes }
151df8bae1dSRodney W. Grimes 
152e3043798SPedro F. Giffuni /* Get an arbitrary pid's process group id */
1531a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1541a5018a0SPeter Wemm struct getpgid_args {
1551a5018a0SPeter Wemm 	pid_t	pid;
1561a5018a0SPeter Wemm };
1571a5018a0SPeter Wemm #endif
1581a5018a0SPeter Wemm int
1598451d0ddSKip Macy sys_getpgid(struct thread *td, struct getpgid_args *uap)
1601a5018a0SPeter Wemm {
161a70a2b74SJohn Baldwin 	struct proc *p;
162f2ae7368SJohn Baldwin 	int error;
16365de0c7aSDon Lewis 
164f591779bSSeigo Tanimura 	if (uap->pid == 0) {
165a70a2b74SJohn Baldwin 		p = td->td_proc;
166f591779bSSeigo Tanimura 		PROC_LOCK(p);
167a70a2b74SJohn Baldwin 	} else {
168a70a2b74SJohn Baldwin 		p = pfind(uap->pid);
169a70a2b74SJohn Baldwin 		if (p == NULL)
170a70a2b74SJohn Baldwin 			return (ESRCH);
171a70a2b74SJohn Baldwin 		error = p_cansee(td, p);
172a70a2b74SJohn Baldwin 		if (error) {
173a70a2b74SJohn Baldwin 			PROC_UNLOCK(p);
174a70a2b74SJohn Baldwin 			return (error);
175a70a2b74SJohn Baldwin 		}
176a70a2b74SJohn Baldwin 	}
177b40ce416SJulian Elischer 	td->td_retval[0] = p->p_pgrp->pg_id;
178f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
179a70a2b74SJohn Baldwin 	return (0);
1801a5018a0SPeter Wemm }
1811a5018a0SPeter Wemm 
1821a5018a0SPeter Wemm /*
183e3043798SPedro F. Giffuni  * Get an arbitrary pid's session id.
1841a5018a0SPeter Wemm  */
1851a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1861a5018a0SPeter Wemm struct getsid_args {
1871a5018a0SPeter Wemm 	pid_t	pid;
1881a5018a0SPeter Wemm };
1891a5018a0SPeter Wemm #endif
1901a5018a0SPeter Wemm int
1918451d0ddSKip Macy sys_getsid(struct thread *td, struct getsid_args *uap)
1921a5018a0SPeter Wemm {
193be2cfdbcSEdward Tomasz Napierala 
194be2cfdbcSEdward Tomasz Napierala 	return (kern_getsid(td, uap->pid));
195be2cfdbcSEdward Tomasz Napierala }
196be2cfdbcSEdward Tomasz Napierala 
197be2cfdbcSEdward Tomasz Napierala int
198be2cfdbcSEdward Tomasz Napierala kern_getsid(struct thread *td, pid_t pid)
199be2cfdbcSEdward Tomasz Napierala {
200a70a2b74SJohn Baldwin 	struct proc *p;
201eb725b4eSRobert Watson 	int error;
20265de0c7aSDon Lewis 
203be2cfdbcSEdward Tomasz Napierala 	if (pid == 0) {
204a70a2b74SJohn Baldwin 		p = td->td_proc;
205f591779bSSeigo Tanimura 		PROC_LOCK(p);
206a70a2b74SJohn Baldwin 	} else {
207be2cfdbcSEdward Tomasz Napierala 		p = pfind(pid);
208a70a2b74SJohn Baldwin 		if (p == NULL)
209a70a2b74SJohn Baldwin 			return (ESRCH);
210a70a2b74SJohn Baldwin 		error = p_cansee(td, p);
211a70a2b74SJohn Baldwin 		if (error) {
212a70a2b74SJohn Baldwin 			PROC_UNLOCK(p);
213a70a2b74SJohn Baldwin 			return (error);
214a70a2b74SJohn Baldwin 		}
215a70a2b74SJohn Baldwin 	}
216b40ce416SJulian Elischer 	td->td_retval[0] = p->p_session->s_sid;
217f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
218a70a2b74SJohn Baldwin 	return (0);
2191a5018a0SPeter Wemm }
2201a5018a0SPeter Wemm 
221d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
222ad7507e2SSteven Wallace struct getuid_args {
223ad7507e2SSteven Wallace         int     dummy;
224ad7507e2SSteven Wallace };
225d2d3e875SBruce Evans #endif
226df8bae1dSRodney W. Grimes /* ARGSUSED */
22726f9a767SRodney W. Grimes int
2288451d0ddSKip Macy sys_getuid(struct thread *td, struct getuid_args *uap)
229df8bae1dSRodney W. Grimes {
230df8bae1dSRodney W. Grimes 
231d846883bSJohn Baldwin 	td->td_retval[0] = td->td_ucred->cr_ruid;
2321930e303SPoul-Henning Kamp #if defined(COMPAT_43)
233d846883bSJohn Baldwin 	td->td_retval[1] = td->td_ucred->cr_uid;
234df8bae1dSRodney W. Grimes #endif
235df8bae1dSRodney W. Grimes 	return (0);
236df8bae1dSRodney W. Grimes }
237df8bae1dSRodney W. Grimes 
238d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
239ad7507e2SSteven Wallace struct geteuid_args {
240ad7507e2SSteven Wallace         int     dummy;
241ad7507e2SSteven Wallace };
242d2d3e875SBruce Evans #endif
243df8bae1dSRodney W. Grimes /* ARGSUSED */
24426f9a767SRodney W. Grimes int
2458451d0ddSKip Macy sys_geteuid(struct thread *td, struct geteuid_args *uap)
246df8bae1dSRodney W. Grimes {
247d846883bSJohn Baldwin 
248d846883bSJohn Baldwin 	td->td_retval[0] = td->td_ucred->cr_uid;
249df8bae1dSRodney W. Grimes 	return (0);
250df8bae1dSRodney W. Grimes }
251df8bae1dSRodney W. Grimes 
252d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
253ad7507e2SSteven Wallace struct getgid_args {
254ad7507e2SSteven Wallace         int     dummy;
255ad7507e2SSteven Wallace };
256d2d3e875SBruce Evans #endif
257df8bae1dSRodney W. Grimes /* ARGSUSED */
25826f9a767SRodney W. Grimes int
2598451d0ddSKip Macy sys_getgid(struct thread *td, struct getgid_args *uap)
260df8bae1dSRodney W. Grimes {
261df8bae1dSRodney W. Grimes 
262d846883bSJohn Baldwin 	td->td_retval[0] = td->td_ucred->cr_rgid;
2631930e303SPoul-Henning Kamp #if defined(COMPAT_43)
264d846883bSJohn Baldwin 	td->td_retval[1] = td->td_ucred->cr_groups[0];
265df8bae1dSRodney W. Grimes #endif
266df8bae1dSRodney W. Grimes 	return (0);
267df8bae1dSRodney W. Grimes }
268df8bae1dSRodney W. Grimes 
269df8bae1dSRodney W. Grimes /*
270df8bae1dSRodney W. Grimes  * Get effective group ID.  The "egid" is groups[0], and could be obtained
271df8bae1dSRodney W. Grimes  * via getgroups.  This syscall exists because it is somewhat painful to do
272df8bae1dSRodney W. Grimes  * correctly in a library function.
273df8bae1dSRodney W. Grimes  */
274d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
275ad7507e2SSteven Wallace struct getegid_args {
276ad7507e2SSteven Wallace         int     dummy;
277ad7507e2SSteven Wallace };
278d2d3e875SBruce Evans #endif
279df8bae1dSRodney W. Grimes /* ARGSUSED */
28026f9a767SRodney W. Grimes int
2818451d0ddSKip Macy sys_getegid(struct thread *td, struct getegid_args *uap)
282df8bae1dSRodney W. Grimes {
283df8bae1dSRodney W. Grimes 
284d846883bSJohn Baldwin 	td->td_retval[0] = td->td_ucred->cr_groups[0];
285df8bae1dSRodney W. Grimes 	return (0);
286df8bae1dSRodney W. Grimes }
287df8bae1dSRodney W. Grimes 
288d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
289df8bae1dSRodney W. Grimes struct getgroups_args {
290df8bae1dSRodney W. Grimes 	u_int	gidsetsize;
291df8bae1dSRodney W. Grimes 	gid_t	*gidset;
292df8bae1dSRodney W. Grimes };
293d2d3e875SBruce Evans #endif
29426f9a767SRodney W. Grimes int
2953e85b721SEd Maste sys_getgroups(struct thread *td, struct getgroups_args *uap)
296df8bae1dSRodney W. Grimes {
29707b384cbSMateusz Guzik 	struct ucred *cred;
298b1fc0ec1SRobert Watson 	u_int ngrp;
299eb725b4eSRobert Watson 	int error;
300df8bae1dSRodney W. Grimes 
3013cb83e71SJohn Baldwin 	cred = td->td_ucred;
30207b384cbSMateusz Guzik 	ngrp = cred->cr_ngroups;
30307b384cbSMateusz Guzik 
30407b384cbSMateusz Guzik 	if (uap->gidsetsize == 0) {
30507b384cbSMateusz Guzik 		error = 0;
30607b384cbSMateusz Guzik 		goto out;
3073cb83e71SJohn Baldwin 	}
30807b384cbSMateusz Guzik 	if (uap->gidsetsize < ngrp)
3093cb83e71SJohn Baldwin 		return (EINVAL);
31007b384cbSMateusz Guzik 
31107b384cbSMateusz Guzik 	error = copyout(cred->cr_groups, uap->gidset, ngrp * sizeof(gid_t));
31207b384cbSMateusz Guzik out:
31307b384cbSMateusz Guzik 	td->td_retval[0] = ngrp;
31407b384cbSMateusz Guzik 	return (error);
3153cb83e71SJohn Baldwin }
3163cb83e71SJohn Baldwin 
317d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
31882970b81SBruce Evans struct setsid_args {
319ad7507e2SSteven Wallace         int     dummy;
320ad7507e2SSteven Wallace };
321d2d3e875SBruce Evans #endif
322df8bae1dSRodney W. Grimes /* ARGSUSED */
32326f9a767SRodney W. Grimes int
3243e85b721SEd Maste sys_setsid(struct thread *td, struct setsid_args *uap)
325df8bae1dSRodney W. Grimes {
326f591779bSSeigo Tanimura 	struct pgrp *pgrp;
327835a82eeSMatthew Dillon 	int error;
328b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
329f591779bSSeigo Tanimura 	struct pgrp *newpgrp;
330f591779bSSeigo Tanimura 	struct session *newsess;
331f591779bSSeigo Tanimura 
332f591779bSSeigo Tanimura 	error = 0;
333f591779bSSeigo Tanimura 	pgrp = NULL;
334df8bae1dSRodney W. Grimes 
3351ede983cSDag-Erling Smørgrav 	newpgrp = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
3361ede983cSDag-Erling Smørgrav 	newsess = malloc(sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO);
337f591779bSSeigo Tanimura 
338c8b1829dSJohn Baldwin 	sx_xlock(&proctree_lock);
339f591779bSSeigo Tanimura 
340f591779bSSeigo Tanimura 	if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) {
341f591779bSSeigo Tanimura 		if (pgrp != NULL)
342f591779bSSeigo Tanimura 			PGRP_UNLOCK(pgrp);
343835a82eeSMatthew Dillon 		error = EPERM;
344f591779bSSeigo Tanimura 	} else {
345f591779bSSeigo Tanimura 		(void)enterpgrp(p, p->p_pid, newpgrp, newsess);
346b40ce416SJulian Elischer 		td->td_retval[0] = p->p_pid;
347c8b1829dSJohn Baldwin 		newpgrp = NULL;
348c8b1829dSJohn Baldwin 		newsess = NULL;
349df8bae1dSRodney W. Grimes 	}
350f591779bSSeigo Tanimura 
351c8b1829dSJohn Baldwin 	sx_xunlock(&proctree_lock);
352f591779bSSeigo Tanimura 
353c8b1829dSJohn Baldwin 	if (newpgrp != NULL)
3541ede983cSDag-Erling Smørgrav 		free(newpgrp, M_PGRP);
355c8b1829dSJohn Baldwin 	if (newsess != NULL)
3561ede983cSDag-Erling Smørgrav 		free(newsess, M_SESSION);
3571c2451c2SSeigo Tanimura 
358c8b1829dSJohn Baldwin 	return (error);
359df8bae1dSRodney W. Grimes }
360df8bae1dSRodney W. Grimes 
361df8bae1dSRodney W. Grimes /*
362df8bae1dSRodney W. Grimes  * set process group (setpgid/old setpgrp)
363df8bae1dSRodney W. Grimes  *
364df8bae1dSRodney W. Grimes  * caller does setpgid(targpid, targpgid)
365df8bae1dSRodney W. Grimes  *
366df8bae1dSRodney W. Grimes  * pid must be caller or child of caller (ESRCH)
367df8bae1dSRodney W. Grimes  * if a child
368df8bae1dSRodney W. Grimes  *	pid must be in same session (EPERM)
369df8bae1dSRodney W. Grimes  *	pid can't have done an exec (EACCES)
370df8bae1dSRodney W. Grimes  * if pgid != pid
371df8bae1dSRodney W. Grimes  * 	there must exist some pid in same session having pgid (EPERM)
372df8bae1dSRodney W. Grimes  * pid must not be session leader (EPERM)
373df8bae1dSRodney W. Grimes  */
374d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
375df8bae1dSRodney W. Grimes struct setpgid_args {
376df8bae1dSRodney W. Grimes 	int	pid;		/* target process id */
377df8bae1dSRodney W. Grimes 	int	pgid;		/* target pgrp id */
378df8bae1dSRodney W. Grimes };
379d2d3e875SBruce Evans #endif
380df8bae1dSRodney W. Grimes /* ARGSUSED */
38126f9a767SRodney W. Grimes int
3823e85b721SEd Maste sys_setpgid(struct thread *td, struct setpgid_args *uap)
383df8bae1dSRodney W. Grimes {
384b40ce416SJulian Elischer 	struct proc *curp = td->td_proc;
3853e85b721SEd Maste 	struct proc *targp;	/* target process */
3863e85b721SEd Maste 	struct pgrp *pgrp;	/* target pgrp */
387eb9e5c1dSRobert Watson 	int error;
388f591779bSSeigo Tanimura 	struct pgrp *newpgrp;
389df8bae1dSRodney W. Grimes 
39078f64bccSBruce Evans 	if (uap->pgid < 0)
39178f64bccSBruce Evans 		return (EINVAL);
392f591779bSSeigo Tanimura 
393f591779bSSeigo Tanimura 	error = 0;
394f591779bSSeigo Tanimura 
3951ede983cSDag-Erling Smørgrav 	newpgrp = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
396f591779bSSeigo Tanimura 
397c8b1829dSJohn Baldwin 	sx_xlock(&proctree_lock);
398df8bae1dSRodney W. Grimes 	if (uap->pid != 0 && uap->pid != curp->p_pid) {
399f591779bSSeigo Tanimura 		if ((targp = pfind(uap->pid)) == NULL) {
400835a82eeSMatthew Dillon 			error = ESRCH;
401c8b1829dSJohn Baldwin 			goto done;
40233a9ed9dSJohn Baldwin 		}
403f591779bSSeigo Tanimura 		if (!inferior(targp)) {
404f591779bSSeigo Tanimura 			PROC_UNLOCK(targp);
4052f932587SSeigo Tanimura 			error = ESRCH;
406c8b1829dSJohn Baldwin 			goto done;
407f591779bSSeigo Tanimura 		}
40871a057bcSRobert Watson 		if ((error = p_cansee(td, targp))) {
40933a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
410c8b1829dSJohn Baldwin 			goto done;
41133a9ed9dSJohn Baldwin 		}
41233a9ed9dSJohn Baldwin 		if (targp->p_pgrp == NULL ||
41333a9ed9dSJohn Baldwin 		    targp->p_session != curp->p_session) {
41433a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
415835a82eeSMatthew Dillon 			error = EPERM;
416c8b1829dSJohn Baldwin 			goto done;
41733a9ed9dSJohn Baldwin 		}
41833a9ed9dSJohn Baldwin 		if (targp->p_flag & P_EXEC) {
41933a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
420835a82eeSMatthew Dillon 			error = EACCES;
421c8b1829dSJohn Baldwin 			goto done;
42233a9ed9dSJohn Baldwin 		}
42333a9ed9dSJohn Baldwin 		PROC_UNLOCK(targp);
424f591779bSSeigo Tanimura 	} else
425f591779bSSeigo Tanimura 		targp = curp;
426f591779bSSeigo Tanimura 	if (SESS_LEADER(targp)) {
427835a82eeSMatthew Dillon 		error = EPERM;
428c8b1829dSJohn Baldwin 		goto done;
42933a9ed9dSJohn Baldwin 	}
430eb725b4eSRobert Watson 	if (uap->pgid == 0)
431df8bae1dSRodney W. Grimes 		uap->pgid = targp->p_pid;
432a10d5f02SOlivier Houchard 	if ((pgrp = pgfind(uap->pgid)) == NULL) {
433f591779bSSeigo Tanimura 		if (uap->pgid == targp->p_pid) {
434a10d5f02SOlivier Houchard 			error = enterpgrp(targp, uap->pgid, newpgrp,
435a10d5f02SOlivier Houchard 			    NULL);
436f591779bSSeigo Tanimura 			if (error == 0)
437f591779bSSeigo Tanimura 				newpgrp = NULL;
438a10d5f02SOlivier Houchard 		} else
439835a82eeSMatthew Dillon 			error = EPERM;
440a10d5f02SOlivier Houchard 	} else {
441f591779bSSeigo Tanimura 		if (pgrp == targp->p_pgrp) {
442f591779bSSeigo Tanimura 			PGRP_UNLOCK(pgrp);
443f591779bSSeigo Tanimura 			goto done;
44433a9ed9dSJohn Baldwin 		}
445a10d5f02SOlivier Houchard 		if (pgrp->pg_id != targp->p_pid &&
446a10d5f02SOlivier Houchard 		    pgrp->pg_session != curp->p_session) {
447a10d5f02SOlivier Houchard 			PGRP_UNLOCK(pgrp);
448a10d5f02SOlivier Houchard 			error = EPERM;
449a10d5f02SOlivier Houchard 			goto done;
450a10d5f02SOlivier Houchard 		}
451f591779bSSeigo Tanimura 		PGRP_UNLOCK(pgrp);
452f591779bSSeigo Tanimura 		error = enterthispgrp(targp, pgrp);
453f591779bSSeigo Tanimura 	}
454f591779bSSeigo Tanimura done:
455c8b1829dSJohn Baldwin 	sx_xunlock(&proctree_lock);
456c8b1829dSJohn Baldwin 	KASSERT((error == 0) || (newpgrp != NULL),
457c8b1829dSJohn Baldwin 	    ("setpgid failed and newpgrp is NULL"));
4586041fa0aSSeigo Tanimura 	if (newpgrp != NULL)
4591ede983cSDag-Erling Smørgrav 		free(newpgrp, M_PGRP);
460835a82eeSMatthew Dillon 	return (error);
461df8bae1dSRodney W. Grimes }
462df8bae1dSRodney W. Grimes 
463a08f4bf6SPeter Wemm /*
464a08f4bf6SPeter Wemm  * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
4652fa72ea7SJeroen Ruigrok van der Werven  * compatible.  It says that setting the uid/gid to euid/egid is a special
466a08f4bf6SPeter Wemm  * case of "appropriate privilege".  Once the rules are expanded out, this
467a08f4bf6SPeter Wemm  * basically means that setuid(nnn) sets all three id's, in all permitted
468a08f4bf6SPeter Wemm  * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
469a08f4bf6SPeter Wemm  * does not set the saved id - this is dangerous for traditional BSD
470a08f4bf6SPeter Wemm  * programs.  For this reason, we *really* do not want to set
471a08f4bf6SPeter Wemm  * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
472a08f4bf6SPeter Wemm  */
473a08f4bf6SPeter Wemm #define POSIX_APPENDIX_B_4_2_2
474a08f4bf6SPeter Wemm 
475d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
476df8bae1dSRodney W. Grimes struct setuid_args {
477df8bae1dSRodney W. Grimes 	uid_t	uid;
478df8bae1dSRodney W. Grimes };
479d2d3e875SBruce Evans #endif
480df8bae1dSRodney W. Grimes /* ARGSUSED */
48126f9a767SRodney W. Grimes int
4828451d0ddSKip Macy sys_setuid(struct thread *td, struct setuid_args *uap)
483df8bae1dSRodney W. Grimes {
484b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
485b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
486b1fc0ec1SRobert Watson 	uid_t uid;
4871419eacbSAlfred Perlstein 	struct uidinfo *uip;
488eb725b4eSRobert Watson 	int error;
489df8bae1dSRodney W. Grimes 
49007f3485dSJohn Baldwin 	uid = uap->uid;
49114961ba7SRobert Watson 	AUDIT_ARG_UID(uid);
49207f3485dSJohn Baldwin 	newcred = crget();
4931419eacbSAlfred Perlstein 	uip = uifind(uid);
49407f3485dSJohn Baldwin 	PROC_LOCK(p);
495838d9858SBrooks Davis 	/*
496838d9858SBrooks Davis 	 * Copy credentials so other references do not see our changes.
497838d9858SBrooks Davis 	 */
498838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
4995a92ee3cSRobert Watson 
500030a28b3SRobert Watson #ifdef MAC
5016f6174a7SRobert Watson 	error = mac_cred_check_setuid(oldcred, uid);
502030a28b3SRobert Watson 	if (error)
503030a28b3SRobert Watson 		goto fail;
504030a28b3SRobert Watson #endif
505030a28b3SRobert Watson 
506a08f4bf6SPeter Wemm 	/*
507a08f4bf6SPeter Wemm 	 * See if we have "permission" by POSIX 1003.1 rules.
508a08f4bf6SPeter Wemm 	 *
509a08f4bf6SPeter Wemm 	 * Note that setuid(geteuid()) is a special case of
510a08f4bf6SPeter Wemm 	 * "appropriate privileges" in appendix B.4.2.2.  We need
5112fa72ea7SJeroen Ruigrok van der Werven 	 * to use this clause to be compatible with traditional BSD
512a08f4bf6SPeter Wemm 	 * semantics.  Basically, it means that "setuid(xx)" sets all
513a08f4bf6SPeter Wemm 	 * three id's (assuming you have privs).
514a08f4bf6SPeter Wemm 	 *
515a08f4bf6SPeter Wemm 	 * Notes on the logic.  We do things in three steps.
516a08f4bf6SPeter Wemm 	 * 1: We determine if the euid is going to change, and do EPERM
517a08f4bf6SPeter Wemm 	 *    right away.  We unconditionally change the euid later if this
518a08f4bf6SPeter Wemm 	 *    test is satisfied, simplifying that part of the logic.
519eb725b4eSRobert Watson 	 * 2: We determine if the real and/or saved uids are going to
520a08f4bf6SPeter Wemm 	 *    change.  Determined by compile options.
521a08f4bf6SPeter Wemm 	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
522a08f4bf6SPeter Wemm 	 */
523b1fc0ec1SRobert Watson 	if (uid != oldcred->cr_ruid &&		/* allow setuid(getuid()) */
5243f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS
525b1fc0ec1SRobert Watson 	    uid != oldcred->cr_svuid &&		/* allow setuid(saved gid) */
526a08f4bf6SPeter Wemm #endif
527a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
528b1fc0ec1SRobert Watson 	    uid != oldcred->cr_uid &&		/* allow setuid(geteuid()) */
5293f246666SAndrey A. Chernov #endif
530cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETUID)) != 0)
531030a28b3SRobert Watson 		goto fail;
532a08f4bf6SPeter Wemm 
533a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS
534df8bae1dSRodney W. Grimes 	/*
535a08f4bf6SPeter Wemm 	 * Do we have "appropriate privileges" (are we root or uid == euid)
536a08f4bf6SPeter Wemm 	 * If so, we are changing the real uid and/or saved uid.
537df8bae1dSRodney W. Grimes 	 */
5383f246666SAndrey A. Chernov 	if (
539a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
540b1fc0ec1SRobert Watson 	    uid == oldcred->cr_uid ||
5413f246666SAndrey A. Chernov #endif
542800c9408SRobert Watson 	    /* We are using privs. */
543cc426dd3SMateusz Guzik 	    priv_check_cred(oldcred, PRIV_CRED_SETUID) == 0)
544a08f4bf6SPeter Wemm #endif
545a08f4bf6SPeter Wemm 	{
546a08f4bf6SPeter Wemm 		/*
547f535380cSDon Lewis 		 * Set the real uid and transfer proc count to new user.
548a08f4bf6SPeter Wemm 		 */
549b1fc0ec1SRobert Watson 		if (uid != oldcred->cr_ruid) {
5501419eacbSAlfred Perlstein 			change_ruid(newcred, uip);
551f535380cSDon Lewis 			setsugid(p);
552d3cdb93dSAndrey A. Chernov 		}
553a08f4bf6SPeter Wemm 		/*
554a08f4bf6SPeter Wemm 		 * Set saved uid
555a08f4bf6SPeter Wemm 		 *
556a08f4bf6SPeter Wemm 		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
557a08f4bf6SPeter Wemm 		 * the security of seteuid() depends on it.  B.4.2.2 says it
558a08f4bf6SPeter Wemm 		 * is important that we should do this.
559a08f4bf6SPeter Wemm 		 */
560b1fc0ec1SRobert Watson 		if (uid != oldcred->cr_svuid) {
561b1fc0ec1SRobert Watson 			change_svuid(newcred, uid);
562d5f81602SSean Eric Fagan 			setsugid(p);
563a08f4bf6SPeter Wemm 		}
564a08f4bf6SPeter Wemm 	}
565a08f4bf6SPeter Wemm 
566a08f4bf6SPeter Wemm 	/*
567a08f4bf6SPeter Wemm 	 * In all permitted cases, we are changing the euid.
568a08f4bf6SPeter Wemm 	 */
569b1fc0ec1SRobert Watson 	if (uid != oldcred->cr_uid) {
5701419eacbSAlfred Perlstein 		change_euid(newcred, uip);
571d5f81602SSean Eric Fagan 		setsugid(p);
572a08f4bf6SPeter Wemm 	}
573daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
574e4dcb704SEdward Tomasz Napierala #ifdef RACCT
575e4dcb704SEdward Tomasz Napierala 	racct_proc_ucred_changed(p, oldcred, newcred);
576f87beb93SAndriy Gapon 	crhold(newcred);
577f87beb93SAndriy Gapon #endif
578f87beb93SAndriy Gapon 	PROC_UNLOCK(p);
579f87beb93SAndriy Gapon #ifdef RCTL
580f87beb93SAndriy Gapon 	rctl_proc_ucred_changed(p, newcred);
581f87beb93SAndriy Gapon 	crfree(newcred);
582e4dcb704SEdward Tomasz Napierala #endif
5831419eacbSAlfred Perlstein 	uifree(uip);
584b1fc0ec1SRobert Watson 	crfree(oldcred);
58507f3485dSJohn Baldwin 	return (0);
586030a28b3SRobert Watson 
587030a28b3SRobert Watson fail:
588030a28b3SRobert Watson 	PROC_UNLOCK(p);
589030a28b3SRobert Watson 	uifree(uip);
590030a28b3SRobert Watson 	crfree(newcred);
591030a28b3SRobert Watson 	return (error);
592df8bae1dSRodney W. Grimes }
593df8bae1dSRodney W. Grimes 
594d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
595df8bae1dSRodney W. Grimes struct seteuid_args {
596df8bae1dSRodney W. Grimes 	uid_t	euid;
597df8bae1dSRodney W. Grimes };
598d2d3e875SBruce Evans #endif
599df8bae1dSRodney W. Grimes /* ARGSUSED */
60026f9a767SRodney W. Grimes int
6018451d0ddSKip Macy sys_seteuid(struct thread *td, struct seteuid_args *uap)
602df8bae1dSRodney W. Grimes {
603b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
604b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
605b1fc0ec1SRobert Watson 	uid_t euid;
6061419eacbSAlfred Perlstein 	struct uidinfo *euip;
607eb725b4eSRobert Watson 	int error;
608df8bae1dSRodney W. Grimes 
609df8bae1dSRodney W. Grimes 	euid = uap->euid;
61014961ba7SRobert Watson 	AUDIT_ARG_EUID(euid);
61107f3485dSJohn Baldwin 	newcred = crget();
6121419eacbSAlfred Perlstein 	euip = uifind(euid);
61307f3485dSJohn Baldwin 	PROC_LOCK(p);
614838d9858SBrooks Davis 	/*
615838d9858SBrooks Davis 	 * Copy credentials so other references do not see our changes.
616838d9858SBrooks Davis 	 */
617838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
618030a28b3SRobert Watson 
619030a28b3SRobert Watson #ifdef MAC
6206f6174a7SRobert Watson 	error = mac_cred_check_seteuid(oldcred, euid);
621030a28b3SRobert Watson 	if (error)
622030a28b3SRobert Watson 		goto fail;
623030a28b3SRobert Watson #endif
624030a28b3SRobert Watson 
625b1fc0ec1SRobert Watson 	if (euid != oldcred->cr_ruid &&		/* allow seteuid(getuid()) */
626b1fc0ec1SRobert Watson 	    euid != oldcred->cr_svuid &&	/* allow seteuid(saved uid) */
627cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETEUID)) != 0)
628030a28b3SRobert Watson 		goto fail;
629030a28b3SRobert Watson 
630df8bae1dSRodney W. Grimes 	/*
631838d9858SBrooks Davis 	 * Everything's okay, do it.
632df8bae1dSRodney W. Grimes 	 */
633b1fc0ec1SRobert Watson 	if (oldcred->cr_uid != euid) {
6341419eacbSAlfred Perlstein 		change_euid(newcred, euip);
635d5f81602SSean Eric Fagan 		setsugid(p);
636229a15f0SPeter Wemm 	}
637daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
63807f3485dSJohn Baldwin 	PROC_UNLOCK(p);
6391419eacbSAlfred Perlstein 	uifree(euip);
640b1fc0ec1SRobert Watson 	crfree(oldcred);
64107f3485dSJohn Baldwin 	return (0);
642030a28b3SRobert Watson 
643030a28b3SRobert Watson fail:
644030a28b3SRobert Watson 	PROC_UNLOCK(p);
645030a28b3SRobert Watson 	uifree(euip);
646030a28b3SRobert Watson 	crfree(newcred);
647030a28b3SRobert Watson 	return (error);
648df8bae1dSRodney W. Grimes }
649df8bae1dSRodney W. Grimes 
650d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
651df8bae1dSRodney W. Grimes struct setgid_args {
652df8bae1dSRodney W. Grimes 	gid_t	gid;
653df8bae1dSRodney W. Grimes };
654d2d3e875SBruce Evans #endif
655df8bae1dSRodney W. Grimes /* ARGSUSED */
65626f9a767SRodney W. Grimes int
6578451d0ddSKip Macy sys_setgid(struct thread *td, struct setgid_args *uap)
658df8bae1dSRodney W. Grimes {
659b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
660b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
661b1fc0ec1SRobert Watson 	gid_t gid;
662eb725b4eSRobert Watson 	int error;
663df8bae1dSRodney W. Grimes 
664b1fc0ec1SRobert Watson 	gid = uap->gid;
66514961ba7SRobert Watson 	AUDIT_ARG_GID(gid);
66607f3485dSJohn Baldwin 	newcred = crget();
66707f3485dSJohn Baldwin 	PROC_LOCK(p);
668838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
6695a92ee3cSRobert Watson 
670030a28b3SRobert Watson #ifdef MAC
6716f6174a7SRobert Watson 	error = mac_cred_check_setgid(oldcred, gid);
672030a28b3SRobert Watson 	if (error)
673030a28b3SRobert Watson 		goto fail;
674030a28b3SRobert Watson #endif
675030a28b3SRobert Watson 
676a08f4bf6SPeter Wemm 	/*
677a08f4bf6SPeter Wemm 	 * See if we have "permission" by POSIX 1003.1 rules.
678a08f4bf6SPeter Wemm 	 *
679a08f4bf6SPeter Wemm 	 * Note that setgid(getegid()) is a special case of
680a08f4bf6SPeter Wemm 	 * "appropriate privileges" in appendix B.4.2.2.  We need
6812fa72ea7SJeroen Ruigrok van der Werven 	 * to use this clause to be compatible with traditional BSD
682a08f4bf6SPeter Wemm 	 * semantics.  Basically, it means that "setgid(xx)" sets all
683a08f4bf6SPeter Wemm 	 * three id's (assuming you have privs).
684a08f4bf6SPeter Wemm 	 *
685a08f4bf6SPeter Wemm 	 * For notes on the logic here, see setuid() above.
686a08f4bf6SPeter Wemm 	 */
687b1fc0ec1SRobert Watson 	if (gid != oldcred->cr_rgid &&		/* allow setgid(getgid()) */
6883f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS
689b1fc0ec1SRobert Watson 	    gid != oldcred->cr_svgid &&		/* allow setgid(saved gid) */
690a08f4bf6SPeter Wemm #endif
691a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
692b1fc0ec1SRobert Watson 	    gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */
6933f246666SAndrey A. Chernov #endif
694cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETGID)) != 0)
695030a28b3SRobert Watson 		goto fail;
696a08f4bf6SPeter Wemm 
697a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS
698a08f4bf6SPeter Wemm 	/*
699a08f4bf6SPeter Wemm 	 * Do we have "appropriate privileges" (are we root or gid == egid)
700a08f4bf6SPeter Wemm 	 * If so, we are changing the real uid and saved gid.
701a08f4bf6SPeter Wemm 	 */
702a08f4bf6SPeter Wemm 	if (
703a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
704b1fc0ec1SRobert Watson 	    gid == oldcred->cr_groups[0] ||
705a08f4bf6SPeter Wemm #endif
706800c9408SRobert Watson 	    /* We are using privs. */
707cc426dd3SMateusz Guzik 	    priv_check_cred(oldcred, PRIV_CRED_SETGID) == 0)
708a08f4bf6SPeter Wemm #endif
709a08f4bf6SPeter Wemm 	{
710a08f4bf6SPeter Wemm 		/*
711a08f4bf6SPeter Wemm 		 * Set real gid
712a08f4bf6SPeter Wemm 		 */
713b1fc0ec1SRobert Watson 		if (oldcred->cr_rgid != gid) {
714b1fc0ec1SRobert Watson 			change_rgid(newcred, gid);
715d5f81602SSean Eric Fagan 			setsugid(p);
716a08f4bf6SPeter Wemm 		}
717a08f4bf6SPeter Wemm 		/*
718a08f4bf6SPeter Wemm 		 * Set saved gid
719a08f4bf6SPeter Wemm 		 *
720a08f4bf6SPeter Wemm 		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
721a08f4bf6SPeter Wemm 		 * the security of setegid() depends on it.  B.4.2.2 says it
722a08f4bf6SPeter Wemm 		 * is important that we should do this.
723a08f4bf6SPeter Wemm 		 */
724b1fc0ec1SRobert Watson 		if (oldcred->cr_svgid != gid) {
725b1fc0ec1SRobert Watson 			change_svgid(newcred, gid);
726d5f81602SSean Eric Fagan 			setsugid(p);
727a08f4bf6SPeter Wemm 		}
728a08f4bf6SPeter Wemm 	}
729a08f4bf6SPeter Wemm 	/*
730a08f4bf6SPeter Wemm 	 * In all cases permitted cases, we are changing the egid.
731a08f4bf6SPeter Wemm 	 * Copy credentials so other references do not see our changes.
732a08f4bf6SPeter Wemm 	 */
733b1fc0ec1SRobert Watson 	if (oldcred->cr_groups[0] != gid) {
734b1fc0ec1SRobert Watson 		change_egid(newcred, gid);
735d5f81602SSean Eric Fagan 		setsugid(p);
736a08f4bf6SPeter Wemm 	}
737daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
73807f3485dSJohn Baldwin 	PROC_UNLOCK(p);
739b1fc0ec1SRobert Watson 	crfree(oldcred);
74007f3485dSJohn Baldwin 	return (0);
741030a28b3SRobert Watson 
742030a28b3SRobert Watson fail:
743030a28b3SRobert Watson 	PROC_UNLOCK(p);
744030a28b3SRobert Watson 	crfree(newcred);
745030a28b3SRobert Watson 	return (error);
746df8bae1dSRodney W. Grimes }
747df8bae1dSRodney W. Grimes 
748d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
749df8bae1dSRodney W. Grimes struct setegid_args {
750df8bae1dSRodney W. Grimes 	gid_t	egid;
751df8bae1dSRodney W. Grimes };
752d2d3e875SBruce Evans #endif
753df8bae1dSRodney W. Grimes /* ARGSUSED */
75426f9a767SRodney W. Grimes int
7558451d0ddSKip Macy sys_setegid(struct thread *td, struct setegid_args *uap)
756df8bae1dSRodney W. Grimes {
757b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
758b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
759b1fc0ec1SRobert Watson 	gid_t egid;
760eb725b4eSRobert Watson 	int error;
761df8bae1dSRodney W. Grimes 
762df8bae1dSRodney W. Grimes 	egid = uap->egid;
76314961ba7SRobert Watson 	AUDIT_ARG_EGID(egid);
76407f3485dSJohn Baldwin 	newcred = crget();
76507f3485dSJohn Baldwin 	PROC_LOCK(p);
766838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
767030a28b3SRobert Watson 
768030a28b3SRobert Watson #ifdef MAC
7696f6174a7SRobert Watson 	error = mac_cred_check_setegid(oldcred, egid);
770030a28b3SRobert Watson 	if (error)
771030a28b3SRobert Watson 		goto fail;
772030a28b3SRobert Watson #endif
773030a28b3SRobert Watson 
774b1fc0ec1SRobert Watson 	if (egid != oldcred->cr_rgid &&		/* allow setegid(getgid()) */
775b1fc0ec1SRobert Watson 	    egid != oldcred->cr_svgid &&	/* allow setegid(saved gid) */
776cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETEGID)) != 0)
777030a28b3SRobert Watson 		goto fail;
778030a28b3SRobert Watson 
779b1fc0ec1SRobert Watson 	if (oldcred->cr_groups[0] != egid) {
780b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
781d5f81602SSean Eric Fagan 		setsugid(p);
782229a15f0SPeter Wemm 	}
783daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
78407f3485dSJohn Baldwin 	PROC_UNLOCK(p);
785b1fc0ec1SRobert Watson 	crfree(oldcred);
78607f3485dSJohn Baldwin 	return (0);
787030a28b3SRobert Watson 
788030a28b3SRobert Watson fail:
789030a28b3SRobert Watson 	PROC_UNLOCK(p);
790030a28b3SRobert Watson 	crfree(newcred);
791030a28b3SRobert Watson 	return (error);
792df8bae1dSRodney W. Grimes }
793df8bae1dSRodney W. Grimes 
794d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
795df8bae1dSRodney W. Grimes struct setgroups_args {
796df8bae1dSRodney W. Grimes 	u_int	gidsetsize;
797df8bae1dSRodney W. Grimes 	gid_t	*gidset;
798df8bae1dSRodney W. Grimes };
799d2d3e875SBruce Evans #endif
800df8bae1dSRodney W. Grimes /* ARGSUSED */
80126f9a767SRodney W. Grimes int
8028451d0ddSKip Macy sys_setgroups(struct thread *td, struct setgroups_args *uap)
803df8bae1dSRodney W. Grimes {
80492b064f4SMateusz Guzik 	gid_t smallgroups[XU_NGROUPS];
8057e9a456aSMateusz Guzik 	gid_t *groups;
80692b064f4SMateusz Guzik 	u_int gidsetsize;
807df8bae1dSRodney W. Grimes 	int error;
808df8bae1dSRodney W. Grimes 
80992b064f4SMateusz Guzik 	gidsetsize = uap->gidsetsize;
81092b064f4SMateusz Guzik 	if (gidsetsize > ngroups_max + 1)
8113cb83e71SJohn Baldwin 		return (EINVAL);
8127e9a456aSMateusz Guzik 
81392b064f4SMateusz Guzik 	if (gidsetsize > XU_NGROUPS)
81492b064f4SMateusz Guzik 		groups = malloc(gidsetsize * sizeof(gid_t), M_TEMP, M_WAITOK);
81592b064f4SMateusz Guzik 	else
81692b064f4SMateusz Guzik 		groups = smallgroups;
8177e9a456aSMateusz Guzik 
81892b064f4SMateusz Guzik 	error = copyin(uap->gidset, groups, gidsetsize * sizeof(gid_t));
8197e9a456aSMateusz Guzik 	if (error == 0)
82092b064f4SMateusz Guzik 		error = kern_setgroups(td, gidsetsize, groups);
8217e9a456aSMateusz Guzik 
82292b064f4SMateusz Guzik 	if (gidsetsize > XU_NGROUPS)
823838d9858SBrooks Davis 		free(groups, M_TEMP);
8243cb83e71SJohn Baldwin 	return (error);
8253cb83e71SJohn Baldwin }
8263cb83e71SJohn Baldwin 
8273cb83e71SJohn Baldwin int
8283cb83e71SJohn Baldwin kern_setgroups(struct thread *td, u_int ngrp, gid_t *groups)
8293cb83e71SJohn Baldwin {
8303cb83e71SJohn Baldwin 	struct proc *p = td->td_proc;
8313cb83e71SJohn Baldwin 	struct ucred *newcred, *oldcred;
8323cb83e71SJohn Baldwin 	int error;
8333cb83e71SJohn Baldwin 
834b9063886SMateusz Guzik 	MPASS(ngrp <= ngroups_max + 1);
83514961ba7SRobert Watson 	AUDIT_ARG_GROUPSET(groups, ngrp);
83607f3485dSJohn Baldwin 	newcred = crget();
837838d9858SBrooks Davis 	crextend(newcred, ngrp);
83807f3485dSJohn Baldwin 	PROC_LOCK(p);
839838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
840030a28b3SRobert Watson 
841030a28b3SRobert Watson #ifdef MAC
8426f6174a7SRobert Watson 	error = mac_cred_check_setgroups(oldcred, ngrp, groups);
843030a28b3SRobert Watson 	if (error)
844030a28b3SRobert Watson 		goto fail;
845030a28b3SRobert Watson #endif
846030a28b3SRobert Watson 
847cc426dd3SMateusz Guzik 	error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS);
848030a28b3SRobert Watson 	if (error)
849030a28b3SRobert Watson 		goto fail;
85007f3485dSJohn Baldwin 
8517e9a456aSMateusz Guzik 	if (ngrp == 0) {
8528a5d815aSPeter Wemm 		/*
8538a5d815aSPeter Wemm 		 * setgroups(0, NULL) is a legitimate way of clearing the
8548a5d815aSPeter Wemm 		 * groups vector on non-BSD systems (which generally do not
8558a5d815aSPeter Wemm 		 * have the egid in the groups[0]).  We risk security holes
8568a5d815aSPeter Wemm 		 * when running non-BSD software if we do not do the same.
8578a5d815aSPeter Wemm 		 */
858b1fc0ec1SRobert Watson 		newcred->cr_ngroups = 1;
8598a5d815aSPeter Wemm 	} else {
860838d9858SBrooks Davis 		crsetgroups_locked(newcred, ngrp, groups);
8618a5d815aSPeter Wemm 	}
862d5f81602SSean Eric Fagan 	setsugid(p);
863daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
86407f3485dSJohn Baldwin 	PROC_UNLOCK(p);
865b1fc0ec1SRobert Watson 	crfree(oldcred);
86607f3485dSJohn Baldwin 	return (0);
867030a28b3SRobert Watson 
868030a28b3SRobert Watson fail:
869030a28b3SRobert Watson 	PROC_UNLOCK(p);
870030a28b3SRobert Watson 	crfree(newcred);
871030a28b3SRobert Watson 	return (error);
872df8bae1dSRodney W. Grimes }
873df8bae1dSRodney W. Grimes 
874d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
875df8bae1dSRodney W. Grimes struct setreuid_args {
87600999cd6SAndrey A. Chernov 	uid_t	ruid;
87700999cd6SAndrey A. Chernov 	uid_t	euid;
878df8bae1dSRodney W. Grimes };
879d2d3e875SBruce Evans #endif
880df8bae1dSRodney W. Grimes /* ARGSUSED */
88126f9a767SRodney W. Grimes int
8823e85b721SEd Maste sys_setreuid(struct thread *td, struct setreuid_args *uap)
883df8bae1dSRodney W. Grimes {
884b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
885b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
886eb725b4eSRobert Watson 	uid_t euid, ruid;
8871419eacbSAlfred Perlstein 	struct uidinfo *euip, *ruip;
888eb725b4eSRobert Watson 	int error;
889df8bae1dSRodney W. Grimes 
89000999cd6SAndrey A. Chernov 	euid = uap->euid;
891eb725b4eSRobert Watson 	ruid = uap->ruid;
89214961ba7SRobert Watson 	AUDIT_ARG_EUID(euid);
89314961ba7SRobert Watson 	AUDIT_ARG_RUID(ruid);
89407f3485dSJohn Baldwin 	newcred = crget();
8951419eacbSAlfred Perlstein 	euip = uifind(euid);
8961419eacbSAlfred Perlstein 	ruip = uifind(ruid);
89707f3485dSJohn Baldwin 	PROC_LOCK(p);
898838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
899030a28b3SRobert Watson 
900030a28b3SRobert Watson #ifdef MAC
9016f6174a7SRobert Watson 	error = mac_cred_check_setreuid(oldcred, ruid, euid);
902030a28b3SRobert Watson 	if (error)
903030a28b3SRobert Watson 		goto fail;
904030a28b3SRobert Watson #endif
905030a28b3SRobert Watson 
906b1fc0ec1SRobert Watson 	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
907b1fc0ec1SRobert Watson 	      ruid != oldcred->cr_svuid) ||
908b1fc0ec1SRobert Watson 	     (euid != (uid_t)-1 && euid != oldcred->cr_uid &&
909b1fc0ec1SRobert Watson 	      euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) &&
910cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETREUID)) != 0)
911030a28b3SRobert Watson 		goto fail;
912030a28b3SRobert Watson 
913b1fc0ec1SRobert Watson 	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
9141419eacbSAlfred Perlstein 		change_euid(newcred, euip);
915d5f81602SSean Eric Fagan 		setsugid(p);
916a89a5370SPeter Wemm 	}
917b1fc0ec1SRobert Watson 	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
9181419eacbSAlfred Perlstein 		change_ruid(newcred, ruip);
919d5f81602SSean Eric Fagan 		setsugid(p);
92000999cd6SAndrey A. Chernov 	}
921b1fc0ec1SRobert Watson 	if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) &&
922b1fc0ec1SRobert Watson 	    newcred->cr_svuid != newcred->cr_uid) {
923b1fc0ec1SRobert Watson 		change_svuid(newcred, newcred->cr_uid);
924d5f81602SSean Eric Fagan 		setsugid(p);
925a89a5370SPeter Wemm 	}
926daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
927e4dcb704SEdward Tomasz Napierala #ifdef RACCT
928e4dcb704SEdward Tomasz Napierala 	racct_proc_ucred_changed(p, oldcred, newcred);
929f87beb93SAndriy Gapon 	crhold(newcred);
930f87beb93SAndriy Gapon #endif
931f87beb93SAndriy Gapon 	PROC_UNLOCK(p);
932f87beb93SAndriy Gapon #ifdef RCTL
933f87beb93SAndriy Gapon 	rctl_proc_ucred_changed(p, newcred);
934f87beb93SAndriy Gapon 	crfree(newcred);
935e4dcb704SEdward Tomasz Napierala #endif
9361419eacbSAlfred Perlstein 	uifree(ruip);
9371419eacbSAlfred Perlstein 	uifree(euip);
938b1fc0ec1SRobert Watson 	crfree(oldcred);
93907f3485dSJohn Baldwin 	return (0);
940030a28b3SRobert Watson 
941030a28b3SRobert Watson fail:
942030a28b3SRobert Watson 	PROC_UNLOCK(p);
943030a28b3SRobert Watson 	uifree(ruip);
944030a28b3SRobert Watson 	uifree(euip);
945030a28b3SRobert Watson 	crfree(newcred);
946030a28b3SRobert Watson 	return (error);
947df8bae1dSRodney W. Grimes }
948df8bae1dSRodney W. Grimes 
949d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
950df8bae1dSRodney W. Grimes struct setregid_args {
95100999cd6SAndrey A. Chernov 	gid_t	rgid;
95200999cd6SAndrey A. Chernov 	gid_t	egid;
953df8bae1dSRodney W. Grimes };
954d2d3e875SBruce Evans #endif
955df8bae1dSRodney W. Grimes /* ARGSUSED */
95626f9a767SRodney W. Grimes int
9573e85b721SEd Maste sys_setregid(struct thread *td, struct setregid_args *uap)
958df8bae1dSRodney W. Grimes {
959b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
960b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
961eb725b4eSRobert Watson 	gid_t egid, rgid;
962eb725b4eSRobert Watson 	int error;
963df8bae1dSRodney W. Grimes 
96400999cd6SAndrey A. Chernov 	egid = uap->egid;
965eb725b4eSRobert Watson 	rgid = uap->rgid;
96614961ba7SRobert Watson 	AUDIT_ARG_EGID(egid);
96714961ba7SRobert Watson 	AUDIT_ARG_RGID(rgid);
96807f3485dSJohn Baldwin 	newcred = crget();
96907f3485dSJohn Baldwin 	PROC_LOCK(p);
970838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
971030a28b3SRobert Watson 
972030a28b3SRobert Watson #ifdef MAC
9736f6174a7SRobert Watson 	error = mac_cred_check_setregid(oldcred, rgid, egid);
974030a28b3SRobert Watson 	if (error)
975030a28b3SRobert Watson 		goto fail;
976030a28b3SRobert Watson #endif
977030a28b3SRobert Watson 
978b1fc0ec1SRobert Watson 	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
979b1fc0ec1SRobert Watson 	    rgid != oldcred->cr_svgid) ||
980b1fc0ec1SRobert Watson 	     (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] &&
981b1fc0ec1SRobert Watson 	     egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) &&
982cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETREGID)) != 0)
983030a28b3SRobert Watson 		goto fail;
98407f3485dSJohn Baldwin 
985b1fc0ec1SRobert Watson 	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
986b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
987d5f81602SSean Eric Fagan 		setsugid(p);
988a89a5370SPeter Wemm 	}
989b1fc0ec1SRobert Watson 	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
990b1fc0ec1SRobert Watson 		change_rgid(newcred, rgid);
991d5f81602SSean Eric Fagan 		setsugid(p);
992a89a5370SPeter Wemm 	}
993b1fc0ec1SRobert Watson 	if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) &&
994b1fc0ec1SRobert Watson 	    newcred->cr_svgid != newcred->cr_groups[0]) {
995b1fc0ec1SRobert Watson 		change_svgid(newcred, newcred->cr_groups[0]);
996d5f81602SSean Eric Fagan 		setsugid(p);
997a89a5370SPeter Wemm 	}
998daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
99907f3485dSJohn Baldwin 	PROC_UNLOCK(p);
10004589be70SRuslan Ermilov 	crfree(oldcred);
100107f3485dSJohn Baldwin 	return (0);
1002030a28b3SRobert Watson 
1003030a28b3SRobert Watson fail:
1004030a28b3SRobert Watson 	PROC_UNLOCK(p);
1005030a28b3SRobert Watson 	crfree(newcred);
1006030a28b3SRobert Watson 	return (error);
1007df8bae1dSRodney W. Grimes }
1008df8bae1dSRodney W. Grimes 
10098ccd6334SPeter Wemm /*
1010873fbcd7SRobert Watson  * setresuid(ruid, euid, suid) is like setreuid except control over the saved
1011873fbcd7SRobert Watson  * uid is explicit.
10128ccd6334SPeter Wemm  */
10138ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
10148ccd6334SPeter Wemm struct setresuid_args {
10158ccd6334SPeter Wemm 	uid_t	ruid;
10168ccd6334SPeter Wemm 	uid_t	euid;
10178ccd6334SPeter Wemm 	uid_t	suid;
10188ccd6334SPeter Wemm };
10198ccd6334SPeter Wemm #endif
10208ccd6334SPeter Wemm /* ARGSUSED */
10218ccd6334SPeter Wemm int
10223e85b721SEd Maste sys_setresuid(struct thread *td, struct setresuid_args *uap)
10238ccd6334SPeter Wemm {
1024b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1025b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
1026eb725b4eSRobert Watson 	uid_t euid, ruid, suid;
10271419eacbSAlfred Perlstein 	struct uidinfo *euip, *ruip;
10288ccd6334SPeter Wemm 	int error;
10298ccd6334SPeter Wemm 
10308ccd6334SPeter Wemm 	euid = uap->euid;
1031eb725b4eSRobert Watson 	ruid = uap->ruid;
10328ccd6334SPeter Wemm 	suid = uap->suid;
103314961ba7SRobert Watson 	AUDIT_ARG_EUID(euid);
103414961ba7SRobert Watson 	AUDIT_ARG_RUID(ruid);
103514961ba7SRobert Watson 	AUDIT_ARG_SUID(suid);
103607f3485dSJohn Baldwin 	newcred = crget();
10371419eacbSAlfred Perlstein 	euip = uifind(euid);
10381419eacbSAlfred Perlstein 	ruip = uifind(ruid);
103907f3485dSJohn Baldwin 	PROC_LOCK(p);
1040838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
1041030a28b3SRobert Watson 
1042030a28b3SRobert Watson #ifdef MAC
10436f6174a7SRobert Watson 	error = mac_cred_check_setresuid(oldcred, ruid, euid, suid);
1044030a28b3SRobert Watson 	if (error)
1045030a28b3SRobert Watson 		goto fail;
1046030a28b3SRobert Watson #endif
1047030a28b3SRobert Watson 
1048b1fc0ec1SRobert Watson 	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
1049b1fc0ec1SRobert Watson 	     ruid != oldcred->cr_svuid &&
1050b1fc0ec1SRobert Watson 	      ruid != oldcred->cr_uid) ||
1051b1fc0ec1SRobert Watson 	     (euid != (uid_t)-1 && euid != oldcred->cr_ruid &&
1052b1fc0ec1SRobert Watson 	    euid != oldcred->cr_svuid &&
1053b1fc0ec1SRobert Watson 	      euid != oldcred->cr_uid) ||
1054b1fc0ec1SRobert Watson 	     (suid != (uid_t)-1 && suid != oldcred->cr_ruid &&
1055b1fc0ec1SRobert Watson 	    suid != oldcred->cr_svuid &&
1056b1fc0ec1SRobert Watson 	      suid != oldcred->cr_uid)) &&
1057cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETRESUID)) != 0)
1058030a28b3SRobert Watson 		goto fail;
105907f3485dSJohn Baldwin 
1060b1fc0ec1SRobert Watson 	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
10611419eacbSAlfred Perlstein 		change_euid(newcred, euip);
10628ccd6334SPeter Wemm 		setsugid(p);
10638ccd6334SPeter Wemm 	}
1064b1fc0ec1SRobert Watson 	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
10651419eacbSAlfred Perlstein 		change_ruid(newcred, ruip);
10668ccd6334SPeter Wemm 		setsugid(p);
10678ccd6334SPeter Wemm 	}
1068b1fc0ec1SRobert Watson 	if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) {
1069b1fc0ec1SRobert Watson 		change_svuid(newcred, suid);
10708ccd6334SPeter Wemm 		setsugid(p);
10718ccd6334SPeter Wemm 	}
1072daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
1073e4dcb704SEdward Tomasz Napierala #ifdef RACCT
1074e4dcb704SEdward Tomasz Napierala 	racct_proc_ucred_changed(p, oldcred, newcred);
1075f87beb93SAndriy Gapon 	crhold(newcred);
1076f87beb93SAndriy Gapon #endif
1077f87beb93SAndriy Gapon 	PROC_UNLOCK(p);
1078f87beb93SAndriy Gapon #ifdef RCTL
1079f87beb93SAndriy Gapon 	rctl_proc_ucred_changed(p, newcred);
1080f87beb93SAndriy Gapon 	crfree(newcred);
1081e4dcb704SEdward Tomasz Napierala #endif
10821419eacbSAlfred Perlstein 	uifree(ruip);
10831419eacbSAlfred Perlstein 	uifree(euip);
1084b1fc0ec1SRobert Watson 	crfree(oldcred);
108507f3485dSJohn Baldwin 	return (0);
1086030a28b3SRobert Watson 
1087030a28b3SRobert Watson fail:
1088030a28b3SRobert Watson 	PROC_UNLOCK(p);
1089030a28b3SRobert Watson 	uifree(ruip);
1090030a28b3SRobert Watson 	uifree(euip);
1091030a28b3SRobert Watson 	crfree(newcred);
1092030a28b3SRobert Watson 	return (error);
1093030a28b3SRobert Watson 
10948ccd6334SPeter Wemm }
10958ccd6334SPeter Wemm 
10968ccd6334SPeter Wemm /*
1097873fbcd7SRobert Watson  * setresgid(rgid, egid, sgid) is like setregid except control over the saved
1098873fbcd7SRobert Watson  * gid is explicit.
10998ccd6334SPeter Wemm  */
11008ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
11018ccd6334SPeter Wemm struct setresgid_args {
11028ccd6334SPeter Wemm 	gid_t	rgid;
11038ccd6334SPeter Wemm 	gid_t	egid;
11048ccd6334SPeter Wemm 	gid_t	sgid;
11058ccd6334SPeter Wemm };
11068ccd6334SPeter Wemm #endif
11078ccd6334SPeter Wemm /* ARGSUSED */
11088ccd6334SPeter Wemm int
11093e85b721SEd Maste sys_setresgid(struct thread *td, struct setresgid_args *uap)
11108ccd6334SPeter Wemm {
1111b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1112b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
1113eb725b4eSRobert Watson 	gid_t egid, rgid, sgid;
11148ccd6334SPeter Wemm 	int error;
11158ccd6334SPeter Wemm 
11168ccd6334SPeter Wemm 	egid = uap->egid;
1117eb725b4eSRobert Watson 	rgid = uap->rgid;
11188ccd6334SPeter Wemm 	sgid = uap->sgid;
111914961ba7SRobert Watson 	AUDIT_ARG_EGID(egid);
112014961ba7SRobert Watson 	AUDIT_ARG_RGID(rgid);
112114961ba7SRobert Watson 	AUDIT_ARG_SGID(sgid);
112207f3485dSJohn Baldwin 	newcred = crget();
112307f3485dSJohn Baldwin 	PROC_LOCK(p);
1124838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
1125030a28b3SRobert Watson 
1126030a28b3SRobert Watson #ifdef MAC
11276f6174a7SRobert Watson 	error = mac_cred_check_setresgid(oldcred, rgid, egid, sgid);
1128030a28b3SRobert Watson 	if (error)
1129030a28b3SRobert Watson 		goto fail;
1130030a28b3SRobert Watson #endif
1131030a28b3SRobert Watson 
1132b1fc0ec1SRobert Watson 	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
1133b1fc0ec1SRobert Watson 	      rgid != oldcred->cr_svgid &&
1134b1fc0ec1SRobert Watson 	      rgid != oldcred->cr_groups[0]) ||
1135b1fc0ec1SRobert Watson 	     (egid != (gid_t)-1 && egid != oldcred->cr_rgid &&
1136b1fc0ec1SRobert Watson 	      egid != oldcred->cr_svgid &&
1137b1fc0ec1SRobert Watson 	      egid != oldcred->cr_groups[0]) ||
1138b1fc0ec1SRobert Watson 	     (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid &&
1139b1fc0ec1SRobert Watson 	      sgid != oldcred->cr_svgid &&
1140b1fc0ec1SRobert Watson 	      sgid != oldcred->cr_groups[0])) &&
1141cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETRESGID)) != 0)
1142030a28b3SRobert Watson 		goto fail;
114307f3485dSJohn Baldwin 
1144b1fc0ec1SRobert Watson 	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
1145b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
11468ccd6334SPeter Wemm 		setsugid(p);
11478ccd6334SPeter Wemm 	}
1148b1fc0ec1SRobert Watson 	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
1149b1fc0ec1SRobert Watson 		change_rgid(newcred, rgid);
11508ccd6334SPeter Wemm 		setsugid(p);
11518ccd6334SPeter Wemm 	}
1152b1fc0ec1SRobert Watson 	if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) {
1153b1fc0ec1SRobert Watson 		change_svgid(newcred, sgid);
11548ccd6334SPeter Wemm 		setsugid(p);
11558ccd6334SPeter Wemm 	}
1156daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
115707f3485dSJohn Baldwin 	PROC_UNLOCK(p);
1158b1fc0ec1SRobert Watson 	crfree(oldcred);
115907f3485dSJohn Baldwin 	return (0);
1160030a28b3SRobert Watson 
1161030a28b3SRobert Watson fail:
1162030a28b3SRobert Watson 	PROC_UNLOCK(p);
1163030a28b3SRobert Watson 	crfree(newcred);
1164030a28b3SRobert Watson 	return (error);
11658ccd6334SPeter Wemm }
11668ccd6334SPeter Wemm 
11678ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
11688ccd6334SPeter Wemm struct getresuid_args {
11698ccd6334SPeter Wemm 	uid_t	*ruid;
11708ccd6334SPeter Wemm 	uid_t	*euid;
11718ccd6334SPeter Wemm 	uid_t	*suid;
11728ccd6334SPeter Wemm };
11738ccd6334SPeter Wemm #endif
11748ccd6334SPeter Wemm /* ARGSUSED */
11758ccd6334SPeter Wemm int
11763e85b721SEd Maste sys_getresuid(struct thread *td, struct getresuid_args *uap)
11778ccd6334SPeter Wemm {
1178835a82eeSMatthew Dillon 	struct ucred *cred;
11798ccd6334SPeter Wemm 	int error1 = 0, error2 = 0, error3 = 0;
11808ccd6334SPeter Wemm 
1181d74ac681SMatthew Dillon 	cred = td->td_ucred;
11828ccd6334SPeter Wemm 	if (uap->ruid)
11837f05b035SAlfred Perlstein 		error1 = copyout(&cred->cr_ruid,
11847f05b035SAlfred Perlstein 		    uap->ruid, sizeof(cred->cr_ruid));
11858ccd6334SPeter Wemm 	if (uap->euid)
11867f05b035SAlfred Perlstein 		error2 = copyout(&cred->cr_uid,
11877f05b035SAlfred Perlstein 		    uap->euid, sizeof(cred->cr_uid));
11888ccd6334SPeter Wemm 	if (uap->suid)
11897f05b035SAlfred Perlstein 		error3 = copyout(&cred->cr_svuid,
11907f05b035SAlfred Perlstein 		    uap->suid, sizeof(cred->cr_svuid));
1191eb725b4eSRobert Watson 	return (error1 ? error1 : error2 ? error2 : error3);
11928ccd6334SPeter Wemm }
11938ccd6334SPeter Wemm 
11948ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
11958ccd6334SPeter Wemm struct getresgid_args {
11968ccd6334SPeter Wemm 	gid_t	*rgid;
11978ccd6334SPeter Wemm 	gid_t	*egid;
11988ccd6334SPeter Wemm 	gid_t	*sgid;
11998ccd6334SPeter Wemm };
12008ccd6334SPeter Wemm #endif
12018ccd6334SPeter Wemm /* ARGSUSED */
12028ccd6334SPeter Wemm int
12033e85b721SEd Maste sys_getresgid(struct thread *td, struct getresgid_args *uap)
12048ccd6334SPeter Wemm {
1205835a82eeSMatthew Dillon 	struct ucred *cred;
12068ccd6334SPeter Wemm 	int error1 = 0, error2 = 0, error3 = 0;
12078ccd6334SPeter Wemm 
1208d74ac681SMatthew Dillon 	cred = td->td_ucred;
12098ccd6334SPeter Wemm 	if (uap->rgid)
12107f05b035SAlfred Perlstein 		error1 = copyout(&cred->cr_rgid,
12117f05b035SAlfred Perlstein 		    uap->rgid, sizeof(cred->cr_rgid));
12128ccd6334SPeter Wemm 	if (uap->egid)
12137f05b035SAlfred Perlstein 		error2 = copyout(&cred->cr_groups[0],
12147f05b035SAlfred Perlstein 		    uap->egid, sizeof(cred->cr_groups[0]));
12158ccd6334SPeter Wemm 	if (uap->sgid)
12167f05b035SAlfred Perlstein 		error3 = copyout(&cred->cr_svgid,
12177f05b035SAlfred Perlstein 		    uap->sgid, sizeof(cred->cr_svgid));
1218eb725b4eSRobert Watson 	return (error1 ? error1 : error2 ? error2 : error3);
12198ccd6334SPeter Wemm }
12208ccd6334SPeter Wemm 
1221b67cbc65SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1222b67cbc65SPeter Wemm struct issetugid_args {
1223b67cbc65SPeter Wemm 	int dummy;
1224b67cbc65SPeter Wemm };
1225b67cbc65SPeter Wemm #endif
1226b67cbc65SPeter Wemm /* ARGSUSED */
1227b67cbc65SPeter Wemm int
12283e85b721SEd Maste sys_issetugid(struct thread *td, struct issetugid_args *uap)
1229b67cbc65SPeter Wemm {
1230b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1231b40ce416SJulian Elischer 
1232b67cbc65SPeter Wemm 	/*
1233b67cbc65SPeter Wemm 	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
1234b67cbc65SPeter Wemm 	 * we use P_SUGID because we consider changing the owners as
1235b67cbc65SPeter Wemm 	 * "tainting" as well.
1236b67cbc65SPeter Wemm 	 * This is significant for procs that start as root and "become"
1237b67cbc65SPeter Wemm 	 * a user without an exec - programs cannot know *everything*
1238b67cbc65SPeter Wemm 	 * that libc *might* have put in their data segment.
1239b67cbc65SPeter Wemm 	 */
1240b40ce416SJulian Elischer 	td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
1241b67cbc65SPeter Wemm 	return (0);
1242b67cbc65SPeter Wemm }
1243b67cbc65SPeter Wemm 
1244130d0157SRobert Watson int
12458451d0ddSKip Macy sys___setugid(struct thread *td, struct __setugid_args *uap)
1246130d0157SRobert Watson {
1247130d0157SRobert Watson #ifdef REGRESSION
124807f3485dSJohn Baldwin 	struct proc *p;
1249835a82eeSMatthew Dillon 
125007f3485dSJohn Baldwin 	p = td->td_proc;
1251130d0157SRobert Watson 	switch (uap->flag) {
1252130d0157SRobert Watson 	case 0:
125307f3485dSJohn Baldwin 		PROC_LOCK(p);
125407f3485dSJohn Baldwin 		p->p_flag &= ~P_SUGID;
125507f3485dSJohn Baldwin 		PROC_UNLOCK(p);
125607f3485dSJohn Baldwin 		return (0);
125707f3485dSJohn Baldwin 	case 1:
125807f3485dSJohn Baldwin 		PROC_LOCK(p);
125907f3485dSJohn Baldwin 		p->p_flag |= P_SUGID;
126007f3485dSJohn Baldwin 		PROC_UNLOCK(p);
126107f3485dSJohn Baldwin 		return (0);
126207f3485dSJohn Baldwin 	default:
126307f3485dSJohn Baldwin 		return (EINVAL);
126407f3485dSJohn Baldwin 	}
1265130d0157SRobert Watson #else /* !REGRESSION */
1266eb725b4eSRobert Watson 
1267130d0157SRobert Watson 	return (ENOSYS);
1268eb725b4eSRobert Watson #endif /* REGRESSION */
1269130d0157SRobert Watson }
1270130d0157SRobert Watson 
1271df8bae1dSRodney W. Grimes /*
1272df8bae1dSRodney W. Grimes  * Check if gid is a member of the group set.
1273df8bae1dSRodney W. Grimes  */
127426f9a767SRodney W. Grimes int
12754c44ad8eSJohn Baldwin groupmember(gid_t gid, struct ucred *cred)
1276df8bae1dSRodney W. Grimes {
12777f92e578SBrooks Davis 	int l;
12787f92e578SBrooks Davis 	int h;
12797f92e578SBrooks Davis 	int m;
1280df8bae1dSRodney W. Grimes 
12817f92e578SBrooks Davis 	if (cred->cr_groups[0] == gid)
1282df8bae1dSRodney W. Grimes 		return(1);
12837f92e578SBrooks Davis 
12847f92e578SBrooks Davis 	/*
12857f92e578SBrooks Davis 	 * If gid was not our primary group, perform a binary search
12867f92e578SBrooks Davis 	 * of the supplemental groups.  This is possible because we
12877f92e578SBrooks Davis 	 * sort the groups in crsetgroups().
12887f92e578SBrooks Davis 	 */
12897f92e578SBrooks Davis 	l = 1;
12907f92e578SBrooks Davis 	h = cred->cr_ngroups;
12917f92e578SBrooks Davis 	while (l < h) {
12927f92e578SBrooks Davis 		m = l + ((h - l) / 2);
12937f92e578SBrooks Davis 		if (cred->cr_groups[m] < gid)
12947f92e578SBrooks Davis 			l = m + 1;
12957f92e578SBrooks Davis 		else
12967f92e578SBrooks Davis 			h = m;
12977f92e578SBrooks Davis 	}
12987f92e578SBrooks Davis 	if ((l < cred->cr_ngroups) && (cred->cr_groups[l] == gid))
12997f92e578SBrooks Davis 		return (1);
13007f92e578SBrooks Davis 
1301df8bae1dSRodney W. Grimes 	return (0);
1302df8bae1dSRodney W. Grimes }
1303df8bae1dSRodney W. Grimes 
13043b243b72SRobert Watson /*
1305eb725b4eSRobert Watson  * Test the active securelevel against a given level.  securelevel_gt()
1306eb725b4eSRobert Watson  * implements (securelevel > level).  securelevel_ge() implements
1307eb725b4eSRobert Watson  * (securelevel >= level).  Note that the logic is inverted -- these
1308eb725b4eSRobert Watson  * functions return EPERM on "success" and 0 on "failure".
13093ca719f1SRobert Watson  *
13100304c731SJamie Gritton  * Due to care taken when setting the securelevel, we know that no jail will
13110304c731SJamie Gritton  * be less secure that its parent (or the physical system), so it is sufficient
13120304c731SJamie Gritton  * to test the current jail only.
13130304c731SJamie Gritton  *
1314800c9408SRobert Watson  * XXXRW: Possibly since this has to do with privilege, it should move to
1315800c9408SRobert Watson  * kern_priv.c.
13163ca719f1SRobert Watson  */
13173ca719f1SRobert Watson int
13183ca719f1SRobert Watson securelevel_gt(struct ucred *cr, int level)
13193ca719f1SRobert Watson {
13203ca719f1SRobert Watson 
13210304c731SJamie Gritton 	return (cr->cr_prison->pr_securelevel > level ? EPERM : 0);
13223ca719f1SRobert Watson }
13233ca719f1SRobert Watson 
13243ca719f1SRobert Watson int
13253ca719f1SRobert Watson securelevel_ge(struct ucred *cr, int level)
13263ca719f1SRobert Watson {
13273ca719f1SRobert Watson 
13280304c731SJamie Gritton 	return (cr->cr_prison->pr_securelevel >= level ? EPERM : 0);
13293ca719f1SRobert Watson }
13303ca719f1SRobert Watson 
13318a7d8cc6SRobert Watson /*
1332e409590dSRobert Watson  * 'see_other_uids' determines whether or not visibility of processes
1333eb725b4eSRobert Watson  * and sockets with credentials holding different real uids is possible
133448713bdcSRobert Watson  * using a variety of system MIBs.
1335eb725b4eSRobert Watson  * XXX: data declarations should be together near the beginning of the file.
13368a7d8cc6SRobert Watson  */
1337e409590dSRobert Watson static int	see_other_uids = 1;
1338d0615c64SAndrew R. Reiter SYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW,
1339eb725b4eSRobert Watson     &see_other_uids, 0,
13408a7d8cc6SRobert Watson     "Unprivileged processes may see subjects/objects with different real uid");
13418a7d8cc6SRobert Watson 
13421a996ed1SEdward Tomasz Napierala /*-
13431b350b45SRobert Watson  * Determine if u1 "can see" the subject specified by u2, according to the
13441b350b45SRobert Watson  * 'see_other_uids' policy.
13451b350b45SRobert Watson  * Returns: 0 for permitted, ESRCH otherwise
13461b350b45SRobert Watson  * Locks: none
13471b350b45SRobert Watson  * References: *u1 and *u2 must not change during the call
13481b350b45SRobert Watson  *             u1 may equal u2, in which case only one reference is required
13491b350b45SRobert Watson  */
13504ac21b4fSStephen J. Kiernan int
13514ac21b4fSStephen J. Kiernan cr_canseeotheruids(struct ucred *u1, struct ucred *u2)
13521b350b45SRobert Watson {
13531b350b45SRobert Watson 
13541b350b45SRobert Watson 	if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) {
1355cc426dd3SMateusz Guzik 		if (priv_check_cred(u1, PRIV_SEEOTHERUIDS) != 0)
13561b350b45SRobert Watson 			return (ESRCH);
13571b350b45SRobert Watson 	}
13581b350b45SRobert Watson 	return (0);
13591b350b45SRobert Watson }
13601b350b45SRobert Watson 
136164d19c2eSRobert Watson /*
136264d19c2eSRobert Watson  * 'see_other_gids' determines whether or not visibility of processes
136364d19c2eSRobert Watson  * and sockets with credentials holding different real gids is possible
136464d19c2eSRobert Watson  * using a variety of system MIBs.
136564d19c2eSRobert Watson  * XXX: data declarations should be together near the beginning of the file.
136664d19c2eSRobert Watson  */
136764d19c2eSRobert Watson static int	see_other_gids = 1;
136864d19c2eSRobert Watson SYSCTL_INT(_security_bsd, OID_AUTO, see_other_gids, CTLFLAG_RW,
136964d19c2eSRobert Watson     &see_other_gids, 0,
137064d19c2eSRobert Watson     "Unprivileged processes may see subjects/objects with different real gid");
137164d19c2eSRobert Watson 
137264d19c2eSRobert Watson /*
137364d19c2eSRobert Watson  * Determine if u1 can "see" the subject specified by u2, according to the
137464d19c2eSRobert Watson  * 'see_other_gids' policy.
137564d19c2eSRobert Watson  * Returns: 0 for permitted, ESRCH otherwise
137664d19c2eSRobert Watson  * Locks: none
137764d19c2eSRobert Watson  * References: *u1 and *u2 must not change during the call
137864d19c2eSRobert Watson  *             u1 may equal u2, in which case only one reference is required
137964d19c2eSRobert Watson  */
13804ac21b4fSStephen J. Kiernan int
13814ac21b4fSStephen J. Kiernan cr_canseeothergids(struct ucred *u1, struct ucred *u2)
138264d19c2eSRobert Watson {
138364d19c2eSRobert Watson 	int i, match;
138464d19c2eSRobert Watson 
138564d19c2eSRobert Watson 	if (!see_other_gids) {
138664d19c2eSRobert Watson 		match = 0;
138764d19c2eSRobert Watson 		for (i = 0; i < u1->cr_ngroups; i++) {
138864d19c2eSRobert Watson 			if (groupmember(u1->cr_groups[i], u2))
138964d19c2eSRobert Watson 				match = 1;
139064d19c2eSRobert Watson 			if (match)
139164d19c2eSRobert Watson 				break;
139264d19c2eSRobert Watson 		}
139364d19c2eSRobert Watson 		if (!match) {
1394cc426dd3SMateusz Guzik 			if (priv_check_cred(u1, PRIV_SEEOTHERGIDS) != 0)
139564d19c2eSRobert Watson 				return (ESRCH);
139664d19c2eSRobert Watson 		}
139764d19c2eSRobert Watson 	}
139864d19c2eSRobert Watson 	return (0);
139964d19c2eSRobert Watson }
140064d19c2eSRobert Watson 
1401a4aaba3bSSteve Wills /*
1402a4aaba3bSSteve Wills  * 'see_jail_proc' determines whether or not visibility of processes and
1403a4aaba3bSSteve Wills  * sockets with credentials holding different jail ids is possible using a
1404a4aaba3bSSteve Wills  * variety of system MIBs.
1405a4aaba3bSSteve Wills  *
1406a4aaba3bSSteve Wills  * XXX: data declarations should be together near the beginning of the file.
1407a4aaba3bSSteve Wills  */
1408a4aaba3bSSteve Wills 
1409a4aaba3bSSteve Wills static int	see_jail_proc = 1;
1410a4aaba3bSSteve Wills SYSCTL_INT(_security_bsd, OID_AUTO, see_jail_proc, CTLFLAG_RW,
1411a4aaba3bSSteve Wills     &see_jail_proc, 0,
1412a4aaba3bSSteve Wills     "Unprivileged processes may see subjects/objects with different jail ids");
1413a4aaba3bSSteve Wills 
1414a4aaba3bSSteve Wills /*-
1415a4aaba3bSSteve Wills  * Determine if u1 "can see" the subject specified by u2, according to the
1416a4aaba3bSSteve Wills  * 'see_jail_proc' policy.
1417a4aaba3bSSteve Wills  * Returns: 0 for permitted, ESRCH otherwise
1418a4aaba3bSSteve Wills  * Locks: none
1419a4aaba3bSSteve Wills  * References: *u1 and *u2 must not change during the call
1420a4aaba3bSSteve Wills  *             u1 may equal u2, in which case only one reference is required
1421a4aaba3bSSteve Wills  */
1422a4aaba3bSSteve Wills int
1423a4aaba3bSSteve Wills cr_canseejailproc(struct ucred *u1, struct ucred *u2)
1424a4aaba3bSSteve Wills {
1425a4aaba3bSSteve Wills 	if (u1->cr_uid == 0)
1426a4aaba3bSSteve Wills 		return (0);
1427a4aaba3bSSteve Wills 	return (!see_jail_proc && u1->cr_prison != u2->cr_prison ? ESRCH : 0);
1428a4aaba3bSSteve Wills }
1429a4aaba3bSSteve Wills 
14301a996ed1SEdward Tomasz Napierala /*-
14317fd6a959SRobert Watson  * Determine if u1 "can see" the subject specified by u2.
1432ed639720SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1433ed639720SRobert Watson  * Locks: none
1434eb725b4eSRobert Watson  * References: *u1 and *u2 must not change during the call
1435ed639720SRobert Watson  *             u1 may equal u2, in which case only one reference is required
1436ed639720SRobert Watson  */
1437ed639720SRobert Watson int
143894088977SRobert Watson cr_cansee(struct ucred *u1, struct ucred *u2)
1439a9e0361bSPoul-Henning Kamp {
144091421ba2SRobert Watson 	int error;
1441a9e0361bSPoul-Henning Kamp 
1442ed639720SRobert Watson 	if ((error = prison_check(u1, u2)))
144391421ba2SRobert Watson 		return (error);
14448a1d977dSRobert Watson #ifdef MAC
144530d239bcSRobert Watson 	if ((error = mac_cred_check_visible(u1, u2)))
14468a1d977dSRobert Watson 		return (error);
14478a1d977dSRobert Watson #endif
14484ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeotheruids(u1, u2)))
14491b350b45SRobert Watson 		return (error);
14504ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeothergids(u1, u2)))
145164d19c2eSRobert Watson 		return (error);
1452a4aaba3bSSteve Wills 	if ((error = cr_canseejailproc(u1, u2)))
1453a4aaba3bSSteve Wills 		return (error);
1454387d2c03SRobert Watson 	return (0);
1455387d2c03SRobert Watson }
1456387d2c03SRobert Watson 
14571a996ed1SEdward Tomasz Napierala /*-
1458f44d9e24SJohn Baldwin  * Determine if td "can see" the subject specified by p.
14593b243b72SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1460f44d9e24SJohn Baldwin  * Locks: Sufficient locks to protect p->p_ucred must be held.  td really
1461f44d9e24SJohn Baldwin  *        should be curthread.
1462f44d9e24SJohn Baldwin  * References: td and p must be valid for the lifetime of the call
14633b243b72SRobert Watson  */
1464a0f75161SRobert Watson int
1465f44d9e24SJohn Baldwin p_cansee(struct thread *td, struct proc *p)
1466ed639720SRobert Watson {
1467ed639720SRobert Watson 
146894088977SRobert Watson 	/* Wrap cr_cansee() for all functionality. */
1469f44d9e24SJohn Baldwin 	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1470f44d9e24SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
1471f44d9e24SJohn Baldwin 	return (cr_cansee(td->td_ucred, p->p_ucred));
1472ed639720SRobert Watson }
1473ed639720SRobert Watson 
147462c45ef4SRobert Watson /*
147562c45ef4SRobert Watson  * 'conservative_signals' prevents the delivery of a broad class of
147662c45ef4SRobert Watson  * signals by unprivileged processes to processes that have changed their
147762c45ef4SRobert Watson  * credentials since the last invocation of execve().  This can prevent
147862c45ef4SRobert Watson  * the leakage of cached information or retained privileges as a result
147962c45ef4SRobert Watson  * of a common class of signal-related vulnerabilities.  However, this
148062c45ef4SRobert Watson  * may interfere with some applications that expect to be able to
148162c45ef4SRobert Watson  * deliver these signals to peer processes after having given up
148262c45ef4SRobert Watson  * privilege.
148362c45ef4SRobert Watson  */
148462c45ef4SRobert Watson static int	conservative_signals = 1;
148562c45ef4SRobert Watson SYSCTL_INT(_security_bsd, OID_AUTO, conservative_signals, CTLFLAG_RW,
148662c45ef4SRobert Watson     &conservative_signals, 0, "Unprivileged processes prevented from "
148762c45ef4SRobert Watson     "sending certain signals to processes whose credentials have changed");
14881a996ed1SEdward Tomasz Napierala /*-
1489c83f8015SRobert Watson  * Determine whether cred may deliver the specified signal to proc.
1490c83f8015SRobert Watson  * Returns: 0 for permitted, an errno value otherwise.
1491c83f8015SRobert Watson  * Locks: A lock must be held for proc.
1492c83f8015SRobert Watson  * References: cred and proc must be valid for the lifetime of the call.
14934c5eb9c3SRobert Watson  */
14944c5eb9c3SRobert Watson int
14951a88a252SMaxim Sobolev cr_cansignal(struct ucred *cred, struct proc *proc, int signum)
1496387d2c03SRobert Watson {
149791421ba2SRobert Watson 	int error;
1498387d2c03SRobert Watson 
1499f44d9e24SJohn Baldwin 	PROC_LOCK_ASSERT(proc, MA_OWNED);
15004c5eb9c3SRobert Watson 	/*
1501c83f8015SRobert Watson 	 * Jail semantics limit the scope of signalling to proc in the
1502c83f8015SRobert Watson 	 * same jail as cred, if cred is in jail.
15034c5eb9c3SRobert Watson 	 */
1504c83f8015SRobert Watson 	error = prison_check(cred, proc->p_ucred);
1505c83f8015SRobert Watson 	if (error)
150691421ba2SRobert Watson 		return (error);
15078a1d977dSRobert Watson #ifdef MAC
150830d239bcSRobert Watson 	if ((error = mac_proc_check_signal(cred, proc, signum)))
15098a1d977dSRobert Watson 		return (error);
15108a1d977dSRobert Watson #endif
15114ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeotheruids(cred, proc->p_ucred)))
151264d19c2eSRobert Watson 		return (error);
15134ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeothergids(cred, proc->p_ucred)))
15141b350b45SRobert Watson 		return (error);
1515387d2c03SRobert Watson 
1516387d2c03SRobert Watson 	/*
15173b243b72SRobert Watson 	 * UNIX signal semantics depend on the status of the P_SUGID
15183b243b72SRobert Watson 	 * bit on the target process.  If the bit is set, then additional
15193b243b72SRobert Watson 	 * restrictions are placed on the set of available signals.
15204c5eb9c3SRobert Watson 	 */
15211a88a252SMaxim Sobolev 	if (conservative_signals && (proc->p_flag & P_SUGID)) {
15224c5eb9c3SRobert Watson 		switch (signum) {
15234c5eb9c3SRobert Watson 		case 0:
15244c5eb9c3SRobert Watson 		case SIGKILL:
15254c5eb9c3SRobert Watson 		case SIGINT:
15264c5eb9c3SRobert Watson 		case SIGTERM:
152762c45ef4SRobert Watson 		case SIGALRM:
15284c5eb9c3SRobert Watson 		case SIGSTOP:
15294c5eb9c3SRobert Watson 		case SIGTTIN:
15304c5eb9c3SRobert Watson 		case SIGTTOU:
15314c5eb9c3SRobert Watson 		case SIGTSTP:
15324c5eb9c3SRobert Watson 		case SIGHUP:
15334c5eb9c3SRobert Watson 		case SIGUSR1:
15344c5eb9c3SRobert Watson 		case SIGUSR2:
15357fd6a959SRobert Watson 			/*
15367fd6a959SRobert Watson 			 * Generally, permit job and terminal control
15377fd6a959SRobert Watson 			 * signals.
15387fd6a959SRobert Watson 			 */
15394c5eb9c3SRobert Watson 			break;
15404c5eb9c3SRobert Watson 		default:
1541c83f8015SRobert Watson 			/* Not permitted without privilege. */
1542cc426dd3SMateusz Guzik 			error = priv_check_cred(cred, PRIV_SIGNAL_SUGID);
15434c5eb9c3SRobert Watson 			if (error)
15444c5eb9c3SRobert Watson 				return (error);
15454c5eb9c3SRobert Watson 		}
1546e9e7ff5bSRobert Watson 	}
1547e9e7ff5bSRobert Watson 
15484c5eb9c3SRobert Watson 	/*
15493b243b72SRobert Watson 	 * Generally, the target credential's ruid or svuid must match the
1550e9e7ff5bSRobert Watson 	 * subject credential's ruid or euid.
15514c5eb9c3SRobert Watson 	 */
1552c83f8015SRobert Watson 	if (cred->cr_ruid != proc->p_ucred->cr_ruid &&
1553c83f8015SRobert Watson 	    cred->cr_ruid != proc->p_ucred->cr_svuid &&
1554c83f8015SRobert Watson 	    cred->cr_uid != proc->p_ucred->cr_ruid &&
1555c83f8015SRobert Watson 	    cred->cr_uid != proc->p_ucred->cr_svuid) {
1556cc426dd3SMateusz Guzik 		error = priv_check_cred(cred, PRIV_SIGNAL_DIFFCRED);
15574c5eb9c3SRobert Watson 		if (error)
15584c5eb9c3SRobert Watson 			return (error);
15594c5eb9c3SRobert Watson 	}
1560387d2c03SRobert Watson 
1561387d2c03SRobert Watson 	return (0);
1562387d2c03SRobert Watson }
1563a9e0361bSPoul-Henning Kamp 
15641a996ed1SEdward Tomasz Napierala /*-
1565f44d9e24SJohn Baldwin  * Determine whether td may deliver the specified signal to p.
1566c83f8015SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1567f44d9e24SJohn Baldwin  * Locks: Sufficient locks to protect various components of td and p
1568f44d9e24SJohn Baldwin  *        must be held.  td must be curthread, and a lock must be
1569f44d9e24SJohn Baldwin  *        held for p.
1570f44d9e24SJohn Baldwin  * References: td and p must be valid for the lifetime of the call
1571c83f8015SRobert Watson  */
1572c83f8015SRobert Watson int
15731a88a252SMaxim Sobolev p_cansignal(struct thread *td, struct proc *p, int signum)
1574c83f8015SRobert Watson {
1575c83f8015SRobert Watson 
1576f44d9e24SJohn Baldwin 	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1577f44d9e24SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
1578f44d9e24SJohn Baldwin 	if (td->td_proc == p)
1579c83f8015SRobert Watson 		return (0);
1580c83f8015SRobert Watson 
1581c83f8015SRobert Watson 	/*
1582c83f8015SRobert Watson 	 * UNIX signalling semantics require that processes in the same
1583c83f8015SRobert Watson 	 * session always be able to deliver SIGCONT to one another,
1584c83f8015SRobert Watson 	 * overriding the remaining protections.
1585c83f8015SRobert Watson 	 */
1586f44d9e24SJohn Baldwin 	/* XXX: This will require an additional lock of some sort. */
1587f44d9e24SJohn Baldwin 	if (signum == SIGCONT && td->td_proc->p_session == p->p_session)
1588c83f8015SRobert Watson 		return (0);
15894b178336SMaxim Sobolev 	/*
1590f9cd63d4SMaxim Sobolev 	 * Some compat layers use SIGTHR and higher signals for
1591f9cd63d4SMaxim Sobolev 	 * communication between different kernel threads of the same
1592f9cd63d4SMaxim Sobolev 	 * process, so that they expect that it's always possible to
1593f9cd63d4SMaxim Sobolev 	 * deliver them, even for suid applications where cr_cansignal() can
15944b178336SMaxim Sobolev 	 * deny such ability for security consideration.  It should be
15954b178336SMaxim Sobolev 	 * pretty safe to do since the only way to create two processes
15964b178336SMaxim Sobolev 	 * with the same p_leader is via rfork(2).
15974b178336SMaxim Sobolev 	 */
15982322a0a7SMaxim Sobolev 	if (td->td_proc->p_leader != NULL && signum >= SIGTHR &&
15992322a0a7SMaxim Sobolev 	    signum < SIGTHR + 4 && td->td_proc->p_leader == p->p_leader)
16004b178336SMaxim Sobolev 		return (0);
1601c83f8015SRobert Watson 
16021a88a252SMaxim Sobolev 	return (cr_cansignal(td->td_ucred, p, signum));
1603c83f8015SRobert Watson }
1604c83f8015SRobert Watson 
16051a996ed1SEdward Tomasz Napierala /*-
1606f44d9e24SJohn Baldwin  * Determine whether td may reschedule p.
16077fd6a959SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1608f44d9e24SJohn Baldwin  * Locks: Sufficient locks to protect various components of td and p
1609f44d9e24SJohn Baldwin  *        must be held.  td must be curthread, and a lock must
1610f44d9e24SJohn Baldwin  *        be held for p.
1611f44d9e24SJohn Baldwin  * References: td and p must be valid for the lifetime of the call
16123b243b72SRobert Watson  */
1613a0f75161SRobert Watson int
1614f44d9e24SJohn Baldwin p_cansched(struct thread *td, struct proc *p)
1615387d2c03SRobert Watson {
161691421ba2SRobert Watson 	int error;
1617387d2c03SRobert Watson 
1618f44d9e24SJohn Baldwin 	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1619f44d9e24SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
1620f44d9e24SJohn Baldwin 	if (td->td_proc == p)
1621387d2c03SRobert Watson 		return (0);
1622f44d9e24SJohn Baldwin 	if ((error = prison_check(td->td_ucred, p->p_ucred)))
162391421ba2SRobert Watson 		return (error);
16248a1d977dSRobert Watson #ifdef MAC
162530d239bcSRobert Watson 	if ((error = mac_proc_check_sched(td->td_ucred, p)))
16268a1d977dSRobert Watson 		return (error);
16278a1d977dSRobert Watson #endif
16284ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeotheruids(td->td_ucred, p->p_ucred)))
16291b350b45SRobert Watson 		return (error);
16304ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeothergids(td->td_ucred, p->p_ucred)))
163164d19c2eSRobert Watson 		return (error);
1632800c9408SRobert Watson 	if (td->td_ucred->cr_ruid != p->p_ucred->cr_ruid &&
1633800c9408SRobert Watson 	    td->td_ucred->cr_uid != p->p_ucred->cr_ruid) {
163432f9753cSRobert Watson 		error = priv_check(td, PRIV_SCHED_DIFFCRED);
1635800c9408SRobert Watson 		if (error)
1636800c9408SRobert Watson 			return (error);
1637800c9408SRobert Watson 	}
1638387d2c03SRobert Watson 	return (0);
1639387d2c03SRobert Watson }
1640387d2c03SRobert Watson 
16413b243b72SRobert Watson /*
1642b3079544SJamie Gritton  * Handle getting or setting the prison's unprivileged_proc_debug
1643b3079544SJamie Gritton  * value.
1644b3079544SJamie Gritton  */
1645b3079544SJamie Gritton static int
1646b3079544SJamie Gritton sysctl_unprivileged_proc_debug(SYSCTL_HANDLER_ARGS)
1647b3079544SJamie Gritton {
1648b3079544SJamie Gritton 	struct prison *pr;
1649b3079544SJamie Gritton 	int error, val;
1650b3079544SJamie Gritton 
1651b3079544SJamie Gritton 	val = prison_allow(req->td->td_ucred, PR_ALLOW_UNPRIV_DEBUG) != 0;
1652b3079544SJamie Gritton 	error = sysctl_handle_int(oidp, &val, 0, req);
1653b3079544SJamie Gritton 	if (error != 0 || req->newptr == NULL)
1654b3079544SJamie Gritton 		return (error);
1655b3079544SJamie Gritton 	pr = req->td->td_ucred->cr_prison;
1656b3079544SJamie Gritton 	mtx_lock(&pr->pr_mtx);
1657b3079544SJamie Gritton 	switch (val) {
1658b3079544SJamie Gritton 	case 0:
1659b3079544SJamie Gritton 		pr->pr_allow &= ~(PR_ALLOW_UNPRIV_DEBUG);
1660b3079544SJamie Gritton 		break;
1661b3079544SJamie Gritton 	case 1:
1662b3079544SJamie Gritton 		pr->pr_allow |= PR_ALLOW_UNPRIV_DEBUG;
1663b3079544SJamie Gritton 		break;
1664b3079544SJamie Gritton 	default:
1665b3079544SJamie Gritton 		error = EINVAL;
1666b3079544SJamie Gritton 	}
1667b3079544SJamie Gritton 	mtx_unlock(&pr->pr_mtx);
1668b3079544SJamie Gritton 
1669b3079544SJamie Gritton 	return (error);
1670b3079544SJamie Gritton }
1671b3079544SJamie Gritton 
1672b3079544SJamie Gritton /*
16735d476e73SRobert Watson  * The 'unprivileged_proc_debug' flag may be used to disable a variety of
16745d476e73SRobert Watson  * unprivileged inter-process debugging services, including some procfs
16755d476e73SRobert Watson  * functionality, ptrace(), and ktrace().  In the past, inter-process
16765d476e73SRobert Watson  * debugging has been involved in a variety of security problems, and sites
16775d476e73SRobert Watson  * not requiring the service might choose to disable it when hardening
16785d476e73SRobert Watson  * systems.
16793b243b72SRobert Watson  */
1680b3079544SJamie Gritton SYSCTL_PROC(_security_bsd, OID_AUTO, unprivileged_proc_debug,
16817029da5cSPawel Biernacki     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_SECURE |
16827029da5cSPawel Biernacki     CTLFLAG_MPSAFE, 0, 0, sysctl_unprivileged_proc_debug, "I",
16830ef5652eSRobert Watson     "Unprivileged processes may use process debugging facilities");
16840ef5652eSRobert Watson 
16851a996ed1SEdward Tomasz Napierala /*-
1686f44d9e24SJohn Baldwin  * Determine whether td may debug p.
16877fd6a959SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1688f44d9e24SJohn Baldwin  * Locks: Sufficient locks to protect various components of td and p
1689f44d9e24SJohn Baldwin  *        must be held.  td must be curthread, and a lock must
1690f44d9e24SJohn Baldwin  *        be held for p.
1691f44d9e24SJohn Baldwin  * References: td and p must be valid for the lifetime of the call
16923b243b72SRobert Watson  */
1693a0f75161SRobert Watson int
1694f44d9e24SJohn Baldwin p_candebug(struct thread *td, struct proc *p)
1695387d2c03SRobert Watson {
1696eb725b4eSRobert Watson 	int credentialchanged, error, grpsubset, i, uidsubset;
1697387d2c03SRobert Watson 
1698f44d9e24SJohn Baldwin 	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1699f44d9e24SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
1700b3079544SJamie Gritton 	if ((error = priv_check(td, PRIV_DEBUG_UNPRIV)))
170132d18604SRobert Watson 		return (error);
1702f44d9e24SJohn Baldwin 	if (td->td_proc == p)
170323fad5b6SDag-Erling Smørgrav 		return (0);
1704f44d9e24SJohn Baldwin 	if ((error = prison_check(td->td_ucred, p->p_ucred)))
170591421ba2SRobert Watson 		return (error);
17068a1d977dSRobert Watson #ifdef MAC
170730d239bcSRobert Watson 	if ((error = mac_proc_check_debug(td->td_ucred, p)))
17088a1d977dSRobert Watson 		return (error);
17098a1d977dSRobert Watson #endif
17104ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeotheruids(td->td_ucred, p->p_ucred)))
17111b350b45SRobert Watson 		return (error);
17124ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeothergids(td->td_ucred, p->p_ucred)))
171364d19c2eSRobert Watson 		return (error);
1714387d2c03SRobert Watson 
17157fd6a959SRobert Watson 	/*
1716f44d9e24SJohn Baldwin 	 * Is p's group set a subset of td's effective group set?  This
1717f44d9e24SJohn Baldwin 	 * includes p's egid, group access list, rgid, and svgid.
17187fd6a959SRobert Watson 	 */
1719db42a33dSRobert Watson 	grpsubset = 1;
1720f44d9e24SJohn Baldwin 	for (i = 0; i < p->p_ucred->cr_ngroups; i++) {
1721f44d9e24SJohn Baldwin 		if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) {
1722db42a33dSRobert Watson 			grpsubset = 0;
1723db42a33dSRobert Watson 			break;
1724db42a33dSRobert Watson 		}
1725db42a33dSRobert Watson 	}
1726db42a33dSRobert Watson 	grpsubset = grpsubset &&
1727f44d9e24SJohn Baldwin 	    groupmember(p->p_ucred->cr_rgid, td->td_ucred) &&
1728f44d9e24SJohn Baldwin 	    groupmember(p->p_ucred->cr_svgid, td->td_ucred);
1729db42a33dSRobert Watson 
1730db42a33dSRobert Watson 	/*
1731f44d9e24SJohn Baldwin 	 * Are the uids present in p's credential equal to td's
1732f44d9e24SJohn Baldwin 	 * effective uid?  This includes p's euid, svuid, and ruid.
1733db42a33dSRobert Watson 	 */
1734f44d9e24SJohn Baldwin 	uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid &&
1735f44d9e24SJohn Baldwin 	    td->td_ucred->cr_uid == p->p_ucred->cr_svuid &&
1736f44d9e24SJohn Baldwin 	    td->td_ucred->cr_uid == p->p_ucred->cr_ruid);
1737db42a33dSRobert Watson 
1738db42a33dSRobert Watson 	/*
1739db42a33dSRobert Watson 	 * Has the credential of the process changed since the last exec()?
1740db42a33dSRobert Watson 	 */
1741f44d9e24SJohn Baldwin 	credentialchanged = (p->p_flag & P_SUGID);
1742db42a33dSRobert Watson 
1743db42a33dSRobert Watson 	/*
1744f44d9e24SJohn Baldwin 	 * If p's gids aren't a subset, or the uids aren't a subset,
1745db42a33dSRobert Watson 	 * or the credential has changed, require appropriate privilege
1746800c9408SRobert Watson 	 * for td to debug p.
1747db42a33dSRobert Watson 	 */
1748800c9408SRobert Watson 	if (!grpsubset || !uidsubset) {
174932f9753cSRobert Watson 		error = priv_check(td, PRIV_DEBUG_DIFFCRED);
1750800c9408SRobert Watson 		if (error)
1751800c9408SRobert Watson 			return (error);
1752800c9408SRobert Watson 	}
1753800c9408SRobert Watson 
1754800c9408SRobert Watson 	if (credentialchanged) {
175532f9753cSRobert Watson 		error = priv_check(td, PRIV_DEBUG_SUGID);
175632d18604SRobert Watson 		if (error)
1757387d2c03SRobert Watson 			return (error);
17587fd6a959SRobert Watson 	}
1759387d2c03SRobert Watson 
1760eb725b4eSRobert Watson 	/* Can't trace init when securelevel > 0. */
1761f44d9e24SJohn Baldwin 	if (p == initproc) {
1762f44d9e24SJohn Baldwin 		error = securelevel_gt(td->td_ucred, 0);
17633ca719f1SRobert Watson 		if (error)
17643ca719f1SRobert Watson 			return (error);
17653ca719f1SRobert Watson 	}
1766387d2c03SRobert Watson 
17675fab7614SRobert Watson 	/*
17685fab7614SRobert Watson 	 * Can't trace a process that's currently exec'ing.
1769800c9408SRobert Watson 	 *
17705fab7614SRobert Watson 	 * XXX: Note, this is not a security policy decision, it's a
17715fab7614SRobert Watson 	 * basic correctness/functionality decision.  Therefore, this check
17725fab7614SRobert Watson 	 * should be moved to the caller's of p_candebug().
17735fab7614SRobert Watson 	 */
1774f44d9e24SJohn Baldwin 	if ((p->p_flag & P_INEXEC) != 0)
1775af80b2c9SKonstantin Belousov 		return (EBUSY);
17769ca45e81SDag-Erling Smørgrav 
1777677258f7SKonstantin Belousov 	/* Denied explicitely */
1778677258f7SKonstantin Belousov 	if ((p->p_flag2 & P2_NOTRACE) != 0) {
1779677258f7SKonstantin Belousov 		error = priv_check(td, PRIV_DEBUG_DENIED);
1780677258f7SKonstantin Belousov 		if (error != 0)
1781677258f7SKonstantin Belousov 			return (error);
1782677258f7SKonstantin Belousov 	}
1783677258f7SKonstantin Belousov 
1784387d2c03SRobert Watson 	return (0);
1785387d2c03SRobert Watson }
1786387d2c03SRobert Watson 
17871a996ed1SEdward Tomasz Napierala /*-
178829dc1288SRobert Watson  * Determine whether the subject represented by cred can "see" a socket.
178929dc1288SRobert Watson  * Returns: 0 for permitted, ENOENT otherwise.
179029dc1288SRobert Watson  */
179129dc1288SRobert Watson int
179229dc1288SRobert Watson cr_canseesocket(struct ucred *cred, struct socket *so)
179329dc1288SRobert Watson {
179429dc1288SRobert Watson 	int error;
179529dc1288SRobert Watson 
179629dc1288SRobert Watson 	error = prison_check(cred, so->so_cred);
179729dc1288SRobert Watson 	if (error)
179829dc1288SRobert Watson 		return (ENOENT);
17998a1d977dSRobert Watson #ifdef MAC
180030d239bcSRobert Watson 	error = mac_socket_check_visible(cred, so);
18018a1d977dSRobert Watson 	if (error)
18028a1d977dSRobert Watson 		return (error);
18038a1d977dSRobert Watson #endif
18044ac21b4fSStephen J. Kiernan 	if (cr_canseeotheruids(cred, so->so_cred))
180529dc1288SRobert Watson 		return (ENOENT);
18064ac21b4fSStephen J. Kiernan 	if (cr_canseeothergids(cred, so->so_cred))
180764d19c2eSRobert Watson 		return (ENOENT);
180829dc1288SRobert Watson 
180929dc1288SRobert Watson 	return (0);
181029dc1288SRobert Watson }
181129dc1288SRobert Watson 
18121a996ed1SEdward Tomasz Napierala /*-
1813babe9a2bSRobert Watson  * Determine whether td can wait for the exit of p.
1814babe9a2bSRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1815babe9a2bSRobert Watson  * Locks: Sufficient locks to protect various components of td and p
1816babe9a2bSRobert Watson  *        must be held.  td must be curthread, and a lock must
1817babe9a2bSRobert Watson  *        be held for p.
1818babe9a2bSRobert Watson  * References: td and p must be valid for the lifetime of the call
1819babe9a2bSRobert Watson 
1820babe9a2bSRobert Watson  */
1821babe9a2bSRobert Watson int
1822babe9a2bSRobert Watson p_canwait(struct thread *td, struct proc *p)
1823babe9a2bSRobert Watson {
1824babe9a2bSRobert Watson 	int error;
1825babe9a2bSRobert Watson 
1826babe9a2bSRobert Watson 	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1827babe9a2bSRobert Watson 	PROC_LOCK_ASSERT(p, MA_OWNED);
18287afcbc18SJamie Gritton 	if ((error = prison_check(td->td_ucred, p->p_ucred)))
1829babe9a2bSRobert Watson 		return (error);
1830babe9a2bSRobert Watson #ifdef MAC
183130d239bcSRobert Watson 	if ((error = mac_proc_check_wait(td->td_ucred, p)))
1832babe9a2bSRobert Watson 		return (error);
1833babe9a2bSRobert Watson #endif
1834babe9a2bSRobert Watson #if 0
1835babe9a2bSRobert Watson 	/* XXXMAC: This could have odd effects on some shells. */
18364ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeotheruids(td->td_ucred, p->p_ucred)))
1837babe9a2bSRobert Watson 		return (error);
1838babe9a2bSRobert Watson #endif
1839babe9a2bSRobert Watson 
1840babe9a2bSRobert Watson 	return (0);
1841babe9a2bSRobert Watson }
1842babe9a2bSRobert Watson 
1843a9e0361bSPoul-Henning Kamp /*
18441724c563SMateusz Guzik  * Credential management.
18451724c563SMateusz Guzik  *
18461724c563SMateusz Guzik  * struct ucred objects are rarely allocated but gain and lose references all
18471724c563SMateusz Guzik  * the time (e.g., on struct file alloc/dealloc) turning refcount updates into
18481724c563SMateusz Guzik  * a significant source of cache-line ping ponging. Common cases are worked
18491724c563SMateusz Guzik  * around by modifying thread-local counter instead if the cred to operate on
18501724c563SMateusz Guzik  * matches td_realucred.
18511724c563SMateusz Guzik  *
18521724c563SMateusz Guzik  * The counter is split into 2 parts:
18531724c563SMateusz Guzik  * - cr_users -- total count of all struct proc and struct thread objects
18541724c563SMateusz Guzik  *   which have given cred in p_ucred and td_ucred respectively
18551724c563SMateusz Guzik  * - cr_ref -- the actual ref count, only valid if cr_users == 0
18561724c563SMateusz Guzik  *
18571724c563SMateusz Guzik  * If users == 0 then cr_ref behaves similarly to refcount(9), in particular if
18581724c563SMateusz Guzik  * the count reaches 0 the object is freeable.
18591724c563SMateusz Guzik  * If users > 0 and curthread->td_realucred == cred, then updates are performed
18601724c563SMateusz Guzik  * against td_ucredref.
18611724c563SMateusz Guzik  * In other cases updates are performed against cr_ref.
18621724c563SMateusz Guzik  *
18631724c563SMateusz Guzik  * Changing td_realucred into something else decrements cr_users and transfers
18641724c563SMateusz Guzik  * accumulated updates.
18651724c563SMateusz Guzik  */
18661724c563SMateusz Guzik struct ucred *
18671724c563SMateusz Guzik crcowget(struct ucred *cr)
18681724c563SMateusz Guzik {
18691724c563SMateusz Guzik 
18701724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
18711724c563SMateusz Guzik 	KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
18721724c563SMateusz Guzik 	    __func__, cr->cr_users, cr));
18731724c563SMateusz Guzik 	cr->cr_users++;
18741724c563SMateusz Guzik 	cr->cr_ref++;
18751724c563SMateusz Guzik 	mtx_unlock(&cr->cr_mtx);
18761724c563SMateusz Guzik 	return (cr);
18771724c563SMateusz Guzik }
18781724c563SMateusz Guzik 
18791724c563SMateusz Guzik static struct ucred *
18801724c563SMateusz Guzik crunuse(struct thread *td)
18811724c563SMateusz Guzik {
18821724c563SMateusz Guzik 	struct ucred *cr, *crold;
18831724c563SMateusz Guzik 
18841724c563SMateusz Guzik 	cr = td->td_ucred;
18851724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
18861724c563SMateusz Guzik 	cr->cr_ref += td->td_ucredref;
18871724c563SMateusz Guzik 	td->td_ucredref = 0;
18881724c563SMateusz Guzik 	KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
18891724c563SMateusz Guzik 	    __func__, cr->cr_users, cr));
18901724c563SMateusz Guzik 	cr->cr_users--;
18911724c563SMateusz Guzik 	if (cr->cr_users == 0) {
18921724c563SMateusz Guzik 		KASSERT(cr->cr_ref > 0, ("%s: ref %d not > 0 on cred %p",
18931724c563SMateusz Guzik 		    __func__, cr->cr_ref, cr));
18941724c563SMateusz Guzik 		crold = cr;
18951724c563SMateusz Guzik 	} else {
18961724c563SMateusz Guzik 		cr->cr_ref--;
18971724c563SMateusz Guzik 		crold = NULL;
18981724c563SMateusz Guzik 	}
18991724c563SMateusz Guzik 	mtx_unlock(&cr->cr_mtx);
19001724c563SMateusz Guzik 	return (crold);
19011724c563SMateusz Guzik }
19021724c563SMateusz Guzik 
19031724c563SMateusz Guzik void
19041724c563SMateusz Guzik crcowfree(struct thread *td)
19051724c563SMateusz Guzik {
19061724c563SMateusz Guzik 	struct ucred *cr;
19071724c563SMateusz Guzik 
19081724c563SMateusz Guzik 	cr = crunuse(td);
19091724c563SMateusz Guzik 	if (cr != NULL)
19101724c563SMateusz Guzik 		crfree(cr);
19111724c563SMateusz Guzik }
19121724c563SMateusz Guzik 
19131724c563SMateusz Guzik struct ucred *
19141724c563SMateusz Guzik crcowsync(void)
19151724c563SMateusz Guzik {
19161724c563SMateusz Guzik 	struct thread *td;
19171724c563SMateusz Guzik 	struct proc *p;
19181724c563SMateusz Guzik 	struct ucred *crnew, *crold;
19191724c563SMateusz Guzik 
19201724c563SMateusz Guzik 	td = curthread;
19211724c563SMateusz Guzik 	p = td->td_proc;
19221724c563SMateusz Guzik 	PROC_LOCK_ASSERT(p, MA_OWNED);
19231724c563SMateusz Guzik 
19241724c563SMateusz Guzik 	MPASS(td->td_realucred == td->td_ucred);
19251724c563SMateusz Guzik 	if (td->td_realucred == p->p_ucred)
19261724c563SMateusz Guzik 		return (NULL);
19271724c563SMateusz Guzik 
19281724c563SMateusz Guzik 	crnew = crcowget(p->p_ucred);
19291724c563SMateusz Guzik 	crold = crunuse(td);
19301724c563SMateusz Guzik 	td->td_realucred = crnew;
19311724c563SMateusz Guzik 	td->td_ucred = td->td_realucred;
19321724c563SMateusz Guzik 	return (crold);
19331724c563SMateusz Guzik }
19341724c563SMateusz Guzik 
19351724c563SMateusz Guzik /*
1936df8bae1dSRodney W. Grimes  * Allocate a zeroed cred structure.
1937df8bae1dSRodney W. Grimes  */
1938df8bae1dSRodney W. Grimes struct ucred *
19394c44ad8eSJohn Baldwin crget(void)
1940df8bae1dSRodney W. Grimes {
19413e85b721SEd Maste 	struct ucred *cr;
1942df8bae1dSRodney W. Grimes 
19431ede983cSDag-Erling Smørgrav 	cr = malloc(sizeof(*cr), M_CRED, M_WAITOK | M_ZERO);
19441724c563SMateusz Guzik 	mtx_init(&cr->cr_mtx, "cred", NULL, MTX_DEF);
19451724c563SMateusz Guzik 	cr->cr_ref = 1;
1946faef5371SRobert Watson #ifdef AUDIT
1947faef5371SRobert Watson 	audit_cred_init(cr);
1948faef5371SRobert Watson #endif
194940244964SRobert Watson #ifdef MAC
195030d239bcSRobert Watson 	mac_cred_init(cr);
195140244964SRobert Watson #endif
1952a99500a9SMateusz Guzik 	cr->cr_groups = cr->cr_smallgroups;
1953a99500a9SMateusz Guzik 	cr->cr_agroups =
1954a99500a9SMateusz Guzik 	    sizeof(cr->cr_smallgroups) / sizeof(cr->cr_smallgroups[0]);
1955df8bae1dSRodney W. Grimes 	return (cr);
1956df8bae1dSRodney W. Grimes }
1957df8bae1dSRodney W. Grimes 
1958df8bae1dSRodney W. Grimes /*
19597fd6a959SRobert Watson  * Claim another reference to a ucred structure.
19605c3f70d7SAlfred Perlstein  */
1961bd78ceceSJohn Baldwin struct ucred *
19624c44ad8eSJohn Baldwin crhold(struct ucred *cr)
19635c3f70d7SAlfred Perlstein {
19641724c563SMateusz Guzik 	struct thread *td;
19655c3f70d7SAlfred Perlstein 
19661724c563SMateusz Guzik 	td = curthread;
19671724c563SMateusz Guzik 	if (__predict_true(td->td_realucred == cr)) {
19681724c563SMateusz Guzik 		KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
19691724c563SMateusz Guzik 		    __func__, cr->cr_users, cr));
19701724c563SMateusz Guzik 		td->td_ucredref++;
19711724c563SMateusz Guzik 		return (cr);
19721724c563SMateusz Guzik 	}
19731724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
19741724c563SMateusz Guzik 	cr->cr_ref++;
19751724c563SMateusz Guzik 	mtx_unlock(&cr->cr_mtx);
1976bd78ceceSJohn Baldwin 	return (cr);
19775c3f70d7SAlfred Perlstein }
19785c3f70d7SAlfred Perlstein 
19795c3f70d7SAlfred Perlstein /*
19800c14ff0eSRobert Watson  * Free a cred structure.  Throws away space when ref count gets to 0.
1981df8bae1dSRodney W. Grimes  */
198226f9a767SRodney W. Grimes void
19834c44ad8eSJohn Baldwin crfree(struct ucred *cr)
1984df8bae1dSRodney W. Grimes {
19851724c563SMateusz Guzik 	struct thread *td;
19861e5d626aSAlfred Perlstein 
19871724c563SMateusz Guzik 	td = curthread;
1988*a2de789eSMateusz Guzik 	if (__predict_true(td->td_realucred == cr)) {
19891724c563SMateusz Guzik 		KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
19901724c563SMateusz Guzik 		    __func__, cr->cr_users, cr));
19911724c563SMateusz Guzik 		td->td_ucredref--;
19921724c563SMateusz Guzik 		return;
19931724c563SMateusz Guzik 	}
19941724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
19951724c563SMateusz Guzik 	KASSERT(cr->cr_users >= 0, ("%s: users %d not >= 0 on cred %p",
19961724c563SMateusz Guzik 	    __func__, cr->cr_users, cr));
19971724c563SMateusz Guzik 	cr->cr_ref--;
19981724c563SMateusz Guzik 	if (cr->cr_users > 0) {
19991724c563SMateusz Guzik 		mtx_unlock(&cr->cr_mtx);
20001724c563SMateusz Guzik 		return;
20011724c563SMateusz Guzik 	}
20021724c563SMateusz Guzik 	KASSERT(cr->cr_ref >= 0, ("%s: ref %d not >= 0 on cred %p",
20031724c563SMateusz Guzik 	    __func__, cr->cr_ref, cr));
20041724c563SMateusz Guzik 	if (cr->cr_ref > 0) {
20051724c563SMateusz Guzik 		mtx_unlock(&cr->cr_mtx);
20061724c563SMateusz Guzik 		return;
20071724c563SMateusz Guzik 	}
2008f535380cSDon Lewis 	/*
20091724c563SMateusz Guzik 	 * Some callers of crget(), such as nfs_statfs(), allocate a temporary
20101724c563SMateusz Guzik 	 * credential, but don't allocate a uidinfo structure.
2011f535380cSDon Lewis 	 */
2012f535380cSDon Lewis 	if (cr->cr_uidinfo != NULL)
2013f535380cSDon Lewis 		uifree(cr->cr_uidinfo);
2014823c224eSRobert Watson 	if (cr->cr_ruidinfo != NULL)
2015823c224eSRobert Watson 		uifree(cr->cr_ruidinfo);
20160304c731SJamie Gritton 	if (cr->cr_prison != NULL)
201791421ba2SRobert Watson 		prison_free(cr->cr_prison);
20182bfc50bcSEdward Tomasz Napierala 	if (cr->cr_loginclass != NULL)
20192bfc50bcSEdward Tomasz Napierala 		loginclass_free(cr->cr_loginclass);
2020faef5371SRobert Watson #ifdef AUDIT
2021faef5371SRobert Watson 	audit_cred_destroy(cr);
2022faef5371SRobert Watson #endif
202340244964SRobert Watson #ifdef MAC
202430d239bcSRobert Watson 	mac_cred_destroy(cr);
202540244964SRobert Watson #endif
20261724c563SMateusz Guzik 	mtx_destroy(&cr->cr_mtx);
2027a99500a9SMateusz Guzik 	if (cr->cr_groups != cr->cr_smallgroups)
2028838d9858SBrooks Davis 		free(cr->cr_groups, M_CRED);
20291ede983cSDag-Erling Smørgrav 	free(cr, M_CRED);
2030e1bca29fSMatthew Dillon }
2031df8bae1dSRodney W. Grimes 
2032df8bae1dSRodney W. Grimes /*
2033bd78ceceSJohn Baldwin  * Copy a ucred's contents from a template.  Does not block.
2034bd78ceceSJohn Baldwin  */
2035bd78ceceSJohn Baldwin void
20364c44ad8eSJohn Baldwin crcopy(struct ucred *dest, struct ucred *src)
2037bd78ceceSJohn Baldwin {
2038bd78ceceSJohn Baldwin 
203925108069SMateusz Guzik 	KASSERT(dest->cr_ref == 1, ("crcopy of shared ucred"));
2040bd78ceceSJohn Baldwin 	bcopy(&src->cr_startcopy, &dest->cr_startcopy,
2041bd78ceceSJohn Baldwin 	    (unsigned)((caddr_t)&src->cr_endcopy -
2042bd78ceceSJohn Baldwin 		(caddr_t)&src->cr_startcopy));
2043838d9858SBrooks Davis 	crsetgroups(dest, src->cr_ngroups, src->cr_groups);
2044bd78ceceSJohn Baldwin 	uihold(dest->cr_uidinfo);
2045bd78ceceSJohn Baldwin 	uihold(dest->cr_ruidinfo);
2046bd78ceceSJohn Baldwin 	prison_hold(dest->cr_prison);
20472bfc50bcSEdward Tomasz Napierala 	loginclass_hold(dest->cr_loginclass);
2048faef5371SRobert Watson #ifdef AUDIT
2049faef5371SRobert Watson 	audit_cred_copy(src, dest);
2050faef5371SRobert Watson #endif
205140244964SRobert Watson #ifdef MAC
205230d239bcSRobert Watson 	mac_cred_copy(src, dest);
205340244964SRobert Watson #endif
2054df8bae1dSRodney W. Grimes }
2055df8bae1dSRodney W. Grimes 
2056df8bae1dSRodney W. Grimes /*
2057df8bae1dSRodney W. Grimes  * Dup cred struct to a new held one.
2058df8bae1dSRodney W. Grimes  */
2059df8bae1dSRodney W. Grimes struct ucred *
20604c44ad8eSJohn Baldwin crdup(struct ucred *cr)
2061df8bae1dSRodney W. Grimes {
2062df8bae1dSRodney W. Grimes 	struct ucred *newcr;
2063df8bae1dSRodney W. Grimes 
2064bd78ceceSJohn Baldwin 	newcr = crget();
2065bd78ceceSJohn Baldwin 	crcopy(newcr, cr);
2066df8bae1dSRodney W. Grimes 	return (newcr);
2067df8bae1dSRodney W. Grimes }
2068df8bae1dSRodney W. Grimes 
2069df8bae1dSRodney W. Grimes /*
207076183f34SDima Dorfman  * Fill in a struct xucred based on a struct ucred.
207176183f34SDima Dorfman  */
207276183f34SDima Dorfman void
20734c44ad8eSJohn Baldwin cru2x(struct ucred *cr, struct xucred *xcr)
207476183f34SDima Dorfman {
2075838d9858SBrooks Davis 	int ngroups;
207676183f34SDima Dorfman 
207776183f34SDima Dorfman 	bzero(xcr, sizeof(*xcr));
207876183f34SDima Dorfman 	xcr->cr_version = XUCRED_VERSION;
207976183f34SDima Dorfman 	xcr->cr_uid = cr->cr_uid;
2080838d9858SBrooks Davis 
2081838d9858SBrooks Davis 	ngroups = MIN(cr->cr_ngroups, XU_NGROUPS);
2082838d9858SBrooks Davis 	xcr->cr_ngroups = ngroups;
2083838d9858SBrooks Davis 	bcopy(cr->cr_groups, xcr->cr_groups,
2084838d9858SBrooks Davis 	    ngroups * sizeof(*cr->cr_groups));
208576183f34SDima Dorfman }
208676183f34SDima Dorfman 
2087c8124e20SDmitry Chagin void
2088c5afec6eSDmitry Chagin cru2xt(struct thread *td, struct xucred *xcr)
2089c5afec6eSDmitry Chagin {
2090c5afec6eSDmitry Chagin 
2091c5afec6eSDmitry Chagin 	cru2x(td->td_ucred, xcr);
2092c5afec6eSDmitry Chagin 	xcr->cr_pid = td->td_proc->p_pid;
2093c5afec6eSDmitry Chagin }
2094c5afec6eSDmitry Chagin 
209576183f34SDima Dorfman /*
2096ffb34484SMateusz Guzik  * Set initial process credentials.
2097ffb34484SMateusz Guzik  * Callers are responsible for providing the reference for provided credentials.
2098ffb34484SMateusz Guzik  */
2099ffb34484SMateusz Guzik void
2100ffb34484SMateusz Guzik proc_set_cred_init(struct proc *p, struct ucred *newcred)
2101ffb34484SMateusz Guzik {
2102ffb34484SMateusz Guzik 
21031724c563SMateusz Guzik 	p->p_ucred = crcowget(newcred);
2104ffb34484SMateusz Guzik }
2105ffb34484SMateusz Guzik 
2106ffb34484SMateusz Guzik /*
2107daf63fd2SMateusz Guzik  * Change process credentials.
2108ffb34484SMateusz Guzik  * Callers are responsible for providing the reference for passed credentials
2109daf63fd2SMateusz Guzik  * and for freeing old ones.
2110daf63fd2SMateusz Guzik  *
2111daf63fd2SMateusz Guzik  * Process has to be locked except when it does not have credentials (as it
2112daf63fd2SMateusz Guzik  * should not be visible just yet) or when newcred is NULL (as this can be
2113daf63fd2SMateusz Guzik  * only used when the process is about to be freed, at which point it should
2114daf63fd2SMateusz Guzik  * not be visible anymore).
2115daf63fd2SMateusz Guzik  */
21166f836483SMateusz Guzik void
2117daf63fd2SMateusz Guzik proc_set_cred(struct proc *p, struct ucred *newcred)
2118daf63fd2SMateusz Guzik {
21191724c563SMateusz Guzik 	struct ucred *cr;
2120daf63fd2SMateusz Guzik 
21211724c563SMateusz Guzik 	cr = p->p_ucred;
21221724c563SMateusz Guzik 	MPASS(cr != NULL);
2123daf63fd2SMateusz Guzik 	PROC_LOCK_ASSERT(p, MA_OWNED);
21241724c563SMateusz Guzik 	KASSERT(newcred->cr_users == 0, ("%s: users %d not 0 on cred %p",
21251724c563SMateusz Guzik 	    __func__, newcred->cr_users, newcred));
21261724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
21271724c563SMateusz Guzik 	KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
21281724c563SMateusz Guzik 	    __func__, cr->cr_users, cr));
21291724c563SMateusz Guzik 	cr->cr_users--;
21301724c563SMateusz Guzik 	mtx_unlock(&cr->cr_mtx);
2131daf63fd2SMateusz Guzik 	p->p_ucred = newcred;
21321724c563SMateusz Guzik 	newcred->cr_users = 1;
21334ea6a9a2SMateusz Guzik 	PROC_UPDATE_COW(p);
2134daf63fd2SMateusz Guzik }
2135daf63fd2SMateusz Guzik 
21365a90435cSMateusz Guzik void
21375a90435cSMateusz Guzik proc_unset_cred(struct proc *p)
21385a90435cSMateusz Guzik {
21395a90435cSMateusz Guzik 	struct ucred *cr;
21405a90435cSMateusz Guzik 
21411724c563SMateusz Guzik 	MPASS(p->p_state == PRS_ZOMBIE || p->p_state == PRS_NEW);
21425a90435cSMateusz Guzik 	cr = p->p_ucred;
21435a90435cSMateusz Guzik 	p->p_ucred = NULL;
21441724c563SMateusz Guzik 	KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
21451724c563SMateusz Guzik 	    __func__, cr->cr_users, cr));
21461724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
21471724c563SMateusz Guzik 	cr->cr_users--;
21481724c563SMateusz Guzik 	if (cr->cr_users == 0)
21491724c563SMateusz Guzik 		KASSERT(cr->cr_ref > 0, ("%s: ref %d not > 0 on cred %p",
21501724c563SMateusz Guzik 		    __func__, cr->cr_ref, cr));
21511724c563SMateusz Guzik 	mtx_unlock(&cr->cr_mtx);
21525a90435cSMateusz Guzik 	crfree(cr);
21535a90435cSMateusz Guzik }
21545a90435cSMateusz Guzik 
2155838d9858SBrooks Davis struct ucred *
2156838d9858SBrooks Davis crcopysafe(struct proc *p, struct ucred *cr)
2157838d9858SBrooks Davis {
2158838d9858SBrooks Davis 	struct ucred *oldcred;
2159838d9858SBrooks Davis 	int groups;
2160838d9858SBrooks Davis 
2161838d9858SBrooks Davis 	PROC_LOCK_ASSERT(p, MA_OWNED);
2162838d9858SBrooks Davis 
2163838d9858SBrooks Davis 	oldcred = p->p_ucred;
2164838d9858SBrooks Davis 	while (cr->cr_agroups < oldcred->cr_agroups) {
2165838d9858SBrooks Davis 		groups = oldcred->cr_agroups;
2166838d9858SBrooks Davis 		PROC_UNLOCK(p);
2167838d9858SBrooks Davis 		crextend(cr, groups);
2168838d9858SBrooks Davis 		PROC_LOCK(p);
2169838d9858SBrooks Davis 		oldcred = p->p_ucred;
2170838d9858SBrooks Davis 	}
2171838d9858SBrooks Davis 	crcopy(cr, oldcred);
2172838d9858SBrooks Davis 
2173838d9858SBrooks Davis 	return (oldcred);
2174838d9858SBrooks Davis }
2175838d9858SBrooks Davis 
2176838d9858SBrooks Davis /*
2177838d9858SBrooks Davis  * Extend the passed in credential to hold n items.
2178838d9858SBrooks Davis  */
2179c8358c6eSGleb Smirnoff void
2180838d9858SBrooks Davis crextend(struct ucred *cr, int n)
2181838d9858SBrooks Davis {
2182838d9858SBrooks Davis 	int cnt;
2183838d9858SBrooks Davis 
2184838d9858SBrooks Davis 	/* Truncate? */
2185838d9858SBrooks Davis 	if (n <= cr->cr_agroups)
2186838d9858SBrooks Davis 		return;
2187838d9858SBrooks Davis 
2188838d9858SBrooks Davis 	/*
2189838d9858SBrooks Davis 	 * We extend by 2 each time since we're using a power of two
2190838d9858SBrooks Davis 	 * allocator until we need enough groups to fill a page.
2191838d9858SBrooks Davis 	 * Once we're allocating multiple pages, only allocate as many
2192838d9858SBrooks Davis 	 * as we actually need.  The case of processes needing a
2193838d9858SBrooks Davis 	 * non-power of two number of pages seems more likely than
2194838d9858SBrooks Davis 	 * a real world process that adds thousands of groups one at a
2195838d9858SBrooks Davis 	 * time.
2196838d9858SBrooks Davis 	 */
2197838d9858SBrooks Davis 	if ( n < PAGE_SIZE / sizeof(gid_t) ) {
2198838d9858SBrooks Davis 		if (cr->cr_agroups == 0)
219951871224SRyan Libby 			cnt = MAX(1, MINALLOCSIZE / sizeof(gid_t));
2200838d9858SBrooks Davis 		else
2201838d9858SBrooks Davis 			cnt = cr->cr_agroups * 2;
2202838d9858SBrooks Davis 
2203838d9858SBrooks Davis 		while (cnt < n)
2204838d9858SBrooks Davis 			cnt *= 2;
2205838d9858SBrooks Davis 	} else
2206838d9858SBrooks Davis 		cnt = roundup2(n, PAGE_SIZE / sizeof(gid_t));
2207838d9858SBrooks Davis 
2208838d9858SBrooks Davis 	/* Free the old array. */
2209a99500a9SMateusz Guzik 	if (cr->cr_groups != cr->cr_smallgroups)
2210838d9858SBrooks Davis 		free(cr->cr_groups, M_CRED);
2211838d9858SBrooks Davis 
2212838d9858SBrooks Davis 	cr->cr_groups = malloc(cnt * sizeof(gid_t), M_CRED, M_WAITOK | M_ZERO);
2213838d9858SBrooks Davis 	cr->cr_agroups = cnt;
2214838d9858SBrooks Davis }
2215838d9858SBrooks Davis 
2216838d9858SBrooks Davis /*
22177f92e578SBrooks Davis  * Copy groups in to a credential, preserving any necessary invariants.
22187f92e578SBrooks Davis  * Currently this includes the sorting of all supplemental gids.
22197f92e578SBrooks Davis  * crextend() must have been called before hand to ensure sufficient
22207f92e578SBrooks Davis  * space is available.
2221838d9858SBrooks Davis  */
2222838d9858SBrooks Davis static void
2223838d9858SBrooks Davis crsetgroups_locked(struct ucred *cr, int ngrp, gid_t *groups)
2224838d9858SBrooks Davis {
22257f92e578SBrooks Davis 	int i;
22267f92e578SBrooks Davis 	int j;
22277f92e578SBrooks Davis 	gid_t g;
2228838d9858SBrooks Davis 
2229838d9858SBrooks Davis 	KASSERT(cr->cr_agroups >= ngrp, ("cr_ngroups is too small"));
2230838d9858SBrooks Davis 
2231838d9858SBrooks Davis 	bcopy(groups, cr->cr_groups, ngrp * sizeof(gid_t));
2232838d9858SBrooks Davis 	cr->cr_ngroups = ngrp;
22337f92e578SBrooks Davis 
22347f92e578SBrooks Davis 	/*
22357f92e578SBrooks Davis 	 * Sort all groups except cr_groups[0] to allow groupmember to
22367f92e578SBrooks Davis 	 * perform a binary search.
22377f92e578SBrooks Davis 	 *
22387f92e578SBrooks Davis 	 * XXX: If large numbers of groups become common this should
22397f92e578SBrooks Davis 	 * be replaced with shell sort like linux uses or possibly
22407f92e578SBrooks Davis 	 * heap sort.
22417f92e578SBrooks Davis 	 */
22427f92e578SBrooks Davis 	for (i = 2; i < ngrp; i++) {
22437f92e578SBrooks Davis 		g = cr->cr_groups[i];
22447f92e578SBrooks Davis 		for (j = i-1; j >= 1 && g < cr->cr_groups[j]; j--)
22457f92e578SBrooks Davis 			cr->cr_groups[j + 1] = cr->cr_groups[j];
22467f92e578SBrooks Davis 		cr->cr_groups[j + 1] = g;
22477f92e578SBrooks Davis 	}
2248838d9858SBrooks Davis }
2249838d9858SBrooks Davis 
2250838d9858SBrooks Davis /*
2251838d9858SBrooks Davis  * Copy groups in to a credential after expanding it if required.
2252412f9500SBrooks Davis  * Truncate the list to (ngroups_max + 1) if it is too large.
2253838d9858SBrooks Davis  */
2254838d9858SBrooks Davis void
2255838d9858SBrooks Davis crsetgroups(struct ucred *cr, int ngrp, gid_t *groups)
2256838d9858SBrooks Davis {
2257838d9858SBrooks Davis 
2258412f9500SBrooks Davis 	if (ngrp > ngroups_max + 1)
2259412f9500SBrooks Davis 		ngrp = ngroups_max + 1;
2260838d9858SBrooks Davis 
2261838d9858SBrooks Davis 	crextend(cr, ngrp);
2262838d9858SBrooks Davis 	crsetgroups_locked(cr, ngrp, groups);
2263838d9858SBrooks Davis }
2264838d9858SBrooks Davis 
22652eb927e2SJulian Elischer /*
2266df8bae1dSRodney W. Grimes  * Get login name, if available.
2267df8bae1dSRodney W. Grimes  */
2268d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
2269df8bae1dSRodney W. Grimes struct getlogin_args {
2270df8bae1dSRodney W. Grimes 	char	*namebuf;
2271df8bae1dSRodney W. Grimes 	u_int	namelen;
2272df8bae1dSRodney W. Grimes };
2273d2d3e875SBruce Evans #endif
2274df8bae1dSRodney W. Grimes /* ARGSUSED */
227526f9a767SRodney W. Grimes int
22768451d0ddSKip Macy sys_getlogin(struct thread *td, struct getlogin_args *uap)
2277df8bae1dSRodney W. Grimes {
2278f591779bSSeigo Tanimura 	char login[MAXLOGNAME];
2279b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
2280bccb6d5aSDag-Erling Smørgrav 	size_t len;
2281df8bae1dSRodney W. Grimes 
228230cf3ac4SAndrey A. Chernov 	if (uap->namelen > MAXLOGNAME)
228353490b76SAndrey A. Chernov 		uap->namelen = MAXLOGNAME;
2284f591779bSSeigo Tanimura 	PROC_LOCK(p);
2285f591779bSSeigo Tanimura 	SESS_LOCK(p->p_session);
2286bccb6d5aSDag-Erling Smørgrav 	len = strlcpy(login, p->p_session->s_login, uap->namelen) + 1;
2287f591779bSSeigo Tanimura 	SESS_UNLOCK(p->p_session);
2288f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
2289bccb6d5aSDag-Erling Smørgrav 	if (len > uap->namelen)
22906f68699fSBaptiste Daroussin 		return (ERANGE);
2291bccb6d5aSDag-Erling Smørgrav 	return (copyout(login, uap->namebuf, len));
2292df8bae1dSRodney W. Grimes }
2293df8bae1dSRodney W. Grimes 
2294df8bae1dSRodney W. Grimes /*
2295df8bae1dSRodney W. Grimes  * Set login name.
2296df8bae1dSRodney W. Grimes  */
2297d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
2298df8bae1dSRodney W. Grimes struct setlogin_args {
2299df8bae1dSRodney W. Grimes 	char	*namebuf;
2300df8bae1dSRodney W. Grimes };
2301d2d3e875SBruce Evans #endif
2302df8bae1dSRodney W. Grimes /* ARGSUSED */
230326f9a767SRodney W. Grimes int
23048451d0ddSKip Macy sys_setlogin(struct thread *td, struct setlogin_args *uap)
2305df8bae1dSRodney W. Grimes {
2306b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
2307df8bae1dSRodney W. Grimes 	int error;
2308964ca0caSAndrey A. Chernov 	char logintmp[MAXLOGNAME];
2309df8bae1dSRodney W. Grimes 
2310bccb6d5aSDag-Erling Smørgrav 	CTASSERT(sizeof(p->p_session->s_login) >= sizeof(logintmp));
2311bccb6d5aSDag-Erling Smørgrav 
231232f9753cSRobert Watson 	error = priv_check(td, PRIV_PROC_SETLOGIN);
231307f3485dSJohn Baldwin 	if (error)
231407f3485dSJohn Baldwin 		return (error);
23157f05b035SAlfred Perlstein 	error = copyinstr(uap->namebuf, logintmp, sizeof(logintmp), NULL);
2316bccb6d5aSDag-Erling Smørgrav 	if (error != 0) {
2317eb725b4eSRobert Watson 		if (error == ENAMETOOLONG)
2318df8bae1dSRodney W. Grimes 			error = EINVAL;
2319bccb6d5aSDag-Erling Smørgrav 		return (error);
2320bccb6d5aSDag-Erling Smørgrav 	}
232170a98c11SRobert Watson 	AUDIT_ARG_LOGIN(logintmp);
2322f591779bSSeigo Tanimura 	PROC_LOCK(p);
2323f591779bSSeigo Tanimura 	SESS_LOCK(p->p_session);
2324bccb6d5aSDag-Erling Smørgrav 	strcpy(p->p_session->s_login, logintmp);
2325f591779bSSeigo Tanimura 	SESS_UNLOCK(p->p_session);
2326f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
2327bccb6d5aSDag-Erling Smørgrav 	return (0);
2328df8bae1dSRodney W. Grimes }
2329d5f81602SSean Eric Fagan 
2330d5f81602SSean Eric Fagan void
23314c44ad8eSJohn Baldwin setsugid(struct proc *p)
2332d5f81602SSean Eric Fagan {
2333f2102dadSAlfred Perlstein 
2334f2102dadSAlfred Perlstein 	PROC_LOCK_ASSERT(p, MA_OWNED);
2335d5f81602SSean Eric Fagan 	p->p_flag |= P_SUGID;
2336d5f81602SSean Eric Fagan }
2337f535380cSDon Lewis 
23381a996ed1SEdward Tomasz Napierala /*-
23397fd6a959SRobert Watson  * Change a process's effective uid.
2340b1fc0ec1SRobert Watson  * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified.
2341b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2342b1fc0ec1SRobert Watson  *             duration of the call.
2343f535380cSDon Lewis  */
2344f535380cSDon Lewis void
23451419eacbSAlfred Perlstein change_euid(struct ucred *newcred, struct uidinfo *euip)
2346f535380cSDon Lewis {
2347f535380cSDon Lewis 
23481419eacbSAlfred Perlstein 	newcred->cr_uid = euip->ui_uid;
23491419eacbSAlfred Perlstein 	uihold(euip);
2350b1fc0ec1SRobert Watson 	uifree(newcred->cr_uidinfo);
23511419eacbSAlfred Perlstein 	newcred->cr_uidinfo = euip;
2352f535380cSDon Lewis }
2353f535380cSDon Lewis 
23541a996ed1SEdward Tomasz Napierala /*-
23557fd6a959SRobert Watson  * Change a process's effective gid.
2356b1fc0ec1SRobert Watson  * Side effects: newcred->cr_gid will be modified.
2357b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2358b1fc0ec1SRobert Watson  *             duration of the call.
2359f535380cSDon Lewis  */
2360810bfc8eSAndrew Gallatin void
23614c44ad8eSJohn Baldwin change_egid(struct ucred *newcred, gid_t egid)
2362b1fc0ec1SRobert Watson {
2363b1fc0ec1SRobert Watson 
2364b1fc0ec1SRobert Watson 	newcred->cr_groups[0] = egid;
2365b1fc0ec1SRobert Watson }
2366b1fc0ec1SRobert Watson 
23671a996ed1SEdward Tomasz Napierala /*-
23687fd6a959SRobert Watson  * Change a process's real uid.
2369b1fc0ec1SRobert Watson  * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo
2370b1fc0ec1SRobert Watson  *               will be updated, and the old and new cr_ruidinfo proc
2371b1fc0ec1SRobert Watson  *               counts will be updated.
2372b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2373b1fc0ec1SRobert Watson  *             duration of the call.
2374b1fc0ec1SRobert Watson  */
2375b1fc0ec1SRobert Watson void
23761419eacbSAlfred Perlstein change_ruid(struct ucred *newcred, struct uidinfo *ruip)
2377f535380cSDon Lewis {
2378f535380cSDon Lewis 
2379b1fc0ec1SRobert Watson 	(void)chgproccnt(newcred->cr_ruidinfo, -1, 0);
23801419eacbSAlfred Perlstein 	newcred->cr_ruid = ruip->ui_uid;
23811419eacbSAlfred Perlstein 	uihold(ruip);
2382b1fc0ec1SRobert Watson 	uifree(newcred->cr_ruidinfo);
23831419eacbSAlfred Perlstein 	newcred->cr_ruidinfo = ruip;
2384b1fc0ec1SRobert Watson 	(void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
2385b1fc0ec1SRobert Watson }
2386b1fc0ec1SRobert Watson 
23871a996ed1SEdward Tomasz Napierala /*-
23887fd6a959SRobert Watson  * Change a process's real gid.
2389b1fc0ec1SRobert Watson  * Side effects: newcred->cr_rgid will be updated.
2390b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2391b1fc0ec1SRobert Watson  *             duration of the call.
2392b1fc0ec1SRobert Watson  */
2393b1fc0ec1SRobert Watson void
23944c44ad8eSJohn Baldwin change_rgid(struct ucred *newcred, gid_t rgid)
2395b1fc0ec1SRobert Watson {
2396b1fc0ec1SRobert Watson 
2397b1fc0ec1SRobert Watson 	newcred->cr_rgid = rgid;
2398b1fc0ec1SRobert Watson }
2399b1fc0ec1SRobert Watson 
24001a996ed1SEdward Tomasz Napierala /*-
24017fd6a959SRobert Watson  * Change a process's saved uid.
2402b1fc0ec1SRobert Watson  * Side effects: newcred->cr_svuid will be updated.
2403b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2404b1fc0ec1SRobert Watson  *             duration of the call.
2405b1fc0ec1SRobert Watson  */
2406b1fc0ec1SRobert Watson void
24074c44ad8eSJohn Baldwin change_svuid(struct ucred *newcred, uid_t svuid)
2408b1fc0ec1SRobert Watson {
2409b1fc0ec1SRobert Watson 
2410b1fc0ec1SRobert Watson 	newcred->cr_svuid = svuid;
2411b1fc0ec1SRobert Watson }
2412b1fc0ec1SRobert Watson 
24131a996ed1SEdward Tomasz Napierala /*-
24147fd6a959SRobert Watson  * Change a process's saved gid.
2415b1fc0ec1SRobert Watson  * Side effects: newcred->cr_svgid will be updated.
2416b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2417b1fc0ec1SRobert Watson  *             duration of the call.
2418b1fc0ec1SRobert Watson  */
2419b1fc0ec1SRobert Watson void
24204c44ad8eSJohn Baldwin change_svgid(struct ucred *newcred, gid_t svgid)
2421b1fc0ec1SRobert Watson {
2422b1fc0ec1SRobert Watson 
2423b1fc0ec1SRobert Watson 	newcred->cr_svgid = svgid;
2424f535380cSDon Lewis }
2425