xref: /freebsd/sys/kern/kern_prot.c (revision fe6db727081936c43250f97a4ff4b9de20eb0091)
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>
61*fe6db727SKonstantin Belousov #include <sys/ptrace.h>
627e9e371fSJohn Baldwin #include <sys/refcount.h>
635b29d6e9SJohn Baldwin #include <sys/sx.h>
64800c9408SRobert Watson #include <sys/priv.h>
65f591779bSSeigo Tanimura #include <sys/proc.h>
667e097daaSKonstantin Belousov #include <sys/sysent.h>
67fb919e4dSMark Murray #include <sys/sysproto.h>
68eb725b4eSRobert Watson #include <sys/jail.h>
69e4dcb704SEdward Tomasz Napierala #include <sys/racct.h>
70f87beb93SAndriy Gapon #include <sys/rctl.h>
71f535380cSDon Lewis #include <sys/resourcevar.h>
7229dc1288SRobert Watson #include <sys/socket.h>
7329dc1288SRobert Watson #include <sys/socketvar.h>
743cb83e71SJohn Baldwin #include <sys/syscallsubr.h>
75579f4eb4SRobert Watson #include <sys/sysctl.h>
76df8bae1dSRodney W. Grimes 
77de5b1952SAlexander Leidinger #ifdef REGRESSION
78de5b1952SAlexander Leidinger FEATURE(regression,
79ca54e1aeSHiroki Sato     "Kernel support for interfaces necessary for regression testing (SECURITY RISK!)");
80de5b1952SAlexander Leidinger #endif
81de5b1952SAlexander Leidinger 
822f8a46d5SWayne Salamon #include <security/audit/audit.h>
83aed55708SRobert Watson #include <security/mac/mac_framework.h>
842f8a46d5SWayne Salamon 
85a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_CRED, "cred", "credentials");
86a1c995b6SPoul-Henning Kamp 
877029da5cSPawel Biernacki SYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
887029da5cSPawel Biernacki     "BSD security policy");
8948713bdcSRobert Watson 
90f34a2f56SMateusz Guzik static void crfree_final(struct ucred *cr);
91838d9858SBrooks Davis static void crsetgroups_locked(struct ucred *cr, int ngrp,
92838d9858SBrooks Davis     gid_t *groups);
93838d9858SBrooks Davis 
94d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
95ad7507e2SSteven Wallace struct getpid_args {
96df8bae1dSRodney W. Grimes 	int	dummy;
97df8bae1dSRodney W. Grimes };
98d2d3e875SBruce Evans #endif
99df8bae1dSRodney W. Grimes /* ARGSUSED */
10026f9a767SRodney W. Grimes int
1018451d0ddSKip Macy sys_getpid(struct thread *td, struct getpid_args *uap)
102df8bae1dSRodney W. Grimes {
103b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
104df8bae1dSRodney W. Grimes 
105b40ce416SJulian Elischer 	td->td_retval[0] = p->p_pid;
1061930e303SPoul-Henning Kamp #if defined(COMPAT_43)
1077e097daaSKonstantin Belousov 	if (SV_PROC_FLAG(p, SV_AOUT))
108abd386baSMateusz Guzik 		td->td_retval[1] = kern_getppid(td);
109df8bae1dSRodney W. Grimes #endif
110df8bae1dSRodney W. Grimes 	return (0);
111df8bae1dSRodney W. Grimes }
112df8bae1dSRodney W. Grimes 
113d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
114ad7507e2SSteven Wallace struct getppid_args {
115ad7507e2SSteven Wallace         int     dummy;
116ad7507e2SSteven Wallace };
117d2d3e875SBruce Evans #endif
118df8bae1dSRodney W. Grimes /* ARGSUSED */
11926f9a767SRodney W. Grimes int
1208451d0ddSKip Macy sys_getppid(struct thread *td, struct getppid_args *uap)
121df8bae1dSRodney W. Grimes {
122abd386baSMateusz Guzik 
123abd386baSMateusz Guzik 	td->td_retval[0] = kern_getppid(td);
124abd386baSMateusz Guzik 	return (0);
125abd386baSMateusz Guzik }
126abd386baSMateusz Guzik 
127abd386baSMateusz Guzik int
128abd386baSMateusz Guzik kern_getppid(struct thread *td)
129abd386baSMateusz Guzik {
130b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
131df8bae1dSRodney W. Grimes 
1322c054ce9SMateusz Guzik 	return (p->p_oppid);
133df8bae1dSRodney W. Grimes }
134df8bae1dSRodney W. Grimes 
13536e9f877SMatthew Dillon /*
136eb725b4eSRobert Watson  * Get process group ID; note that POSIX getpgrp takes no parameter.
13736e9f877SMatthew Dillon  */
138d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
139ad7507e2SSteven Wallace struct getpgrp_args {
140ad7507e2SSteven Wallace         int     dummy;
141ad7507e2SSteven Wallace };
142d2d3e875SBruce Evans #endif
14326f9a767SRodney W. Grimes int
1448451d0ddSKip Macy sys_getpgrp(struct thread *td, struct getpgrp_args *uap)
145df8bae1dSRodney W. Grimes {
146b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
147df8bae1dSRodney W. Grimes 
148f591779bSSeigo Tanimura 	PROC_LOCK(p);
149b40ce416SJulian Elischer 	td->td_retval[0] = p->p_pgrp->pg_id;
150f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
151df8bae1dSRodney W. Grimes 	return (0);
152df8bae1dSRodney W. Grimes }
153df8bae1dSRodney W. Grimes 
154e3043798SPedro F. Giffuni /* Get an arbitrary pid's process group id */
1551a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1561a5018a0SPeter Wemm struct getpgid_args {
1571a5018a0SPeter Wemm 	pid_t	pid;
1581a5018a0SPeter Wemm };
1591a5018a0SPeter Wemm #endif
1601a5018a0SPeter Wemm int
1618451d0ddSKip Macy sys_getpgid(struct thread *td, struct getpgid_args *uap)
1621a5018a0SPeter Wemm {
163a70a2b74SJohn Baldwin 	struct proc *p;
164f2ae7368SJohn Baldwin 	int error;
16565de0c7aSDon Lewis 
166f591779bSSeigo Tanimura 	if (uap->pid == 0) {
167a70a2b74SJohn Baldwin 		p = td->td_proc;
168f591779bSSeigo Tanimura 		PROC_LOCK(p);
169a70a2b74SJohn Baldwin 	} else {
170a70a2b74SJohn Baldwin 		p = pfind(uap->pid);
171a70a2b74SJohn Baldwin 		if (p == NULL)
172a70a2b74SJohn Baldwin 			return (ESRCH);
173a70a2b74SJohn Baldwin 		error = p_cansee(td, p);
174a70a2b74SJohn Baldwin 		if (error) {
175a70a2b74SJohn Baldwin 			PROC_UNLOCK(p);
176a70a2b74SJohn Baldwin 			return (error);
177a70a2b74SJohn Baldwin 		}
178a70a2b74SJohn Baldwin 	}
179b40ce416SJulian Elischer 	td->td_retval[0] = p->p_pgrp->pg_id;
180f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
181a70a2b74SJohn Baldwin 	return (0);
1821a5018a0SPeter Wemm }
1831a5018a0SPeter Wemm 
1841a5018a0SPeter Wemm /*
185e3043798SPedro F. Giffuni  * Get an arbitrary pid's session id.
1861a5018a0SPeter Wemm  */
1871a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1881a5018a0SPeter Wemm struct getsid_args {
1891a5018a0SPeter Wemm 	pid_t	pid;
1901a5018a0SPeter Wemm };
1911a5018a0SPeter Wemm #endif
1921a5018a0SPeter Wemm int
1938451d0ddSKip Macy sys_getsid(struct thread *td, struct getsid_args *uap)
1941a5018a0SPeter Wemm {
195be2cfdbcSEdward Tomasz Napierala 
196be2cfdbcSEdward Tomasz Napierala 	return (kern_getsid(td, uap->pid));
197be2cfdbcSEdward Tomasz Napierala }
198be2cfdbcSEdward Tomasz Napierala 
199be2cfdbcSEdward Tomasz Napierala int
200be2cfdbcSEdward Tomasz Napierala kern_getsid(struct thread *td, pid_t pid)
201be2cfdbcSEdward Tomasz Napierala {
202a70a2b74SJohn Baldwin 	struct proc *p;
203eb725b4eSRobert Watson 	int error;
20465de0c7aSDon Lewis 
205be2cfdbcSEdward Tomasz Napierala 	if (pid == 0) {
206a70a2b74SJohn Baldwin 		p = td->td_proc;
207f591779bSSeigo Tanimura 		PROC_LOCK(p);
208a70a2b74SJohn Baldwin 	} else {
209be2cfdbcSEdward Tomasz Napierala 		p = pfind(pid);
210a70a2b74SJohn Baldwin 		if (p == NULL)
211a70a2b74SJohn Baldwin 			return (ESRCH);
212a70a2b74SJohn Baldwin 		error = p_cansee(td, p);
213a70a2b74SJohn Baldwin 		if (error) {
214a70a2b74SJohn Baldwin 			PROC_UNLOCK(p);
215a70a2b74SJohn Baldwin 			return (error);
216a70a2b74SJohn Baldwin 		}
217a70a2b74SJohn Baldwin 	}
218b40ce416SJulian Elischer 	td->td_retval[0] = p->p_session->s_sid;
219f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
220a70a2b74SJohn Baldwin 	return (0);
2211a5018a0SPeter Wemm }
2221a5018a0SPeter Wemm 
223d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
224ad7507e2SSteven Wallace struct getuid_args {
225ad7507e2SSteven Wallace         int     dummy;
226ad7507e2SSteven Wallace };
227d2d3e875SBruce Evans #endif
228df8bae1dSRodney W. Grimes /* ARGSUSED */
22926f9a767SRodney W. Grimes int
2308451d0ddSKip Macy sys_getuid(struct thread *td, struct getuid_args *uap)
231df8bae1dSRodney W. Grimes {
232df8bae1dSRodney W. Grimes 
233d846883bSJohn Baldwin 	td->td_retval[0] = td->td_ucred->cr_ruid;
2341930e303SPoul-Henning Kamp #if defined(COMPAT_43)
235d846883bSJohn Baldwin 	td->td_retval[1] = td->td_ucred->cr_uid;
236df8bae1dSRodney W. Grimes #endif
237df8bae1dSRodney W. Grimes 	return (0);
238df8bae1dSRodney W. Grimes }
239df8bae1dSRodney W. Grimes 
240d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
241ad7507e2SSteven Wallace struct geteuid_args {
242ad7507e2SSteven Wallace         int     dummy;
243ad7507e2SSteven Wallace };
244d2d3e875SBruce Evans #endif
245df8bae1dSRodney W. Grimes /* ARGSUSED */
24626f9a767SRodney W. Grimes int
2478451d0ddSKip Macy sys_geteuid(struct thread *td, struct geteuid_args *uap)
248df8bae1dSRodney W. Grimes {
249d846883bSJohn Baldwin 
250d846883bSJohn Baldwin 	td->td_retval[0] = td->td_ucred->cr_uid;
251df8bae1dSRodney W. Grimes 	return (0);
252df8bae1dSRodney W. Grimes }
253df8bae1dSRodney W. Grimes 
254d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
255ad7507e2SSteven Wallace struct getgid_args {
256ad7507e2SSteven Wallace         int     dummy;
257ad7507e2SSteven Wallace };
258d2d3e875SBruce Evans #endif
259df8bae1dSRodney W. Grimes /* ARGSUSED */
26026f9a767SRodney W. Grimes int
2618451d0ddSKip Macy sys_getgid(struct thread *td, struct getgid_args *uap)
262df8bae1dSRodney W. Grimes {
263df8bae1dSRodney W. Grimes 
264d846883bSJohn Baldwin 	td->td_retval[0] = td->td_ucred->cr_rgid;
2651930e303SPoul-Henning Kamp #if defined(COMPAT_43)
266d846883bSJohn Baldwin 	td->td_retval[1] = td->td_ucred->cr_groups[0];
267df8bae1dSRodney W. Grimes #endif
268df8bae1dSRodney W. Grimes 	return (0);
269df8bae1dSRodney W. Grimes }
270df8bae1dSRodney W. Grimes 
271df8bae1dSRodney W. Grimes /*
272df8bae1dSRodney W. Grimes  * Get effective group ID.  The "egid" is groups[0], and could be obtained
273df8bae1dSRodney W. Grimes  * via getgroups.  This syscall exists because it is somewhat painful to do
274df8bae1dSRodney W. Grimes  * correctly in a library function.
275df8bae1dSRodney W. Grimes  */
276d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
277ad7507e2SSteven Wallace struct getegid_args {
278ad7507e2SSteven Wallace         int     dummy;
279ad7507e2SSteven Wallace };
280d2d3e875SBruce Evans #endif
281df8bae1dSRodney W. Grimes /* ARGSUSED */
28226f9a767SRodney W. Grimes int
2838451d0ddSKip Macy sys_getegid(struct thread *td, struct getegid_args *uap)
284df8bae1dSRodney W. Grimes {
285df8bae1dSRodney W. Grimes 
286d846883bSJohn Baldwin 	td->td_retval[0] = td->td_ucred->cr_groups[0];
287df8bae1dSRodney W. Grimes 	return (0);
288df8bae1dSRodney W. Grimes }
289df8bae1dSRodney W. Grimes 
290d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
291df8bae1dSRodney W. Grimes struct getgroups_args {
2924bc2174aSMoritz Buhl 	int	gidsetsize;
293df8bae1dSRodney W. Grimes 	gid_t	*gidset;
294df8bae1dSRodney W. Grimes };
295d2d3e875SBruce Evans #endif
29626f9a767SRodney W. Grimes int
2973e85b721SEd Maste sys_getgroups(struct thread *td, struct getgroups_args *uap)
298df8bae1dSRodney W. Grimes {
29907b384cbSMateusz Guzik 	struct ucred *cred;
3004bc2174aSMoritz Buhl 	int ngrp, error;
301df8bae1dSRodney W. Grimes 
3023cb83e71SJohn Baldwin 	cred = td->td_ucred;
30307b384cbSMateusz Guzik 	ngrp = cred->cr_ngroups;
30407b384cbSMateusz Guzik 
30507b384cbSMateusz Guzik 	if (uap->gidsetsize == 0) {
30607b384cbSMateusz Guzik 		error = 0;
30707b384cbSMateusz Guzik 		goto out;
3083cb83e71SJohn Baldwin 	}
30907b384cbSMateusz Guzik 	if (uap->gidsetsize < ngrp)
3103cb83e71SJohn Baldwin 		return (EINVAL);
31107b384cbSMateusz Guzik 
31207b384cbSMateusz Guzik 	error = copyout(cred->cr_groups, uap->gidset, ngrp * sizeof(gid_t));
31307b384cbSMateusz Guzik out:
31407b384cbSMateusz Guzik 	td->td_retval[0] = ngrp;
31507b384cbSMateusz Guzik 	return (error);
3163cb83e71SJohn Baldwin }
3173cb83e71SJohn Baldwin 
318d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
31982970b81SBruce Evans struct setsid_args {
320ad7507e2SSteven Wallace         int     dummy;
321ad7507e2SSteven Wallace };
322d2d3e875SBruce Evans #endif
323df8bae1dSRodney W. Grimes /* ARGSUSED */
32426f9a767SRodney W. Grimes int
3253e85b721SEd Maste sys_setsid(struct thread *td, struct setsid_args *uap)
326df8bae1dSRodney W. Grimes {
327f591779bSSeigo Tanimura 	struct pgrp *pgrp;
328835a82eeSMatthew Dillon 	int error;
329b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
330f591779bSSeigo Tanimura 	struct pgrp *newpgrp;
331f591779bSSeigo Tanimura 	struct session *newsess;
332f591779bSSeigo Tanimura 
333f591779bSSeigo Tanimura 	error = 0;
334f591779bSSeigo Tanimura 	pgrp = NULL;
335df8bae1dSRodney W. Grimes 
336ef739c73SKonstantin Belousov 	newpgrp = uma_zalloc(pgrp_zone, M_WAITOK);
3371ede983cSDag-Erling Smørgrav 	newsess = malloc(sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO);
338f591779bSSeigo Tanimura 
339c8b1829dSJohn Baldwin 	sx_xlock(&proctree_lock);
340f591779bSSeigo Tanimura 
341f591779bSSeigo Tanimura 	if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) {
342f591779bSSeigo Tanimura 		if (pgrp != NULL)
343f591779bSSeigo Tanimura 			PGRP_UNLOCK(pgrp);
344835a82eeSMatthew Dillon 		error = EPERM;
345f591779bSSeigo Tanimura 	} else {
346f591779bSSeigo Tanimura 		(void)enterpgrp(p, p->p_pid, newpgrp, newsess);
347b40ce416SJulian Elischer 		td->td_retval[0] = p->p_pid;
348c8b1829dSJohn Baldwin 		newpgrp = NULL;
349c8b1829dSJohn Baldwin 		newsess = NULL;
350df8bae1dSRodney W. Grimes 	}
351f591779bSSeigo Tanimura 
352c8b1829dSJohn Baldwin 	sx_xunlock(&proctree_lock);
353f591779bSSeigo Tanimura 
354ef739c73SKonstantin Belousov 	uma_zfree(pgrp_zone, newpgrp);
3551ede983cSDag-Erling Smørgrav 	free(newsess, M_SESSION);
3561c2451c2SSeigo Tanimura 
357c8b1829dSJohn Baldwin 	return (error);
358df8bae1dSRodney W. Grimes }
359df8bae1dSRodney W. Grimes 
360df8bae1dSRodney W. Grimes /*
361df8bae1dSRodney W. Grimes  * set process group (setpgid/old setpgrp)
362df8bae1dSRodney W. Grimes  *
363df8bae1dSRodney W. Grimes  * caller does setpgid(targpid, targpgid)
364df8bae1dSRodney W. Grimes  *
365df8bae1dSRodney W. Grimes  * pid must be caller or child of caller (ESRCH)
366df8bae1dSRodney W. Grimes  * if a child
367df8bae1dSRodney W. Grimes  *	pid must be in same session (EPERM)
368df8bae1dSRodney W. Grimes  *	pid can't have done an exec (EACCES)
369df8bae1dSRodney W. Grimes  * if pgid != pid
370df8bae1dSRodney W. Grimes  * 	there must exist some pid in same session having pgid (EPERM)
371df8bae1dSRodney W. Grimes  * pid must not be session leader (EPERM)
372df8bae1dSRodney W. Grimes  */
373d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
374df8bae1dSRodney W. Grimes struct setpgid_args {
375df8bae1dSRodney W. Grimes 	int	pid;		/* target process id */
376df8bae1dSRodney W. Grimes 	int	pgid;		/* target pgrp id */
377df8bae1dSRodney W. Grimes };
378d2d3e875SBruce Evans #endif
379df8bae1dSRodney W. Grimes /* ARGSUSED */
38026f9a767SRodney W. Grimes int
3813e85b721SEd Maste sys_setpgid(struct thread *td, struct setpgid_args *uap)
382df8bae1dSRodney W. Grimes {
383b40ce416SJulian Elischer 	struct proc *curp = td->td_proc;
3843e85b721SEd Maste 	struct proc *targp;	/* target process */
3853e85b721SEd Maste 	struct pgrp *pgrp;	/* target pgrp */
386eb9e5c1dSRobert Watson 	int error;
387f591779bSSeigo Tanimura 	struct pgrp *newpgrp;
388df8bae1dSRodney W. Grimes 
38978f64bccSBruce Evans 	if (uap->pgid < 0)
39078f64bccSBruce Evans 		return (EINVAL);
391f591779bSSeigo Tanimura 
392f591779bSSeigo Tanimura 	error = 0;
393f591779bSSeigo Tanimura 
394ef739c73SKonstantin Belousov 	newpgrp = uma_zalloc(pgrp_zone, M_WAITOK);
395f591779bSSeigo Tanimura 
396c8b1829dSJohn Baldwin 	sx_xlock(&proctree_lock);
397df8bae1dSRodney W. Grimes 	if (uap->pid != 0 && uap->pid != curp->p_pid) {
398f591779bSSeigo Tanimura 		if ((targp = pfind(uap->pid)) == NULL) {
399835a82eeSMatthew Dillon 			error = ESRCH;
400c8b1829dSJohn Baldwin 			goto done;
40133a9ed9dSJohn Baldwin 		}
402f591779bSSeigo Tanimura 		if (!inferior(targp)) {
403f591779bSSeigo Tanimura 			PROC_UNLOCK(targp);
4042f932587SSeigo Tanimura 			error = ESRCH;
405c8b1829dSJohn Baldwin 			goto done;
406f591779bSSeigo Tanimura 		}
40771a057bcSRobert Watson 		if ((error = p_cansee(td, targp))) {
40833a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
409c8b1829dSJohn Baldwin 			goto done;
41033a9ed9dSJohn Baldwin 		}
41133a9ed9dSJohn Baldwin 		if (targp->p_pgrp == NULL ||
41233a9ed9dSJohn Baldwin 		    targp->p_session != curp->p_session) {
41333a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
414835a82eeSMatthew Dillon 			error = EPERM;
415c8b1829dSJohn Baldwin 			goto done;
41633a9ed9dSJohn Baldwin 		}
41733a9ed9dSJohn Baldwin 		if (targp->p_flag & P_EXEC) {
41833a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
419835a82eeSMatthew Dillon 			error = EACCES;
420c8b1829dSJohn Baldwin 			goto done;
42133a9ed9dSJohn Baldwin 		}
42233a9ed9dSJohn Baldwin 		PROC_UNLOCK(targp);
423f591779bSSeigo Tanimura 	} else
424f591779bSSeigo Tanimura 		targp = curp;
425f591779bSSeigo Tanimura 	if (SESS_LEADER(targp)) {
426835a82eeSMatthew Dillon 		error = EPERM;
427c8b1829dSJohn Baldwin 		goto done;
42833a9ed9dSJohn Baldwin 	}
429eb725b4eSRobert Watson 	if (uap->pgid == 0)
430df8bae1dSRodney W. Grimes 		uap->pgid = targp->p_pid;
431a10d5f02SOlivier Houchard 	if ((pgrp = pgfind(uap->pgid)) == NULL) {
432f591779bSSeigo Tanimura 		if (uap->pgid == targp->p_pid) {
433a10d5f02SOlivier Houchard 			error = enterpgrp(targp, uap->pgid, newpgrp,
434a10d5f02SOlivier Houchard 			    NULL);
435f591779bSSeigo Tanimura 			if (error == 0)
436f591779bSSeigo Tanimura 				newpgrp = NULL;
437a10d5f02SOlivier Houchard 		} else
438835a82eeSMatthew Dillon 			error = EPERM;
439a10d5f02SOlivier Houchard 	} else {
440f591779bSSeigo Tanimura 		if (pgrp == targp->p_pgrp) {
441f591779bSSeigo Tanimura 			PGRP_UNLOCK(pgrp);
442f591779bSSeigo Tanimura 			goto done;
44333a9ed9dSJohn Baldwin 		}
444a10d5f02SOlivier Houchard 		if (pgrp->pg_id != targp->p_pid &&
445a10d5f02SOlivier Houchard 		    pgrp->pg_session != curp->p_session) {
446a10d5f02SOlivier Houchard 			PGRP_UNLOCK(pgrp);
447a10d5f02SOlivier Houchard 			error = EPERM;
448a10d5f02SOlivier Houchard 			goto done;
449a10d5f02SOlivier Houchard 		}
450f591779bSSeigo Tanimura 		PGRP_UNLOCK(pgrp);
451f591779bSSeigo Tanimura 		error = enterthispgrp(targp, pgrp);
452f591779bSSeigo Tanimura 	}
453f591779bSSeigo Tanimura done:
454c8b1829dSJohn Baldwin 	sx_xunlock(&proctree_lock);
455c8b1829dSJohn Baldwin 	KASSERT((error == 0) || (newpgrp != NULL),
456c8b1829dSJohn Baldwin 	    ("setpgid failed and newpgrp is NULL"));
457ef739c73SKonstantin Belousov 	uma_zfree(pgrp_zone, newpgrp);
458835a82eeSMatthew Dillon 	return (error);
459df8bae1dSRodney W. Grimes }
460df8bae1dSRodney W. Grimes 
461a08f4bf6SPeter Wemm /*
462a08f4bf6SPeter Wemm  * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
4632fa72ea7SJeroen Ruigrok van der Werven  * compatible.  It says that setting the uid/gid to euid/egid is a special
464a08f4bf6SPeter Wemm  * case of "appropriate privilege".  Once the rules are expanded out, this
465a08f4bf6SPeter Wemm  * basically means that setuid(nnn) sets all three id's, in all permitted
466a08f4bf6SPeter Wemm  * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
467a08f4bf6SPeter Wemm  * does not set the saved id - this is dangerous for traditional BSD
468a08f4bf6SPeter Wemm  * programs.  For this reason, we *really* do not want to set
469a08f4bf6SPeter Wemm  * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
470a08f4bf6SPeter Wemm  */
471a08f4bf6SPeter Wemm #define POSIX_APPENDIX_B_4_2_2
472a08f4bf6SPeter Wemm 
473d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
474df8bae1dSRodney W. Grimes struct setuid_args {
475df8bae1dSRodney W. Grimes 	uid_t	uid;
476df8bae1dSRodney W. Grimes };
477d2d3e875SBruce Evans #endif
478df8bae1dSRodney W. Grimes /* ARGSUSED */
47926f9a767SRodney W. Grimes int
4808451d0ddSKip Macy sys_setuid(struct thread *td, struct setuid_args *uap)
481df8bae1dSRodney W. Grimes {
482b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
483b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
484b1fc0ec1SRobert Watson 	uid_t uid;
4851419eacbSAlfred Perlstein 	struct uidinfo *uip;
486eb725b4eSRobert Watson 	int error;
487df8bae1dSRodney W. Grimes 
48807f3485dSJohn Baldwin 	uid = uap->uid;
48914961ba7SRobert Watson 	AUDIT_ARG_UID(uid);
49007f3485dSJohn Baldwin 	newcred = crget();
4911419eacbSAlfred Perlstein 	uip = uifind(uid);
49207f3485dSJohn Baldwin 	PROC_LOCK(p);
493838d9858SBrooks Davis 	/*
494838d9858SBrooks Davis 	 * Copy credentials so other references do not see our changes.
495838d9858SBrooks Davis 	 */
496838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
4975a92ee3cSRobert Watson 
498030a28b3SRobert Watson #ifdef MAC
4996f6174a7SRobert Watson 	error = mac_cred_check_setuid(oldcred, uid);
500030a28b3SRobert Watson 	if (error)
501030a28b3SRobert Watson 		goto fail;
502030a28b3SRobert Watson #endif
503030a28b3SRobert Watson 
504a08f4bf6SPeter Wemm 	/*
505a08f4bf6SPeter Wemm 	 * See if we have "permission" by POSIX 1003.1 rules.
506a08f4bf6SPeter Wemm 	 *
507a08f4bf6SPeter Wemm 	 * Note that setuid(geteuid()) is a special case of
508a08f4bf6SPeter Wemm 	 * "appropriate privileges" in appendix B.4.2.2.  We need
5092fa72ea7SJeroen Ruigrok van der Werven 	 * to use this clause to be compatible with traditional BSD
510a08f4bf6SPeter Wemm 	 * semantics.  Basically, it means that "setuid(xx)" sets all
511a08f4bf6SPeter Wemm 	 * three id's (assuming you have privs).
512a08f4bf6SPeter Wemm 	 *
513a08f4bf6SPeter Wemm 	 * Notes on the logic.  We do things in three steps.
514a08f4bf6SPeter Wemm 	 * 1: We determine if the euid is going to change, and do EPERM
515a08f4bf6SPeter Wemm 	 *    right away.  We unconditionally change the euid later if this
516a08f4bf6SPeter Wemm 	 *    test is satisfied, simplifying that part of the logic.
517eb725b4eSRobert Watson 	 * 2: We determine if the real and/or saved uids are going to
518a08f4bf6SPeter Wemm 	 *    change.  Determined by compile options.
519a08f4bf6SPeter Wemm 	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
520a08f4bf6SPeter Wemm 	 */
521b1fc0ec1SRobert Watson 	if (uid != oldcred->cr_ruid &&		/* allow setuid(getuid()) */
5223f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS
523b1fc0ec1SRobert Watson 	    uid != oldcred->cr_svuid &&		/* allow setuid(saved gid) */
524a08f4bf6SPeter Wemm #endif
525a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
526b1fc0ec1SRobert Watson 	    uid != oldcred->cr_uid &&		/* allow setuid(geteuid()) */
5273f246666SAndrey A. Chernov #endif
528cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETUID)) != 0)
529030a28b3SRobert Watson 		goto fail;
530a08f4bf6SPeter Wemm 
531a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS
532df8bae1dSRodney W. Grimes 	/*
533a08f4bf6SPeter Wemm 	 * Do we have "appropriate privileges" (are we root or uid == euid)
534a08f4bf6SPeter Wemm 	 * If so, we are changing the real uid and/or saved uid.
535df8bae1dSRodney W. Grimes 	 */
5363f246666SAndrey A. Chernov 	if (
537a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
538b1fc0ec1SRobert Watson 	    uid == oldcred->cr_uid ||
5393f246666SAndrey A. Chernov #endif
540800c9408SRobert Watson 	    /* We are using privs. */
541cc426dd3SMateusz Guzik 	    priv_check_cred(oldcred, PRIV_CRED_SETUID) == 0)
542a08f4bf6SPeter Wemm #endif
543a08f4bf6SPeter Wemm 	{
544a08f4bf6SPeter Wemm 		/*
545f535380cSDon Lewis 		 * Set the real uid and transfer proc count to new user.
546a08f4bf6SPeter Wemm 		 */
547b1fc0ec1SRobert Watson 		if (uid != oldcred->cr_ruid) {
5481419eacbSAlfred Perlstein 			change_ruid(newcred, uip);
549f535380cSDon Lewis 			setsugid(p);
550d3cdb93dSAndrey A. Chernov 		}
551a08f4bf6SPeter Wemm 		/*
552a08f4bf6SPeter Wemm 		 * Set saved uid
553a08f4bf6SPeter Wemm 		 *
554a08f4bf6SPeter Wemm 		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
555a08f4bf6SPeter Wemm 		 * the security of seteuid() depends on it.  B.4.2.2 says it
556a08f4bf6SPeter Wemm 		 * is important that we should do this.
557a08f4bf6SPeter Wemm 		 */
558b1fc0ec1SRobert Watson 		if (uid != oldcred->cr_svuid) {
559b1fc0ec1SRobert Watson 			change_svuid(newcred, uid);
560d5f81602SSean Eric Fagan 			setsugid(p);
561a08f4bf6SPeter Wemm 		}
562a08f4bf6SPeter Wemm 	}
563a08f4bf6SPeter Wemm 
564a08f4bf6SPeter Wemm 	/*
565a08f4bf6SPeter Wemm 	 * In all permitted cases, we are changing the euid.
566a08f4bf6SPeter Wemm 	 */
567b1fc0ec1SRobert Watson 	if (uid != oldcred->cr_uid) {
5681419eacbSAlfred Perlstein 		change_euid(newcred, uip);
569d5f81602SSean Eric Fagan 		setsugid(p);
570a08f4bf6SPeter Wemm 	}
571daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
572e4dcb704SEdward Tomasz Napierala #ifdef RACCT
573e4dcb704SEdward Tomasz Napierala 	racct_proc_ucred_changed(p, oldcred, newcred);
574f87beb93SAndriy Gapon 	crhold(newcred);
575f87beb93SAndriy Gapon #endif
576f87beb93SAndriy Gapon 	PROC_UNLOCK(p);
577f87beb93SAndriy Gapon #ifdef RCTL
578f87beb93SAndriy Gapon 	rctl_proc_ucred_changed(p, newcred);
579f87beb93SAndriy Gapon 	crfree(newcred);
580e4dcb704SEdward Tomasz Napierala #endif
5811419eacbSAlfred Perlstein 	uifree(uip);
582b1fc0ec1SRobert Watson 	crfree(oldcred);
58307f3485dSJohn Baldwin 	return (0);
584030a28b3SRobert Watson 
585030a28b3SRobert Watson fail:
586030a28b3SRobert Watson 	PROC_UNLOCK(p);
587030a28b3SRobert Watson 	uifree(uip);
588030a28b3SRobert Watson 	crfree(newcred);
589030a28b3SRobert Watson 	return (error);
590df8bae1dSRodney W. Grimes }
591df8bae1dSRodney W. Grimes 
592d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
593df8bae1dSRodney W. Grimes struct seteuid_args {
594df8bae1dSRodney W. Grimes 	uid_t	euid;
595df8bae1dSRodney W. Grimes };
596d2d3e875SBruce Evans #endif
597df8bae1dSRodney W. Grimes /* ARGSUSED */
59826f9a767SRodney W. Grimes int
5998451d0ddSKip Macy sys_seteuid(struct thread *td, struct seteuid_args *uap)
600df8bae1dSRodney W. Grimes {
601b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
602b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
603b1fc0ec1SRobert Watson 	uid_t euid;
6041419eacbSAlfred Perlstein 	struct uidinfo *euip;
605eb725b4eSRobert Watson 	int error;
606df8bae1dSRodney W. Grimes 
607df8bae1dSRodney W. Grimes 	euid = uap->euid;
60814961ba7SRobert Watson 	AUDIT_ARG_EUID(euid);
60907f3485dSJohn Baldwin 	newcred = crget();
6101419eacbSAlfred Perlstein 	euip = uifind(euid);
61107f3485dSJohn Baldwin 	PROC_LOCK(p);
612838d9858SBrooks Davis 	/*
613838d9858SBrooks Davis 	 * Copy credentials so other references do not see our changes.
614838d9858SBrooks Davis 	 */
615838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
616030a28b3SRobert Watson 
617030a28b3SRobert Watson #ifdef MAC
6186f6174a7SRobert Watson 	error = mac_cred_check_seteuid(oldcred, euid);
619030a28b3SRobert Watson 	if (error)
620030a28b3SRobert Watson 		goto fail;
621030a28b3SRobert Watson #endif
622030a28b3SRobert Watson 
623b1fc0ec1SRobert Watson 	if (euid != oldcred->cr_ruid &&		/* allow seteuid(getuid()) */
624b1fc0ec1SRobert Watson 	    euid != oldcred->cr_svuid &&	/* allow seteuid(saved uid) */
625cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETEUID)) != 0)
626030a28b3SRobert Watson 		goto fail;
627030a28b3SRobert Watson 
628df8bae1dSRodney W. Grimes 	/*
629838d9858SBrooks Davis 	 * Everything's okay, do it.
630df8bae1dSRodney W. Grimes 	 */
631b1fc0ec1SRobert Watson 	if (oldcred->cr_uid != euid) {
6321419eacbSAlfred Perlstein 		change_euid(newcred, euip);
633d5f81602SSean Eric Fagan 		setsugid(p);
634229a15f0SPeter Wemm 	}
635daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
63607f3485dSJohn Baldwin 	PROC_UNLOCK(p);
6371419eacbSAlfred Perlstein 	uifree(euip);
638b1fc0ec1SRobert Watson 	crfree(oldcred);
63907f3485dSJohn Baldwin 	return (0);
640030a28b3SRobert Watson 
641030a28b3SRobert Watson fail:
642030a28b3SRobert Watson 	PROC_UNLOCK(p);
643030a28b3SRobert Watson 	uifree(euip);
644030a28b3SRobert Watson 	crfree(newcred);
645030a28b3SRobert Watson 	return (error);
646df8bae1dSRodney W. Grimes }
647df8bae1dSRodney W. Grimes 
648d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
649df8bae1dSRodney W. Grimes struct setgid_args {
650df8bae1dSRodney W. Grimes 	gid_t	gid;
651df8bae1dSRodney W. Grimes };
652d2d3e875SBruce Evans #endif
653df8bae1dSRodney W. Grimes /* ARGSUSED */
65426f9a767SRodney W. Grimes int
6558451d0ddSKip Macy sys_setgid(struct thread *td, struct setgid_args *uap)
656df8bae1dSRodney W. Grimes {
657b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
658b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
659b1fc0ec1SRobert Watson 	gid_t gid;
660eb725b4eSRobert Watson 	int error;
661df8bae1dSRodney W. Grimes 
662b1fc0ec1SRobert Watson 	gid = uap->gid;
66314961ba7SRobert Watson 	AUDIT_ARG_GID(gid);
66407f3485dSJohn Baldwin 	newcred = crget();
66507f3485dSJohn Baldwin 	PROC_LOCK(p);
666838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
6675a92ee3cSRobert Watson 
668030a28b3SRobert Watson #ifdef MAC
6696f6174a7SRobert Watson 	error = mac_cred_check_setgid(oldcred, gid);
670030a28b3SRobert Watson 	if (error)
671030a28b3SRobert Watson 		goto fail;
672030a28b3SRobert Watson #endif
673030a28b3SRobert Watson 
674a08f4bf6SPeter Wemm 	/*
675a08f4bf6SPeter Wemm 	 * See if we have "permission" by POSIX 1003.1 rules.
676a08f4bf6SPeter Wemm 	 *
677a08f4bf6SPeter Wemm 	 * Note that setgid(getegid()) is a special case of
678a08f4bf6SPeter Wemm 	 * "appropriate privileges" in appendix B.4.2.2.  We need
6792fa72ea7SJeroen Ruigrok van der Werven 	 * to use this clause to be compatible with traditional BSD
680a08f4bf6SPeter Wemm 	 * semantics.  Basically, it means that "setgid(xx)" sets all
681a08f4bf6SPeter Wemm 	 * three id's (assuming you have privs).
682a08f4bf6SPeter Wemm 	 *
683a08f4bf6SPeter Wemm 	 * For notes on the logic here, see setuid() above.
684a08f4bf6SPeter Wemm 	 */
685b1fc0ec1SRobert Watson 	if (gid != oldcred->cr_rgid &&		/* allow setgid(getgid()) */
6863f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS
687b1fc0ec1SRobert Watson 	    gid != oldcred->cr_svgid &&		/* allow setgid(saved gid) */
688a08f4bf6SPeter Wemm #endif
689a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
690b1fc0ec1SRobert Watson 	    gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */
6913f246666SAndrey A. Chernov #endif
692cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETGID)) != 0)
693030a28b3SRobert Watson 		goto fail;
694a08f4bf6SPeter Wemm 
695a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS
696a08f4bf6SPeter Wemm 	/*
697a08f4bf6SPeter Wemm 	 * Do we have "appropriate privileges" (are we root or gid == egid)
698a08f4bf6SPeter Wemm 	 * If so, we are changing the real uid and saved gid.
699a08f4bf6SPeter Wemm 	 */
700a08f4bf6SPeter Wemm 	if (
701a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
702b1fc0ec1SRobert Watson 	    gid == oldcred->cr_groups[0] ||
703a08f4bf6SPeter Wemm #endif
704800c9408SRobert Watson 	    /* We are using privs. */
705cc426dd3SMateusz Guzik 	    priv_check_cred(oldcred, PRIV_CRED_SETGID) == 0)
706a08f4bf6SPeter Wemm #endif
707a08f4bf6SPeter Wemm 	{
708a08f4bf6SPeter Wemm 		/*
709a08f4bf6SPeter Wemm 		 * Set real gid
710a08f4bf6SPeter Wemm 		 */
711b1fc0ec1SRobert Watson 		if (oldcred->cr_rgid != gid) {
712b1fc0ec1SRobert Watson 			change_rgid(newcred, gid);
713d5f81602SSean Eric Fagan 			setsugid(p);
714a08f4bf6SPeter Wemm 		}
715a08f4bf6SPeter Wemm 		/*
716a08f4bf6SPeter Wemm 		 * Set saved gid
717a08f4bf6SPeter Wemm 		 *
718a08f4bf6SPeter Wemm 		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
719a08f4bf6SPeter Wemm 		 * the security of setegid() depends on it.  B.4.2.2 says it
720a08f4bf6SPeter Wemm 		 * is important that we should do this.
721a08f4bf6SPeter Wemm 		 */
722b1fc0ec1SRobert Watson 		if (oldcred->cr_svgid != gid) {
723b1fc0ec1SRobert Watson 			change_svgid(newcred, gid);
724d5f81602SSean Eric Fagan 			setsugid(p);
725a08f4bf6SPeter Wemm 		}
726a08f4bf6SPeter Wemm 	}
727a08f4bf6SPeter Wemm 	/*
728a08f4bf6SPeter Wemm 	 * In all cases permitted cases, we are changing the egid.
729a08f4bf6SPeter Wemm 	 * Copy credentials so other references do not see our changes.
730a08f4bf6SPeter Wemm 	 */
731b1fc0ec1SRobert Watson 	if (oldcred->cr_groups[0] != gid) {
732b1fc0ec1SRobert Watson 		change_egid(newcred, gid);
733d5f81602SSean Eric Fagan 		setsugid(p);
734a08f4bf6SPeter Wemm 	}
735daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
73607f3485dSJohn Baldwin 	PROC_UNLOCK(p);
737b1fc0ec1SRobert Watson 	crfree(oldcred);
73807f3485dSJohn Baldwin 	return (0);
739030a28b3SRobert Watson 
740030a28b3SRobert Watson fail:
741030a28b3SRobert Watson 	PROC_UNLOCK(p);
742030a28b3SRobert Watson 	crfree(newcred);
743030a28b3SRobert Watson 	return (error);
744df8bae1dSRodney W. Grimes }
745df8bae1dSRodney W. Grimes 
746d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
747df8bae1dSRodney W. Grimes struct setegid_args {
748df8bae1dSRodney W. Grimes 	gid_t	egid;
749df8bae1dSRodney W. Grimes };
750d2d3e875SBruce Evans #endif
751df8bae1dSRodney W. Grimes /* ARGSUSED */
75226f9a767SRodney W. Grimes int
7538451d0ddSKip Macy sys_setegid(struct thread *td, struct setegid_args *uap)
754df8bae1dSRodney W. Grimes {
755b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
756b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
757b1fc0ec1SRobert Watson 	gid_t egid;
758eb725b4eSRobert Watson 	int error;
759df8bae1dSRodney W. Grimes 
760df8bae1dSRodney W. Grimes 	egid = uap->egid;
76114961ba7SRobert Watson 	AUDIT_ARG_EGID(egid);
76207f3485dSJohn Baldwin 	newcred = crget();
76307f3485dSJohn Baldwin 	PROC_LOCK(p);
764838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
765030a28b3SRobert Watson 
766030a28b3SRobert Watson #ifdef MAC
7676f6174a7SRobert Watson 	error = mac_cred_check_setegid(oldcred, egid);
768030a28b3SRobert Watson 	if (error)
769030a28b3SRobert Watson 		goto fail;
770030a28b3SRobert Watson #endif
771030a28b3SRobert Watson 
772b1fc0ec1SRobert Watson 	if (egid != oldcred->cr_rgid &&		/* allow setegid(getgid()) */
773b1fc0ec1SRobert Watson 	    egid != oldcred->cr_svgid &&	/* allow setegid(saved gid) */
774cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETEGID)) != 0)
775030a28b3SRobert Watson 		goto fail;
776030a28b3SRobert Watson 
777b1fc0ec1SRobert Watson 	if (oldcred->cr_groups[0] != egid) {
778b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
779d5f81602SSean Eric Fagan 		setsugid(p);
780229a15f0SPeter Wemm 	}
781daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
78207f3485dSJohn Baldwin 	PROC_UNLOCK(p);
783b1fc0ec1SRobert Watson 	crfree(oldcred);
78407f3485dSJohn Baldwin 	return (0);
785030a28b3SRobert Watson 
786030a28b3SRobert Watson fail:
787030a28b3SRobert Watson 	PROC_UNLOCK(p);
788030a28b3SRobert Watson 	crfree(newcred);
789030a28b3SRobert Watson 	return (error);
790df8bae1dSRodney W. Grimes }
791df8bae1dSRodney W. Grimes 
792d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
793df8bae1dSRodney W. Grimes struct setgroups_args {
7944bc2174aSMoritz Buhl 	int	gidsetsize;
795df8bae1dSRodney W. Grimes 	gid_t	*gidset;
796df8bae1dSRodney W. Grimes };
797d2d3e875SBruce Evans #endif
798df8bae1dSRodney W. Grimes /* ARGSUSED */
79926f9a767SRodney W. Grimes int
8008451d0ddSKip Macy sys_setgroups(struct thread *td, struct setgroups_args *uap)
801df8bae1dSRodney W. Grimes {
80292b064f4SMateusz Guzik 	gid_t smallgroups[XU_NGROUPS];
8037e9a456aSMateusz Guzik 	gid_t *groups;
8044bc2174aSMoritz Buhl 	int gidsetsize, error;
805df8bae1dSRodney W. Grimes 
80692b064f4SMateusz Guzik 	gidsetsize = uap->gidsetsize;
8074bc2174aSMoritz Buhl 	if (gidsetsize > ngroups_max + 1 || gidsetsize < 0)
8083cb83e71SJohn Baldwin 		return (EINVAL);
8097e9a456aSMateusz Guzik 
81092b064f4SMateusz Guzik 	if (gidsetsize > XU_NGROUPS)
81192b064f4SMateusz Guzik 		groups = malloc(gidsetsize * sizeof(gid_t), M_TEMP, M_WAITOK);
81292b064f4SMateusz Guzik 	else
81392b064f4SMateusz Guzik 		groups = smallgroups;
8147e9a456aSMateusz Guzik 
81592b064f4SMateusz Guzik 	error = copyin(uap->gidset, groups, gidsetsize * sizeof(gid_t));
8167e9a456aSMateusz Guzik 	if (error == 0)
81792b064f4SMateusz Guzik 		error = kern_setgroups(td, gidsetsize, groups);
8187e9a456aSMateusz Guzik 
81992b064f4SMateusz Guzik 	if (gidsetsize > XU_NGROUPS)
820838d9858SBrooks Davis 		free(groups, M_TEMP);
8213cb83e71SJohn Baldwin 	return (error);
8223cb83e71SJohn Baldwin }
8233cb83e71SJohn Baldwin 
8243cb83e71SJohn Baldwin int
8253cb83e71SJohn Baldwin kern_setgroups(struct thread *td, u_int ngrp, gid_t *groups)
8263cb83e71SJohn Baldwin {
8273cb83e71SJohn Baldwin 	struct proc *p = td->td_proc;
8283cb83e71SJohn Baldwin 	struct ucred *newcred, *oldcred;
8293cb83e71SJohn Baldwin 	int error;
8303cb83e71SJohn Baldwin 
831b9063886SMateusz Guzik 	MPASS(ngrp <= ngroups_max + 1);
83214961ba7SRobert Watson 	AUDIT_ARG_GROUPSET(groups, ngrp);
83307f3485dSJohn Baldwin 	newcred = crget();
834838d9858SBrooks Davis 	crextend(newcred, ngrp);
83507f3485dSJohn Baldwin 	PROC_LOCK(p);
836838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
837030a28b3SRobert Watson 
838030a28b3SRobert Watson #ifdef MAC
8396f6174a7SRobert Watson 	error = mac_cred_check_setgroups(oldcred, ngrp, groups);
840030a28b3SRobert Watson 	if (error)
841030a28b3SRobert Watson 		goto fail;
842030a28b3SRobert Watson #endif
843030a28b3SRobert Watson 
844cc426dd3SMateusz Guzik 	error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS);
845030a28b3SRobert Watson 	if (error)
846030a28b3SRobert Watson 		goto fail;
84707f3485dSJohn Baldwin 
8487e9a456aSMateusz Guzik 	if (ngrp == 0) {
8498a5d815aSPeter Wemm 		/*
8508a5d815aSPeter Wemm 		 * setgroups(0, NULL) is a legitimate way of clearing the
8518a5d815aSPeter Wemm 		 * groups vector on non-BSD systems (which generally do not
8528a5d815aSPeter Wemm 		 * have the egid in the groups[0]).  We risk security holes
8538a5d815aSPeter Wemm 		 * when running non-BSD software if we do not do the same.
8548a5d815aSPeter Wemm 		 */
855b1fc0ec1SRobert Watson 		newcred->cr_ngroups = 1;
8568a5d815aSPeter Wemm 	} else {
857838d9858SBrooks Davis 		crsetgroups_locked(newcred, ngrp, groups);
8588a5d815aSPeter Wemm 	}
859d5f81602SSean Eric Fagan 	setsugid(p);
860daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
86107f3485dSJohn Baldwin 	PROC_UNLOCK(p);
862b1fc0ec1SRobert Watson 	crfree(oldcred);
86307f3485dSJohn Baldwin 	return (0);
864030a28b3SRobert Watson 
865030a28b3SRobert Watson fail:
866030a28b3SRobert Watson 	PROC_UNLOCK(p);
867030a28b3SRobert Watson 	crfree(newcred);
868030a28b3SRobert Watson 	return (error);
869df8bae1dSRodney W. Grimes }
870df8bae1dSRodney W. Grimes 
871d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
872df8bae1dSRodney W. Grimes struct setreuid_args {
87300999cd6SAndrey A. Chernov 	uid_t	ruid;
87400999cd6SAndrey A. Chernov 	uid_t	euid;
875df8bae1dSRodney W. Grimes };
876d2d3e875SBruce Evans #endif
877df8bae1dSRodney W. Grimes /* ARGSUSED */
87826f9a767SRodney W. Grimes int
8793e85b721SEd Maste sys_setreuid(struct thread *td, struct setreuid_args *uap)
880df8bae1dSRodney W. Grimes {
881b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
882b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
883eb725b4eSRobert Watson 	uid_t euid, ruid;
8841419eacbSAlfred Perlstein 	struct uidinfo *euip, *ruip;
885eb725b4eSRobert Watson 	int error;
886df8bae1dSRodney W. Grimes 
88700999cd6SAndrey A. Chernov 	euid = uap->euid;
888eb725b4eSRobert Watson 	ruid = uap->ruid;
88914961ba7SRobert Watson 	AUDIT_ARG_EUID(euid);
89014961ba7SRobert Watson 	AUDIT_ARG_RUID(ruid);
89107f3485dSJohn Baldwin 	newcred = crget();
8921419eacbSAlfred Perlstein 	euip = uifind(euid);
8931419eacbSAlfred Perlstein 	ruip = uifind(ruid);
89407f3485dSJohn Baldwin 	PROC_LOCK(p);
895838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
896030a28b3SRobert Watson 
897030a28b3SRobert Watson #ifdef MAC
8986f6174a7SRobert Watson 	error = mac_cred_check_setreuid(oldcred, ruid, euid);
899030a28b3SRobert Watson 	if (error)
900030a28b3SRobert Watson 		goto fail;
901030a28b3SRobert Watson #endif
902030a28b3SRobert Watson 
903b1fc0ec1SRobert Watson 	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
904b1fc0ec1SRobert Watson 	      ruid != oldcred->cr_svuid) ||
905b1fc0ec1SRobert Watson 	     (euid != (uid_t)-1 && euid != oldcred->cr_uid &&
906b1fc0ec1SRobert Watson 	      euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) &&
907cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETREUID)) != 0)
908030a28b3SRobert Watson 		goto fail;
909030a28b3SRobert Watson 
910b1fc0ec1SRobert Watson 	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
9111419eacbSAlfred Perlstein 		change_euid(newcred, euip);
912d5f81602SSean Eric Fagan 		setsugid(p);
913a89a5370SPeter Wemm 	}
914b1fc0ec1SRobert Watson 	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
9151419eacbSAlfred Perlstein 		change_ruid(newcred, ruip);
916d5f81602SSean Eric Fagan 		setsugid(p);
91700999cd6SAndrey A. Chernov 	}
918b1fc0ec1SRobert Watson 	if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) &&
919b1fc0ec1SRobert Watson 	    newcred->cr_svuid != newcred->cr_uid) {
920b1fc0ec1SRobert Watson 		change_svuid(newcred, newcred->cr_uid);
921d5f81602SSean Eric Fagan 		setsugid(p);
922a89a5370SPeter Wemm 	}
923daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
924e4dcb704SEdward Tomasz Napierala #ifdef RACCT
925e4dcb704SEdward Tomasz Napierala 	racct_proc_ucred_changed(p, oldcred, newcred);
926f87beb93SAndriy Gapon 	crhold(newcred);
927f87beb93SAndriy Gapon #endif
928f87beb93SAndriy Gapon 	PROC_UNLOCK(p);
929f87beb93SAndriy Gapon #ifdef RCTL
930f87beb93SAndriy Gapon 	rctl_proc_ucred_changed(p, newcred);
931f87beb93SAndriy Gapon 	crfree(newcred);
932e4dcb704SEdward Tomasz Napierala #endif
9331419eacbSAlfred Perlstein 	uifree(ruip);
9341419eacbSAlfred Perlstein 	uifree(euip);
935b1fc0ec1SRobert Watson 	crfree(oldcred);
93607f3485dSJohn Baldwin 	return (0);
937030a28b3SRobert Watson 
938030a28b3SRobert Watson fail:
939030a28b3SRobert Watson 	PROC_UNLOCK(p);
940030a28b3SRobert Watson 	uifree(ruip);
941030a28b3SRobert Watson 	uifree(euip);
942030a28b3SRobert Watson 	crfree(newcred);
943030a28b3SRobert Watson 	return (error);
944df8bae1dSRodney W. Grimes }
945df8bae1dSRodney W. Grimes 
946d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
947df8bae1dSRodney W. Grimes struct setregid_args {
94800999cd6SAndrey A. Chernov 	gid_t	rgid;
94900999cd6SAndrey A. Chernov 	gid_t	egid;
950df8bae1dSRodney W. Grimes };
951d2d3e875SBruce Evans #endif
952df8bae1dSRodney W. Grimes /* ARGSUSED */
95326f9a767SRodney W. Grimes int
9543e85b721SEd Maste sys_setregid(struct thread *td, struct setregid_args *uap)
955df8bae1dSRodney W. Grimes {
956b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
957b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
958eb725b4eSRobert Watson 	gid_t egid, rgid;
959eb725b4eSRobert Watson 	int error;
960df8bae1dSRodney W. Grimes 
96100999cd6SAndrey A. Chernov 	egid = uap->egid;
962eb725b4eSRobert Watson 	rgid = uap->rgid;
96314961ba7SRobert Watson 	AUDIT_ARG_EGID(egid);
96414961ba7SRobert Watson 	AUDIT_ARG_RGID(rgid);
96507f3485dSJohn Baldwin 	newcred = crget();
96607f3485dSJohn Baldwin 	PROC_LOCK(p);
967838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
968030a28b3SRobert Watson 
969030a28b3SRobert Watson #ifdef MAC
9706f6174a7SRobert Watson 	error = mac_cred_check_setregid(oldcred, rgid, egid);
971030a28b3SRobert Watson 	if (error)
972030a28b3SRobert Watson 		goto fail;
973030a28b3SRobert Watson #endif
974030a28b3SRobert Watson 
975b1fc0ec1SRobert Watson 	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
976b1fc0ec1SRobert Watson 	    rgid != oldcred->cr_svgid) ||
977b1fc0ec1SRobert Watson 	     (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] &&
978b1fc0ec1SRobert Watson 	     egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) &&
979cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETREGID)) != 0)
980030a28b3SRobert Watson 		goto fail;
98107f3485dSJohn Baldwin 
982b1fc0ec1SRobert Watson 	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
983b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
984d5f81602SSean Eric Fagan 		setsugid(p);
985a89a5370SPeter Wemm 	}
986b1fc0ec1SRobert Watson 	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
987b1fc0ec1SRobert Watson 		change_rgid(newcred, rgid);
988d5f81602SSean Eric Fagan 		setsugid(p);
989a89a5370SPeter Wemm 	}
990b1fc0ec1SRobert Watson 	if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) &&
991b1fc0ec1SRobert Watson 	    newcred->cr_svgid != newcred->cr_groups[0]) {
992b1fc0ec1SRobert Watson 		change_svgid(newcred, newcred->cr_groups[0]);
993d5f81602SSean Eric Fagan 		setsugid(p);
994a89a5370SPeter Wemm 	}
995daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
99607f3485dSJohn Baldwin 	PROC_UNLOCK(p);
9974589be70SRuslan Ermilov 	crfree(oldcred);
99807f3485dSJohn Baldwin 	return (0);
999030a28b3SRobert Watson 
1000030a28b3SRobert Watson fail:
1001030a28b3SRobert Watson 	PROC_UNLOCK(p);
1002030a28b3SRobert Watson 	crfree(newcred);
1003030a28b3SRobert Watson 	return (error);
1004df8bae1dSRodney W. Grimes }
1005df8bae1dSRodney W. Grimes 
10068ccd6334SPeter Wemm /*
1007873fbcd7SRobert Watson  * setresuid(ruid, euid, suid) is like setreuid except control over the saved
1008873fbcd7SRobert Watson  * uid is explicit.
10098ccd6334SPeter Wemm  */
10108ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
10118ccd6334SPeter Wemm struct setresuid_args {
10128ccd6334SPeter Wemm 	uid_t	ruid;
10138ccd6334SPeter Wemm 	uid_t	euid;
10148ccd6334SPeter Wemm 	uid_t	suid;
10158ccd6334SPeter Wemm };
10168ccd6334SPeter Wemm #endif
10178ccd6334SPeter Wemm /* ARGSUSED */
10188ccd6334SPeter Wemm int
10193e85b721SEd Maste sys_setresuid(struct thread *td, struct setresuid_args *uap)
10208ccd6334SPeter Wemm {
1021b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1022b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
1023eb725b4eSRobert Watson 	uid_t euid, ruid, suid;
10241419eacbSAlfred Perlstein 	struct uidinfo *euip, *ruip;
10258ccd6334SPeter Wemm 	int error;
10268ccd6334SPeter Wemm 
10278ccd6334SPeter Wemm 	euid = uap->euid;
1028eb725b4eSRobert Watson 	ruid = uap->ruid;
10298ccd6334SPeter Wemm 	suid = uap->suid;
103014961ba7SRobert Watson 	AUDIT_ARG_EUID(euid);
103114961ba7SRobert Watson 	AUDIT_ARG_RUID(ruid);
103214961ba7SRobert Watson 	AUDIT_ARG_SUID(suid);
103307f3485dSJohn Baldwin 	newcred = crget();
10341419eacbSAlfred Perlstein 	euip = uifind(euid);
10351419eacbSAlfred Perlstein 	ruip = uifind(ruid);
103607f3485dSJohn Baldwin 	PROC_LOCK(p);
1037838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
1038030a28b3SRobert Watson 
1039030a28b3SRobert Watson #ifdef MAC
10406f6174a7SRobert Watson 	error = mac_cred_check_setresuid(oldcred, ruid, euid, suid);
1041030a28b3SRobert Watson 	if (error)
1042030a28b3SRobert Watson 		goto fail;
1043030a28b3SRobert Watson #endif
1044030a28b3SRobert Watson 
1045b1fc0ec1SRobert Watson 	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
1046b1fc0ec1SRobert Watson 	     ruid != oldcred->cr_svuid &&
1047b1fc0ec1SRobert Watson 	      ruid != oldcred->cr_uid) ||
1048b1fc0ec1SRobert Watson 	     (euid != (uid_t)-1 && euid != oldcred->cr_ruid &&
1049b1fc0ec1SRobert Watson 	    euid != oldcred->cr_svuid &&
1050b1fc0ec1SRobert Watson 	      euid != oldcred->cr_uid) ||
1051b1fc0ec1SRobert Watson 	     (suid != (uid_t)-1 && suid != oldcred->cr_ruid &&
1052b1fc0ec1SRobert Watson 	    suid != oldcred->cr_svuid &&
1053b1fc0ec1SRobert Watson 	      suid != oldcred->cr_uid)) &&
1054cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETRESUID)) != 0)
1055030a28b3SRobert Watson 		goto fail;
105607f3485dSJohn Baldwin 
1057b1fc0ec1SRobert Watson 	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
10581419eacbSAlfred Perlstein 		change_euid(newcred, euip);
10598ccd6334SPeter Wemm 		setsugid(p);
10608ccd6334SPeter Wemm 	}
1061b1fc0ec1SRobert Watson 	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
10621419eacbSAlfred Perlstein 		change_ruid(newcred, ruip);
10638ccd6334SPeter Wemm 		setsugid(p);
10648ccd6334SPeter Wemm 	}
1065b1fc0ec1SRobert Watson 	if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) {
1066b1fc0ec1SRobert Watson 		change_svuid(newcred, suid);
10678ccd6334SPeter Wemm 		setsugid(p);
10688ccd6334SPeter Wemm 	}
1069daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
1070e4dcb704SEdward Tomasz Napierala #ifdef RACCT
1071e4dcb704SEdward Tomasz Napierala 	racct_proc_ucred_changed(p, oldcred, newcred);
1072f87beb93SAndriy Gapon 	crhold(newcred);
1073f87beb93SAndriy Gapon #endif
1074f87beb93SAndriy Gapon 	PROC_UNLOCK(p);
1075f87beb93SAndriy Gapon #ifdef RCTL
1076f87beb93SAndriy Gapon 	rctl_proc_ucred_changed(p, newcred);
1077f87beb93SAndriy Gapon 	crfree(newcred);
1078e4dcb704SEdward Tomasz Napierala #endif
10791419eacbSAlfred Perlstein 	uifree(ruip);
10801419eacbSAlfred Perlstein 	uifree(euip);
1081b1fc0ec1SRobert Watson 	crfree(oldcred);
108207f3485dSJohn Baldwin 	return (0);
1083030a28b3SRobert Watson 
1084030a28b3SRobert Watson fail:
1085030a28b3SRobert Watson 	PROC_UNLOCK(p);
1086030a28b3SRobert Watson 	uifree(ruip);
1087030a28b3SRobert Watson 	uifree(euip);
1088030a28b3SRobert Watson 	crfree(newcred);
1089030a28b3SRobert Watson 	return (error);
1090030a28b3SRobert Watson 
10918ccd6334SPeter Wemm }
10928ccd6334SPeter Wemm 
10938ccd6334SPeter Wemm /*
1094873fbcd7SRobert Watson  * setresgid(rgid, egid, sgid) is like setregid except control over the saved
1095873fbcd7SRobert Watson  * gid is explicit.
10968ccd6334SPeter Wemm  */
10978ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
10988ccd6334SPeter Wemm struct setresgid_args {
10998ccd6334SPeter Wemm 	gid_t	rgid;
11008ccd6334SPeter Wemm 	gid_t	egid;
11018ccd6334SPeter Wemm 	gid_t	sgid;
11028ccd6334SPeter Wemm };
11038ccd6334SPeter Wemm #endif
11048ccd6334SPeter Wemm /* ARGSUSED */
11058ccd6334SPeter Wemm int
11063e85b721SEd Maste sys_setresgid(struct thread *td, struct setresgid_args *uap)
11078ccd6334SPeter Wemm {
1108b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1109b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
1110eb725b4eSRobert Watson 	gid_t egid, rgid, sgid;
11118ccd6334SPeter Wemm 	int error;
11128ccd6334SPeter Wemm 
11138ccd6334SPeter Wemm 	egid = uap->egid;
1114eb725b4eSRobert Watson 	rgid = uap->rgid;
11158ccd6334SPeter Wemm 	sgid = uap->sgid;
111614961ba7SRobert Watson 	AUDIT_ARG_EGID(egid);
111714961ba7SRobert Watson 	AUDIT_ARG_RGID(rgid);
111814961ba7SRobert Watson 	AUDIT_ARG_SGID(sgid);
111907f3485dSJohn Baldwin 	newcred = crget();
112007f3485dSJohn Baldwin 	PROC_LOCK(p);
1121838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
1122030a28b3SRobert Watson 
1123030a28b3SRobert Watson #ifdef MAC
11246f6174a7SRobert Watson 	error = mac_cred_check_setresgid(oldcred, rgid, egid, sgid);
1125030a28b3SRobert Watson 	if (error)
1126030a28b3SRobert Watson 		goto fail;
1127030a28b3SRobert Watson #endif
1128030a28b3SRobert Watson 
1129b1fc0ec1SRobert Watson 	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
1130b1fc0ec1SRobert Watson 	      rgid != oldcred->cr_svgid &&
1131b1fc0ec1SRobert Watson 	      rgid != oldcred->cr_groups[0]) ||
1132b1fc0ec1SRobert Watson 	     (egid != (gid_t)-1 && egid != oldcred->cr_rgid &&
1133b1fc0ec1SRobert Watson 	      egid != oldcred->cr_svgid &&
1134b1fc0ec1SRobert Watson 	      egid != oldcred->cr_groups[0]) ||
1135b1fc0ec1SRobert Watson 	     (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid &&
1136b1fc0ec1SRobert Watson 	      sgid != oldcred->cr_svgid &&
1137b1fc0ec1SRobert Watson 	      sgid != oldcred->cr_groups[0])) &&
1138cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETRESGID)) != 0)
1139030a28b3SRobert Watson 		goto fail;
114007f3485dSJohn Baldwin 
1141b1fc0ec1SRobert Watson 	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
1142b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
11438ccd6334SPeter Wemm 		setsugid(p);
11448ccd6334SPeter Wemm 	}
1145b1fc0ec1SRobert Watson 	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
1146b1fc0ec1SRobert Watson 		change_rgid(newcred, rgid);
11478ccd6334SPeter Wemm 		setsugid(p);
11488ccd6334SPeter Wemm 	}
1149b1fc0ec1SRobert Watson 	if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) {
1150b1fc0ec1SRobert Watson 		change_svgid(newcred, sgid);
11518ccd6334SPeter Wemm 		setsugid(p);
11528ccd6334SPeter Wemm 	}
1153daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
115407f3485dSJohn Baldwin 	PROC_UNLOCK(p);
1155b1fc0ec1SRobert Watson 	crfree(oldcred);
115607f3485dSJohn Baldwin 	return (0);
1157030a28b3SRobert Watson 
1158030a28b3SRobert Watson fail:
1159030a28b3SRobert Watson 	PROC_UNLOCK(p);
1160030a28b3SRobert Watson 	crfree(newcred);
1161030a28b3SRobert Watson 	return (error);
11628ccd6334SPeter Wemm }
11638ccd6334SPeter Wemm 
11648ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
11658ccd6334SPeter Wemm struct getresuid_args {
11668ccd6334SPeter Wemm 	uid_t	*ruid;
11678ccd6334SPeter Wemm 	uid_t	*euid;
11688ccd6334SPeter Wemm 	uid_t	*suid;
11698ccd6334SPeter Wemm };
11708ccd6334SPeter Wemm #endif
11718ccd6334SPeter Wemm /* ARGSUSED */
11728ccd6334SPeter Wemm int
11733e85b721SEd Maste sys_getresuid(struct thread *td, struct getresuid_args *uap)
11748ccd6334SPeter Wemm {
1175835a82eeSMatthew Dillon 	struct ucred *cred;
11768ccd6334SPeter Wemm 	int error1 = 0, error2 = 0, error3 = 0;
11778ccd6334SPeter Wemm 
1178d74ac681SMatthew Dillon 	cred = td->td_ucred;
11798ccd6334SPeter Wemm 	if (uap->ruid)
11807f05b035SAlfred Perlstein 		error1 = copyout(&cred->cr_ruid,
11817f05b035SAlfred Perlstein 		    uap->ruid, sizeof(cred->cr_ruid));
11828ccd6334SPeter Wemm 	if (uap->euid)
11837f05b035SAlfred Perlstein 		error2 = copyout(&cred->cr_uid,
11847f05b035SAlfred Perlstein 		    uap->euid, sizeof(cred->cr_uid));
11858ccd6334SPeter Wemm 	if (uap->suid)
11867f05b035SAlfred Perlstein 		error3 = copyout(&cred->cr_svuid,
11877f05b035SAlfred Perlstein 		    uap->suid, sizeof(cred->cr_svuid));
1188eb725b4eSRobert Watson 	return (error1 ? error1 : error2 ? error2 : error3);
11898ccd6334SPeter Wemm }
11908ccd6334SPeter Wemm 
11918ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
11928ccd6334SPeter Wemm struct getresgid_args {
11938ccd6334SPeter Wemm 	gid_t	*rgid;
11948ccd6334SPeter Wemm 	gid_t	*egid;
11958ccd6334SPeter Wemm 	gid_t	*sgid;
11968ccd6334SPeter Wemm };
11978ccd6334SPeter Wemm #endif
11988ccd6334SPeter Wemm /* ARGSUSED */
11998ccd6334SPeter Wemm int
12003e85b721SEd Maste sys_getresgid(struct thread *td, struct getresgid_args *uap)
12018ccd6334SPeter Wemm {
1202835a82eeSMatthew Dillon 	struct ucred *cred;
12038ccd6334SPeter Wemm 	int error1 = 0, error2 = 0, error3 = 0;
12048ccd6334SPeter Wemm 
1205d74ac681SMatthew Dillon 	cred = td->td_ucred;
12068ccd6334SPeter Wemm 	if (uap->rgid)
12077f05b035SAlfred Perlstein 		error1 = copyout(&cred->cr_rgid,
12087f05b035SAlfred Perlstein 		    uap->rgid, sizeof(cred->cr_rgid));
12098ccd6334SPeter Wemm 	if (uap->egid)
12107f05b035SAlfred Perlstein 		error2 = copyout(&cred->cr_groups[0],
12117f05b035SAlfred Perlstein 		    uap->egid, sizeof(cred->cr_groups[0]));
12128ccd6334SPeter Wemm 	if (uap->sgid)
12137f05b035SAlfred Perlstein 		error3 = copyout(&cred->cr_svgid,
12147f05b035SAlfred Perlstein 		    uap->sgid, sizeof(cred->cr_svgid));
1215eb725b4eSRobert Watson 	return (error1 ? error1 : error2 ? error2 : error3);
12168ccd6334SPeter Wemm }
12178ccd6334SPeter Wemm 
1218b67cbc65SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1219b67cbc65SPeter Wemm struct issetugid_args {
1220b67cbc65SPeter Wemm 	int dummy;
1221b67cbc65SPeter Wemm };
1222b67cbc65SPeter Wemm #endif
1223b67cbc65SPeter Wemm /* ARGSUSED */
1224b67cbc65SPeter Wemm int
12253e85b721SEd Maste sys_issetugid(struct thread *td, struct issetugid_args *uap)
1226b67cbc65SPeter Wemm {
1227b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1228b40ce416SJulian Elischer 
1229b67cbc65SPeter Wemm 	/*
1230b67cbc65SPeter Wemm 	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
1231b67cbc65SPeter Wemm 	 * we use P_SUGID because we consider changing the owners as
1232b67cbc65SPeter Wemm 	 * "tainting" as well.
1233b67cbc65SPeter Wemm 	 * This is significant for procs that start as root and "become"
1234b67cbc65SPeter Wemm 	 * a user without an exec - programs cannot know *everything*
1235b67cbc65SPeter Wemm 	 * that libc *might* have put in their data segment.
1236b67cbc65SPeter Wemm 	 */
1237b40ce416SJulian Elischer 	td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
1238b67cbc65SPeter Wemm 	return (0);
1239b67cbc65SPeter Wemm }
1240b67cbc65SPeter Wemm 
1241130d0157SRobert Watson int
12428451d0ddSKip Macy sys___setugid(struct thread *td, struct __setugid_args *uap)
1243130d0157SRobert Watson {
1244130d0157SRobert Watson #ifdef REGRESSION
124507f3485dSJohn Baldwin 	struct proc *p;
1246835a82eeSMatthew Dillon 
124707f3485dSJohn Baldwin 	p = td->td_proc;
1248130d0157SRobert Watson 	switch (uap->flag) {
1249130d0157SRobert Watson 	case 0:
125007f3485dSJohn Baldwin 		PROC_LOCK(p);
125107f3485dSJohn Baldwin 		p->p_flag &= ~P_SUGID;
125207f3485dSJohn Baldwin 		PROC_UNLOCK(p);
125307f3485dSJohn Baldwin 		return (0);
125407f3485dSJohn Baldwin 	case 1:
125507f3485dSJohn Baldwin 		PROC_LOCK(p);
125607f3485dSJohn Baldwin 		p->p_flag |= P_SUGID;
125707f3485dSJohn Baldwin 		PROC_UNLOCK(p);
125807f3485dSJohn Baldwin 		return (0);
125907f3485dSJohn Baldwin 	default:
126007f3485dSJohn Baldwin 		return (EINVAL);
126107f3485dSJohn Baldwin 	}
1262130d0157SRobert Watson #else /* !REGRESSION */
1263eb725b4eSRobert Watson 
1264130d0157SRobert Watson 	return (ENOSYS);
1265eb725b4eSRobert Watson #endif /* REGRESSION */
1266130d0157SRobert Watson }
1267130d0157SRobert Watson 
1268df8bae1dSRodney W. Grimes /*
1269df8bae1dSRodney W. Grimes  * Check if gid is a member of the group set.
1270df8bae1dSRodney W. Grimes  */
127126f9a767SRodney W. Grimes int
12724c44ad8eSJohn Baldwin groupmember(gid_t gid, struct ucred *cred)
1273df8bae1dSRodney W. Grimes {
12747f92e578SBrooks Davis 	int l;
12757f92e578SBrooks Davis 	int h;
12767f92e578SBrooks Davis 	int m;
1277df8bae1dSRodney W. Grimes 
12787f92e578SBrooks Davis 	if (cred->cr_groups[0] == gid)
1279df8bae1dSRodney W. Grimes 		return(1);
12807f92e578SBrooks Davis 
12817f92e578SBrooks Davis 	/*
12827f92e578SBrooks Davis 	 * If gid was not our primary group, perform a binary search
12837f92e578SBrooks Davis 	 * of the supplemental groups.  This is possible because we
12847f92e578SBrooks Davis 	 * sort the groups in crsetgroups().
12857f92e578SBrooks Davis 	 */
12867f92e578SBrooks Davis 	l = 1;
12877f92e578SBrooks Davis 	h = cred->cr_ngroups;
12887f92e578SBrooks Davis 	while (l < h) {
12897f92e578SBrooks Davis 		m = l + ((h - l) / 2);
12907f92e578SBrooks Davis 		if (cred->cr_groups[m] < gid)
12917f92e578SBrooks Davis 			l = m + 1;
12927f92e578SBrooks Davis 		else
12937f92e578SBrooks Davis 			h = m;
12947f92e578SBrooks Davis 	}
12957f92e578SBrooks Davis 	if ((l < cred->cr_ngroups) && (cred->cr_groups[l] == gid))
12967f92e578SBrooks Davis 		return (1);
12977f92e578SBrooks Davis 
1298df8bae1dSRodney W. Grimes 	return (0);
1299df8bae1dSRodney W. Grimes }
1300df8bae1dSRodney W. Grimes 
13013b243b72SRobert Watson /*
1302eb725b4eSRobert Watson  * Test the active securelevel against a given level.  securelevel_gt()
1303eb725b4eSRobert Watson  * implements (securelevel > level).  securelevel_ge() implements
1304eb725b4eSRobert Watson  * (securelevel >= level).  Note that the logic is inverted -- these
1305eb725b4eSRobert Watson  * functions return EPERM on "success" and 0 on "failure".
13063ca719f1SRobert Watson  *
13070304c731SJamie Gritton  * Due to care taken when setting the securelevel, we know that no jail will
13080304c731SJamie Gritton  * be less secure that its parent (or the physical system), so it is sufficient
13090304c731SJamie Gritton  * to test the current jail only.
13100304c731SJamie Gritton  *
1311800c9408SRobert Watson  * XXXRW: Possibly since this has to do with privilege, it should move to
1312800c9408SRobert Watson  * kern_priv.c.
13133ca719f1SRobert Watson  */
13143ca719f1SRobert Watson int
13153ca719f1SRobert Watson securelevel_gt(struct ucred *cr, int level)
13163ca719f1SRobert Watson {
13173ca719f1SRobert Watson 
13180304c731SJamie Gritton 	return (cr->cr_prison->pr_securelevel > level ? EPERM : 0);
13193ca719f1SRobert Watson }
13203ca719f1SRobert Watson 
13213ca719f1SRobert Watson int
13223ca719f1SRobert Watson securelevel_ge(struct ucred *cr, int level)
13233ca719f1SRobert Watson {
13243ca719f1SRobert Watson 
13250304c731SJamie Gritton 	return (cr->cr_prison->pr_securelevel >= level ? EPERM : 0);
13263ca719f1SRobert Watson }
13273ca719f1SRobert Watson 
13288a7d8cc6SRobert Watson /*
1329e409590dSRobert Watson  * 'see_other_uids' determines whether or not visibility of processes
1330eb725b4eSRobert Watson  * and sockets with credentials holding different real uids is possible
133148713bdcSRobert Watson  * using a variety of system MIBs.
1332eb725b4eSRobert Watson  * XXX: data declarations should be together near the beginning of the file.
13338a7d8cc6SRobert Watson  */
1334e409590dSRobert Watson static int	see_other_uids = 1;
1335d0615c64SAndrew R. Reiter SYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW,
1336eb725b4eSRobert Watson     &see_other_uids, 0,
13378a7d8cc6SRobert Watson     "Unprivileged processes may see subjects/objects with different real uid");
13388a7d8cc6SRobert Watson 
13391a996ed1SEdward Tomasz Napierala /*-
13401b350b45SRobert Watson  * Determine if u1 "can see" the subject specified by u2, according to the
13411b350b45SRobert Watson  * 'see_other_uids' policy.
13421b350b45SRobert Watson  * Returns: 0 for permitted, ESRCH otherwise
13431b350b45SRobert Watson  * Locks: none
13441b350b45SRobert Watson  * References: *u1 and *u2 must not change during the call
13451b350b45SRobert Watson  *             u1 may equal u2, in which case only one reference is required
13461b350b45SRobert Watson  */
13474ac21b4fSStephen J. Kiernan int
13484ac21b4fSStephen J. Kiernan cr_canseeotheruids(struct ucred *u1, struct ucred *u2)
13491b350b45SRobert Watson {
13501b350b45SRobert Watson 
13511b350b45SRobert Watson 	if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) {
1352cc426dd3SMateusz Guzik 		if (priv_check_cred(u1, PRIV_SEEOTHERUIDS) != 0)
13531b350b45SRobert Watson 			return (ESRCH);
13541b350b45SRobert Watson 	}
13551b350b45SRobert Watson 	return (0);
13561b350b45SRobert Watson }
13571b350b45SRobert Watson 
135864d19c2eSRobert Watson /*
135964d19c2eSRobert Watson  * 'see_other_gids' determines whether or not visibility of processes
136064d19c2eSRobert Watson  * and sockets with credentials holding different real gids is possible
136164d19c2eSRobert Watson  * using a variety of system MIBs.
136264d19c2eSRobert Watson  * XXX: data declarations should be together near the beginning of the file.
136364d19c2eSRobert Watson  */
136464d19c2eSRobert Watson static int	see_other_gids = 1;
136564d19c2eSRobert Watson SYSCTL_INT(_security_bsd, OID_AUTO, see_other_gids, CTLFLAG_RW,
136664d19c2eSRobert Watson     &see_other_gids, 0,
136764d19c2eSRobert Watson     "Unprivileged processes may see subjects/objects with different real gid");
136864d19c2eSRobert Watson 
136964d19c2eSRobert Watson /*
137064d19c2eSRobert Watson  * Determine if u1 can "see" the subject specified by u2, according to the
137164d19c2eSRobert Watson  * 'see_other_gids' policy.
137264d19c2eSRobert Watson  * Returns: 0 for permitted, ESRCH otherwise
137364d19c2eSRobert Watson  * Locks: none
137464d19c2eSRobert Watson  * References: *u1 and *u2 must not change during the call
137564d19c2eSRobert Watson  *             u1 may equal u2, in which case only one reference is required
137664d19c2eSRobert Watson  */
13774ac21b4fSStephen J. Kiernan int
13784ac21b4fSStephen J. Kiernan cr_canseeothergids(struct ucred *u1, struct ucred *u2)
137964d19c2eSRobert Watson {
138064d19c2eSRobert Watson 	int i, match;
138164d19c2eSRobert Watson 
138264d19c2eSRobert Watson 	if (!see_other_gids) {
138364d19c2eSRobert Watson 		match = 0;
138464d19c2eSRobert Watson 		for (i = 0; i < u1->cr_ngroups; i++) {
138564d19c2eSRobert Watson 			if (groupmember(u1->cr_groups[i], u2))
138664d19c2eSRobert Watson 				match = 1;
138764d19c2eSRobert Watson 			if (match)
138864d19c2eSRobert Watson 				break;
138964d19c2eSRobert Watson 		}
139064d19c2eSRobert Watson 		if (!match) {
1391cc426dd3SMateusz Guzik 			if (priv_check_cred(u1, PRIV_SEEOTHERGIDS) != 0)
139264d19c2eSRobert Watson 				return (ESRCH);
139364d19c2eSRobert Watson 		}
139464d19c2eSRobert Watson 	}
139564d19c2eSRobert Watson 	return (0);
139664d19c2eSRobert Watson }
139764d19c2eSRobert Watson 
1398a4aaba3bSSteve Wills /*
1399a4aaba3bSSteve Wills  * 'see_jail_proc' determines whether or not visibility of processes and
1400a4aaba3bSSteve Wills  * sockets with credentials holding different jail ids is possible using a
1401a4aaba3bSSteve Wills  * variety of system MIBs.
1402a4aaba3bSSteve Wills  *
1403a4aaba3bSSteve Wills  * XXX: data declarations should be together near the beginning of the file.
1404a4aaba3bSSteve Wills  */
1405a4aaba3bSSteve Wills 
1406a4aaba3bSSteve Wills static int	see_jail_proc = 1;
1407a4aaba3bSSteve Wills SYSCTL_INT(_security_bsd, OID_AUTO, see_jail_proc, CTLFLAG_RW,
1408a4aaba3bSSteve Wills     &see_jail_proc, 0,
1409a4aaba3bSSteve Wills     "Unprivileged processes may see subjects/objects with different jail ids");
1410a4aaba3bSSteve Wills 
1411a4aaba3bSSteve Wills /*-
1412a4aaba3bSSteve Wills  * Determine if u1 "can see" the subject specified by u2, according to the
1413a4aaba3bSSteve Wills  * 'see_jail_proc' policy.
1414a4aaba3bSSteve Wills  * Returns: 0 for permitted, ESRCH otherwise
1415a4aaba3bSSteve Wills  * Locks: none
1416a4aaba3bSSteve Wills  * References: *u1 and *u2 must not change during the call
1417a4aaba3bSSteve Wills  *             u1 may equal u2, in which case only one reference is required
1418a4aaba3bSSteve Wills  */
1419a4aaba3bSSteve Wills int
1420a4aaba3bSSteve Wills cr_canseejailproc(struct ucred *u1, struct ucred *u2)
1421a4aaba3bSSteve Wills {
1422a4aaba3bSSteve Wills 	if (u1->cr_uid == 0)
1423a4aaba3bSSteve Wills 		return (0);
1424a4aaba3bSSteve Wills 	return (!see_jail_proc && u1->cr_prison != u2->cr_prison ? ESRCH : 0);
1425a4aaba3bSSteve Wills }
1426a4aaba3bSSteve Wills 
14271a996ed1SEdward Tomasz Napierala /*-
14287fd6a959SRobert Watson  * Determine if u1 "can see" the subject specified by u2.
1429ed639720SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1430ed639720SRobert Watson  * Locks: none
1431eb725b4eSRobert Watson  * References: *u1 and *u2 must not change during the call
1432ed639720SRobert Watson  *             u1 may equal u2, in which case only one reference is required
1433ed639720SRobert Watson  */
1434ed639720SRobert Watson int
143594088977SRobert Watson cr_cansee(struct ucred *u1, struct ucred *u2)
1436a9e0361bSPoul-Henning Kamp {
143791421ba2SRobert Watson 	int error;
1438a9e0361bSPoul-Henning Kamp 
1439ed639720SRobert Watson 	if ((error = prison_check(u1, u2)))
144091421ba2SRobert Watson 		return (error);
14418a1d977dSRobert Watson #ifdef MAC
144230d239bcSRobert Watson 	if ((error = mac_cred_check_visible(u1, u2)))
14438a1d977dSRobert Watson 		return (error);
14448a1d977dSRobert Watson #endif
14454ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeotheruids(u1, u2)))
14461b350b45SRobert Watson 		return (error);
14474ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeothergids(u1, u2)))
144864d19c2eSRobert Watson 		return (error);
1449a4aaba3bSSteve Wills 	if ((error = cr_canseejailproc(u1, u2)))
1450a4aaba3bSSteve Wills 		return (error);
1451387d2c03SRobert Watson 	return (0);
1452387d2c03SRobert Watson }
1453387d2c03SRobert Watson 
14541a996ed1SEdward Tomasz Napierala /*-
1455f44d9e24SJohn Baldwin  * Determine if td "can see" the subject specified by p.
14563b243b72SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1457f44d9e24SJohn Baldwin  * Locks: Sufficient locks to protect p->p_ucred must be held.  td really
1458f44d9e24SJohn Baldwin  *        should be curthread.
1459f44d9e24SJohn Baldwin  * References: td and p must be valid for the lifetime of the call
14603b243b72SRobert Watson  */
1461a0f75161SRobert Watson int
1462f44d9e24SJohn Baldwin p_cansee(struct thread *td, struct proc *p)
1463ed639720SRobert Watson {
146494088977SRobert Watson 	/* Wrap cr_cansee() for all functionality. */
1465f44d9e24SJohn Baldwin 	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1466f44d9e24SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
146755a0aa21SKonstantin Belousov 
146855a0aa21SKonstantin Belousov 	if (td->td_proc == p)
146955a0aa21SKonstantin Belousov 		return (0);
1470f44d9e24SJohn Baldwin 	return (cr_cansee(td->td_ucred, p->p_ucred));
1471ed639720SRobert Watson }
1472ed639720SRobert Watson 
147362c45ef4SRobert Watson /*
147462c45ef4SRobert Watson  * 'conservative_signals' prevents the delivery of a broad class of
147562c45ef4SRobert Watson  * signals by unprivileged processes to processes that have changed their
147662c45ef4SRobert Watson  * credentials since the last invocation of execve().  This can prevent
147762c45ef4SRobert Watson  * the leakage of cached information or retained privileges as a result
147862c45ef4SRobert Watson  * of a common class of signal-related vulnerabilities.  However, this
147962c45ef4SRobert Watson  * may interfere with some applications that expect to be able to
148062c45ef4SRobert Watson  * deliver these signals to peer processes after having given up
148162c45ef4SRobert Watson  * privilege.
148262c45ef4SRobert Watson  */
148362c45ef4SRobert Watson static int	conservative_signals = 1;
148462c45ef4SRobert Watson SYSCTL_INT(_security_bsd, OID_AUTO, conservative_signals, CTLFLAG_RW,
148562c45ef4SRobert Watson     &conservative_signals, 0, "Unprivileged processes prevented from "
148662c45ef4SRobert Watson     "sending certain signals to processes whose credentials have changed");
14871a996ed1SEdward Tomasz Napierala /*-
1488c83f8015SRobert Watson  * Determine whether cred may deliver the specified signal to proc.
1489c83f8015SRobert Watson  * Returns: 0 for permitted, an errno value otherwise.
1490c83f8015SRobert Watson  * Locks: A lock must be held for proc.
1491c83f8015SRobert Watson  * References: cred and proc must be valid for the lifetime of the call.
14924c5eb9c3SRobert Watson  */
14934c5eb9c3SRobert Watson int
14941a88a252SMaxim Sobolev cr_cansignal(struct ucred *cred, struct proc *proc, int signum)
1495387d2c03SRobert Watson {
149691421ba2SRobert Watson 	int error;
1497387d2c03SRobert Watson 
1498f44d9e24SJohn Baldwin 	PROC_LOCK_ASSERT(proc, MA_OWNED);
14994c5eb9c3SRobert Watson 	/*
1500c83f8015SRobert Watson 	 * Jail semantics limit the scope of signalling to proc in the
1501c83f8015SRobert Watson 	 * same jail as cred, if cred is in jail.
15024c5eb9c3SRobert Watson 	 */
1503c83f8015SRobert Watson 	error = prison_check(cred, proc->p_ucred);
1504c83f8015SRobert Watson 	if (error)
150591421ba2SRobert Watson 		return (error);
15068a1d977dSRobert Watson #ifdef MAC
150730d239bcSRobert Watson 	if ((error = mac_proc_check_signal(cred, proc, signum)))
15088a1d977dSRobert Watson 		return (error);
15098a1d977dSRobert Watson #endif
15104ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeotheruids(cred, proc->p_ucred)))
151164d19c2eSRobert Watson 		return (error);
15124ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeothergids(cred, proc->p_ucred)))
15131b350b45SRobert Watson 		return (error);
1514387d2c03SRobert Watson 
1515387d2c03SRobert Watson 	/*
15163b243b72SRobert Watson 	 * UNIX signal semantics depend on the status of the P_SUGID
15173b243b72SRobert Watson 	 * bit on the target process.  If the bit is set, then additional
15183b243b72SRobert Watson 	 * restrictions are placed on the set of available signals.
15194c5eb9c3SRobert Watson 	 */
15201a88a252SMaxim Sobolev 	if (conservative_signals && (proc->p_flag & P_SUGID)) {
15214c5eb9c3SRobert Watson 		switch (signum) {
15224c5eb9c3SRobert Watson 		case 0:
15234c5eb9c3SRobert Watson 		case SIGKILL:
15244c5eb9c3SRobert Watson 		case SIGINT:
15254c5eb9c3SRobert Watson 		case SIGTERM:
152662c45ef4SRobert Watson 		case SIGALRM:
15274c5eb9c3SRobert Watson 		case SIGSTOP:
15284c5eb9c3SRobert Watson 		case SIGTTIN:
15294c5eb9c3SRobert Watson 		case SIGTTOU:
15304c5eb9c3SRobert Watson 		case SIGTSTP:
15314c5eb9c3SRobert Watson 		case SIGHUP:
15324c5eb9c3SRobert Watson 		case SIGUSR1:
15334c5eb9c3SRobert Watson 		case SIGUSR2:
15347fd6a959SRobert Watson 			/*
15357fd6a959SRobert Watson 			 * Generally, permit job and terminal control
15367fd6a959SRobert Watson 			 * signals.
15377fd6a959SRobert Watson 			 */
15384c5eb9c3SRobert Watson 			break;
15394c5eb9c3SRobert Watson 		default:
1540c83f8015SRobert Watson 			/* Not permitted without privilege. */
1541cc426dd3SMateusz Guzik 			error = priv_check_cred(cred, PRIV_SIGNAL_SUGID);
15424c5eb9c3SRobert Watson 			if (error)
15434c5eb9c3SRobert Watson 				return (error);
15444c5eb9c3SRobert Watson 		}
1545e9e7ff5bSRobert Watson 	}
1546e9e7ff5bSRobert Watson 
15474c5eb9c3SRobert Watson 	/*
15483b243b72SRobert Watson 	 * Generally, the target credential's ruid or svuid must match the
1549e9e7ff5bSRobert Watson 	 * subject credential's ruid or euid.
15504c5eb9c3SRobert Watson 	 */
1551c83f8015SRobert Watson 	if (cred->cr_ruid != proc->p_ucred->cr_ruid &&
1552c83f8015SRobert Watson 	    cred->cr_ruid != proc->p_ucred->cr_svuid &&
1553c83f8015SRobert Watson 	    cred->cr_uid != proc->p_ucred->cr_ruid &&
1554c83f8015SRobert Watson 	    cred->cr_uid != proc->p_ucred->cr_svuid) {
1555cc426dd3SMateusz Guzik 		error = priv_check_cred(cred, PRIV_SIGNAL_DIFFCRED);
15564c5eb9c3SRobert Watson 		if (error)
15574c5eb9c3SRobert Watson 			return (error);
15584c5eb9c3SRobert Watson 	}
1559387d2c03SRobert Watson 
1560387d2c03SRobert Watson 	return (0);
1561387d2c03SRobert Watson }
1562a9e0361bSPoul-Henning Kamp 
15631a996ed1SEdward Tomasz Napierala /*-
1564f44d9e24SJohn Baldwin  * Determine whether td may deliver the specified signal to p.
1565c83f8015SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1566f44d9e24SJohn Baldwin  * Locks: Sufficient locks to protect various components of td and p
1567f44d9e24SJohn Baldwin  *        must be held.  td must be curthread, and a lock must be
1568f44d9e24SJohn Baldwin  *        held for p.
1569f44d9e24SJohn Baldwin  * References: td and p must be valid for the lifetime of the call
1570c83f8015SRobert Watson  */
1571c83f8015SRobert Watson int
15721a88a252SMaxim Sobolev p_cansignal(struct thread *td, struct proc *p, int signum)
1573c83f8015SRobert Watson {
1574c83f8015SRobert Watson 
1575f44d9e24SJohn Baldwin 	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1576f44d9e24SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
1577f44d9e24SJohn Baldwin 	if (td->td_proc == p)
1578c83f8015SRobert Watson 		return (0);
1579c83f8015SRobert Watson 
1580c83f8015SRobert Watson 	/*
1581c83f8015SRobert Watson 	 * UNIX signalling semantics require that processes in the same
1582c83f8015SRobert Watson 	 * session always be able to deliver SIGCONT to one another,
1583c83f8015SRobert Watson 	 * overriding the remaining protections.
1584c83f8015SRobert Watson 	 */
1585f44d9e24SJohn Baldwin 	/* XXX: This will require an additional lock of some sort. */
1586f44d9e24SJohn Baldwin 	if (signum == SIGCONT && td->td_proc->p_session == p->p_session)
1587c83f8015SRobert Watson 		return (0);
15884b178336SMaxim Sobolev 	/*
1589f9cd63d4SMaxim Sobolev 	 * Some compat layers use SIGTHR and higher signals for
1590f9cd63d4SMaxim Sobolev 	 * communication between different kernel threads of the same
1591f9cd63d4SMaxim Sobolev 	 * process, so that they expect that it's always possible to
1592f9cd63d4SMaxim Sobolev 	 * deliver them, even for suid applications where cr_cansignal() can
15934b178336SMaxim Sobolev 	 * deny such ability for security consideration.  It should be
15944b178336SMaxim Sobolev 	 * pretty safe to do since the only way to create two processes
15954b178336SMaxim Sobolev 	 * with the same p_leader is via rfork(2).
15964b178336SMaxim Sobolev 	 */
15972322a0a7SMaxim Sobolev 	if (td->td_proc->p_leader != NULL && signum >= SIGTHR &&
15982322a0a7SMaxim Sobolev 	    signum < SIGTHR + 4 && td->td_proc->p_leader == p->p_leader)
15994b178336SMaxim Sobolev 		return (0);
1600c83f8015SRobert Watson 
16011a88a252SMaxim Sobolev 	return (cr_cansignal(td->td_ucred, p, signum));
1602c83f8015SRobert Watson }
1603c83f8015SRobert Watson 
16041a996ed1SEdward Tomasz Napierala /*-
1605f44d9e24SJohn Baldwin  * Determine whether td may reschedule p.
16067fd6a959SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1607f44d9e24SJohn Baldwin  * Locks: Sufficient locks to protect various components of td and p
1608f44d9e24SJohn Baldwin  *        must be held.  td must be curthread, and a lock must
1609f44d9e24SJohn Baldwin  *        be held for p.
1610f44d9e24SJohn Baldwin  * References: td and p must be valid for the lifetime of the call
16113b243b72SRobert Watson  */
1612a0f75161SRobert Watson int
1613f44d9e24SJohn Baldwin p_cansched(struct thread *td, struct proc *p)
1614387d2c03SRobert Watson {
161591421ba2SRobert Watson 	int error;
1616387d2c03SRobert Watson 
1617f44d9e24SJohn Baldwin 	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1618f44d9e24SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
1619f44d9e24SJohn Baldwin 	if (td->td_proc == p)
1620387d2c03SRobert Watson 		return (0);
1621f44d9e24SJohn Baldwin 	if ((error = prison_check(td->td_ucred, p->p_ucred)))
162291421ba2SRobert Watson 		return (error);
16238a1d977dSRobert Watson #ifdef MAC
162430d239bcSRobert Watson 	if ((error = mac_proc_check_sched(td->td_ucred, p)))
16258a1d977dSRobert Watson 		return (error);
16268a1d977dSRobert Watson #endif
16274ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeotheruids(td->td_ucred, p->p_ucred)))
16281b350b45SRobert Watson 		return (error);
16294ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeothergids(td->td_ucred, p->p_ucred)))
163064d19c2eSRobert Watson 		return (error);
1631800c9408SRobert Watson 	if (td->td_ucred->cr_ruid != p->p_ucred->cr_ruid &&
1632800c9408SRobert Watson 	    td->td_ucred->cr_uid != p->p_ucred->cr_ruid) {
163332f9753cSRobert Watson 		error = priv_check(td, PRIV_SCHED_DIFFCRED);
1634800c9408SRobert Watson 		if (error)
1635800c9408SRobert Watson 			return (error);
1636800c9408SRobert Watson 	}
1637387d2c03SRobert Watson 	return (0);
1638387d2c03SRobert Watson }
1639387d2c03SRobert Watson 
16403b243b72SRobert Watson /*
1641b3079544SJamie Gritton  * Handle getting or setting the prison's unprivileged_proc_debug
1642b3079544SJamie Gritton  * value.
1643b3079544SJamie Gritton  */
1644b3079544SJamie Gritton static int
1645b3079544SJamie Gritton sysctl_unprivileged_proc_debug(SYSCTL_HANDLER_ARGS)
1646b3079544SJamie Gritton {
1647b3079544SJamie Gritton 	int error, val;
1648b3079544SJamie Gritton 
16490fe74ae6SJamie Gritton 	val = prison_allow(req->td->td_ucred, PR_ALLOW_UNPRIV_DEBUG);
1650b3079544SJamie Gritton 	error = sysctl_handle_int(oidp, &val, 0, req);
1651b3079544SJamie Gritton 	if (error != 0 || req->newptr == NULL)
1652b3079544SJamie Gritton 		return (error);
16530fe74ae6SJamie Gritton 	if (val != 0 && val != 1)
16540fe74ae6SJamie Gritton 		return (EINVAL);
16550fe74ae6SJamie Gritton 	prison_set_allow(req->td->td_ucred, PR_ALLOW_UNPRIV_DEBUG, val);
16560fe74ae6SJamie Gritton 	return (0);
1657b3079544SJamie Gritton }
1658b3079544SJamie Gritton 
1659b3079544SJamie Gritton /*
16605d476e73SRobert Watson  * The 'unprivileged_proc_debug' flag may be used to disable a variety of
16615d476e73SRobert Watson  * unprivileged inter-process debugging services, including some procfs
16625d476e73SRobert Watson  * functionality, ptrace(), and ktrace().  In the past, inter-process
16635d476e73SRobert Watson  * debugging has been involved in a variety of security problems, and sites
16645d476e73SRobert Watson  * not requiring the service might choose to disable it when hardening
16655d476e73SRobert Watson  * systems.
16663b243b72SRobert Watson  */
1667b3079544SJamie Gritton SYSCTL_PROC(_security_bsd, OID_AUTO, unprivileged_proc_debug,
16687029da5cSPawel Biernacki     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_SECURE |
16697029da5cSPawel Biernacki     CTLFLAG_MPSAFE, 0, 0, sysctl_unprivileged_proc_debug, "I",
16700ef5652eSRobert Watson     "Unprivileged processes may use process debugging facilities");
16710ef5652eSRobert Watson 
16721a996ed1SEdward Tomasz Napierala /*-
1673f44d9e24SJohn Baldwin  * Determine whether td may debug p.
16747fd6a959SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1675f44d9e24SJohn Baldwin  * Locks: Sufficient locks to protect various components of td and p
1676f44d9e24SJohn Baldwin  *        must be held.  td must be curthread, and a lock must
1677f44d9e24SJohn Baldwin  *        be held for p.
1678f44d9e24SJohn Baldwin  * References: td and p must be valid for the lifetime of the call
16793b243b72SRobert Watson  */
1680a0f75161SRobert Watson int
1681f44d9e24SJohn Baldwin p_candebug(struct thread *td, struct proc *p)
1682387d2c03SRobert Watson {
1683eb725b4eSRobert Watson 	int credentialchanged, error, grpsubset, i, uidsubset;
1684387d2c03SRobert Watson 
1685f44d9e24SJohn Baldwin 	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1686f44d9e24SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
1687f44d9e24SJohn Baldwin 	if (td->td_proc == p)
168823fad5b6SDag-Erling Smørgrav 		return (0);
168955a0aa21SKonstantin Belousov 	if ((error = priv_check(td, PRIV_DEBUG_UNPRIV)))
169055a0aa21SKonstantin Belousov 		return (error);
1691f44d9e24SJohn Baldwin 	if ((error = prison_check(td->td_ucred, p->p_ucred)))
169291421ba2SRobert Watson 		return (error);
16938a1d977dSRobert Watson #ifdef MAC
169430d239bcSRobert Watson 	if ((error = mac_proc_check_debug(td->td_ucred, p)))
16958a1d977dSRobert Watson 		return (error);
16968a1d977dSRobert Watson #endif
16974ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeotheruids(td->td_ucred, p->p_ucred)))
16981b350b45SRobert Watson 		return (error);
16994ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeothergids(td->td_ucred, p->p_ucred)))
170064d19c2eSRobert Watson 		return (error);
1701387d2c03SRobert Watson 
17027fd6a959SRobert Watson 	/*
1703f44d9e24SJohn Baldwin 	 * Is p's group set a subset of td's effective group set?  This
1704f44d9e24SJohn Baldwin 	 * includes p's egid, group access list, rgid, and svgid.
17057fd6a959SRobert Watson 	 */
1706db42a33dSRobert Watson 	grpsubset = 1;
1707f44d9e24SJohn Baldwin 	for (i = 0; i < p->p_ucred->cr_ngroups; i++) {
1708f44d9e24SJohn Baldwin 		if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) {
1709db42a33dSRobert Watson 			grpsubset = 0;
1710db42a33dSRobert Watson 			break;
1711db42a33dSRobert Watson 		}
1712db42a33dSRobert Watson 	}
1713db42a33dSRobert Watson 	grpsubset = grpsubset &&
1714f44d9e24SJohn Baldwin 	    groupmember(p->p_ucred->cr_rgid, td->td_ucred) &&
1715f44d9e24SJohn Baldwin 	    groupmember(p->p_ucred->cr_svgid, td->td_ucred);
1716db42a33dSRobert Watson 
1717db42a33dSRobert Watson 	/*
1718f44d9e24SJohn Baldwin 	 * Are the uids present in p's credential equal to td's
1719f44d9e24SJohn Baldwin 	 * effective uid?  This includes p's euid, svuid, and ruid.
1720db42a33dSRobert Watson 	 */
1721f44d9e24SJohn Baldwin 	uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid &&
1722f44d9e24SJohn Baldwin 	    td->td_ucred->cr_uid == p->p_ucred->cr_svuid &&
1723f44d9e24SJohn Baldwin 	    td->td_ucred->cr_uid == p->p_ucred->cr_ruid);
1724db42a33dSRobert Watson 
1725db42a33dSRobert Watson 	/*
1726db42a33dSRobert Watson 	 * Has the credential of the process changed since the last exec()?
1727db42a33dSRobert Watson 	 */
1728f44d9e24SJohn Baldwin 	credentialchanged = (p->p_flag & P_SUGID);
1729db42a33dSRobert Watson 
1730db42a33dSRobert Watson 	/*
1731f44d9e24SJohn Baldwin 	 * If p's gids aren't a subset, or the uids aren't a subset,
1732db42a33dSRobert Watson 	 * or the credential has changed, require appropriate privilege
1733800c9408SRobert Watson 	 * for td to debug p.
1734db42a33dSRobert Watson 	 */
1735800c9408SRobert Watson 	if (!grpsubset || !uidsubset) {
173632f9753cSRobert Watson 		error = priv_check(td, PRIV_DEBUG_DIFFCRED);
1737800c9408SRobert Watson 		if (error)
1738800c9408SRobert Watson 			return (error);
1739800c9408SRobert Watson 	}
1740800c9408SRobert Watson 
1741800c9408SRobert Watson 	if (credentialchanged) {
174232f9753cSRobert Watson 		error = priv_check(td, PRIV_DEBUG_SUGID);
174332d18604SRobert Watson 		if (error)
1744387d2c03SRobert Watson 			return (error);
17457fd6a959SRobert Watson 	}
1746387d2c03SRobert Watson 
1747eb725b4eSRobert Watson 	/* Can't trace init when securelevel > 0. */
1748f44d9e24SJohn Baldwin 	if (p == initproc) {
1749f44d9e24SJohn Baldwin 		error = securelevel_gt(td->td_ucred, 0);
17503ca719f1SRobert Watson 		if (error)
17513ca719f1SRobert Watson 			return (error);
17523ca719f1SRobert Watson 	}
1753387d2c03SRobert Watson 
17545fab7614SRobert Watson 	/*
17555fab7614SRobert Watson 	 * Can't trace a process that's currently exec'ing.
1756800c9408SRobert Watson 	 *
17575fab7614SRobert Watson 	 * XXX: Note, this is not a security policy decision, it's a
17585fab7614SRobert Watson 	 * basic correctness/functionality decision.  Therefore, this check
17595fab7614SRobert Watson 	 * should be moved to the caller's of p_candebug().
17605fab7614SRobert Watson 	 */
1761f44d9e24SJohn Baldwin 	if ((p->p_flag & P_INEXEC) != 0)
1762af80b2c9SKonstantin Belousov 		return (EBUSY);
17639ca45e81SDag-Erling Smørgrav 
1764677258f7SKonstantin Belousov 	/* Denied explicitely */
1765677258f7SKonstantin Belousov 	if ((p->p_flag2 & P2_NOTRACE) != 0) {
1766677258f7SKonstantin Belousov 		error = priv_check(td, PRIV_DEBUG_DENIED);
1767677258f7SKonstantin Belousov 		if (error != 0)
1768677258f7SKonstantin Belousov 			return (error);
1769677258f7SKonstantin Belousov 	}
1770677258f7SKonstantin Belousov 
1771387d2c03SRobert Watson 	return (0);
1772387d2c03SRobert Watson }
1773387d2c03SRobert Watson 
17741a996ed1SEdward Tomasz Napierala /*-
177529dc1288SRobert Watson  * Determine whether the subject represented by cred can "see" a socket.
177629dc1288SRobert Watson  * Returns: 0 for permitted, ENOENT otherwise.
177729dc1288SRobert Watson  */
177829dc1288SRobert Watson int
177929dc1288SRobert Watson cr_canseesocket(struct ucred *cred, struct socket *so)
178029dc1288SRobert Watson {
178129dc1288SRobert Watson 	int error;
178229dc1288SRobert Watson 
178329dc1288SRobert Watson 	error = prison_check(cred, so->so_cred);
178429dc1288SRobert Watson 	if (error)
178529dc1288SRobert Watson 		return (ENOENT);
17868a1d977dSRobert Watson #ifdef MAC
178730d239bcSRobert Watson 	error = mac_socket_check_visible(cred, so);
17888a1d977dSRobert Watson 	if (error)
17898a1d977dSRobert Watson 		return (error);
17908a1d977dSRobert Watson #endif
17914ac21b4fSStephen J. Kiernan 	if (cr_canseeotheruids(cred, so->so_cred))
179229dc1288SRobert Watson 		return (ENOENT);
17934ac21b4fSStephen J. Kiernan 	if (cr_canseeothergids(cred, so->so_cred))
179464d19c2eSRobert Watson 		return (ENOENT);
179529dc1288SRobert Watson 
179629dc1288SRobert Watson 	return (0);
179729dc1288SRobert Watson }
179829dc1288SRobert Watson 
17991a996ed1SEdward Tomasz Napierala /*-
1800babe9a2bSRobert Watson  * Determine whether td can wait for the exit of p.
1801babe9a2bSRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1802babe9a2bSRobert Watson  * Locks: Sufficient locks to protect various components of td and p
1803babe9a2bSRobert Watson  *        must be held.  td must be curthread, and a lock must
1804babe9a2bSRobert Watson  *        be held for p.
1805babe9a2bSRobert Watson  * References: td and p must be valid for the lifetime of the call
1806babe9a2bSRobert Watson 
1807babe9a2bSRobert Watson  */
1808babe9a2bSRobert Watson int
1809babe9a2bSRobert Watson p_canwait(struct thread *td, struct proc *p)
1810babe9a2bSRobert Watson {
1811babe9a2bSRobert Watson 	int error;
1812babe9a2bSRobert Watson 
1813babe9a2bSRobert Watson 	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1814babe9a2bSRobert Watson 	PROC_LOCK_ASSERT(p, MA_OWNED);
18157afcbc18SJamie Gritton 	if ((error = prison_check(td->td_ucred, p->p_ucred)))
1816babe9a2bSRobert Watson 		return (error);
1817babe9a2bSRobert Watson #ifdef MAC
181830d239bcSRobert Watson 	if ((error = mac_proc_check_wait(td->td_ucred, p)))
1819babe9a2bSRobert Watson 		return (error);
1820babe9a2bSRobert Watson #endif
1821babe9a2bSRobert Watson #if 0
1822babe9a2bSRobert Watson 	/* XXXMAC: This could have odd effects on some shells. */
18234ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeotheruids(td->td_ucred, p->p_ucred)))
1824babe9a2bSRobert Watson 		return (error);
1825babe9a2bSRobert Watson #endif
1826babe9a2bSRobert Watson 
1827babe9a2bSRobert Watson 	return (0);
1828babe9a2bSRobert Watson }
1829babe9a2bSRobert Watson 
1830a9e0361bSPoul-Henning Kamp /*
18311724c563SMateusz Guzik  * Credential management.
18321724c563SMateusz Guzik  *
18331724c563SMateusz Guzik  * struct ucred objects are rarely allocated but gain and lose references all
18341724c563SMateusz Guzik  * the time (e.g., on struct file alloc/dealloc) turning refcount updates into
18351724c563SMateusz Guzik  * a significant source of cache-line ping ponging. Common cases are worked
18361724c563SMateusz Guzik  * around by modifying thread-local counter instead if the cred to operate on
18371724c563SMateusz Guzik  * matches td_realucred.
18381724c563SMateusz Guzik  *
18391724c563SMateusz Guzik  * The counter is split into 2 parts:
18401724c563SMateusz Guzik  * - cr_users -- total count of all struct proc and struct thread objects
18411724c563SMateusz Guzik  *   which have given cred in p_ucred and td_ucred respectively
18421724c563SMateusz Guzik  * - cr_ref -- the actual ref count, only valid if cr_users == 0
18431724c563SMateusz Guzik  *
18441724c563SMateusz Guzik  * If users == 0 then cr_ref behaves similarly to refcount(9), in particular if
18451724c563SMateusz Guzik  * the count reaches 0 the object is freeable.
18461724c563SMateusz Guzik  * If users > 0 and curthread->td_realucred == cred, then updates are performed
18471724c563SMateusz Guzik  * against td_ucredref.
18481724c563SMateusz Guzik  * In other cases updates are performed against cr_ref.
18491724c563SMateusz Guzik  *
18501724c563SMateusz Guzik  * Changing td_realucred into something else decrements cr_users and transfers
18511724c563SMateusz Guzik  * accumulated updates.
18521724c563SMateusz Guzik  */
18531724c563SMateusz Guzik struct ucred *
18541724c563SMateusz Guzik crcowget(struct ucred *cr)
18551724c563SMateusz Guzik {
18561724c563SMateusz Guzik 
18571724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
18581724c563SMateusz Guzik 	KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
18591724c563SMateusz Guzik 	    __func__, cr->cr_users, cr));
18601724c563SMateusz Guzik 	cr->cr_users++;
18611724c563SMateusz Guzik 	cr->cr_ref++;
18621724c563SMateusz Guzik 	mtx_unlock(&cr->cr_mtx);
18631724c563SMateusz Guzik 	return (cr);
18641724c563SMateusz Guzik }
18651724c563SMateusz Guzik 
18661724c563SMateusz Guzik static struct ucred *
18671724c563SMateusz Guzik crunuse(struct thread *td)
18681724c563SMateusz Guzik {
18691724c563SMateusz Guzik 	struct ucred *cr, *crold;
18701724c563SMateusz Guzik 
1871936c24faSMateusz Guzik 	MPASS(td->td_realucred == td->td_ucred);
1872936c24faSMateusz Guzik 	cr = td->td_realucred;
18731724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
18741724c563SMateusz Guzik 	cr->cr_ref += td->td_ucredref;
18751724c563SMateusz Guzik 	td->td_ucredref = 0;
18761724c563SMateusz Guzik 	KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
18771724c563SMateusz Guzik 	    __func__, cr->cr_users, cr));
18781724c563SMateusz Guzik 	cr->cr_users--;
18791724c563SMateusz Guzik 	if (cr->cr_users == 0) {
18801724c563SMateusz Guzik 		KASSERT(cr->cr_ref > 0, ("%s: ref %d not > 0 on cred %p",
18811724c563SMateusz Guzik 		    __func__, cr->cr_ref, cr));
18821724c563SMateusz Guzik 		crold = cr;
18831724c563SMateusz Guzik 	} else {
18841724c563SMateusz Guzik 		cr->cr_ref--;
18851724c563SMateusz Guzik 		crold = NULL;
18861724c563SMateusz Guzik 	}
18871724c563SMateusz Guzik 	mtx_unlock(&cr->cr_mtx);
1888936c24faSMateusz Guzik 	td->td_realucred = NULL;
18891724c563SMateusz Guzik 	return (crold);
18901724c563SMateusz Guzik }
18911724c563SMateusz Guzik 
1892f34a2f56SMateusz Guzik static void
1893f34a2f56SMateusz Guzik crunusebatch(struct ucred *cr, int users, int ref)
1894f34a2f56SMateusz Guzik {
1895f34a2f56SMateusz Guzik 
1896f34a2f56SMateusz Guzik 	KASSERT(users > 0, ("%s: passed users %d not > 0 ; cred %p",
1897f34a2f56SMateusz Guzik 	    __func__, users, cr));
1898f34a2f56SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
1899f34a2f56SMateusz Guzik 	KASSERT(cr->cr_users >= users, ("%s: users %d not > %d on cred %p",
1900f34a2f56SMateusz Guzik 	    __func__, cr->cr_users, users, cr));
1901f34a2f56SMateusz Guzik 	cr->cr_users -= users;
1902f34a2f56SMateusz Guzik 	cr->cr_ref += ref;
1903f34a2f56SMateusz Guzik 	cr->cr_ref -= users;
1904f34a2f56SMateusz Guzik 	if (cr->cr_users > 0) {
1905f34a2f56SMateusz Guzik 		mtx_unlock(&cr->cr_mtx);
1906f34a2f56SMateusz Guzik 		return;
1907f34a2f56SMateusz Guzik 	}
1908f34a2f56SMateusz Guzik 	KASSERT(cr->cr_ref >= 0, ("%s: ref %d not >= 0 on cred %p",
1909f34a2f56SMateusz Guzik 	    __func__, cr->cr_ref, cr));
1910f34a2f56SMateusz Guzik 	if (cr->cr_ref > 0) {
1911f34a2f56SMateusz Guzik 		mtx_unlock(&cr->cr_mtx);
1912f34a2f56SMateusz Guzik 		return;
1913f34a2f56SMateusz Guzik 	}
1914f34a2f56SMateusz Guzik 	crfree_final(cr);
1915f34a2f56SMateusz Guzik }
1916f34a2f56SMateusz Guzik 
19171724c563SMateusz Guzik void
19181724c563SMateusz Guzik crcowfree(struct thread *td)
19191724c563SMateusz Guzik {
19201724c563SMateusz Guzik 	struct ucred *cr;
19211724c563SMateusz Guzik 
19221724c563SMateusz Guzik 	cr = crunuse(td);
19231724c563SMateusz Guzik 	if (cr != NULL)
19241724c563SMateusz Guzik 		crfree(cr);
19251724c563SMateusz Guzik }
19261724c563SMateusz Guzik 
19271724c563SMateusz Guzik struct ucred *
19281724c563SMateusz Guzik crcowsync(void)
19291724c563SMateusz Guzik {
19301724c563SMateusz Guzik 	struct thread *td;
19311724c563SMateusz Guzik 	struct proc *p;
19321724c563SMateusz Guzik 	struct ucred *crnew, *crold;
19331724c563SMateusz Guzik 
19341724c563SMateusz Guzik 	td = curthread;
19351724c563SMateusz Guzik 	p = td->td_proc;
19361724c563SMateusz Guzik 	PROC_LOCK_ASSERT(p, MA_OWNED);
19371724c563SMateusz Guzik 
19381724c563SMateusz Guzik 	MPASS(td->td_realucred == td->td_ucred);
19391724c563SMateusz Guzik 	if (td->td_realucred == p->p_ucred)
19401724c563SMateusz Guzik 		return (NULL);
19411724c563SMateusz Guzik 
19421724c563SMateusz Guzik 	crnew = crcowget(p->p_ucred);
19431724c563SMateusz Guzik 	crold = crunuse(td);
19441724c563SMateusz Guzik 	td->td_realucred = crnew;
19451724c563SMateusz Guzik 	td->td_ucred = td->td_realucred;
19461724c563SMateusz Guzik 	return (crold);
19471724c563SMateusz Guzik }
19481724c563SMateusz Guzik 
19491724c563SMateusz Guzik /*
1950f34a2f56SMateusz Guzik  * Batching.
1951f34a2f56SMateusz Guzik  */
1952f34a2f56SMateusz Guzik void
1953f34a2f56SMateusz Guzik credbatch_add(struct credbatch *crb, struct thread *td)
1954f34a2f56SMateusz Guzik {
1955f34a2f56SMateusz Guzik 	struct ucred *cr;
1956f34a2f56SMateusz Guzik 
1957f34a2f56SMateusz Guzik 	MPASS(td->td_realucred != NULL);
1958f34a2f56SMateusz Guzik 	MPASS(td->td_realucred == td->td_ucred);
1959fa2528acSAlex Richardson 	MPASS(TD_GET_STATE(td) == TDS_INACTIVE);
1960f34a2f56SMateusz Guzik 	cr = td->td_realucred;
1961f34a2f56SMateusz Guzik 	KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
1962f34a2f56SMateusz Guzik 	    __func__, cr->cr_users, cr));
1963f34a2f56SMateusz Guzik 	if (crb->cred != cr) {
1964f34a2f56SMateusz Guzik 		if (crb->users > 0) {
1965f34a2f56SMateusz Guzik 			MPASS(crb->cred != NULL);
1966f34a2f56SMateusz Guzik 			crunusebatch(crb->cred, crb->users, crb->ref);
1967f34a2f56SMateusz Guzik 			crb->users = 0;
1968f34a2f56SMateusz Guzik 			crb->ref = 0;
1969f34a2f56SMateusz Guzik 		}
1970f34a2f56SMateusz Guzik 	}
1971f34a2f56SMateusz Guzik 	crb->cred = cr;
1972f34a2f56SMateusz Guzik 	crb->users++;
1973f34a2f56SMateusz Guzik 	crb->ref += td->td_ucredref;
1974f34a2f56SMateusz Guzik 	td->td_ucredref = 0;
1975f34a2f56SMateusz Guzik 	td->td_realucred = NULL;
1976f34a2f56SMateusz Guzik }
1977f34a2f56SMateusz Guzik 
1978f34a2f56SMateusz Guzik void
1979f34a2f56SMateusz Guzik credbatch_final(struct credbatch *crb)
1980f34a2f56SMateusz Guzik {
1981f34a2f56SMateusz Guzik 
1982f34a2f56SMateusz Guzik 	MPASS(crb->cred != NULL);
1983f34a2f56SMateusz Guzik 	MPASS(crb->users > 0);
1984f34a2f56SMateusz Guzik 	crunusebatch(crb->cred, crb->users, crb->ref);
1985f34a2f56SMateusz Guzik }
1986f34a2f56SMateusz Guzik 
1987f34a2f56SMateusz Guzik /*
1988df8bae1dSRodney W. Grimes  * Allocate a zeroed cred structure.
1989df8bae1dSRodney W. Grimes  */
1990df8bae1dSRodney W. Grimes struct ucred *
19914c44ad8eSJohn Baldwin crget(void)
1992df8bae1dSRodney W. Grimes {
19933e85b721SEd Maste 	struct ucred *cr;
1994df8bae1dSRodney W. Grimes 
19951ede983cSDag-Erling Smørgrav 	cr = malloc(sizeof(*cr), M_CRED, M_WAITOK | M_ZERO);
19961724c563SMateusz Guzik 	mtx_init(&cr->cr_mtx, "cred", NULL, MTX_DEF);
19971724c563SMateusz Guzik 	cr->cr_ref = 1;
1998faef5371SRobert Watson #ifdef AUDIT
1999faef5371SRobert Watson 	audit_cred_init(cr);
2000faef5371SRobert Watson #endif
200140244964SRobert Watson #ifdef MAC
200230d239bcSRobert Watson 	mac_cred_init(cr);
200340244964SRobert Watson #endif
2004a99500a9SMateusz Guzik 	cr->cr_groups = cr->cr_smallgroups;
2005a99500a9SMateusz Guzik 	cr->cr_agroups =
2006a99500a9SMateusz Guzik 	    sizeof(cr->cr_smallgroups) / sizeof(cr->cr_smallgroups[0]);
2007df8bae1dSRodney W. Grimes 	return (cr);
2008df8bae1dSRodney W. Grimes }
2009df8bae1dSRodney W. Grimes 
2010df8bae1dSRodney W. Grimes /*
20117fd6a959SRobert Watson  * Claim another reference to a ucred structure.
20125c3f70d7SAlfred Perlstein  */
2013bd78ceceSJohn Baldwin struct ucred *
20144c44ad8eSJohn Baldwin crhold(struct ucred *cr)
20155c3f70d7SAlfred Perlstein {
20161724c563SMateusz Guzik 	struct thread *td;
20175c3f70d7SAlfred Perlstein 
20181724c563SMateusz Guzik 	td = curthread;
20191724c563SMateusz Guzik 	if (__predict_true(td->td_realucred == cr)) {
20201724c563SMateusz Guzik 		KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
20211724c563SMateusz Guzik 		    __func__, cr->cr_users, cr));
20221724c563SMateusz Guzik 		td->td_ucredref++;
20231724c563SMateusz Guzik 		return (cr);
20241724c563SMateusz Guzik 	}
20251724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
20261724c563SMateusz Guzik 	cr->cr_ref++;
20271724c563SMateusz Guzik 	mtx_unlock(&cr->cr_mtx);
2028bd78ceceSJohn Baldwin 	return (cr);
20295c3f70d7SAlfred Perlstein }
20305c3f70d7SAlfred Perlstein 
20315c3f70d7SAlfred Perlstein /*
20320c14ff0eSRobert Watson  * Free a cred structure.  Throws away space when ref count gets to 0.
2033df8bae1dSRodney W. Grimes  */
203426f9a767SRodney W. Grimes void
20354c44ad8eSJohn Baldwin crfree(struct ucred *cr)
2036df8bae1dSRodney W. Grimes {
20371724c563SMateusz Guzik 	struct thread *td;
20381e5d626aSAlfred Perlstein 
20391724c563SMateusz Guzik 	td = curthread;
2040a2de789eSMateusz Guzik 	if (__predict_true(td->td_realucred == cr)) {
20411724c563SMateusz Guzik 		KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
20421724c563SMateusz Guzik 		    __func__, cr->cr_users, cr));
20431724c563SMateusz Guzik 		td->td_ucredref--;
20441724c563SMateusz Guzik 		return;
20451724c563SMateusz Guzik 	}
20461724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
20471724c563SMateusz Guzik 	KASSERT(cr->cr_users >= 0, ("%s: users %d not >= 0 on cred %p",
20481724c563SMateusz Guzik 	    __func__, cr->cr_users, cr));
20491724c563SMateusz Guzik 	cr->cr_ref--;
20501724c563SMateusz Guzik 	if (cr->cr_users > 0) {
20511724c563SMateusz Guzik 		mtx_unlock(&cr->cr_mtx);
20521724c563SMateusz Guzik 		return;
20531724c563SMateusz Guzik 	}
20541724c563SMateusz Guzik 	KASSERT(cr->cr_ref >= 0, ("%s: ref %d not >= 0 on cred %p",
20551724c563SMateusz Guzik 	    __func__, cr->cr_ref, cr));
20561724c563SMateusz Guzik 	if (cr->cr_ref > 0) {
20571724c563SMateusz Guzik 		mtx_unlock(&cr->cr_mtx);
20581724c563SMateusz Guzik 		return;
20591724c563SMateusz Guzik 	}
2060f34a2f56SMateusz Guzik 	crfree_final(cr);
2061f34a2f56SMateusz Guzik }
2062f34a2f56SMateusz Guzik 
2063f34a2f56SMateusz Guzik static void
2064f34a2f56SMateusz Guzik crfree_final(struct ucred *cr)
2065f34a2f56SMateusz Guzik {
2066f34a2f56SMateusz Guzik 
2067f34a2f56SMateusz Guzik 	KASSERT(cr->cr_users == 0, ("%s: users %d not == 0 on cred %p",
2068f34a2f56SMateusz Guzik 	    __func__, cr->cr_users, cr));
2069f34a2f56SMateusz Guzik 	KASSERT(cr->cr_ref == 0, ("%s: ref %d not == 0 on cred %p",
2070f34a2f56SMateusz Guzik 	    __func__, cr->cr_ref, cr));
20712f5b0b48SMateusz Guzik 
2072f535380cSDon Lewis 	/*
20731724c563SMateusz Guzik 	 * Some callers of crget(), such as nfs_statfs(), allocate a temporary
20741724c563SMateusz Guzik 	 * credential, but don't allocate a uidinfo structure.
2075f535380cSDon Lewis 	 */
2076f535380cSDon Lewis 	if (cr->cr_uidinfo != NULL)
2077f535380cSDon Lewis 		uifree(cr->cr_uidinfo);
2078823c224eSRobert Watson 	if (cr->cr_ruidinfo != NULL)
2079823c224eSRobert Watson 		uifree(cr->cr_ruidinfo);
20800304c731SJamie Gritton 	if (cr->cr_prison != NULL)
208191421ba2SRobert Watson 		prison_free(cr->cr_prison);
20822bfc50bcSEdward Tomasz Napierala 	if (cr->cr_loginclass != NULL)
20832bfc50bcSEdward Tomasz Napierala 		loginclass_free(cr->cr_loginclass);
2084faef5371SRobert Watson #ifdef AUDIT
2085faef5371SRobert Watson 	audit_cred_destroy(cr);
2086faef5371SRobert Watson #endif
208740244964SRobert Watson #ifdef MAC
208830d239bcSRobert Watson 	mac_cred_destroy(cr);
208940244964SRobert Watson #endif
20901724c563SMateusz Guzik 	mtx_destroy(&cr->cr_mtx);
2091a99500a9SMateusz Guzik 	if (cr->cr_groups != cr->cr_smallgroups)
2092838d9858SBrooks Davis 		free(cr->cr_groups, M_CRED);
20931ede983cSDag-Erling Smørgrav 	free(cr, M_CRED);
2094e1bca29fSMatthew Dillon }
2095df8bae1dSRodney W. Grimes 
2096df8bae1dSRodney W. Grimes /*
2097bd78ceceSJohn Baldwin  * Copy a ucred's contents from a template.  Does not block.
2098bd78ceceSJohn Baldwin  */
2099bd78ceceSJohn Baldwin void
21004c44ad8eSJohn Baldwin crcopy(struct ucred *dest, struct ucred *src)
2101bd78ceceSJohn Baldwin {
2102bd78ceceSJohn Baldwin 
210325108069SMateusz Guzik 	KASSERT(dest->cr_ref == 1, ("crcopy of shared ucred"));
2104bd78ceceSJohn Baldwin 	bcopy(&src->cr_startcopy, &dest->cr_startcopy,
2105bd78ceceSJohn Baldwin 	    (unsigned)((caddr_t)&src->cr_endcopy -
2106bd78ceceSJohn Baldwin 		(caddr_t)&src->cr_startcopy));
2107838d9858SBrooks Davis 	crsetgroups(dest, src->cr_ngroups, src->cr_groups);
2108bd78ceceSJohn Baldwin 	uihold(dest->cr_uidinfo);
2109bd78ceceSJohn Baldwin 	uihold(dest->cr_ruidinfo);
2110bd78ceceSJohn Baldwin 	prison_hold(dest->cr_prison);
21112bfc50bcSEdward Tomasz Napierala 	loginclass_hold(dest->cr_loginclass);
2112faef5371SRobert Watson #ifdef AUDIT
2113faef5371SRobert Watson 	audit_cred_copy(src, dest);
2114faef5371SRobert Watson #endif
211540244964SRobert Watson #ifdef MAC
211630d239bcSRobert Watson 	mac_cred_copy(src, dest);
211740244964SRobert Watson #endif
2118df8bae1dSRodney W. Grimes }
2119df8bae1dSRodney W. Grimes 
2120df8bae1dSRodney W. Grimes /*
2121df8bae1dSRodney W. Grimes  * Dup cred struct to a new held one.
2122df8bae1dSRodney W. Grimes  */
2123df8bae1dSRodney W. Grimes struct ucred *
21244c44ad8eSJohn Baldwin crdup(struct ucred *cr)
2125df8bae1dSRodney W. Grimes {
2126df8bae1dSRodney W. Grimes 	struct ucred *newcr;
2127df8bae1dSRodney W. Grimes 
2128bd78ceceSJohn Baldwin 	newcr = crget();
2129bd78ceceSJohn Baldwin 	crcopy(newcr, cr);
2130df8bae1dSRodney W. Grimes 	return (newcr);
2131df8bae1dSRodney W. Grimes }
2132df8bae1dSRodney W. Grimes 
2133df8bae1dSRodney W. Grimes /*
213476183f34SDima Dorfman  * Fill in a struct xucred based on a struct ucred.
213576183f34SDima Dorfman  */
213676183f34SDima Dorfman void
21374c44ad8eSJohn Baldwin cru2x(struct ucred *cr, struct xucred *xcr)
213876183f34SDima Dorfman {
2139838d9858SBrooks Davis 	int ngroups;
214076183f34SDima Dorfman 
214176183f34SDima Dorfman 	bzero(xcr, sizeof(*xcr));
214276183f34SDima Dorfman 	xcr->cr_version = XUCRED_VERSION;
214376183f34SDima Dorfman 	xcr->cr_uid = cr->cr_uid;
2144838d9858SBrooks Davis 
2145838d9858SBrooks Davis 	ngroups = MIN(cr->cr_ngroups, XU_NGROUPS);
2146838d9858SBrooks Davis 	xcr->cr_ngroups = ngroups;
2147838d9858SBrooks Davis 	bcopy(cr->cr_groups, xcr->cr_groups,
2148838d9858SBrooks Davis 	    ngroups * sizeof(*cr->cr_groups));
214976183f34SDima Dorfman }
215076183f34SDima Dorfman 
2151c8124e20SDmitry Chagin void
2152c5afec6eSDmitry Chagin cru2xt(struct thread *td, struct xucred *xcr)
2153c5afec6eSDmitry Chagin {
2154c5afec6eSDmitry Chagin 
2155c5afec6eSDmitry Chagin 	cru2x(td->td_ucred, xcr);
2156c5afec6eSDmitry Chagin 	xcr->cr_pid = td->td_proc->p_pid;
2157c5afec6eSDmitry Chagin }
2158c5afec6eSDmitry Chagin 
215976183f34SDima Dorfman /*
2160ffb34484SMateusz Guzik  * Set initial process credentials.
2161ffb34484SMateusz Guzik  * Callers are responsible for providing the reference for provided credentials.
2162ffb34484SMateusz Guzik  */
2163ffb34484SMateusz Guzik void
2164ffb34484SMateusz Guzik proc_set_cred_init(struct proc *p, struct ucred *newcred)
2165ffb34484SMateusz Guzik {
2166ffb34484SMateusz Guzik 
21671724c563SMateusz Guzik 	p->p_ucred = crcowget(newcred);
2168ffb34484SMateusz Guzik }
2169ffb34484SMateusz Guzik 
2170ffb34484SMateusz Guzik /*
2171daf63fd2SMateusz Guzik  * Change process credentials.
2172ffb34484SMateusz Guzik  * Callers are responsible for providing the reference for passed credentials
2173daf63fd2SMateusz Guzik  * and for freeing old ones.
2174daf63fd2SMateusz Guzik  *
2175daf63fd2SMateusz Guzik  * Process has to be locked except when it does not have credentials (as it
2176daf63fd2SMateusz Guzik  * should not be visible just yet) or when newcred is NULL (as this can be
2177daf63fd2SMateusz Guzik  * only used when the process is about to be freed, at which point it should
2178daf63fd2SMateusz Guzik  * not be visible anymore).
2179daf63fd2SMateusz Guzik  */
21806f836483SMateusz Guzik void
2181daf63fd2SMateusz Guzik proc_set_cred(struct proc *p, struct ucred *newcred)
2182daf63fd2SMateusz Guzik {
21831724c563SMateusz Guzik 	struct ucred *cr;
2184daf63fd2SMateusz Guzik 
21851724c563SMateusz Guzik 	cr = p->p_ucred;
21861724c563SMateusz Guzik 	MPASS(cr != NULL);
2187daf63fd2SMateusz Guzik 	PROC_LOCK_ASSERT(p, MA_OWNED);
21881724c563SMateusz Guzik 	KASSERT(newcred->cr_users == 0, ("%s: users %d not 0 on cred %p",
21891724c563SMateusz Guzik 	    __func__, newcred->cr_users, newcred));
21901724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
21911724c563SMateusz Guzik 	KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
21921724c563SMateusz Guzik 	    __func__, cr->cr_users, cr));
21931724c563SMateusz Guzik 	cr->cr_users--;
21941724c563SMateusz Guzik 	mtx_unlock(&cr->cr_mtx);
2195daf63fd2SMateusz Guzik 	p->p_ucred = newcred;
21961724c563SMateusz Guzik 	newcred->cr_users = 1;
21974ea6a9a2SMateusz Guzik 	PROC_UPDATE_COW(p);
2198daf63fd2SMateusz Guzik }
2199daf63fd2SMateusz Guzik 
22005a90435cSMateusz Guzik void
22015a90435cSMateusz Guzik proc_unset_cred(struct proc *p)
22025a90435cSMateusz Guzik {
22035a90435cSMateusz Guzik 	struct ucred *cr;
22045a90435cSMateusz Guzik 
22051724c563SMateusz Guzik 	MPASS(p->p_state == PRS_ZOMBIE || p->p_state == PRS_NEW);
22065a90435cSMateusz Guzik 	cr = p->p_ucred;
22075a90435cSMateusz Guzik 	p->p_ucred = NULL;
22081724c563SMateusz Guzik 	KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
22091724c563SMateusz Guzik 	    __func__, cr->cr_users, cr));
22101724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
22111724c563SMateusz Guzik 	cr->cr_users--;
22121724c563SMateusz Guzik 	if (cr->cr_users == 0)
22131724c563SMateusz Guzik 		KASSERT(cr->cr_ref > 0, ("%s: ref %d not > 0 on cred %p",
22141724c563SMateusz Guzik 		    __func__, cr->cr_ref, cr));
22151724c563SMateusz Guzik 	mtx_unlock(&cr->cr_mtx);
22165a90435cSMateusz Guzik 	crfree(cr);
22175a90435cSMateusz Guzik }
22185a90435cSMateusz Guzik 
2219838d9858SBrooks Davis struct ucred *
2220838d9858SBrooks Davis crcopysafe(struct proc *p, struct ucred *cr)
2221838d9858SBrooks Davis {
2222838d9858SBrooks Davis 	struct ucred *oldcred;
2223838d9858SBrooks Davis 	int groups;
2224838d9858SBrooks Davis 
2225838d9858SBrooks Davis 	PROC_LOCK_ASSERT(p, MA_OWNED);
2226838d9858SBrooks Davis 
2227838d9858SBrooks Davis 	oldcred = p->p_ucred;
2228838d9858SBrooks Davis 	while (cr->cr_agroups < oldcred->cr_agroups) {
2229838d9858SBrooks Davis 		groups = oldcred->cr_agroups;
2230838d9858SBrooks Davis 		PROC_UNLOCK(p);
2231838d9858SBrooks Davis 		crextend(cr, groups);
2232838d9858SBrooks Davis 		PROC_LOCK(p);
2233838d9858SBrooks Davis 		oldcred = p->p_ucred;
2234838d9858SBrooks Davis 	}
2235838d9858SBrooks Davis 	crcopy(cr, oldcred);
2236838d9858SBrooks Davis 
2237838d9858SBrooks Davis 	return (oldcred);
2238838d9858SBrooks Davis }
2239838d9858SBrooks Davis 
2240838d9858SBrooks Davis /*
2241838d9858SBrooks Davis  * Extend the passed in credential to hold n items.
2242838d9858SBrooks Davis  */
2243c8358c6eSGleb Smirnoff void
2244838d9858SBrooks Davis crextend(struct ucred *cr, int n)
2245838d9858SBrooks Davis {
2246838d9858SBrooks Davis 	int cnt;
2247838d9858SBrooks Davis 
2248838d9858SBrooks Davis 	/* Truncate? */
2249838d9858SBrooks Davis 	if (n <= cr->cr_agroups)
2250838d9858SBrooks Davis 		return;
2251838d9858SBrooks Davis 
2252838d9858SBrooks Davis 	/*
2253838d9858SBrooks Davis 	 * We extend by 2 each time since we're using a power of two
2254838d9858SBrooks Davis 	 * allocator until we need enough groups to fill a page.
2255838d9858SBrooks Davis 	 * Once we're allocating multiple pages, only allocate as many
2256838d9858SBrooks Davis 	 * as we actually need.  The case of processes needing a
2257838d9858SBrooks Davis 	 * non-power of two number of pages seems more likely than
2258838d9858SBrooks Davis 	 * a real world process that adds thousands of groups one at a
2259838d9858SBrooks Davis 	 * time.
2260838d9858SBrooks Davis 	 */
2261838d9858SBrooks Davis 	if ( n < PAGE_SIZE / sizeof(gid_t) ) {
2262838d9858SBrooks Davis 		if (cr->cr_agroups == 0)
226351871224SRyan Libby 			cnt = MAX(1, MINALLOCSIZE / sizeof(gid_t));
2264838d9858SBrooks Davis 		else
2265838d9858SBrooks Davis 			cnt = cr->cr_agroups * 2;
2266838d9858SBrooks Davis 
2267838d9858SBrooks Davis 		while (cnt < n)
2268838d9858SBrooks Davis 			cnt *= 2;
2269838d9858SBrooks Davis 	} else
2270838d9858SBrooks Davis 		cnt = roundup2(n, PAGE_SIZE / sizeof(gid_t));
2271838d9858SBrooks Davis 
2272838d9858SBrooks Davis 	/* Free the old array. */
2273a99500a9SMateusz Guzik 	if (cr->cr_groups != cr->cr_smallgroups)
2274838d9858SBrooks Davis 		free(cr->cr_groups, M_CRED);
2275838d9858SBrooks Davis 
2276838d9858SBrooks Davis 	cr->cr_groups = malloc(cnt * sizeof(gid_t), M_CRED, M_WAITOK | M_ZERO);
2277838d9858SBrooks Davis 	cr->cr_agroups = cnt;
2278838d9858SBrooks Davis }
2279838d9858SBrooks Davis 
2280838d9858SBrooks Davis /*
22817f92e578SBrooks Davis  * Copy groups in to a credential, preserving any necessary invariants.
22827f92e578SBrooks Davis  * Currently this includes the sorting of all supplemental gids.
22837f92e578SBrooks Davis  * crextend() must have been called before hand to ensure sufficient
22847f92e578SBrooks Davis  * space is available.
2285838d9858SBrooks Davis  */
2286838d9858SBrooks Davis static void
2287838d9858SBrooks Davis crsetgroups_locked(struct ucred *cr, int ngrp, gid_t *groups)
2288838d9858SBrooks Davis {
22897f92e578SBrooks Davis 	int i;
22907f92e578SBrooks Davis 	int j;
22917f92e578SBrooks Davis 	gid_t g;
2292838d9858SBrooks Davis 
2293838d9858SBrooks Davis 	KASSERT(cr->cr_agroups >= ngrp, ("cr_ngroups is too small"));
2294838d9858SBrooks Davis 
2295838d9858SBrooks Davis 	bcopy(groups, cr->cr_groups, ngrp * sizeof(gid_t));
2296838d9858SBrooks Davis 	cr->cr_ngroups = ngrp;
22977f92e578SBrooks Davis 
22987f92e578SBrooks Davis 	/*
22997f92e578SBrooks Davis 	 * Sort all groups except cr_groups[0] to allow groupmember to
23007f92e578SBrooks Davis 	 * perform a binary search.
23017f92e578SBrooks Davis 	 *
23027f92e578SBrooks Davis 	 * XXX: If large numbers of groups become common this should
23037f92e578SBrooks Davis 	 * be replaced with shell sort like linux uses or possibly
23047f92e578SBrooks Davis 	 * heap sort.
23057f92e578SBrooks Davis 	 */
23067f92e578SBrooks Davis 	for (i = 2; i < ngrp; i++) {
23077f92e578SBrooks Davis 		g = cr->cr_groups[i];
23087f92e578SBrooks Davis 		for (j = i-1; j >= 1 && g < cr->cr_groups[j]; j--)
23097f92e578SBrooks Davis 			cr->cr_groups[j + 1] = cr->cr_groups[j];
23107f92e578SBrooks Davis 		cr->cr_groups[j + 1] = g;
23117f92e578SBrooks Davis 	}
2312838d9858SBrooks Davis }
2313838d9858SBrooks Davis 
2314838d9858SBrooks Davis /*
2315838d9858SBrooks Davis  * Copy groups in to a credential after expanding it if required.
2316412f9500SBrooks Davis  * Truncate the list to (ngroups_max + 1) if it is too large.
2317838d9858SBrooks Davis  */
2318838d9858SBrooks Davis void
2319838d9858SBrooks Davis crsetgroups(struct ucred *cr, int ngrp, gid_t *groups)
2320838d9858SBrooks Davis {
2321838d9858SBrooks Davis 
2322412f9500SBrooks Davis 	if (ngrp > ngroups_max + 1)
2323412f9500SBrooks Davis 		ngrp = ngroups_max + 1;
2324838d9858SBrooks Davis 
2325838d9858SBrooks Davis 	crextend(cr, ngrp);
2326838d9858SBrooks Davis 	crsetgroups_locked(cr, ngrp, groups);
2327838d9858SBrooks Davis }
2328838d9858SBrooks Davis 
23292eb927e2SJulian Elischer /*
2330df8bae1dSRodney W. Grimes  * Get login name, if available.
2331df8bae1dSRodney W. Grimes  */
2332d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
2333df8bae1dSRodney W. Grimes struct getlogin_args {
2334df8bae1dSRodney W. Grimes 	char	*namebuf;
2335df8bae1dSRodney W. Grimes 	u_int	namelen;
2336df8bae1dSRodney W. Grimes };
2337d2d3e875SBruce Evans #endif
2338df8bae1dSRodney W. Grimes /* ARGSUSED */
233926f9a767SRodney W. Grimes int
23408451d0ddSKip Macy sys_getlogin(struct thread *td, struct getlogin_args *uap)
2341df8bae1dSRodney W. Grimes {
2342f591779bSSeigo Tanimura 	char login[MAXLOGNAME];
2343b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
2344bccb6d5aSDag-Erling Smørgrav 	size_t len;
2345df8bae1dSRodney W. Grimes 
234630cf3ac4SAndrey A. Chernov 	if (uap->namelen > MAXLOGNAME)
234753490b76SAndrey A. Chernov 		uap->namelen = MAXLOGNAME;
2348f591779bSSeigo Tanimura 	PROC_LOCK(p);
2349f591779bSSeigo Tanimura 	SESS_LOCK(p->p_session);
2350bccb6d5aSDag-Erling Smørgrav 	len = strlcpy(login, p->p_session->s_login, uap->namelen) + 1;
2351f591779bSSeigo Tanimura 	SESS_UNLOCK(p->p_session);
2352f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
2353bccb6d5aSDag-Erling Smørgrav 	if (len > uap->namelen)
23546f68699fSBaptiste Daroussin 		return (ERANGE);
2355bccb6d5aSDag-Erling Smørgrav 	return (copyout(login, uap->namebuf, len));
2356df8bae1dSRodney W. Grimes }
2357df8bae1dSRodney W. Grimes 
2358df8bae1dSRodney W. Grimes /*
2359df8bae1dSRodney W. Grimes  * Set login name.
2360df8bae1dSRodney W. Grimes  */
2361d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
2362df8bae1dSRodney W. Grimes struct setlogin_args {
2363df8bae1dSRodney W. Grimes 	char	*namebuf;
2364df8bae1dSRodney W. Grimes };
2365d2d3e875SBruce Evans #endif
2366df8bae1dSRodney W. Grimes /* ARGSUSED */
236726f9a767SRodney W. Grimes int
23688451d0ddSKip Macy sys_setlogin(struct thread *td, struct setlogin_args *uap)
2369df8bae1dSRodney W. Grimes {
2370b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
2371df8bae1dSRodney W. Grimes 	int error;
2372964ca0caSAndrey A. Chernov 	char logintmp[MAXLOGNAME];
2373df8bae1dSRodney W. Grimes 
2374bccb6d5aSDag-Erling Smørgrav 	CTASSERT(sizeof(p->p_session->s_login) >= sizeof(logintmp));
2375bccb6d5aSDag-Erling Smørgrav 
237632f9753cSRobert Watson 	error = priv_check(td, PRIV_PROC_SETLOGIN);
237707f3485dSJohn Baldwin 	if (error)
237807f3485dSJohn Baldwin 		return (error);
23797f05b035SAlfred Perlstein 	error = copyinstr(uap->namebuf, logintmp, sizeof(logintmp), NULL);
2380bccb6d5aSDag-Erling Smørgrav 	if (error != 0) {
2381eb725b4eSRobert Watson 		if (error == ENAMETOOLONG)
2382df8bae1dSRodney W. Grimes 			error = EINVAL;
2383bccb6d5aSDag-Erling Smørgrav 		return (error);
2384bccb6d5aSDag-Erling Smørgrav 	}
238570a98c11SRobert Watson 	AUDIT_ARG_LOGIN(logintmp);
2386f591779bSSeigo Tanimura 	PROC_LOCK(p);
2387f591779bSSeigo Tanimura 	SESS_LOCK(p->p_session);
2388bccb6d5aSDag-Erling Smørgrav 	strcpy(p->p_session->s_login, logintmp);
2389f591779bSSeigo Tanimura 	SESS_UNLOCK(p->p_session);
2390f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
2391bccb6d5aSDag-Erling Smørgrav 	return (0);
2392df8bae1dSRodney W. Grimes }
2393d5f81602SSean Eric Fagan 
2394d5f81602SSean Eric Fagan void
23954c44ad8eSJohn Baldwin setsugid(struct proc *p)
2396d5f81602SSean Eric Fagan {
2397f2102dadSAlfred Perlstein 
2398f2102dadSAlfred Perlstein 	PROC_LOCK_ASSERT(p, MA_OWNED);
2399d5f81602SSean Eric Fagan 	p->p_flag |= P_SUGID;
2400d5f81602SSean Eric Fagan }
2401f535380cSDon Lewis 
24021a996ed1SEdward Tomasz Napierala /*-
24037fd6a959SRobert Watson  * Change a process's effective uid.
2404b1fc0ec1SRobert Watson  * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified.
2405b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2406b1fc0ec1SRobert Watson  *             duration of the call.
2407f535380cSDon Lewis  */
2408f535380cSDon Lewis void
24091419eacbSAlfred Perlstein change_euid(struct ucred *newcred, struct uidinfo *euip)
2410f535380cSDon Lewis {
2411f535380cSDon Lewis 
24121419eacbSAlfred Perlstein 	newcred->cr_uid = euip->ui_uid;
24131419eacbSAlfred Perlstein 	uihold(euip);
2414b1fc0ec1SRobert Watson 	uifree(newcred->cr_uidinfo);
24151419eacbSAlfred Perlstein 	newcred->cr_uidinfo = euip;
2416f535380cSDon Lewis }
2417f535380cSDon Lewis 
24181a996ed1SEdward Tomasz Napierala /*-
24197fd6a959SRobert Watson  * Change a process's effective gid.
2420b1fc0ec1SRobert Watson  * Side effects: newcred->cr_gid will be modified.
2421b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2422b1fc0ec1SRobert Watson  *             duration of the call.
2423f535380cSDon Lewis  */
2424810bfc8eSAndrew Gallatin void
24254c44ad8eSJohn Baldwin change_egid(struct ucred *newcred, gid_t egid)
2426b1fc0ec1SRobert Watson {
2427b1fc0ec1SRobert Watson 
2428b1fc0ec1SRobert Watson 	newcred->cr_groups[0] = egid;
2429b1fc0ec1SRobert Watson }
2430b1fc0ec1SRobert Watson 
24311a996ed1SEdward Tomasz Napierala /*-
24327fd6a959SRobert Watson  * Change a process's real uid.
2433b1fc0ec1SRobert Watson  * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo
2434b1fc0ec1SRobert Watson  *               will be updated, and the old and new cr_ruidinfo proc
2435b1fc0ec1SRobert Watson  *               counts will be updated.
2436b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2437b1fc0ec1SRobert Watson  *             duration of the call.
2438b1fc0ec1SRobert Watson  */
2439b1fc0ec1SRobert Watson void
24401419eacbSAlfred Perlstein change_ruid(struct ucred *newcred, struct uidinfo *ruip)
2441f535380cSDon Lewis {
2442f535380cSDon Lewis 
2443b1fc0ec1SRobert Watson 	(void)chgproccnt(newcred->cr_ruidinfo, -1, 0);
24441419eacbSAlfred Perlstein 	newcred->cr_ruid = ruip->ui_uid;
24451419eacbSAlfred Perlstein 	uihold(ruip);
2446b1fc0ec1SRobert Watson 	uifree(newcred->cr_ruidinfo);
24471419eacbSAlfred Perlstein 	newcred->cr_ruidinfo = ruip;
2448b1fc0ec1SRobert Watson 	(void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
2449b1fc0ec1SRobert Watson }
2450b1fc0ec1SRobert Watson 
24511a996ed1SEdward Tomasz Napierala /*-
24527fd6a959SRobert Watson  * Change a process's real gid.
2453b1fc0ec1SRobert Watson  * Side effects: newcred->cr_rgid will be updated.
2454b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2455b1fc0ec1SRobert Watson  *             duration of the call.
2456b1fc0ec1SRobert Watson  */
2457b1fc0ec1SRobert Watson void
24584c44ad8eSJohn Baldwin change_rgid(struct ucred *newcred, gid_t rgid)
2459b1fc0ec1SRobert Watson {
2460b1fc0ec1SRobert Watson 
2461b1fc0ec1SRobert Watson 	newcred->cr_rgid = rgid;
2462b1fc0ec1SRobert Watson }
2463b1fc0ec1SRobert Watson 
24641a996ed1SEdward Tomasz Napierala /*-
24657fd6a959SRobert Watson  * Change a process's saved uid.
2466b1fc0ec1SRobert Watson  * Side effects: newcred->cr_svuid will be updated.
2467b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2468b1fc0ec1SRobert Watson  *             duration of the call.
2469b1fc0ec1SRobert Watson  */
2470b1fc0ec1SRobert Watson void
24714c44ad8eSJohn Baldwin change_svuid(struct ucred *newcred, uid_t svuid)
2472b1fc0ec1SRobert Watson {
2473b1fc0ec1SRobert Watson 
2474b1fc0ec1SRobert Watson 	newcred->cr_svuid = svuid;
2475b1fc0ec1SRobert Watson }
2476b1fc0ec1SRobert Watson 
24771a996ed1SEdward Tomasz Napierala /*-
24787fd6a959SRobert Watson  * Change a process's saved gid.
2479b1fc0ec1SRobert Watson  * Side effects: newcred->cr_svgid will be updated.
2480b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2481b1fc0ec1SRobert Watson  *             duration of the call.
2482b1fc0ec1SRobert Watson  */
2483b1fc0ec1SRobert Watson void
24844c44ad8eSJohn Baldwin change_svgid(struct ucred *newcred, gid_t svgid)
2485b1fc0ec1SRobert Watson {
2486b1fc0ec1SRobert Watson 
2487b1fc0ec1SRobert Watson 	newcred->cr_svgid = svgid;
2488f535380cSDon Lewis }
2489*fe6db727SKonstantin Belousov 
2490*fe6db727SKonstantin Belousov bool allow_ptrace = true;
2491*fe6db727SKonstantin Belousov SYSCTL_BOOL(_security_bsd, OID_AUTO, allow_ptrace, CTLFLAG_RWTUN,
2492*fe6db727SKonstantin Belousov     &allow_ptrace, 0,
2493*fe6db727SKonstantin Belousov     "Deny ptrace(2) use by returning ENOSYS");
2494