xref: /freebsd/sys/kern/kern_prot.c (revision 7974ca1cdbee949f5e453eea112be265b425c407)
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>
47f08ef6c5SBjoern A. Zeeb #include "opt_inet.h"
48f08ef6c5SBjoern A. Zeeb #include "opt_inet6.h"
495591b823SEivind Eklund 
50df8bae1dSRodney W. Grimes #include <sys/param.h>
51df8bae1dSRodney W. Grimes #include <sys/systm.h>
52fb919e4dSMark Murray #include <sys/acct.h>
53df04411aSRobert Watson #include <sys/kdb.h>
541c5bb3eaSPeter Wemm #include <sys/kernel.h>
5598f03f90SJake Burkholder #include <sys/lock.h>
562bfc50bcSEdward Tomasz Napierala #include <sys/loginclass.h>
57f9d0d524SRobert Watson #include <sys/malloc.h>
58fb919e4dSMark Murray #include <sys/mutex.h>
59fe6db727SKonstantin Belousov #include <sys/ptrace.h>
607e9e371fSJohn Baldwin #include <sys/refcount.h>
615b29d6e9SJohn Baldwin #include <sys/sx.h>
62800c9408SRobert Watson #include <sys/priv.h>
63f591779bSSeigo Tanimura #include <sys/proc.h>
6431d1b816SDmitry Chagin #ifdef COMPAT_43
657e097daaSKonstantin Belousov #include <sys/sysent.h>
6631d1b816SDmitry Chagin #endif
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 	pgrp = NULL;
334df8bae1dSRodney W. Grimes 
335ef739c73SKonstantin Belousov 	newpgrp = uma_zalloc(pgrp_zone, M_WAITOK);
3361ede983cSDag-Erling Smørgrav 	newsess = malloc(sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO);
337f591779bSSeigo Tanimura 
3383360b485SKonstantin Belousov again:
3393360b485SKonstantin Belousov 	error = 0;
340c8b1829dSJohn Baldwin 	sx_xlock(&proctree_lock);
341f591779bSSeigo Tanimura 
342f591779bSSeigo Tanimura 	if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) {
343f591779bSSeigo Tanimura 		if (pgrp != NULL)
344f591779bSSeigo Tanimura 			PGRP_UNLOCK(pgrp);
345835a82eeSMatthew Dillon 		error = EPERM;
346f591779bSSeigo Tanimura 	} else {
3473360b485SKonstantin Belousov 		error = enterpgrp(p, p->p_pid, newpgrp, newsess);
3487a70f17aSKonstantin Belousov 		if (error == ERESTART)
3493360b485SKonstantin Belousov 			goto again;
3503360b485SKonstantin Belousov 		MPASS(error == 0);
351b40ce416SJulian Elischer 		td->td_retval[0] = p->p_pid;
352c8b1829dSJohn Baldwin 		newpgrp = NULL;
353c8b1829dSJohn Baldwin 		newsess = NULL;
354df8bae1dSRodney W. Grimes 	}
355f591779bSSeigo Tanimura 
356c8b1829dSJohn Baldwin 	sx_xunlock(&proctree_lock);
357f591779bSSeigo Tanimura 
358ef739c73SKonstantin Belousov 	uma_zfree(pgrp_zone, newpgrp);
3591ede983cSDag-Erling Smørgrav 	free(newsess, M_SESSION);
3601c2451c2SSeigo Tanimura 
361c8b1829dSJohn Baldwin 	return (error);
362df8bae1dSRodney W. Grimes }
363df8bae1dSRodney W. Grimes 
364df8bae1dSRodney W. Grimes /*
365df8bae1dSRodney W. Grimes  * set process group (setpgid/old setpgrp)
366df8bae1dSRodney W. Grimes  *
367df8bae1dSRodney W. Grimes  * caller does setpgid(targpid, targpgid)
368df8bae1dSRodney W. Grimes  *
369df8bae1dSRodney W. Grimes  * pid must be caller or child of caller (ESRCH)
370df8bae1dSRodney W. Grimes  * if a child
371df8bae1dSRodney W. Grimes  *	pid must be in same session (EPERM)
372df8bae1dSRodney W. Grimes  *	pid can't have done an exec (EACCES)
373df8bae1dSRodney W. Grimes  * if pgid != pid
374df8bae1dSRodney W. Grimes  * 	there must exist some pid in same session having pgid (EPERM)
375df8bae1dSRodney W. Grimes  * pid must not be session leader (EPERM)
376df8bae1dSRodney W. Grimes  */
377d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
378df8bae1dSRodney W. Grimes struct setpgid_args {
379df8bae1dSRodney W. Grimes 	int	pid;		/* target process id */
380df8bae1dSRodney W. Grimes 	int	pgid;		/* target pgrp id */
381df8bae1dSRodney W. Grimes };
382d2d3e875SBruce Evans #endif
383df8bae1dSRodney W. Grimes /* ARGSUSED */
38426f9a767SRodney W. Grimes int
3853e85b721SEd Maste sys_setpgid(struct thread *td, struct setpgid_args *uap)
386df8bae1dSRodney W. Grimes {
387b40ce416SJulian Elischer 	struct proc *curp = td->td_proc;
3883e85b721SEd Maste 	struct proc *targp;	/* target process */
3893e85b721SEd Maste 	struct pgrp *pgrp;	/* target pgrp */
390eb9e5c1dSRobert Watson 	int error;
391f591779bSSeigo Tanimura 	struct pgrp *newpgrp;
392df8bae1dSRodney W. Grimes 
39378f64bccSBruce Evans 	if (uap->pgid < 0)
39478f64bccSBruce Evans 		return (EINVAL);
395f591779bSSeigo Tanimura 
396ef739c73SKonstantin Belousov 	newpgrp = uma_zalloc(pgrp_zone, M_WAITOK);
397f591779bSSeigo Tanimura 
3983360b485SKonstantin Belousov again:
3993360b485SKonstantin Belousov 	error = 0;
4003360b485SKonstantin Belousov 
401c8b1829dSJohn Baldwin 	sx_xlock(&proctree_lock);
402df8bae1dSRodney W. Grimes 	if (uap->pid != 0 && uap->pid != curp->p_pid) {
403f591779bSSeigo Tanimura 		if ((targp = pfind(uap->pid)) == NULL) {
404835a82eeSMatthew Dillon 			error = ESRCH;
405c8b1829dSJohn Baldwin 			goto done;
40633a9ed9dSJohn Baldwin 		}
407f591779bSSeigo Tanimura 		if (!inferior(targp)) {
408f591779bSSeigo Tanimura 			PROC_UNLOCK(targp);
4092f932587SSeigo Tanimura 			error = ESRCH;
410c8b1829dSJohn Baldwin 			goto done;
411f591779bSSeigo Tanimura 		}
41271a057bcSRobert Watson 		if ((error = p_cansee(td, targp))) {
41333a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
414c8b1829dSJohn Baldwin 			goto done;
41533a9ed9dSJohn Baldwin 		}
41633a9ed9dSJohn Baldwin 		if (targp->p_pgrp == NULL ||
41733a9ed9dSJohn Baldwin 		    targp->p_session != curp->p_session) {
41833a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
419835a82eeSMatthew Dillon 			error = EPERM;
420c8b1829dSJohn Baldwin 			goto done;
42133a9ed9dSJohn Baldwin 		}
42233a9ed9dSJohn Baldwin 		if (targp->p_flag & P_EXEC) {
42333a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
424835a82eeSMatthew Dillon 			error = EACCES;
425c8b1829dSJohn Baldwin 			goto done;
42633a9ed9dSJohn Baldwin 		}
42733a9ed9dSJohn Baldwin 		PROC_UNLOCK(targp);
428f591779bSSeigo Tanimura 	} else
429f591779bSSeigo Tanimura 		targp = curp;
430f591779bSSeigo Tanimura 	if (SESS_LEADER(targp)) {
431835a82eeSMatthew Dillon 		error = EPERM;
432c8b1829dSJohn Baldwin 		goto done;
43333a9ed9dSJohn Baldwin 	}
434eb725b4eSRobert Watson 	if (uap->pgid == 0)
435df8bae1dSRodney W. Grimes 		uap->pgid = targp->p_pid;
436a10d5f02SOlivier Houchard 	if ((pgrp = pgfind(uap->pgid)) == NULL) {
437f591779bSSeigo Tanimura 		if (uap->pgid == targp->p_pid) {
438a10d5f02SOlivier Houchard 			error = enterpgrp(targp, uap->pgid, newpgrp,
439a10d5f02SOlivier Houchard 			    NULL);
440f591779bSSeigo Tanimura 			if (error == 0)
441f591779bSSeigo Tanimura 				newpgrp = NULL;
442a10d5f02SOlivier Houchard 		} else
443835a82eeSMatthew Dillon 			error = EPERM;
444a10d5f02SOlivier Houchard 	} else {
445f591779bSSeigo Tanimura 		if (pgrp == targp->p_pgrp) {
446f591779bSSeigo Tanimura 			PGRP_UNLOCK(pgrp);
447f591779bSSeigo Tanimura 			goto done;
44833a9ed9dSJohn Baldwin 		}
449a10d5f02SOlivier Houchard 		if (pgrp->pg_id != targp->p_pid &&
450a10d5f02SOlivier Houchard 		    pgrp->pg_session != curp->p_session) {
451a10d5f02SOlivier Houchard 			PGRP_UNLOCK(pgrp);
452a10d5f02SOlivier Houchard 			error = EPERM;
453a10d5f02SOlivier Houchard 			goto done;
454a10d5f02SOlivier Houchard 		}
455f591779bSSeigo Tanimura 		PGRP_UNLOCK(pgrp);
456f591779bSSeigo Tanimura 		error = enterthispgrp(targp, pgrp);
457f591779bSSeigo Tanimura 	}
458f591779bSSeigo Tanimura done:
459ed84cb59SKonstantin Belousov 	KASSERT(error == 0 || newpgrp != NULL,
460c8b1829dSJohn Baldwin 	    ("setpgid failed and newpgrp is NULL"));
4613360b485SKonstantin Belousov 	if (error == ERESTART)
4623360b485SKonstantin Belousov 		goto again;
4637a70f17aSKonstantin Belousov 	sx_xunlock(&proctree_lock);
464ef739c73SKonstantin Belousov 	uma_zfree(pgrp_zone, newpgrp);
465835a82eeSMatthew Dillon 	return (error);
466df8bae1dSRodney W. Grimes }
467df8bae1dSRodney W. Grimes 
468a08f4bf6SPeter Wemm /*
469a08f4bf6SPeter Wemm  * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
4702fa72ea7SJeroen Ruigrok van der Werven  * compatible.  It says that setting the uid/gid to euid/egid is a special
471a08f4bf6SPeter Wemm  * case of "appropriate privilege".  Once the rules are expanded out, this
472a08f4bf6SPeter Wemm  * basically means that setuid(nnn) sets all three id's, in all permitted
473a08f4bf6SPeter Wemm  * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
474a08f4bf6SPeter Wemm  * does not set the saved id - this is dangerous for traditional BSD
475a08f4bf6SPeter Wemm  * programs.  For this reason, we *really* do not want to set
476a08f4bf6SPeter Wemm  * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
477a08f4bf6SPeter Wemm  */
478a08f4bf6SPeter Wemm #define POSIX_APPENDIX_B_4_2_2
479a08f4bf6SPeter Wemm 
480d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
481df8bae1dSRodney W. Grimes struct setuid_args {
482df8bae1dSRodney W. Grimes 	uid_t	uid;
483df8bae1dSRodney W. Grimes };
484d2d3e875SBruce Evans #endif
485df8bae1dSRodney W. Grimes /* ARGSUSED */
48626f9a767SRodney W. Grimes int
4878451d0ddSKip Macy sys_setuid(struct thread *td, struct setuid_args *uap)
488df8bae1dSRodney W. Grimes {
489b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
490b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
491b1fc0ec1SRobert Watson 	uid_t uid;
4921419eacbSAlfred Perlstein 	struct uidinfo *uip;
493eb725b4eSRobert Watson 	int error;
494df8bae1dSRodney W. Grimes 
49507f3485dSJohn Baldwin 	uid = uap->uid;
49614961ba7SRobert Watson 	AUDIT_ARG_UID(uid);
49707f3485dSJohn Baldwin 	newcred = crget();
4981419eacbSAlfred Perlstein 	uip = uifind(uid);
49907f3485dSJohn Baldwin 	PROC_LOCK(p);
500838d9858SBrooks Davis 	/*
501838d9858SBrooks Davis 	 * Copy credentials so other references do not see our changes.
502838d9858SBrooks Davis 	 */
503838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
5045a92ee3cSRobert Watson 
505030a28b3SRobert Watson #ifdef MAC
5066f6174a7SRobert Watson 	error = mac_cred_check_setuid(oldcred, uid);
507030a28b3SRobert Watson 	if (error)
508030a28b3SRobert Watson 		goto fail;
509030a28b3SRobert Watson #endif
510030a28b3SRobert Watson 
511a08f4bf6SPeter Wemm 	/*
512a08f4bf6SPeter Wemm 	 * See if we have "permission" by POSIX 1003.1 rules.
513a08f4bf6SPeter Wemm 	 *
514a08f4bf6SPeter Wemm 	 * Note that setuid(geteuid()) is a special case of
515a08f4bf6SPeter Wemm 	 * "appropriate privileges" in appendix B.4.2.2.  We need
5162fa72ea7SJeroen Ruigrok van der Werven 	 * to use this clause to be compatible with traditional BSD
517a08f4bf6SPeter Wemm 	 * semantics.  Basically, it means that "setuid(xx)" sets all
518a08f4bf6SPeter Wemm 	 * three id's (assuming you have privs).
519a08f4bf6SPeter Wemm 	 *
520a08f4bf6SPeter Wemm 	 * Notes on the logic.  We do things in three steps.
521a08f4bf6SPeter Wemm 	 * 1: We determine if the euid is going to change, and do EPERM
522a08f4bf6SPeter Wemm 	 *    right away.  We unconditionally change the euid later if this
523a08f4bf6SPeter Wemm 	 *    test is satisfied, simplifying that part of the logic.
524eb725b4eSRobert Watson 	 * 2: We determine if the real and/or saved uids are going to
525a08f4bf6SPeter Wemm 	 *    change.  Determined by compile options.
526a08f4bf6SPeter Wemm 	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
527a08f4bf6SPeter Wemm 	 */
528b1fc0ec1SRobert Watson 	if (uid != oldcred->cr_ruid &&		/* allow setuid(getuid()) */
5293f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS
530b1fc0ec1SRobert Watson 	    uid != oldcred->cr_svuid &&		/* allow setuid(saved gid) */
531a08f4bf6SPeter Wemm #endif
532a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
533b1fc0ec1SRobert Watson 	    uid != oldcred->cr_uid &&		/* allow setuid(geteuid()) */
5343f246666SAndrey A. Chernov #endif
535cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETUID)) != 0)
536030a28b3SRobert Watson 		goto fail;
537a08f4bf6SPeter Wemm 
538a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS
539df8bae1dSRodney W. Grimes 	/*
540a08f4bf6SPeter Wemm 	 * Do we have "appropriate privileges" (are we root or uid == euid)
541a08f4bf6SPeter Wemm 	 * If so, we are changing the real uid and/or saved uid.
542df8bae1dSRodney W. Grimes 	 */
5433f246666SAndrey A. Chernov 	if (
544a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
545b1fc0ec1SRobert Watson 	    uid == oldcred->cr_uid ||
5463f246666SAndrey A. Chernov #endif
547800c9408SRobert Watson 	    /* We are using privs. */
548cc426dd3SMateusz Guzik 	    priv_check_cred(oldcred, PRIV_CRED_SETUID) == 0)
549a08f4bf6SPeter Wemm #endif
550a08f4bf6SPeter Wemm 	{
551a08f4bf6SPeter Wemm 		/*
552f535380cSDon Lewis 		 * Set the real uid and transfer proc count to new user.
553a08f4bf6SPeter Wemm 		 */
554b1fc0ec1SRobert Watson 		if (uid != oldcred->cr_ruid) {
5551419eacbSAlfred Perlstein 			change_ruid(newcred, uip);
556f535380cSDon Lewis 			setsugid(p);
557d3cdb93dSAndrey A. Chernov 		}
558a08f4bf6SPeter Wemm 		/*
559a08f4bf6SPeter Wemm 		 * Set saved uid
560a08f4bf6SPeter Wemm 		 *
561a08f4bf6SPeter Wemm 		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
562a08f4bf6SPeter Wemm 		 * the security of seteuid() depends on it.  B.4.2.2 says it
563a08f4bf6SPeter Wemm 		 * is important that we should do this.
564a08f4bf6SPeter Wemm 		 */
565b1fc0ec1SRobert Watson 		if (uid != oldcred->cr_svuid) {
566b1fc0ec1SRobert Watson 			change_svuid(newcred, uid);
567d5f81602SSean Eric Fagan 			setsugid(p);
568a08f4bf6SPeter Wemm 		}
569a08f4bf6SPeter Wemm 	}
570a08f4bf6SPeter Wemm 
571a08f4bf6SPeter Wemm 	/*
572a08f4bf6SPeter Wemm 	 * In all permitted cases, we are changing the euid.
573a08f4bf6SPeter Wemm 	 */
574b1fc0ec1SRobert Watson 	if (uid != oldcred->cr_uid) {
5751419eacbSAlfred Perlstein 		change_euid(newcred, uip);
576d5f81602SSean Eric Fagan 		setsugid(p);
577a08f4bf6SPeter Wemm 	}
578daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
579e4dcb704SEdward Tomasz Napierala #ifdef RACCT
580e4dcb704SEdward Tomasz Napierala 	racct_proc_ucred_changed(p, oldcred, newcred);
581f87beb93SAndriy Gapon 	crhold(newcred);
582f87beb93SAndriy Gapon #endif
583f87beb93SAndriy Gapon 	PROC_UNLOCK(p);
584f87beb93SAndriy Gapon #ifdef RCTL
585f87beb93SAndriy Gapon 	rctl_proc_ucred_changed(p, newcred);
586f87beb93SAndriy Gapon 	crfree(newcred);
587e4dcb704SEdward Tomasz Napierala #endif
5881419eacbSAlfred Perlstein 	uifree(uip);
589b1fc0ec1SRobert Watson 	crfree(oldcred);
59007f3485dSJohn Baldwin 	return (0);
591030a28b3SRobert Watson 
592030a28b3SRobert Watson fail:
593030a28b3SRobert Watson 	PROC_UNLOCK(p);
594030a28b3SRobert Watson 	uifree(uip);
595030a28b3SRobert Watson 	crfree(newcred);
596030a28b3SRobert Watson 	return (error);
597df8bae1dSRodney W. Grimes }
598df8bae1dSRodney W. Grimes 
599d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
600df8bae1dSRodney W. Grimes struct seteuid_args {
601df8bae1dSRodney W. Grimes 	uid_t	euid;
602df8bae1dSRodney W. Grimes };
603d2d3e875SBruce Evans #endif
604df8bae1dSRodney W. Grimes /* ARGSUSED */
60526f9a767SRodney W. Grimes int
6068451d0ddSKip Macy sys_seteuid(struct thread *td, struct seteuid_args *uap)
607df8bae1dSRodney W. Grimes {
608b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
609b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
610b1fc0ec1SRobert Watson 	uid_t euid;
6111419eacbSAlfred Perlstein 	struct uidinfo *euip;
612eb725b4eSRobert Watson 	int error;
613df8bae1dSRodney W. Grimes 
614df8bae1dSRodney W. Grimes 	euid = uap->euid;
61514961ba7SRobert Watson 	AUDIT_ARG_EUID(euid);
61607f3485dSJohn Baldwin 	newcred = crget();
6171419eacbSAlfred Perlstein 	euip = uifind(euid);
61807f3485dSJohn Baldwin 	PROC_LOCK(p);
619838d9858SBrooks Davis 	/*
620838d9858SBrooks Davis 	 * Copy credentials so other references do not see our changes.
621838d9858SBrooks Davis 	 */
622838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
623030a28b3SRobert Watson 
624030a28b3SRobert Watson #ifdef MAC
6256f6174a7SRobert Watson 	error = mac_cred_check_seteuid(oldcred, euid);
626030a28b3SRobert Watson 	if (error)
627030a28b3SRobert Watson 		goto fail;
628030a28b3SRobert Watson #endif
629030a28b3SRobert Watson 
630b1fc0ec1SRobert Watson 	if (euid != oldcred->cr_ruid &&		/* allow seteuid(getuid()) */
631b1fc0ec1SRobert Watson 	    euid != oldcred->cr_svuid &&	/* allow seteuid(saved uid) */
632cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETEUID)) != 0)
633030a28b3SRobert Watson 		goto fail;
634030a28b3SRobert Watson 
635df8bae1dSRodney W. Grimes 	/*
636838d9858SBrooks Davis 	 * Everything's okay, do it.
637df8bae1dSRodney W. Grimes 	 */
638b1fc0ec1SRobert Watson 	if (oldcred->cr_uid != euid) {
6391419eacbSAlfred Perlstein 		change_euid(newcred, euip);
640d5f81602SSean Eric Fagan 		setsugid(p);
641229a15f0SPeter Wemm 	}
642daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
64307f3485dSJohn Baldwin 	PROC_UNLOCK(p);
6441419eacbSAlfred Perlstein 	uifree(euip);
645b1fc0ec1SRobert Watson 	crfree(oldcred);
64607f3485dSJohn Baldwin 	return (0);
647030a28b3SRobert Watson 
648030a28b3SRobert Watson fail:
649030a28b3SRobert Watson 	PROC_UNLOCK(p);
650030a28b3SRobert Watson 	uifree(euip);
651030a28b3SRobert Watson 	crfree(newcred);
652030a28b3SRobert Watson 	return (error);
653df8bae1dSRodney W. Grimes }
654df8bae1dSRodney W. Grimes 
655d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
656df8bae1dSRodney W. Grimes struct setgid_args {
657df8bae1dSRodney W. Grimes 	gid_t	gid;
658df8bae1dSRodney W. Grimes };
659d2d3e875SBruce Evans #endif
660df8bae1dSRodney W. Grimes /* ARGSUSED */
66126f9a767SRodney W. Grimes int
6628451d0ddSKip Macy sys_setgid(struct thread *td, struct setgid_args *uap)
663df8bae1dSRodney W. Grimes {
664b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
665b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
666b1fc0ec1SRobert Watson 	gid_t gid;
667eb725b4eSRobert Watson 	int error;
668df8bae1dSRodney W. Grimes 
669b1fc0ec1SRobert Watson 	gid = uap->gid;
67014961ba7SRobert Watson 	AUDIT_ARG_GID(gid);
67107f3485dSJohn Baldwin 	newcred = crget();
67207f3485dSJohn Baldwin 	PROC_LOCK(p);
673838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
6745a92ee3cSRobert Watson 
675030a28b3SRobert Watson #ifdef MAC
6766f6174a7SRobert Watson 	error = mac_cred_check_setgid(oldcred, gid);
677030a28b3SRobert Watson 	if (error)
678030a28b3SRobert Watson 		goto fail;
679030a28b3SRobert Watson #endif
680030a28b3SRobert Watson 
681a08f4bf6SPeter Wemm 	/*
682a08f4bf6SPeter Wemm 	 * See if we have "permission" by POSIX 1003.1 rules.
683a08f4bf6SPeter Wemm 	 *
684a08f4bf6SPeter Wemm 	 * Note that setgid(getegid()) is a special case of
685a08f4bf6SPeter Wemm 	 * "appropriate privileges" in appendix B.4.2.2.  We need
6862fa72ea7SJeroen Ruigrok van der Werven 	 * to use this clause to be compatible with traditional BSD
687a08f4bf6SPeter Wemm 	 * semantics.  Basically, it means that "setgid(xx)" sets all
688a08f4bf6SPeter Wemm 	 * three id's (assuming you have privs).
689a08f4bf6SPeter Wemm 	 *
690a08f4bf6SPeter Wemm 	 * For notes on the logic here, see setuid() above.
691a08f4bf6SPeter Wemm 	 */
692b1fc0ec1SRobert Watson 	if (gid != oldcred->cr_rgid &&		/* allow setgid(getgid()) */
6933f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS
694b1fc0ec1SRobert Watson 	    gid != oldcred->cr_svgid &&		/* allow setgid(saved gid) */
695a08f4bf6SPeter Wemm #endif
696a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
697b1fc0ec1SRobert Watson 	    gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */
6983f246666SAndrey A. Chernov #endif
699cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETGID)) != 0)
700030a28b3SRobert Watson 		goto fail;
701a08f4bf6SPeter Wemm 
702a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS
703a08f4bf6SPeter Wemm 	/*
704a08f4bf6SPeter Wemm 	 * Do we have "appropriate privileges" (are we root or gid == egid)
705a08f4bf6SPeter Wemm 	 * If so, we are changing the real uid and saved gid.
706a08f4bf6SPeter Wemm 	 */
707a08f4bf6SPeter Wemm 	if (
708a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
709b1fc0ec1SRobert Watson 	    gid == oldcred->cr_groups[0] ||
710a08f4bf6SPeter Wemm #endif
711800c9408SRobert Watson 	    /* We are using privs. */
712cc426dd3SMateusz Guzik 	    priv_check_cred(oldcred, PRIV_CRED_SETGID) == 0)
713a08f4bf6SPeter Wemm #endif
714a08f4bf6SPeter Wemm 	{
715a08f4bf6SPeter Wemm 		/*
716a08f4bf6SPeter Wemm 		 * Set real gid
717a08f4bf6SPeter Wemm 		 */
718b1fc0ec1SRobert Watson 		if (oldcred->cr_rgid != gid) {
719b1fc0ec1SRobert Watson 			change_rgid(newcred, gid);
720d5f81602SSean Eric Fagan 			setsugid(p);
721a08f4bf6SPeter Wemm 		}
722a08f4bf6SPeter Wemm 		/*
723a08f4bf6SPeter Wemm 		 * Set saved gid
724a08f4bf6SPeter Wemm 		 *
725a08f4bf6SPeter Wemm 		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
726a08f4bf6SPeter Wemm 		 * the security of setegid() depends on it.  B.4.2.2 says it
727a08f4bf6SPeter Wemm 		 * is important that we should do this.
728a08f4bf6SPeter Wemm 		 */
729b1fc0ec1SRobert Watson 		if (oldcred->cr_svgid != gid) {
730b1fc0ec1SRobert Watson 			change_svgid(newcred, gid);
731d5f81602SSean Eric Fagan 			setsugid(p);
732a08f4bf6SPeter Wemm 		}
733a08f4bf6SPeter Wemm 	}
734a08f4bf6SPeter Wemm 	/*
735a08f4bf6SPeter Wemm 	 * In all cases permitted cases, we are changing the egid.
736a08f4bf6SPeter Wemm 	 * Copy credentials so other references do not see our changes.
737a08f4bf6SPeter Wemm 	 */
738b1fc0ec1SRobert Watson 	if (oldcred->cr_groups[0] != gid) {
739b1fc0ec1SRobert Watson 		change_egid(newcred, gid);
740d5f81602SSean Eric Fagan 		setsugid(p);
741a08f4bf6SPeter Wemm 	}
742daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
74307f3485dSJohn Baldwin 	PROC_UNLOCK(p);
744b1fc0ec1SRobert Watson 	crfree(oldcred);
74507f3485dSJohn Baldwin 	return (0);
746030a28b3SRobert Watson 
747030a28b3SRobert Watson fail:
748030a28b3SRobert Watson 	PROC_UNLOCK(p);
749030a28b3SRobert Watson 	crfree(newcred);
750030a28b3SRobert Watson 	return (error);
751df8bae1dSRodney W. Grimes }
752df8bae1dSRodney W. Grimes 
753d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
754df8bae1dSRodney W. Grimes struct setegid_args {
755df8bae1dSRodney W. Grimes 	gid_t	egid;
756df8bae1dSRodney W. Grimes };
757d2d3e875SBruce Evans #endif
758df8bae1dSRodney W. Grimes /* ARGSUSED */
75926f9a767SRodney W. Grimes int
7608451d0ddSKip Macy sys_setegid(struct thread *td, struct setegid_args *uap)
761df8bae1dSRodney W. Grimes {
762b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
763b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
764b1fc0ec1SRobert Watson 	gid_t egid;
765eb725b4eSRobert Watson 	int error;
766df8bae1dSRodney W. Grimes 
767df8bae1dSRodney W. Grimes 	egid = uap->egid;
76814961ba7SRobert Watson 	AUDIT_ARG_EGID(egid);
76907f3485dSJohn Baldwin 	newcred = crget();
77007f3485dSJohn Baldwin 	PROC_LOCK(p);
771838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
772030a28b3SRobert Watson 
773030a28b3SRobert Watson #ifdef MAC
7746f6174a7SRobert Watson 	error = mac_cred_check_setegid(oldcred, egid);
775030a28b3SRobert Watson 	if (error)
776030a28b3SRobert Watson 		goto fail;
777030a28b3SRobert Watson #endif
778030a28b3SRobert Watson 
779b1fc0ec1SRobert Watson 	if (egid != oldcred->cr_rgid &&		/* allow setegid(getgid()) */
780b1fc0ec1SRobert Watson 	    egid != oldcred->cr_svgid &&	/* allow setegid(saved gid) */
781cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETEGID)) != 0)
782030a28b3SRobert Watson 		goto fail;
783030a28b3SRobert Watson 
784b1fc0ec1SRobert Watson 	if (oldcred->cr_groups[0] != egid) {
785b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
786d5f81602SSean Eric Fagan 		setsugid(p);
787229a15f0SPeter Wemm 	}
788daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
78907f3485dSJohn Baldwin 	PROC_UNLOCK(p);
790b1fc0ec1SRobert Watson 	crfree(oldcred);
79107f3485dSJohn Baldwin 	return (0);
792030a28b3SRobert Watson 
793030a28b3SRobert Watson fail:
794030a28b3SRobert Watson 	PROC_UNLOCK(p);
795030a28b3SRobert Watson 	crfree(newcred);
796030a28b3SRobert Watson 	return (error);
797df8bae1dSRodney W. Grimes }
798df8bae1dSRodney W. Grimes 
799d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
800df8bae1dSRodney W. Grimes struct setgroups_args {
8014bc2174aSMoritz Buhl 	int	gidsetsize;
802df8bae1dSRodney W. Grimes 	gid_t	*gidset;
803df8bae1dSRodney W. Grimes };
804d2d3e875SBruce Evans #endif
805df8bae1dSRodney W. Grimes /* ARGSUSED */
80626f9a767SRodney W. Grimes int
8078451d0ddSKip Macy sys_setgroups(struct thread *td, struct setgroups_args *uap)
808df8bae1dSRodney W. Grimes {
80992b064f4SMateusz Guzik 	gid_t smallgroups[XU_NGROUPS];
8107e9a456aSMateusz Guzik 	gid_t *groups;
8114bc2174aSMoritz Buhl 	int gidsetsize, error;
812df8bae1dSRodney W. Grimes 
81392b064f4SMateusz Guzik 	gidsetsize = uap->gidsetsize;
8144bc2174aSMoritz Buhl 	if (gidsetsize > ngroups_max + 1 || gidsetsize < 0)
8153cb83e71SJohn Baldwin 		return (EINVAL);
8167e9a456aSMateusz Guzik 
81792b064f4SMateusz Guzik 	if (gidsetsize > XU_NGROUPS)
81892b064f4SMateusz Guzik 		groups = malloc(gidsetsize * sizeof(gid_t), M_TEMP, M_WAITOK);
81992b064f4SMateusz Guzik 	else
82092b064f4SMateusz Guzik 		groups = smallgroups;
8217e9a456aSMateusz Guzik 
82292b064f4SMateusz Guzik 	error = copyin(uap->gidset, groups, gidsetsize * sizeof(gid_t));
8237e9a456aSMateusz Guzik 	if (error == 0)
82492b064f4SMateusz Guzik 		error = kern_setgroups(td, gidsetsize, groups);
8257e9a456aSMateusz Guzik 
82692b064f4SMateusz Guzik 	if (gidsetsize > XU_NGROUPS)
827838d9858SBrooks Davis 		free(groups, M_TEMP);
8283cb83e71SJohn Baldwin 	return (error);
8293cb83e71SJohn Baldwin }
8303cb83e71SJohn Baldwin 
8313cb83e71SJohn Baldwin int
8323cb83e71SJohn Baldwin kern_setgroups(struct thread *td, u_int ngrp, gid_t *groups)
8333cb83e71SJohn Baldwin {
8343cb83e71SJohn Baldwin 	struct proc *p = td->td_proc;
8353cb83e71SJohn Baldwin 	struct ucred *newcred, *oldcred;
8363cb83e71SJohn Baldwin 	int error;
8373cb83e71SJohn Baldwin 
838b9063886SMateusz Guzik 	MPASS(ngrp <= ngroups_max + 1);
83914961ba7SRobert Watson 	AUDIT_ARG_GROUPSET(groups, ngrp);
84007f3485dSJohn Baldwin 	newcred = crget();
841838d9858SBrooks Davis 	crextend(newcred, ngrp);
84207f3485dSJohn Baldwin 	PROC_LOCK(p);
843838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
844030a28b3SRobert Watson 
845030a28b3SRobert Watson #ifdef MAC
8466f6174a7SRobert Watson 	error = mac_cred_check_setgroups(oldcred, ngrp, groups);
847030a28b3SRobert Watson 	if (error)
848030a28b3SRobert Watson 		goto fail;
849030a28b3SRobert Watson #endif
850030a28b3SRobert Watson 
851cc426dd3SMateusz Guzik 	error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS);
852030a28b3SRobert Watson 	if (error)
853030a28b3SRobert Watson 		goto fail;
85407f3485dSJohn Baldwin 
8557e9a456aSMateusz Guzik 	if (ngrp == 0) {
8568a5d815aSPeter Wemm 		/*
8578a5d815aSPeter Wemm 		 * setgroups(0, NULL) is a legitimate way of clearing the
8588a5d815aSPeter Wemm 		 * groups vector on non-BSD systems (which generally do not
8598a5d815aSPeter Wemm 		 * have the egid in the groups[0]).  We risk security holes
8608a5d815aSPeter Wemm 		 * when running non-BSD software if we do not do the same.
8618a5d815aSPeter Wemm 		 */
862b1fc0ec1SRobert Watson 		newcred->cr_ngroups = 1;
8638a5d815aSPeter Wemm 	} else {
864838d9858SBrooks Davis 		crsetgroups_locked(newcred, ngrp, groups);
8658a5d815aSPeter Wemm 	}
866d5f81602SSean Eric Fagan 	setsugid(p);
867daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
86807f3485dSJohn Baldwin 	PROC_UNLOCK(p);
869b1fc0ec1SRobert Watson 	crfree(oldcred);
87007f3485dSJohn Baldwin 	return (0);
871030a28b3SRobert Watson 
872030a28b3SRobert Watson fail:
873030a28b3SRobert Watson 	PROC_UNLOCK(p);
874030a28b3SRobert Watson 	crfree(newcred);
875030a28b3SRobert Watson 	return (error);
876df8bae1dSRodney W. Grimes }
877df8bae1dSRodney W. Grimes 
878d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
879df8bae1dSRodney W. Grimes struct setreuid_args {
88000999cd6SAndrey A. Chernov 	uid_t	ruid;
88100999cd6SAndrey A. Chernov 	uid_t	euid;
882df8bae1dSRodney W. Grimes };
883d2d3e875SBruce Evans #endif
884df8bae1dSRodney W. Grimes /* ARGSUSED */
88526f9a767SRodney W. Grimes int
8863e85b721SEd Maste sys_setreuid(struct thread *td, struct setreuid_args *uap)
887df8bae1dSRodney W. Grimes {
888b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
889b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
890eb725b4eSRobert Watson 	uid_t euid, ruid;
8911419eacbSAlfred Perlstein 	struct uidinfo *euip, *ruip;
892eb725b4eSRobert Watson 	int error;
893df8bae1dSRodney W. Grimes 
89400999cd6SAndrey A. Chernov 	euid = uap->euid;
895eb725b4eSRobert Watson 	ruid = uap->ruid;
89614961ba7SRobert Watson 	AUDIT_ARG_EUID(euid);
89714961ba7SRobert Watson 	AUDIT_ARG_RUID(ruid);
89807f3485dSJohn Baldwin 	newcred = crget();
8991419eacbSAlfred Perlstein 	euip = uifind(euid);
9001419eacbSAlfred Perlstein 	ruip = uifind(ruid);
90107f3485dSJohn Baldwin 	PROC_LOCK(p);
902838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
903030a28b3SRobert Watson 
904030a28b3SRobert Watson #ifdef MAC
9056f6174a7SRobert Watson 	error = mac_cred_check_setreuid(oldcred, ruid, euid);
906030a28b3SRobert Watson 	if (error)
907030a28b3SRobert Watson 		goto fail;
908030a28b3SRobert Watson #endif
909030a28b3SRobert Watson 
910b1fc0ec1SRobert Watson 	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
911b1fc0ec1SRobert Watson 	      ruid != oldcred->cr_svuid) ||
912b1fc0ec1SRobert Watson 	     (euid != (uid_t)-1 && euid != oldcred->cr_uid &&
913b1fc0ec1SRobert Watson 	      euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) &&
914cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETREUID)) != 0)
915030a28b3SRobert Watson 		goto fail;
916030a28b3SRobert Watson 
917b1fc0ec1SRobert Watson 	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
9181419eacbSAlfred Perlstein 		change_euid(newcred, euip);
919d5f81602SSean Eric Fagan 		setsugid(p);
920a89a5370SPeter Wemm 	}
921b1fc0ec1SRobert Watson 	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
9221419eacbSAlfred Perlstein 		change_ruid(newcred, ruip);
923d5f81602SSean Eric Fagan 		setsugid(p);
92400999cd6SAndrey A. Chernov 	}
925b1fc0ec1SRobert Watson 	if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) &&
926b1fc0ec1SRobert Watson 	    newcred->cr_svuid != newcred->cr_uid) {
927b1fc0ec1SRobert Watson 		change_svuid(newcred, newcred->cr_uid);
928d5f81602SSean Eric Fagan 		setsugid(p);
929a89a5370SPeter Wemm 	}
930daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
931e4dcb704SEdward Tomasz Napierala #ifdef RACCT
932e4dcb704SEdward Tomasz Napierala 	racct_proc_ucred_changed(p, oldcred, newcred);
933f87beb93SAndriy Gapon 	crhold(newcred);
934f87beb93SAndriy Gapon #endif
935f87beb93SAndriy Gapon 	PROC_UNLOCK(p);
936f87beb93SAndriy Gapon #ifdef RCTL
937f87beb93SAndriy Gapon 	rctl_proc_ucred_changed(p, newcred);
938f87beb93SAndriy Gapon 	crfree(newcred);
939e4dcb704SEdward Tomasz Napierala #endif
9401419eacbSAlfred Perlstein 	uifree(ruip);
9411419eacbSAlfred Perlstein 	uifree(euip);
942b1fc0ec1SRobert Watson 	crfree(oldcred);
94307f3485dSJohn Baldwin 	return (0);
944030a28b3SRobert Watson 
945030a28b3SRobert Watson fail:
946030a28b3SRobert Watson 	PROC_UNLOCK(p);
947030a28b3SRobert Watson 	uifree(ruip);
948030a28b3SRobert Watson 	uifree(euip);
949030a28b3SRobert Watson 	crfree(newcred);
950030a28b3SRobert Watson 	return (error);
951df8bae1dSRodney W. Grimes }
952df8bae1dSRodney W. Grimes 
953d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
954df8bae1dSRodney W. Grimes struct setregid_args {
95500999cd6SAndrey A. Chernov 	gid_t	rgid;
95600999cd6SAndrey A. Chernov 	gid_t	egid;
957df8bae1dSRodney W. Grimes };
958d2d3e875SBruce Evans #endif
959df8bae1dSRodney W. Grimes /* ARGSUSED */
96026f9a767SRodney W. Grimes int
9613e85b721SEd Maste sys_setregid(struct thread *td, struct setregid_args *uap)
962df8bae1dSRodney W. Grimes {
963b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
964b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
965eb725b4eSRobert Watson 	gid_t egid, rgid;
966eb725b4eSRobert Watson 	int error;
967df8bae1dSRodney W. Grimes 
96800999cd6SAndrey A. Chernov 	egid = uap->egid;
969eb725b4eSRobert Watson 	rgid = uap->rgid;
97014961ba7SRobert Watson 	AUDIT_ARG_EGID(egid);
97114961ba7SRobert Watson 	AUDIT_ARG_RGID(rgid);
97207f3485dSJohn Baldwin 	newcred = crget();
97307f3485dSJohn Baldwin 	PROC_LOCK(p);
974838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
975030a28b3SRobert Watson 
976030a28b3SRobert Watson #ifdef MAC
9776f6174a7SRobert Watson 	error = mac_cred_check_setregid(oldcred, rgid, egid);
978030a28b3SRobert Watson 	if (error)
979030a28b3SRobert Watson 		goto fail;
980030a28b3SRobert Watson #endif
981030a28b3SRobert Watson 
982b1fc0ec1SRobert Watson 	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
983b1fc0ec1SRobert Watson 	    rgid != oldcred->cr_svgid) ||
984b1fc0ec1SRobert Watson 	     (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] &&
985b1fc0ec1SRobert Watson 	     egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) &&
986cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETREGID)) != 0)
987030a28b3SRobert Watson 		goto fail;
98807f3485dSJohn Baldwin 
989b1fc0ec1SRobert Watson 	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
990b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
991d5f81602SSean Eric Fagan 		setsugid(p);
992a89a5370SPeter Wemm 	}
993b1fc0ec1SRobert Watson 	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
994b1fc0ec1SRobert Watson 		change_rgid(newcred, rgid);
995d5f81602SSean Eric Fagan 		setsugid(p);
996a89a5370SPeter Wemm 	}
997b1fc0ec1SRobert Watson 	if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) &&
998b1fc0ec1SRobert Watson 	    newcred->cr_svgid != newcred->cr_groups[0]) {
999b1fc0ec1SRobert Watson 		change_svgid(newcred, newcred->cr_groups[0]);
1000d5f81602SSean Eric Fagan 		setsugid(p);
1001a89a5370SPeter Wemm 	}
1002daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
100307f3485dSJohn Baldwin 	PROC_UNLOCK(p);
10044589be70SRuslan Ermilov 	crfree(oldcred);
100507f3485dSJohn Baldwin 	return (0);
1006030a28b3SRobert Watson 
1007030a28b3SRobert Watson fail:
1008030a28b3SRobert Watson 	PROC_UNLOCK(p);
1009030a28b3SRobert Watson 	crfree(newcred);
1010030a28b3SRobert Watson 	return (error);
1011df8bae1dSRodney W. Grimes }
1012df8bae1dSRodney W. Grimes 
10138ccd6334SPeter Wemm /*
1014873fbcd7SRobert Watson  * setresuid(ruid, euid, suid) is like setreuid except control over the saved
1015873fbcd7SRobert Watson  * uid is explicit.
10168ccd6334SPeter Wemm  */
10178ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
10188ccd6334SPeter Wemm struct setresuid_args {
10198ccd6334SPeter Wemm 	uid_t	ruid;
10208ccd6334SPeter Wemm 	uid_t	euid;
10218ccd6334SPeter Wemm 	uid_t	suid;
10228ccd6334SPeter Wemm };
10238ccd6334SPeter Wemm #endif
10248ccd6334SPeter Wemm /* ARGSUSED */
10258ccd6334SPeter Wemm int
10263e85b721SEd Maste sys_setresuid(struct thread *td, struct setresuid_args *uap)
10278ccd6334SPeter Wemm {
1028b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1029b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
1030eb725b4eSRobert Watson 	uid_t euid, ruid, suid;
10311419eacbSAlfred Perlstein 	struct uidinfo *euip, *ruip;
10328ccd6334SPeter Wemm 	int error;
10338ccd6334SPeter Wemm 
10348ccd6334SPeter Wemm 	euid = uap->euid;
1035eb725b4eSRobert Watson 	ruid = uap->ruid;
10368ccd6334SPeter Wemm 	suid = uap->suid;
103714961ba7SRobert Watson 	AUDIT_ARG_EUID(euid);
103814961ba7SRobert Watson 	AUDIT_ARG_RUID(ruid);
103914961ba7SRobert Watson 	AUDIT_ARG_SUID(suid);
104007f3485dSJohn Baldwin 	newcred = crget();
10411419eacbSAlfred Perlstein 	euip = uifind(euid);
10421419eacbSAlfred Perlstein 	ruip = uifind(ruid);
104307f3485dSJohn Baldwin 	PROC_LOCK(p);
1044838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
1045030a28b3SRobert Watson 
1046030a28b3SRobert Watson #ifdef MAC
10476f6174a7SRobert Watson 	error = mac_cred_check_setresuid(oldcred, ruid, euid, suid);
1048030a28b3SRobert Watson 	if (error)
1049030a28b3SRobert Watson 		goto fail;
1050030a28b3SRobert Watson #endif
1051030a28b3SRobert Watson 
1052b1fc0ec1SRobert Watson 	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
1053b1fc0ec1SRobert Watson 	     ruid != oldcred->cr_svuid &&
1054b1fc0ec1SRobert Watson 	      ruid != oldcred->cr_uid) ||
1055b1fc0ec1SRobert Watson 	     (euid != (uid_t)-1 && euid != oldcred->cr_ruid &&
1056b1fc0ec1SRobert Watson 	    euid != oldcred->cr_svuid &&
1057b1fc0ec1SRobert Watson 	      euid != oldcred->cr_uid) ||
1058b1fc0ec1SRobert Watson 	     (suid != (uid_t)-1 && suid != oldcred->cr_ruid &&
1059b1fc0ec1SRobert Watson 	    suid != oldcred->cr_svuid &&
1060b1fc0ec1SRobert Watson 	      suid != oldcred->cr_uid)) &&
1061cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETRESUID)) != 0)
1062030a28b3SRobert Watson 		goto fail;
106307f3485dSJohn Baldwin 
1064b1fc0ec1SRobert Watson 	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
10651419eacbSAlfred Perlstein 		change_euid(newcred, euip);
10668ccd6334SPeter Wemm 		setsugid(p);
10678ccd6334SPeter Wemm 	}
1068b1fc0ec1SRobert Watson 	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
10691419eacbSAlfred Perlstein 		change_ruid(newcred, ruip);
10708ccd6334SPeter Wemm 		setsugid(p);
10718ccd6334SPeter Wemm 	}
1072b1fc0ec1SRobert Watson 	if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) {
1073b1fc0ec1SRobert Watson 		change_svuid(newcred, suid);
10748ccd6334SPeter Wemm 		setsugid(p);
10758ccd6334SPeter Wemm 	}
1076daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
1077e4dcb704SEdward Tomasz Napierala #ifdef RACCT
1078e4dcb704SEdward Tomasz Napierala 	racct_proc_ucred_changed(p, oldcred, newcred);
1079f87beb93SAndriy Gapon 	crhold(newcred);
1080f87beb93SAndriy Gapon #endif
1081f87beb93SAndriy Gapon 	PROC_UNLOCK(p);
1082f87beb93SAndriy Gapon #ifdef RCTL
1083f87beb93SAndriy Gapon 	rctl_proc_ucred_changed(p, newcred);
1084f87beb93SAndriy Gapon 	crfree(newcred);
1085e4dcb704SEdward Tomasz Napierala #endif
10861419eacbSAlfred Perlstein 	uifree(ruip);
10871419eacbSAlfred Perlstein 	uifree(euip);
1088b1fc0ec1SRobert Watson 	crfree(oldcred);
108907f3485dSJohn Baldwin 	return (0);
1090030a28b3SRobert Watson 
1091030a28b3SRobert Watson fail:
1092030a28b3SRobert Watson 	PROC_UNLOCK(p);
1093030a28b3SRobert Watson 	uifree(ruip);
1094030a28b3SRobert Watson 	uifree(euip);
1095030a28b3SRobert Watson 	crfree(newcred);
1096030a28b3SRobert Watson 	return (error);
1097030a28b3SRobert Watson 
10988ccd6334SPeter Wemm }
10998ccd6334SPeter Wemm 
11008ccd6334SPeter Wemm /*
1101873fbcd7SRobert Watson  * setresgid(rgid, egid, sgid) is like setregid except control over the saved
1102873fbcd7SRobert Watson  * gid is explicit.
11038ccd6334SPeter Wemm  */
11048ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
11058ccd6334SPeter Wemm struct setresgid_args {
11068ccd6334SPeter Wemm 	gid_t	rgid;
11078ccd6334SPeter Wemm 	gid_t	egid;
11088ccd6334SPeter Wemm 	gid_t	sgid;
11098ccd6334SPeter Wemm };
11108ccd6334SPeter Wemm #endif
11118ccd6334SPeter Wemm /* ARGSUSED */
11128ccd6334SPeter Wemm int
11133e85b721SEd Maste sys_setresgid(struct thread *td, struct setresgid_args *uap)
11148ccd6334SPeter Wemm {
1115b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1116b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
1117eb725b4eSRobert Watson 	gid_t egid, rgid, sgid;
11188ccd6334SPeter Wemm 	int error;
11198ccd6334SPeter Wemm 
11208ccd6334SPeter Wemm 	egid = uap->egid;
1121eb725b4eSRobert Watson 	rgid = uap->rgid;
11228ccd6334SPeter Wemm 	sgid = uap->sgid;
112314961ba7SRobert Watson 	AUDIT_ARG_EGID(egid);
112414961ba7SRobert Watson 	AUDIT_ARG_RGID(rgid);
112514961ba7SRobert Watson 	AUDIT_ARG_SGID(sgid);
112607f3485dSJohn Baldwin 	newcred = crget();
112707f3485dSJohn Baldwin 	PROC_LOCK(p);
1128838d9858SBrooks Davis 	oldcred = crcopysafe(p, newcred);
1129030a28b3SRobert Watson 
1130030a28b3SRobert Watson #ifdef MAC
11316f6174a7SRobert Watson 	error = mac_cred_check_setresgid(oldcred, rgid, egid, sgid);
1132030a28b3SRobert Watson 	if (error)
1133030a28b3SRobert Watson 		goto fail;
1134030a28b3SRobert Watson #endif
1135030a28b3SRobert Watson 
1136b1fc0ec1SRobert Watson 	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
1137b1fc0ec1SRobert Watson 	      rgid != oldcred->cr_svgid &&
1138b1fc0ec1SRobert Watson 	      rgid != oldcred->cr_groups[0]) ||
1139b1fc0ec1SRobert Watson 	     (egid != (gid_t)-1 && egid != oldcred->cr_rgid &&
1140b1fc0ec1SRobert Watson 	      egid != oldcred->cr_svgid &&
1141b1fc0ec1SRobert Watson 	      egid != oldcred->cr_groups[0]) ||
1142b1fc0ec1SRobert Watson 	     (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid &&
1143b1fc0ec1SRobert Watson 	      sgid != oldcred->cr_svgid &&
1144b1fc0ec1SRobert Watson 	      sgid != oldcred->cr_groups[0])) &&
1145cc426dd3SMateusz Guzik 	    (error = priv_check_cred(oldcred, PRIV_CRED_SETRESGID)) != 0)
1146030a28b3SRobert Watson 		goto fail;
114707f3485dSJohn Baldwin 
1148b1fc0ec1SRobert Watson 	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
1149b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
11508ccd6334SPeter Wemm 		setsugid(p);
11518ccd6334SPeter Wemm 	}
1152b1fc0ec1SRobert Watson 	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
1153b1fc0ec1SRobert Watson 		change_rgid(newcred, rgid);
11548ccd6334SPeter Wemm 		setsugid(p);
11558ccd6334SPeter Wemm 	}
1156b1fc0ec1SRobert Watson 	if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) {
1157b1fc0ec1SRobert Watson 		change_svgid(newcred, sgid);
11588ccd6334SPeter Wemm 		setsugid(p);
11598ccd6334SPeter Wemm 	}
1160daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
116107f3485dSJohn Baldwin 	PROC_UNLOCK(p);
1162b1fc0ec1SRobert Watson 	crfree(oldcred);
116307f3485dSJohn Baldwin 	return (0);
1164030a28b3SRobert Watson 
1165030a28b3SRobert Watson fail:
1166030a28b3SRobert Watson 	PROC_UNLOCK(p);
1167030a28b3SRobert Watson 	crfree(newcred);
1168030a28b3SRobert Watson 	return (error);
11698ccd6334SPeter Wemm }
11708ccd6334SPeter Wemm 
11718ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
11728ccd6334SPeter Wemm struct getresuid_args {
11738ccd6334SPeter Wemm 	uid_t	*ruid;
11748ccd6334SPeter Wemm 	uid_t	*euid;
11758ccd6334SPeter Wemm 	uid_t	*suid;
11768ccd6334SPeter Wemm };
11778ccd6334SPeter Wemm #endif
11788ccd6334SPeter Wemm /* ARGSUSED */
11798ccd6334SPeter Wemm int
11803e85b721SEd Maste sys_getresuid(struct thread *td, struct getresuid_args *uap)
11818ccd6334SPeter Wemm {
1182835a82eeSMatthew Dillon 	struct ucred *cred;
11838ccd6334SPeter Wemm 	int error1 = 0, error2 = 0, error3 = 0;
11848ccd6334SPeter Wemm 
1185d74ac681SMatthew Dillon 	cred = td->td_ucred;
11868ccd6334SPeter Wemm 	if (uap->ruid)
11877f05b035SAlfred Perlstein 		error1 = copyout(&cred->cr_ruid,
11887f05b035SAlfred Perlstein 		    uap->ruid, sizeof(cred->cr_ruid));
11898ccd6334SPeter Wemm 	if (uap->euid)
11907f05b035SAlfred Perlstein 		error2 = copyout(&cred->cr_uid,
11917f05b035SAlfred Perlstein 		    uap->euid, sizeof(cred->cr_uid));
11928ccd6334SPeter Wemm 	if (uap->suid)
11937f05b035SAlfred Perlstein 		error3 = copyout(&cred->cr_svuid,
11947f05b035SAlfred Perlstein 		    uap->suid, sizeof(cred->cr_svuid));
1195eb725b4eSRobert Watson 	return (error1 ? error1 : error2 ? error2 : error3);
11968ccd6334SPeter Wemm }
11978ccd6334SPeter Wemm 
11988ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
11998ccd6334SPeter Wemm struct getresgid_args {
12008ccd6334SPeter Wemm 	gid_t	*rgid;
12018ccd6334SPeter Wemm 	gid_t	*egid;
12028ccd6334SPeter Wemm 	gid_t	*sgid;
12038ccd6334SPeter Wemm };
12048ccd6334SPeter Wemm #endif
12058ccd6334SPeter Wemm /* ARGSUSED */
12068ccd6334SPeter Wemm int
12073e85b721SEd Maste sys_getresgid(struct thread *td, struct getresgid_args *uap)
12088ccd6334SPeter Wemm {
1209835a82eeSMatthew Dillon 	struct ucred *cred;
12108ccd6334SPeter Wemm 	int error1 = 0, error2 = 0, error3 = 0;
12118ccd6334SPeter Wemm 
1212d74ac681SMatthew Dillon 	cred = td->td_ucred;
12138ccd6334SPeter Wemm 	if (uap->rgid)
12147f05b035SAlfred Perlstein 		error1 = copyout(&cred->cr_rgid,
12157f05b035SAlfred Perlstein 		    uap->rgid, sizeof(cred->cr_rgid));
12168ccd6334SPeter Wemm 	if (uap->egid)
12177f05b035SAlfred Perlstein 		error2 = copyout(&cred->cr_groups[0],
12187f05b035SAlfred Perlstein 		    uap->egid, sizeof(cred->cr_groups[0]));
12198ccd6334SPeter Wemm 	if (uap->sgid)
12207f05b035SAlfred Perlstein 		error3 = copyout(&cred->cr_svgid,
12217f05b035SAlfred Perlstein 		    uap->sgid, sizeof(cred->cr_svgid));
1222eb725b4eSRobert Watson 	return (error1 ? error1 : error2 ? error2 : error3);
12238ccd6334SPeter Wemm }
12248ccd6334SPeter Wemm 
1225b67cbc65SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1226b67cbc65SPeter Wemm struct issetugid_args {
1227b67cbc65SPeter Wemm 	int dummy;
1228b67cbc65SPeter Wemm };
1229b67cbc65SPeter Wemm #endif
1230b67cbc65SPeter Wemm /* ARGSUSED */
1231b67cbc65SPeter Wemm int
12323e85b721SEd Maste sys_issetugid(struct thread *td, struct issetugid_args *uap)
1233b67cbc65SPeter Wemm {
1234b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1235b40ce416SJulian Elischer 
1236b67cbc65SPeter Wemm 	/*
1237b67cbc65SPeter Wemm 	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
1238b67cbc65SPeter Wemm 	 * we use P_SUGID because we consider changing the owners as
1239b67cbc65SPeter Wemm 	 * "tainting" as well.
1240b67cbc65SPeter Wemm 	 * This is significant for procs that start as root and "become"
1241b67cbc65SPeter Wemm 	 * a user without an exec - programs cannot know *everything*
1242b67cbc65SPeter Wemm 	 * that libc *might* have put in their data segment.
1243b67cbc65SPeter Wemm 	 */
1244b40ce416SJulian Elischer 	td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
1245b67cbc65SPeter Wemm 	return (0);
1246b67cbc65SPeter Wemm }
1247b67cbc65SPeter Wemm 
1248130d0157SRobert Watson int
12498451d0ddSKip Macy sys___setugid(struct thread *td, struct __setugid_args *uap)
1250130d0157SRobert Watson {
1251130d0157SRobert Watson #ifdef REGRESSION
125207f3485dSJohn Baldwin 	struct proc *p;
1253835a82eeSMatthew Dillon 
125407f3485dSJohn Baldwin 	p = td->td_proc;
1255130d0157SRobert Watson 	switch (uap->flag) {
1256130d0157SRobert Watson 	case 0:
125707f3485dSJohn Baldwin 		PROC_LOCK(p);
125807f3485dSJohn Baldwin 		p->p_flag &= ~P_SUGID;
125907f3485dSJohn Baldwin 		PROC_UNLOCK(p);
126007f3485dSJohn Baldwin 		return (0);
126107f3485dSJohn Baldwin 	case 1:
126207f3485dSJohn Baldwin 		PROC_LOCK(p);
126307f3485dSJohn Baldwin 		p->p_flag |= P_SUGID;
126407f3485dSJohn Baldwin 		PROC_UNLOCK(p);
126507f3485dSJohn Baldwin 		return (0);
126607f3485dSJohn Baldwin 	default:
126707f3485dSJohn Baldwin 		return (EINVAL);
126807f3485dSJohn Baldwin 	}
1269130d0157SRobert Watson #else /* !REGRESSION */
1270eb725b4eSRobert Watson 
1271130d0157SRobert Watson 	return (ENOSYS);
1272eb725b4eSRobert Watson #endif /* REGRESSION */
1273130d0157SRobert Watson }
1274130d0157SRobert Watson 
1275df8bae1dSRodney W. Grimes /*
1276df8bae1dSRodney W. Grimes  * Check if gid is a member of the group set.
1277df8bae1dSRodney W. Grimes  */
127826f9a767SRodney W. Grimes int
12794c44ad8eSJohn Baldwin groupmember(gid_t gid, struct ucred *cred)
1280df8bae1dSRodney W. Grimes {
12817f92e578SBrooks Davis 	int l;
12827f92e578SBrooks Davis 	int h;
12837f92e578SBrooks Davis 	int m;
1284df8bae1dSRodney W. Grimes 
12857f92e578SBrooks Davis 	if (cred->cr_groups[0] == gid)
1286df8bae1dSRodney W. Grimes 		return(1);
12877f92e578SBrooks Davis 
12887f92e578SBrooks Davis 	/*
12897f92e578SBrooks Davis 	 * If gid was not our primary group, perform a binary search
12907f92e578SBrooks Davis 	 * of the supplemental groups.  This is possible because we
12917f92e578SBrooks Davis 	 * sort the groups in crsetgroups().
12927f92e578SBrooks Davis 	 */
12937f92e578SBrooks Davis 	l = 1;
12947f92e578SBrooks Davis 	h = cred->cr_ngroups;
12957f92e578SBrooks Davis 	while (l < h) {
12967f92e578SBrooks Davis 		m = l + ((h - l) / 2);
12977f92e578SBrooks Davis 		if (cred->cr_groups[m] < gid)
12987f92e578SBrooks Davis 			l = m + 1;
12997f92e578SBrooks Davis 		else
13007f92e578SBrooks Davis 			h = m;
13017f92e578SBrooks Davis 	}
13027f92e578SBrooks Davis 	if ((l < cred->cr_ngroups) && (cred->cr_groups[l] == gid))
13037f92e578SBrooks Davis 		return (1);
13047f92e578SBrooks Davis 
1305df8bae1dSRodney W. Grimes 	return (0);
1306df8bae1dSRodney W. Grimes }
1307df8bae1dSRodney W. Grimes 
13083b243b72SRobert Watson /*
1309eb725b4eSRobert Watson  * Test the active securelevel against a given level.  securelevel_gt()
1310eb725b4eSRobert Watson  * implements (securelevel > level).  securelevel_ge() implements
1311eb725b4eSRobert Watson  * (securelevel >= level).  Note that the logic is inverted -- these
1312eb725b4eSRobert Watson  * functions return EPERM on "success" and 0 on "failure".
13133ca719f1SRobert Watson  *
13140304c731SJamie Gritton  * Due to care taken when setting the securelevel, we know that no jail will
13150304c731SJamie Gritton  * be less secure that its parent (or the physical system), so it is sufficient
13160304c731SJamie Gritton  * to test the current jail only.
13170304c731SJamie Gritton  *
1318800c9408SRobert Watson  * XXXRW: Possibly since this has to do with privilege, it should move to
1319800c9408SRobert Watson  * kern_priv.c.
13203ca719f1SRobert Watson  */
13213ca719f1SRobert Watson int
13223ca719f1SRobert Watson securelevel_gt(struct ucred *cr, int level)
13233ca719f1SRobert Watson {
13243ca719f1SRobert Watson 
13250304c731SJamie Gritton 	return (cr->cr_prison->pr_securelevel > level ? EPERM : 0);
13263ca719f1SRobert Watson }
13273ca719f1SRobert Watson 
13283ca719f1SRobert Watson int
13293ca719f1SRobert Watson securelevel_ge(struct ucred *cr, int level)
13303ca719f1SRobert Watson {
13313ca719f1SRobert Watson 
13320304c731SJamie Gritton 	return (cr->cr_prison->pr_securelevel >= level ? EPERM : 0);
13333ca719f1SRobert Watson }
13343ca719f1SRobert Watson 
13358a7d8cc6SRobert Watson /*
1336e409590dSRobert Watson  * 'see_other_uids' determines whether or not visibility of processes
1337eb725b4eSRobert Watson  * and sockets with credentials holding different real uids is possible
133848713bdcSRobert Watson  * using a variety of system MIBs.
1339eb725b4eSRobert Watson  * XXX: data declarations should be together near the beginning of the file.
13408a7d8cc6SRobert Watson  */
1341e409590dSRobert Watson static int	see_other_uids = 1;
1342d0615c64SAndrew R. Reiter SYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW,
1343eb725b4eSRobert Watson     &see_other_uids, 0,
13448a7d8cc6SRobert Watson     "Unprivileged processes may see subjects/objects with different real uid");
13458a7d8cc6SRobert Watson 
13461a996ed1SEdward Tomasz Napierala /*-
13471b350b45SRobert Watson  * Determine if u1 "can see" the subject specified by u2, according to the
13481b350b45SRobert Watson  * 'see_other_uids' policy.
13491b350b45SRobert Watson  * Returns: 0 for permitted, ESRCH otherwise
13501b350b45SRobert Watson  * Locks: none
13511b350b45SRobert Watson  * References: *u1 and *u2 must not change during the call
13521b350b45SRobert Watson  *             u1 may equal u2, in which case only one reference is required
13531b350b45SRobert Watson  */
13544ac21b4fSStephen J. Kiernan int
13554ac21b4fSStephen J. Kiernan cr_canseeotheruids(struct ucred *u1, struct ucred *u2)
13561b350b45SRobert Watson {
13571b350b45SRobert Watson 
13581b350b45SRobert Watson 	if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) {
1359cc426dd3SMateusz Guzik 		if (priv_check_cred(u1, PRIV_SEEOTHERUIDS) != 0)
13601b350b45SRobert Watson 			return (ESRCH);
13611b350b45SRobert Watson 	}
13621b350b45SRobert Watson 	return (0);
13631b350b45SRobert Watson }
13641b350b45SRobert Watson 
136564d19c2eSRobert Watson /*
136664d19c2eSRobert Watson  * 'see_other_gids' determines whether or not visibility of processes
136764d19c2eSRobert Watson  * and sockets with credentials holding different real gids is possible
136864d19c2eSRobert Watson  * using a variety of system MIBs.
136964d19c2eSRobert Watson  * XXX: data declarations should be together near the beginning of the file.
137064d19c2eSRobert Watson  */
137164d19c2eSRobert Watson static int	see_other_gids = 1;
137264d19c2eSRobert Watson SYSCTL_INT(_security_bsd, OID_AUTO, see_other_gids, CTLFLAG_RW,
137364d19c2eSRobert Watson     &see_other_gids, 0,
137464d19c2eSRobert Watson     "Unprivileged processes may see subjects/objects with different real gid");
137564d19c2eSRobert Watson 
137664d19c2eSRobert Watson /*
137764d19c2eSRobert Watson  * Determine if u1 can "see" the subject specified by u2, according to the
137864d19c2eSRobert Watson  * 'see_other_gids' policy.
137964d19c2eSRobert Watson  * Returns: 0 for permitted, ESRCH otherwise
138064d19c2eSRobert Watson  * Locks: none
138164d19c2eSRobert Watson  * References: *u1 and *u2 must not change during the call
138264d19c2eSRobert Watson  *             u1 may equal u2, in which case only one reference is required
138364d19c2eSRobert Watson  */
13844ac21b4fSStephen J. Kiernan int
13854ac21b4fSStephen J. Kiernan cr_canseeothergids(struct ucred *u1, struct ucred *u2)
138664d19c2eSRobert Watson {
138764d19c2eSRobert Watson 	int i, match;
138864d19c2eSRobert Watson 
138964d19c2eSRobert Watson 	if (!see_other_gids) {
139064d19c2eSRobert Watson 		match = 0;
139164d19c2eSRobert Watson 		for (i = 0; i < u1->cr_ngroups; i++) {
139264d19c2eSRobert Watson 			if (groupmember(u1->cr_groups[i], u2))
139364d19c2eSRobert Watson 				match = 1;
139464d19c2eSRobert Watson 			if (match)
139564d19c2eSRobert Watson 				break;
139664d19c2eSRobert Watson 		}
139764d19c2eSRobert Watson 		if (!match) {
1398cc426dd3SMateusz Guzik 			if (priv_check_cred(u1, PRIV_SEEOTHERGIDS) != 0)
139964d19c2eSRobert Watson 				return (ESRCH);
140064d19c2eSRobert Watson 		}
140164d19c2eSRobert Watson 	}
140264d19c2eSRobert Watson 	return (0);
140364d19c2eSRobert Watson }
140464d19c2eSRobert Watson 
1405a4aaba3bSSteve Wills /*
1406a4aaba3bSSteve Wills  * 'see_jail_proc' determines whether or not visibility of processes and
1407a4aaba3bSSteve Wills  * sockets with credentials holding different jail ids is possible using a
1408a4aaba3bSSteve Wills  * variety of system MIBs.
1409a4aaba3bSSteve Wills  *
1410a4aaba3bSSteve Wills  * XXX: data declarations should be together near the beginning of the file.
1411a4aaba3bSSteve Wills  */
1412a4aaba3bSSteve Wills 
1413a4aaba3bSSteve Wills static int	see_jail_proc = 1;
1414a4aaba3bSSteve Wills SYSCTL_INT(_security_bsd, OID_AUTO, see_jail_proc, CTLFLAG_RW,
1415a4aaba3bSSteve Wills     &see_jail_proc, 0,
1416a4aaba3bSSteve Wills     "Unprivileged processes may see subjects/objects with different jail ids");
1417a4aaba3bSSteve Wills 
1418a4aaba3bSSteve Wills /*-
1419a4aaba3bSSteve Wills  * Determine if u1 "can see" the subject specified by u2, according to the
1420a4aaba3bSSteve Wills  * 'see_jail_proc' policy.
1421a4aaba3bSSteve Wills  * Returns: 0 for permitted, ESRCH otherwise
1422a4aaba3bSSteve Wills  * Locks: none
1423a4aaba3bSSteve Wills  * References: *u1 and *u2 must not change during the call
1424a4aaba3bSSteve Wills  *             u1 may equal u2, in which case only one reference is required
1425a4aaba3bSSteve Wills  */
1426a4aaba3bSSteve Wills int
1427a4aaba3bSSteve Wills cr_canseejailproc(struct ucred *u1, struct ucred *u2)
1428a4aaba3bSSteve Wills {
1429*7974ca1cSOlivier Certner 	if (see_jail_proc || /* Policy deactivated. */
1430*7974ca1cSOlivier Certner 	    u1->cr_prison == u2->cr_prison || /* Same jail. */
1431*7974ca1cSOlivier Certner 	    priv_check_cred(u1, PRIV_SEEJAILPROC) == 0) /* Privileged. */
1432a4aaba3bSSteve Wills 		return (0);
1433*7974ca1cSOlivier Certner 
1434*7974ca1cSOlivier Certner 	return (ESRCH);
1435a4aaba3bSSteve Wills }
1436a4aaba3bSSteve Wills 
14371a996ed1SEdward Tomasz Napierala /*-
14387fd6a959SRobert Watson  * Determine if u1 "can see" the subject specified by u2.
1439ed639720SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1440ed639720SRobert Watson  * Locks: none
1441eb725b4eSRobert Watson  * References: *u1 and *u2 must not change during the call
1442ed639720SRobert Watson  *             u1 may equal u2, in which case only one reference is required
1443ed639720SRobert Watson  */
1444ed639720SRobert Watson int
144594088977SRobert Watson cr_cansee(struct ucred *u1, struct ucred *u2)
1446a9e0361bSPoul-Henning Kamp {
144791421ba2SRobert Watson 	int error;
1448a9e0361bSPoul-Henning Kamp 
1449ed639720SRobert Watson 	if ((error = prison_check(u1, u2)))
145091421ba2SRobert Watson 		return (error);
14518a1d977dSRobert Watson #ifdef MAC
145230d239bcSRobert Watson 	if ((error = mac_cred_check_visible(u1, u2)))
14538a1d977dSRobert Watson 		return (error);
14548a1d977dSRobert Watson #endif
14554ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeotheruids(u1, u2)))
14561b350b45SRobert Watson 		return (error);
14574ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeothergids(u1, u2)))
145864d19c2eSRobert Watson 		return (error);
1459a4aaba3bSSteve Wills 	if ((error = cr_canseejailproc(u1, u2)))
1460a4aaba3bSSteve Wills 		return (error);
1461387d2c03SRobert Watson 	return (0);
1462387d2c03SRobert Watson }
1463387d2c03SRobert Watson 
14641a996ed1SEdward Tomasz Napierala /*-
1465f44d9e24SJohn Baldwin  * Determine if td "can see" the subject specified by p.
14663b243b72SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1467f44d9e24SJohn Baldwin  * Locks: Sufficient locks to protect p->p_ucred must be held.  td really
1468f44d9e24SJohn Baldwin  *        should be curthread.
1469f44d9e24SJohn Baldwin  * References: td and p must be valid for the lifetime of the call
14703b243b72SRobert Watson  */
1471a0f75161SRobert Watson int
1472f44d9e24SJohn Baldwin p_cansee(struct thread *td, struct proc *p)
1473ed639720SRobert Watson {
147494088977SRobert Watson 	/* Wrap cr_cansee() for all functionality. */
1475f44d9e24SJohn Baldwin 	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1476f44d9e24SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
147755a0aa21SKonstantin Belousov 
147855a0aa21SKonstantin Belousov 	if (td->td_proc == p)
147955a0aa21SKonstantin Belousov 		return (0);
1480f44d9e24SJohn Baldwin 	return (cr_cansee(td->td_ucred, p->p_ucred));
1481ed639720SRobert Watson }
1482ed639720SRobert Watson 
148362c45ef4SRobert Watson /*
148462c45ef4SRobert Watson  * 'conservative_signals' prevents the delivery of a broad class of
148562c45ef4SRobert Watson  * signals by unprivileged processes to processes that have changed their
148662c45ef4SRobert Watson  * credentials since the last invocation of execve().  This can prevent
148762c45ef4SRobert Watson  * the leakage of cached information or retained privileges as a result
148862c45ef4SRobert Watson  * of a common class of signal-related vulnerabilities.  However, this
148962c45ef4SRobert Watson  * may interfere with some applications that expect to be able to
149062c45ef4SRobert Watson  * deliver these signals to peer processes after having given up
149162c45ef4SRobert Watson  * privilege.
149262c45ef4SRobert Watson  */
149362c45ef4SRobert Watson static int	conservative_signals = 1;
149462c45ef4SRobert Watson SYSCTL_INT(_security_bsd, OID_AUTO, conservative_signals, CTLFLAG_RW,
149562c45ef4SRobert Watson     &conservative_signals, 0, "Unprivileged processes prevented from "
149662c45ef4SRobert Watson     "sending certain signals to processes whose credentials have changed");
14971a996ed1SEdward Tomasz Napierala /*-
1498c83f8015SRobert Watson  * Determine whether cred may deliver the specified signal to proc.
1499c83f8015SRobert Watson  * Returns: 0 for permitted, an errno value otherwise.
1500c83f8015SRobert Watson  * Locks: A lock must be held for proc.
1501c83f8015SRobert Watson  * References: cred and proc must be valid for the lifetime of the call.
15024c5eb9c3SRobert Watson  */
15034c5eb9c3SRobert Watson int
15041a88a252SMaxim Sobolev cr_cansignal(struct ucred *cred, struct proc *proc, int signum)
1505387d2c03SRobert Watson {
150691421ba2SRobert Watson 	int error;
1507387d2c03SRobert Watson 
1508f44d9e24SJohn Baldwin 	PROC_LOCK_ASSERT(proc, MA_OWNED);
15094c5eb9c3SRobert Watson 	/*
1510c83f8015SRobert Watson 	 * Jail semantics limit the scope of signalling to proc in the
1511c83f8015SRobert Watson 	 * same jail as cred, if cred is in jail.
15124c5eb9c3SRobert Watson 	 */
1513c83f8015SRobert Watson 	error = prison_check(cred, proc->p_ucred);
1514c83f8015SRobert Watson 	if (error)
151591421ba2SRobert Watson 		return (error);
15168a1d977dSRobert Watson #ifdef MAC
151730d239bcSRobert Watson 	if ((error = mac_proc_check_signal(cred, proc, signum)))
15188a1d977dSRobert Watson 		return (error);
15198a1d977dSRobert Watson #endif
15204ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeotheruids(cred, proc->p_ucred)))
152164d19c2eSRobert Watson 		return (error);
15224ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeothergids(cred, proc->p_ucred)))
15231b350b45SRobert Watson 		return (error);
1524387d2c03SRobert Watson 
1525387d2c03SRobert Watson 	/*
15263b243b72SRobert Watson 	 * UNIX signal semantics depend on the status of the P_SUGID
15273b243b72SRobert Watson 	 * bit on the target process.  If the bit is set, then additional
15283b243b72SRobert Watson 	 * restrictions are placed on the set of available signals.
15294c5eb9c3SRobert Watson 	 */
15301a88a252SMaxim Sobolev 	if (conservative_signals && (proc->p_flag & P_SUGID)) {
15314c5eb9c3SRobert Watson 		switch (signum) {
15324c5eb9c3SRobert Watson 		case 0:
15334c5eb9c3SRobert Watson 		case SIGKILL:
15344c5eb9c3SRobert Watson 		case SIGINT:
15354c5eb9c3SRobert Watson 		case SIGTERM:
153662c45ef4SRobert Watson 		case SIGALRM:
15374c5eb9c3SRobert Watson 		case SIGSTOP:
15384c5eb9c3SRobert Watson 		case SIGTTIN:
15394c5eb9c3SRobert Watson 		case SIGTTOU:
15404c5eb9c3SRobert Watson 		case SIGTSTP:
15414c5eb9c3SRobert Watson 		case SIGHUP:
15424c5eb9c3SRobert Watson 		case SIGUSR1:
15434c5eb9c3SRobert Watson 		case SIGUSR2:
15447fd6a959SRobert Watson 			/*
15457fd6a959SRobert Watson 			 * Generally, permit job and terminal control
15467fd6a959SRobert Watson 			 * signals.
15477fd6a959SRobert Watson 			 */
15484c5eb9c3SRobert Watson 			break;
15494c5eb9c3SRobert Watson 		default:
1550c83f8015SRobert Watson 			/* Not permitted without privilege. */
1551cc426dd3SMateusz Guzik 			error = priv_check_cred(cred, PRIV_SIGNAL_SUGID);
15524c5eb9c3SRobert Watson 			if (error)
15534c5eb9c3SRobert Watson 				return (error);
15544c5eb9c3SRobert Watson 		}
1555e9e7ff5bSRobert Watson 	}
1556e9e7ff5bSRobert Watson 
15574c5eb9c3SRobert Watson 	/*
15583b243b72SRobert Watson 	 * Generally, the target credential's ruid or svuid must match the
1559e9e7ff5bSRobert Watson 	 * subject credential's ruid or euid.
15604c5eb9c3SRobert Watson 	 */
1561c83f8015SRobert Watson 	if (cred->cr_ruid != proc->p_ucred->cr_ruid &&
1562c83f8015SRobert Watson 	    cred->cr_ruid != proc->p_ucred->cr_svuid &&
1563c83f8015SRobert Watson 	    cred->cr_uid != proc->p_ucred->cr_ruid &&
1564c83f8015SRobert Watson 	    cred->cr_uid != proc->p_ucred->cr_svuid) {
1565cc426dd3SMateusz Guzik 		error = priv_check_cred(cred, PRIV_SIGNAL_DIFFCRED);
15664c5eb9c3SRobert Watson 		if (error)
15674c5eb9c3SRobert Watson 			return (error);
15684c5eb9c3SRobert Watson 	}
1569387d2c03SRobert Watson 
1570387d2c03SRobert Watson 	return (0);
1571387d2c03SRobert Watson }
1572a9e0361bSPoul-Henning Kamp 
15731a996ed1SEdward Tomasz Napierala /*-
1574f44d9e24SJohn Baldwin  * Determine whether td may deliver the specified signal to p.
1575c83f8015SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1576f44d9e24SJohn Baldwin  * Locks: Sufficient locks to protect various components of td and p
1577f44d9e24SJohn Baldwin  *        must be held.  td must be curthread, and a lock must be
1578f44d9e24SJohn Baldwin  *        held for p.
1579f44d9e24SJohn Baldwin  * References: td and p must be valid for the lifetime of the call
1580c83f8015SRobert Watson  */
1581c83f8015SRobert Watson int
15821a88a252SMaxim Sobolev p_cansignal(struct thread *td, struct proc *p, int signum)
1583c83f8015SRobert Watson {
1584c83f8015SRobert Watson 
1585f44d9e24SJohn Baldwin 	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1586f44d9e24SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
1587f44d9e24SJohn Baldwin 	if (td->td_proc == p)
1588c83f8015SRobert Watson 		return (0);
1589c83f8015SRobert Watson 
1590c83f8015SRobert Watson 	/*
1591c83f8015SRobert Watson 	 * UNIX signalling semantics require that processes in the same
1592c83f8015SRobert Watson 	 * session always be able to deliver SIGCONT to one another,
1593c83f8015SRobert Watson 	 * overriding the remaining protections.
1594c83f8015SRobert Watson 	 */
1595f44d9e24SJohn Baldwin 	/* XXX: This will require an additional lock of some sort. */
1596f44d9e24SJohn Baldwin 	if (signum == SIGCONT && td->td_proc->p_session == p->p_session)
1597c83f8015SRobert Watson 		return (0);
15984b178336SMaxim Sobolev 	/*
1599f9cd63d4SMaxim Sobolev 	 * Some compat layers use SIGTHR and higher signals for
1600f9cd63d4SMaxim Sobolev 	 * communication between different kernel threads of the same
1601f9cd63d4SMaxim Sobolev 	 * process, so that they expect that it's always possible to
1602f9cd63d4SMaxim Sobolev 	 * deliver them, even for suid applications where cr_cansignal() can
16034b178336SMaxim Sobolev 	 * deny such ability for security consideration.  It should be
16044b178336SMaxim Sobolev 	 * pretty safe to do since the only way to create two processes
16054b178336SMaxim Sobolev 	 * with the same p_leader is via rfork(2).
16064b178336SMaxim Sobolev 	 */
16072322a0a7SMaxim Sobolev 	if (td->td_proc->p_leader != NULL && signum >= SIGTHR &&
16082322a0a7SMaxim Sobolev 	    signum < SIGTHR + 4 && td->td_proc->p_leader == p->p_leader)
16094b178336SMaxim Sobolev 		return (0);
1610c83f8015SRobert Watson 
16111a88a252SMaxim Sobolev 	return (cr_cansignal(td->td_ucred, p, signum));
1612c83f8015SRobert Watson }
1613c83f8015SRobert Watson 
16141a996ed1SEdward Tomasz Napierala /*-
1615f44d9e24SJohn Baldwin  * Determine whether td may reschedule p.
16167fd6a959SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1617f44d9e24SJohn Baldwin  * Locks: Sufficient locks to protect various components of td and p
1618f44d9e24SJohn Baldwin  *        must be held.  td must be curthread, and a lock must
1619f44d9e24SJohn Baldwin  *        be held for p.
1620f44d9e24SJohn Baldwin  * References: td and p must be valid for the lifetime of the call
16213b243b72SRobert Watson  */
1622a0f75161SRobert Watson int
1623f44d9e24SJohn Baldwin p_cansched(struct thread *td, struct proc *p)
1624387d2c03SRobert Watson {
162591421ba2SRobert Watson 	int error;
1626387d2c03SRobert Watson 
1627f44d9e24SJohn Baldwin 	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1628f44d9e24SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
1629f44d9e24SJohn Baldwin 	if (td->td_proc == p)
1630387d2c03SRobert Watson 		return (0);
1631f44d9e24SJohn Baldwin 	if ((error = prison_check(td->td_ucred, p->p_ucred)))
163291421ba2SRobert Watson 		return (error);
16338a1d977dSRobert Watson #ifdef MAC
163430d239bcSRobert Watson 	if ((error = mac_proc_check_sched(td->td_ucred, p)))
16358a1d977dSRobert Watson 		return (error);
16368a1d977dSRobert Watson #endif
16374ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeotheruids(td->td_ucred, p->p_ucred)))
16381b350b45SRobert Watson 		return (error);
16394ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeothergids(td->td_ucred, p->p_ucred)))
164064d19c2eSRobert Watson 		return (error);
1641800c9408SRobert Watson 	if (td->td_ucred->cr_ruid != p->p_ucred->cr_ruid &&
1642800c9408SRobert Watson 	    td->td_ucred->cr_uid != p->p_ucred->cr_ruid) {
164332f9753cSRobert Watson 		error = priv_check(td, PRIV_SCHED_DIFFCRED);
1644800c9408SRobert Watson 		if (error)
1645800c9408SRobert Watson 			return (error);
1646800c9408SRobert Watson 	}
1647387d2c03SRobert Watson 	return (0);
1648387d2c03SRobert Watson }
1649387d2c03SRobert Watson 
16503b243b72SRobert Watson /*
1651b3079544SJamie Gritton  * Handle getting or setting the prison's unprivileged_proc_debug
1652b3079544SJamie Gritton  * value.
1653b3079544SJamie Gritton  */
1654b3079544SJamie Gritton static int
1655b3079544SJamie Gritton sysctl_unprivileged_proc_debug(SYSCTL_HANDLER_ARGS)
1656b3079544SJamie Gritton {
1657b3079544SJamie Gritton 	int error, val;
1658b3079544SJamie Gritton 
16590fe74ae6SJamie Gritton 	val = prison_allow(req->td->td_ucred, PR_ALLOW_UNPRIV_DEBUG);
1660b3079544SJamie Gritton 	error = sysctl_handle_int(oidp, &val, 0, req);
1661b3079544SJamie Gritton 	if (error != 0 || req->newptr == NULL)
1662b3079544SJamie Gritton 		return (error);
16630fe74ae6SJamie Gritton 	if (val != 0 && val != 1)
16640fe74ae6SJamie Gritton 		return (EINVAL);
16650fe74ae6SJamie Gritton 	prison_set_allow(req->td->td_ucred, PR_ALLOW_UNPRIV_DEBUG, val);
16660fe74ae6SJamie Gritton 	return (0);
1667b3079544SJamie Gritton }
1668b3079544SJamie Gritton 
1669b3079544SJamie Gritton /*
16705d476e73SRobert Watson  * The 'unprivileged_proc_debug' flag may be used to disable a variety of
16715d476e73SRobert Watson  * unprivileged inter-process debugging services, including some procfs
16725d476e73SRobert Watson  * functionality, ptrace(), and ktrace().  In the past, inter-process
16735d476e73SRobert Watson  * debugging has been involved in a variety of security problems, and sites
16745d476e73SRobert Watson  * not requiring the service might choose to disable it when hardening
16755d476e73SRobert Watson  * systems.
16763b243b72SRobert Watson  */
1677b3079544SJamie Gritton SYSCTL_PROC(_security_bsd, OID_AUTO, unprivileged_proc_debug,
16787029da5cSPawel Biernacki     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_SECURE |
16797029da5cSPawel Biernacki     CTLFLAG_MPSAFE, 0, 0, sysctl_unprivileged_proc_debug, "I",
16800ef5652eSRobert Watson     "Unprivileged processes may use process debugging facilities");
16810ef5652eSRobert Watson 
16821a996ed1SEdward Tomasz Napierala /*-
1683f44d9e24SJohn Baldwin  * Determine whether td may debug p.
16847fd6a959SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1685f44d9e24SJohn Baldwin  * Locks: Sufficient locks to protect various components of td and p
1686f44d9e24SJohn Baldwin  *        must be held.  td must be curthread, and a lock must
1687f44d9e24SJohn Baldwin  *        be held for p.
1688f44d9e24SJohn Baldwin  * References: td and p must be valid for the lifetime of the call
16893b243b72SRobert Watson  */
1690a0f75161SRobert Watson int
1691f44d9e24SJohn Baldwin p_candebug(struct thread *td, struct proc *p)
1692387d2c03SRobert Watson {
1693c54d240eSPawel Jakub Dawidek 	int error, grpsubset, i, uidsubset;
1694387d2c03SRobert Watson 
1695f44d9e24SJohn Baldwin 	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1696f44d9e24SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
1697f44d9e24SJohn Baldwin 	if (td->td_proc == p)
169823fad5b6SDag-Erling Smørgrav 		return (0);
169955a0aa21SKonstantin Belousov 	if ((error = priv_check(td, PRIV_DEBUG_UNPRIV)))
170055a0aa21SKonstantin Belousov 		return (error);
1701f44d9e24SJohn Baldwin 	if ((error = prison_check(td->td_ucred, p->p_ucred)))
170291421ba2SRobert Watson 		return (error);
17038a1d977dSRobert Watson #ifdef MAC
170430d239bcSRobert Watson 	if ((error = mac_proc_check_debug(td->td_ucred, p)))
17058a1d977dSRobert Watson 		return (error);
17068a1d977dSRobert Watson #endif
17074ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeotheruids(td->td_ucred, p->p_ucred)))
17081b350b45SRobert Watson 		return (error);
17094ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeothergids(td->td_ucred, p->p_ucred)))
171064d19c2eSRobert Watson 		return (error);
1711387d2c03SRobert Watson 
17127fd6a959SRobert Watson 	/*
1713f44d9e24SJohn Baldwin 	 * Is p's group set a subset of td's effective group set?  This
1714f44d9e24SJohn Baldwin 	 * includes p's egid, group access list, rgid, and svgid.
17157fd6a959SRobert Watson 	 */
1716db42a33dSRobert Watson 	grpsubset = 1;
1717f44d9e24SJohn Baldwin 	for (i = 0; i < p->p_ucred->cr_ngroups; i++) {
1718f44d9e24SJohn Baldwin 		if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) {
1719db42a33dSRobert Watson 			grpsubset = 0;
1720db42a33dSRobert Watson 			break;
1721db42a33dSRobert Watson 		}
1722db42a33dSRobert Watson 	}
1723db42a33dSRobert Watson 	grpsubset = grpsubset &&
1724f44d9e24SJohn Baldwin 	    groupmember(p->p_ucred->cr_rgid, td->td_ucred) &&
1725f44d9e24SJohn Baldwin 	    groupmember(p->p_ucred->cr_svgid, td->td_ucred);
1726db42a33dSRobert Watson 
1727db42a33dSRobert Watson 	/*
1728f44d9e24SJohn Baldwin 	 * Are the uids present in p's credential equal to td's
1729f44d9e24SJohn Baldwin 	 * effective uid?  This includes p's euid, svuid, and ruid.
1730db42a33dSRobert Watson 	 */
1731f44d9e24SJohn Baldwin 	uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid &&
1732f44d9e24SJohn Baldwin 	    td->td_ucred->cr_uid == p->p_ucred->cr_svuid &&
1733f44d9e24SJohn Baldwin 	    td->td_ucred->cr_uid == p->p_ucred->cr_ruid);
1734db42a33dSRobert Watson 
1735db42a33dSRobert Watson 	/*
1736f44d9e24SJohn Baldwin 	 * If p's gids aren't a subset, or the uids aren't a subset,
1737db42a33dSRobert Watson 	 * or the credential has changed, require appropriate privilege
1738800c9408SRobert Watson 	 * for td to debug p.
1739db42a33dSRobert Watson 	 */
1740800c9408SRobert Watson 	if (!grpsubset || !uidsubset) {
174132f9753cSRobert Watson 		error = priv_check(td, PRIV_DEBUG_DIFFCRED);
1742800c9408SRobert Watson 		if (error)
1743800c9408SRobert Watson 			return (error);
1744800c9408SRobert Watson 	}
1745800c9408SRobert Watson 
1746c54d240eSPawel Jakub Dawidek 	/*
1747c54d240eSPawel Jakub Dawidek 	 * Has the credential of the process changed since the last exec()?
1748c54d240eSPawel Jakub Dawidek 	 */
1749c54d240eSPawel Jakub Dawidek 	if ((p->p_flag & P_SUGID) != 0) {
175032f9753cSRobert Watson 		error = priv_check(td, PRIV_DEBUG_SUGID);
175132d18604SRobert Watson 		if (error)
1752387d2c03SRobert Watson 			return (error);
17537fd6a959SRobert Watson 	}
1754387d2c03SRobert Watson 
1755eb725b4eSRobert Watson 	/* Can't trace init when securelevel > 0. */
1756f44d9e24SJohn Baldwin 	if (p == initproc) {
1757f44d9e24SJohn Baldwin 		error = securelevel_gt(td->td_ucred, 0);
17583ca719f1SRobert Watson 		if (error)
17593ca719f1SRobert Watson 			return (error);
17603ca719f1SRobert Watson 	}
1761387d2c03SRobert Watson 
17625fab7614SRobert Watson 	/*
17635fab7614SRobert Watson 	 * Can't trace a process that's currently exec'ing.
1764800c9408SRobert Watson 	 *
17655fab7614SRobert Watson 	 * XXX: Note, this is not a security policy decision, it's a
17665fab7614SRobert Watson 	 * basic correctness/functionality decision.  Therefore, this check
17675fab7614SRobert Watson 	 * should be moved to the caller's of p_candebug().
17685fab7614SRobert Watson 	 */
1769f44d9e24SJohn Baldwin 	if ((p->p_flag & P_INEXEC) != 0)
1770af80b2c9SKonstantin Belousov 		return (EBUSY);
17719ca45e81SDag-Erling Smørgrav 
1772768f9b8bSGordon Bergling 	/* Denied explicitly */
1773677258f7SKonstantin Belousov 	if ((p->p_flag2 & P2_NOTRACE) != 0) {
1774677258f7SKonstantin Belousov 		error = priv_check(td, PRIV_DEBUG_DENIED);
1775677258f7SKonstantin Belousov 		if (error != 0)
1776677258f7SKonstantin Belousov 			return (error);
1777677258f7SKonstantin Belousov 	}
1778677258f7SKonstantin Belousov 
1779387d2c03SRobert Watson 	return (0);
1780387d2c03SRobert Watson }
1781387d2c03SRobert Watson 
17821a996ed1SEdward Tomasz Napierala /*-
178329dc1288SRobert Watson  * Determine whether the subject represented by cred can "see" a socket.
178429dc1288SRobert Watson  * Returns: 0 for permitted, ENOENT otherwise.
178529dc1288SRobert Watson  */
178629dc1288SRobert Watson int
178729dc1288SRobert Watson cr_canseesocket(struct ucred *cred, struct socket *so)
178829dc1288SRobert Watson {
178929dc1288SRobert Watson 	int error;
179029dc1288SRobert Watson 
179129dc1288SRobert Watson 	error = prison_check(cred, so->so_cred);
179229dc1288SRobert Watson 	if (error)
179329dc1288SRobert Watson 		return (ENOENT);
17948a1d977dSRobert Watson #ifdef MAC
179530d239bcSRobert Watson 	error = mac_socket_check_visible(cred, so);
17968a1d977dSRobert Watson 	if (error)
17978a1d977dSRobert Watson 		return (error);
17988a1d977dSRobert Watson #endif
17994ac21b4fSStephen J. Kiernan 	if (cr_canseeotheruids(cred, so->so_cred))
180029dc1288SRobert Watson 		return (ENOENT);
18014ac21b4fSStephen J. Kiernan 	if (cr_canseeothergids(cred, so->so_cred))
180264d19c2eSRobert Watson 		return (ENOENT);
180329dc1288SRobert Watson 
180429dc1288SRobert Watson 	return (0);
180529dc1288SRobert Watson }
180629dc1288SRobert Watson 
18071a996ed1SEdward Tomasz Napierala /*-
1808babe9a2bSRobert Watson  * Determine whether td can wait for the exit of p.
1809babe9a2bSRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1810babe9a2bSRobert Watson  * Locks: Sufficient locks to protect various components of td and p
1811babe9a2bSRobert Watson  *        must be held.  td must be curthread, and a lock must
1812babe9a2bSRobert Watson  *        be held for p.
1813babe9a2bSRobert Watson  * References: td and p must be valid for the lifetime of the call
1814babe9a2bSRobert Watson 
1815babe9a2bSRobert Watson  */
1816babe9a2bSRobert Watson int
1817babe9a2bSRobert Watson p_canwait(struct thread *td, struct proc *p)
1818babe9a2bSRobert Watson {
1819babe9a2bSRobert Watson 	int error;
1820babe9a2bSRobert Watson 
1821babe9a2bSRobert Watson 	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1822babe9a2bSRobert Watson 	PROC_LOCK_ASSERT(p, MA_OWNED);
18237afcbc18SJamie Gritton 	if ((error = prison_check(td->td_ucred, p->p_ucred)))
1824babe9a2bSRobert Watson 		return (error);
1825babe9a2bSRobert Watson #ifdef MAC
182630d239bcSRobert Watson 	if ((error = mac_proc_check_wait(td->td_ucred, p)))
1827babe9a2bSRobert Watson 		return (error);
1828babe9a2bSRobert Watson #endif
1829babe9a2bSRobert Watson #if 0
1830babe9a2bSRobert Watson 	/* XXXMAC: This could have odd effects on some shells. */
18314ac21b4fSStephen J. Kiernan 	if ((error = cr_canseeotheruids(td->td_ucred, p->p_ucred)))
1832babe9a2bSRobert Watson 		return (error);
1833babe9a2bSRobert Watson #endif
1834babe9a2bSRobert Watson 
1835babe9a2bSRobert Watson 	return (0);
1836babe9a2bSRobert Watson }
1837babe9a2bSRobert Watson 
1838a9e0361bSPoul-Henning Kamp /*
18391724c563SMateusz Guzik  * Credential management.
18401724c563SMateusz Guzik  *
18411724c563SMateusz Guzik  * struct ucred objects are rarely allocated but gain and lose references all
18421724c563SMateusz Guzik  * the time (e.g., on struct file alloc/dealloc) turning refcount updates into
18431724c563SMateusz Guzik  * a significant source of cache-line ping ponging. Common cases are worked
18441724c563SMateusz Guzik  * around by modifying thread-local counter instead if the cred to operate on
18451724c563SMateusz Guzik  * matches td_realucred.
18461724c563SMateusz Guzik  *
18471724c563SMateusz Guzik  * The counter is split into 2 parts:
18481724c563SMateusz Guzik  * - cr_users -- total count of all struct proc and struct thread objects
18491724c563SMateusz Guzik  *   which have given cred in p_ucred and td_ucred respectively
18501724c563SMateusz Guzik  * - cr_ref -- the actual ref count, only valid if cr_users == 0
18511724c563SMateusz Guzik  *
18521724c563SMateusz Guzik  * If users == 0 then cr_ref behaves similarly to refcount(9), in particular if
18531724c563SMateusz Guzik  * the count reaches 0 the object is freeable.
18541724c563SMateusz Guzik  * If users > 0 and curthread->td_realucred == cred, then updates are performed
18551724c563SMateusz Guzik  * against td_ucredref.
18561724c563SMateusz Guzik  * In other cases updates are performed against cr_ref.
18571724c563SMateusz Guzik  *
18581724c563SMateusz Guzik  * Changing td_realucred into something else decrements cr_users and transfers
18591724c563SMateusz Guzik  * accumulated updates.
18601724c563SMateusz Guzik  */
18611724c563SMateusz Guzik struct ucred *
18621724c563SMateusz Guzik crcowget(struct ucred *cr)
18631724c563SMateusz Guzik {
18641724c563SMateusz Guzik 
18651724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
18661724c563SMateusz Guzik 	KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
18671724c563SMateusz Guzik 	    __func__, cr->cr_users, cr));
18681724c563SMateusz Guzik 	cr->cr_users++;
18691724c563SMateusz Guzik 	cr->cr_ref++;
18701724c563SMateusz Guzik 	mtx_unlock(&cr->cr_mtx);
18711724c563SMateusz Guzik 	return (cr);
18721724c563SMateusz Guzik }
18731724c563SMateusz Guzik 
18741724c563SMateusz Guzik static struct ucred *
18751724c563SMateusz Guzik crunuse(struct thread *td)
18761724c563SMateusz Guzik {
18771724c563SMateusz Guzik 	struct ucred *cr, *crold;
18781724c563SMateusz Guzik 
1879936c24faSMateusz Guzik 	MPASS(td->td_realucred == td->td_ucred);
1880936c24faSMateusz Guzik 	cr = td->td_realucred;
18811724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
18821724c563SMateusz Guzik 	cr->cr_ref += td->td_ucredref;
18831724c563SMateusz Guzik 	td->td_ucredref = 0;
18841724c563SMateusz Guzik 	KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
18851724c563SMateusz Guzik 	    __func__, cr->cr_users, cr));
18861724c563SMateusz Guzik 	cr->cr_users--;
18871724c563SMateusz Guzik 	if (cr->cr_users == 0) {
188837337709SMateusz Guzik 		KASSERT(cr->cr_ref > 0, ("%s: ref %ld not > 0 on cred %p",
18891724c563SMateusz Guzik 		    __func__, cr->cr_ref, cr));
18901724c563SMateusz Guzik 		crold = cr;
18911724c563SMateusz Guzik 	} else {
18921724c563SMateusz Guzik 		cr->cr_ref--;
18931724c563SMateusz Guzik 		crold = NULL;
18941724c563SMateusz Guzik 	}
18951724c563SMateusz Guzik 	mtx_unlock(&cr->cr_mtx);
1896936c24faSMateusz Guzik 	td->td_realucred = NULL;
18971724c563SMateusz Guzik 	return (crold);
18981724c563SMateusz Guzik }
18991724c563SMateusz Guzik 
1900f34a2f56SMateusz Guzik static void
1901f34a2f56SMateusz Guzik crunusebatch(struct ucred *cr, int users, int ref)
1902f34a2f56SMateusz Guzik {
1903f34a2f56SMateusz Guzik 
1904f34a2f56SMateusz Guzik 	KASSERT(users > 0, ("%s: passed users %d not > 0 ; cred %p",
1905f34a2f56SMateusz Guzik 	    __func__, users, cr));
1906f34a2f56SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
1907f34a2f56SMateusz Guzik 	KASSERT(cr->cr_users >= users, ("%s: users %d not > %d on cred %p",
1908f34a2f56SMateusz Guzik 	    __func__, cr->cr_users, users, cr));
1909f34a2f56SMateusz Guzik 	cr->cr_users -= users;
1910f34a2f56SMateusz Guzik 	cr->cr_ref += ref;
1911f34a2f56SMateusz Guzik 	cr->cr_ref -= users;
1912f34a2f56SMateusz Guzik 	if (cr->cr_users > 0) {
1913f34a2f56SMateusz Guzik 		mtx_unlock(&cr->cr_mtx);
1914f34a2f56SMateusz Guzik 		return;
1915f34a2f56SMateusz Guzik 	}
191637337709SMateusz Guzik 	KASSERT(cr->cr_ref >= 0, ("%s: ref %ld not >= 0 on cred %p",
1917f34a2f56SMateusz Guzik 	    __func__, cr->cr_ref, cr));
1918f34a2f56SMateusz Guzik 	if (cr->cr_ref > 0) {
1919f34a2f56SMateusz Guzik 		mtx_unlock(&cr->cr_mtx);
1920f34a2f56SMateusz Guzik 		return;
1921f34a2f56SMateusz Guzik 	}
1922f34a2f56SMateusz Guzik 	crfree_final(cr);
1923f34a2f56SMateusz Guzik }
1924f34a2f56SMateusz Guzik 
19251724c563SMateusz Guzik void
19261724c563SMateusz Guzik crcowfree(struct thread *td)
19271724c563SMateusz Guzik {
19281724c563SMateusz Guzik 	struct ucred *cr;
19291724c563SMateusz Guzik 
19301724c563SMateusz Guzik 	cr = crunuse(td);
19311724c563SMateusz Guzik 	if (cr != NULL)
19321724c563SMateusz Guzik 		crfree(cr);
19331724c563SMateusz Guzik }
19341724c563SMateusz Guzik 
19351724c563SMateusz Guzik struct ucred *
19361724c563SMateusz Guzik crcowsync(void)
19371724c563SMateusz Guzik {
19381724c563SMateusz Guzik 	struct thread *td;
19391724c563SMateusz Guzik 	struct proc *p;
19401724c563SMateusz Guzik 	struct ucred *crnew, *crold;
19411724c563SMateusz Guzik 
19421724c563SMateusz Guzik 	td = curthread;
19431724c563SMateusz Guzik 	p = td->td_proc;
19441724c563SMateusz Guzik 	PROC_LOCK_ASSERT(p, MA_OWNED);
19451724c563SMateusz Guzik 
19461724c563SMateusz Guzik 	MPASS(td->td_realucred == td->td_ucred);
19471724c563SMateusz Guzik 	if (td->td_realucred == p->p_ucred)
19481724c563SMateusz Guzik 		return (NULL);
19491724c563SMateusz Guzik 
19501724c563SMateusz Guzik 	crnew = crcowget(p->p_ucred);
19511724c563SMateusz Guzik 	crold = crunuse(td);
19521724c563SMateusz Guzik 	td->td_realucred = crnew;
19531724c563SMateusz Guzik 	td->td_ucred = td->td_realucred;
19541724c563SMateusz Guzik 	return (crold);
19551724c563SMateusz Guzik }
19561724c563SMateusz Guzik 
19571724c563SMateusz Guzik /*
1958f34a2f56SMateusz Guzik  * Batching.
1959f34a2f56SMateusz Guzik  */
1960f34a2f56SMateusz Guzik void
1961f34a2f56SMateusz Guzik credbatch_add(struct credbatch *crb, struct thread *td)
1962f34a2f56SMateusz Guzik {
1963f34a2f56SMateusz Guzik 	struct ucred *cr;
1964f34a2f56SMateusz Guzik 
1965f34a2f56SMateusz Guzik 	MPASS(td->td_realucred != NULL);
1966f34a2f56SMateusz Guzik 	MPASS(td->td_realucred == td->td_ucred);
1967fa2528acSAlex Richardson 	MPASS(TD_GET_STATE(td) == TDS_INACTIVE);
1968f34a2f56SMateusz Guzik 	cr = td->td_realucred;
1969f34a2f56SMateusz Guzik 	KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
1970f34a2f56SMateusz Guzik 	    __func__, cr->cr_users, cr));
1971f34a2f56SMateusz Guzik 	if (crb->cred != cr) {
1972f34a2f56SMateusz Guzik 		if (crb->users > 0) {
1973f34a2f56SMateusz Guzik 			MPASS(crb->cred != NULL);
1974f34a2f56SMateusz Guzik 			crunusebatch(crb->cred, crb->users, crb->ref);
1975f34a2f56SMateusz Guzik 			crb->users = 0;
1976f34a2f56SMateusz Guzik 			crb->ref = 0;
1977f34a2f56SMateusz Guzik 		}
1978f34a2f56SMateusz Guzik 	}
1979f34a2f56SMateusz Guzik 	crb->cred = cr;
1980f34a2f56SMateusz Guzik 	crb->users++;
1981f34a2f56SMateusz Guzik 	crb->ref += td->td_ucredref;
1982f34a2f56SMateusz Guzik 	td->td_ucredref = 0;
1983f34a2f56SMateusz Guzik 	td->td_realucred = NULL;
1984f34a2f56SMateusz Guzik }
1985f34a2f56SMateusz Guzik 
1986f34a2f56SMateusz Guzik void
1987f34a2f56SMateusz Guzik credbatch_final(struct credbatch *crb)
1988f34a2f56SMateusz Guzik {
1989f34a2f56SMateusz Guzik 
1990f34a2f56SMateusz Guzik 	MPASS(crb->cred != NULL);
1991f34a2f56SMateusz Guzik 	MPASS(crb->users > 0);
1992f34a2f56SMateusz Guzik 	crunusebatch(crb->cred, crb->users, crb->ref);
1993f34a2f56SMateusz Guzik }
1994f34a2f56SMateusz Guzik 
1995f34a2f56SMateusz Guzik /*
1996df8bae1dSRodney W. Grimes  * Allocate a zeroed cred structure.
1997df8bae1dSRodney W. Grimes  */
1998df8bae1dSRodney W. Grimes struct ucred *
19994c44ad8eSJohn Baldwin crget(void)
2000df8bae1dSRodney W. Grimes {
20013e85b721SEd Maste 	struct ucred *cr;
2002df8bae1dSRodney W. Grimes 
20031ede983cSDag-Erling Smørgrav 	cr = malloc(sizeof(*cr), M_CRED, M_WAITOK | M_ZERO);
20041724c563SMateusz Guzik 	mtx_init(&cr->cr_mtx, "cred", NULL, MTX_DEF);
20051724c563SMateusz Guzik 	cr->cr_ref = 1;
2006faef5371SRobert Watson #ifdef AUDIT
2007faef5371SRobert Watson 	audit_cred_init(cr);
2008faef5371SRobert Watson #endif
200940244964SRobert Watson #ifdef MAC
201030d239bcSRobert Watson 	mac_cred_init(cr);
201140244964SRobert Watson #endif
2012a99500a9SMateusz Guzik 	cr->cr_groups = cr->cr_smallgroups;
2013a99500a9SMateusz Guzik 	cr->cr_agroups =
2014a99500a9SMateusz Guzik 	    sizeof(cr->cr_smallgroups) / sizeof(cr->cr_smallgroups[0]);
2015df8bae1dSRodney W. Grimes 	return (cr);
2016df8bae1dSRodney W. Grimes }
2017df8bae1dSRodney W. Grimes 
2018df8bae1dSRodney W. Grimes /*
20197fd6a959SRobert Watson  * Claim another reference to a ucred structure.
20205c3f70d7SAlfred Perlstein  */
2021bd78ceceSJohn Baldwin struct ucred *
20224c44ad8eSJohn Baldwin crhold(struct ucred *cr)
20235c3f70d7SAlfred Perlstein {
20241724c563SMateusz Guzik 	struct thread *td;
20255c3f70d7SAlfred Perlstein 
20261724c563SMateusz Guzik 	td = curthread;
20271724c563SMateusz Guzik 	if (__predict_true(td->td_realucred == cr)) {
20281724c563SMateusz Guzik 		KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
20291724c563SMateusz Guzik 		    __func__, cr->cr_users, cr));
20301724c563SMateusz Guzik 		td->td_ucredref++;
20311724c563SMateusz Guzik 		return (cr);
20321724c563SMateusz Guzik 	}
20331724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
20341724c563SMateusz Guzik 	cr->cr_ref++;
20351724c563SMateusz Guzik 	mtx_unlock(&cr->cr_mtx);
2036bd78ceceSJohn Baldwin 	return (cr);
20375c3f70d7SAlfred Perlstein }
20385c3f70d7SAlfred Perlstein 
20395c3f70d7SAlfred Perlstein /*
20400c14ff0eSRobert Watson  * Free a cred structure.  Throws away space when ref count gets to 0.
2041df8bae1dSRodney W. Grimes  */
204226f9a767SRodney W. Grimes void
20434c44ad8eSJohn Baldwin crfree(struct ucred *cr)
2044df8bae1dSRodney W. Grimes {
20451724c563SMateusz Guzik 	struct thread *td;
20461e5d626aSAlfred Perlstein 
20471724c563SMateusz Guzik 	td = curthread;
2048a2de789eSMateusz Guzik 	if (__predict_true(td->td_realucred == cr)) {
20491724c563SMateusz Guzik 		KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
20501724c563SMateusz Guzik 		    __func__, cr->cr_users, cr));
20511724c563SMateusz Guzik 		td->td_ucredref--;
20521724c563SMateusz Guzik 		return;
20531724c563SMateusz Guzik 	}
20541724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
20551724c563SMateusz Guzik 	KASSERT(cr->cr_users >= 0, ("%s: users %d not >= 0 on cred %p",
20561724c563SMateusz Guzik 	    __func__, cr->cr_users, cr));
20571724c563SMateusz Guzik 	cr->cr_ref--;
20581724c563SMateusz Guzik 	if (cr->cr_users > 0) {
20591724c563SMateusz Guzik 		mtx_unlock(&cr->cr_mtx);
20601724c563SMateusz Guzik 		return;
20611724c563SMateusz Guzik 	}
206237337709SMateusz Guzik 	KASSERT(cr->cr_ref >= 0, ("%s: ref %ld not >= 0 on cred %p",
20631724c563SMateusz Guzik 	    __func__, cr->cr_ref, cr));
20641724c563SMateusz Guzik 	if (cr->cr_ref > 0) {
20651724c563SMateusz Guzik 		mtx_unlock(&cr->cr_mtx);
20661724c563SMateusz Guzik 		return;
20671724c563SMateusz Guzik 	}
2068f34a2f56SMateusz Guzik 	crfree_final(cr);
2069f34a2f56SMateusz Guzik }
2070f34a2f56SMateusz Guzik 
2071f34a2f56SMateusz Guzik static void
2072f34a2f56SMateusz Guzik crfree_final(struct ucred *cr)
2073f34a2f56SMateusz Guzik {
2074f34a2f56SMateusz Guzik 
2075f34a2f56SMateusz Guzik 	KASSERT(cr->cr_users == 0, ("%s: users %d not == 0 on cred %p",
2076f34a2f56SMateusz Guzik 	    __func__, cr->cr_users, cr));
207737337709SMateusz Guzik 	KASSERT(cr->cr_ref == 0, ("%s: ref %ld not == 0 on cred %p",
2078f34a2f56SMateusz Guzik 	    __func__, cr->cr_ref, cr));
20792f5b0b48SMateusz Guzik 
2080f535380cSDon Lewis 	/*
20811724c563SMateusz Guzik 	 * Some callers of crget(), such as nfs_statfs(), allocate a temporary
20821724c563SMateusz Guzik 	 * credential, but don't allocate a uidinfo structure.
2083f535380cSDon Lewis 	 */
2084f535380cSDon Lewis 	if (cr->cr_uidinfo != NULL)
2085f535380cSDon Lewis 		uifree(cr->cr_uidinfo);
2086823c224eSRobert Watson 	if (cr->cr_ruidinfo != NULL)
2087823c224eSRobert Watson 		uifree(cr->cr_ruidinfo);
20880304c731SJamie Gritton 	if (cr->cr_prison != NULL)
208991421ba2SRobert Watson 		prison_free(cr->cr_prison);
20902bfc50bcSEdward Tomasz Napierala 	if (cr->cr_loginclass != NULL)
20912bfc50bcSEdward Tomasz Napierala 		loginclass_free(cr->cr_loginclass);
2092faef5371SRobert Watson #ifdef AUDIT
2093faef5371SRobert Watson 	audit_cred_destroy(cr);
2094faef5371SRobert Watson #endif
209540244964SRobert Watson #ifdef MAC
209630d239bcSRobert Watson 	mac_cred_destroy(cr);
209740244964SRobert Watson #endif
20981724c563SMateusz Guzik 	mtx_destroy(&cr->cr_mtx);
2099a99500a9SMateusz Guzik 	if (cr->cr_groups != cr->cr_smallgroups)
2100838d9858SBrooks Davis 		free(cr->cr_groups, M_CRED);
21011ede983cSDag-Erling Smørgrav 	free(cr, M_CRED);
2102e1bca29fSMatthew Dillon }
2103df8bae1dSRodney W. Grimes 
2104df8bae1dSRodney W. Grimes /*
2105bd78ceceSJohn Baldwin  * Copy a ucred's contents from a template.  Does not block.
2106bd78ceceSJohn Baldwin  */
2107bd78ceceSJohn Baldwin void
21084c44ad8eSJohn Baldwin crcopy(struct ucred *dest, struct ucred *src)
2109bd78ceceSJohn Baldwin {
2110bd78ceceSJohn Baldwin 
211125108069SMateusz Guzik 	KASSERT(dest->cr_ref == 1, ("crcopy of shared ucred"));
2112bd78ceceSJohn Baldwin 	bcopy(&src->cr_startcopy, &dest->cr_startcopy,
2113bd78ceceSJohn Baldwin 	    (unsigned)((caddr_t)&src->cr_endcopy -
2114bd78ceceSJohn Baldwin 		(caddr_t)&src->cr_startcopy));
211537337709SMateusz Guzik 	dest->cr_flags = src->cr_flags;
2116838d9858SBrooks Davis 	crsetgroups(dest, src->cr_ngroups, src->cr_groups);
2117bd78ceceSJohn Baldwin 	uihold(dest->cr_uidinfo);
2118bd78ceceSJohn Baldwin 	uihold(dest->cr_ruidinfo);
2119bd78ceceSJohn Baldwin 	prison_hold(dest->cr_prison);
21202bfc50bcSEdward Tomasz Napierala 	loginclass_hold(dest->cr_loginclass);
2121faef5371SRobert Watson #ifdef AUDIT
2122faef5371SRobert Watson 	audit_cred_copy(src, dest);
2123faef5371SRobert Watson #endif
212440244964SRobert Watson #ifdef MAC
212530d239bcSRobert Watson 	mac_cred_copy(src, dest);
212640244964SRobert Watson #endif
2127df8bae1dSRodney W. Grimes }
2128df8bae1dSRodney W. Grimes 
2129df8bae1dSRodney W. Grimes /*
2130df8bae1dSRodney W. Grimes  * Dup cred struct to a new held one.
2131df8bae1dSRodney W. Grimes  */
2132df8bae1dSRodney W. Grimes struct ucred *
21334c44ad8eSJohn Baldwin crdup(struct ucred *cr)
2134df8bae1dSRodney W. Grimes {
2135df8bae1dSRodney W. Grimes 	struct ucred *newcr;
2136df8bae1dSRodney W. Grimes 
2137bd78ceceSJohn Baldwin 	newcr = crget();
2138bd78ceceSJohn Baldwin 	crcopy(newcr, cr);
2139df8bae1dSRodney W. Grimes 	return (newcr);
2140df8bae1dSRodney W. Grimes }
2141df8bae1dSRodney W. Grimes 
2142df8bae1dSRodney W. Grimes /*
214376183f34SDima Dorfman  * Fill in a struct xucred based on a struct ucred.
214476183f34SDima Dorfman  */
214576183f34SDima Dorfman void
21464c44ad8eSJohn Baldwin cru2x(struct ucred *cr, struct xucred *xcr)
214776183f34SDima Dorfman {
2148838d9858SBrooks Davis 	int ngroups;
214976183f34SDima Dorfman 
215076183f34SDima Dorfman 	bzero(xcr, sizeof(*xcr));
215176183f34SDima Dorfman 	xcr->cr_version = XUCRED_VERSION;
215276183f34SDima Dorfman 	xcr->cr_uid = cr->cr_uid;
2153838d9858SBrooks Davis 
2154838d9858SBrooks Davis 	ngroups = MIN(cr->cr_ngroups, XU_NGROUPS);
2155838d9858SBrooks Davis 	xcr->cr_ngroups = ngroups;
2156838d9858SBrooks Davis 	bcopy(cr->cr_groups, xcr->cr_groups,
2157838d9858SBrooks Davis 	    ngroups * sizeof(*cr->cr_groups));
215876183f34SDima Dorfman }
215976183f34SDima Dorfman 
2160c8124e20SDmitry Chagin void
2161c5afec6eSDmitry Chagin cru2xt(struct thread *td, struct xucred *xcr)
2162c5afec6eSDmitry Chagin {
2163c5afec6eSDmitry Chagin 
2164c5afec6eSDmitry Chagin 	cru2x(td->td_ucred, xcr);
2165c5afec6eSDmitry Chagin 	xcr->cr_pid = td->td_proc->p_pid;
2166c5afec6eSDmitry Chagin }
2167c5afec6eSDmitry Chagin 
216876183f34SDima Dorfman /*
2169ffb34484SMateusz Guzik  * Set initial process credentials.
2170ffb34484SMateusz Guzik  * Callers are responsible for providing the reference for provided credentials.
2171ffb34484SMateusz Guzik  */
2172ffb34484SMateusz Guzik void
2173ffb34484SMateusz Guzik proc_set_cred_init(struct proc *p, struct ucred *newcred)
2174ffb34484SMateusz Guzik {
2175ffb34484SMateusz Guzik 
21761724c563SMateusz Guzik 	p->p_ucred = crcowget(newcred);
2177ffb34484SMateusz Guzik }
2178ffb34484SMateusz Guzik 
2179ffb34484SMateusz Guzik /*
2180daf63fd2SMateusz Guzik  * Change process credentials.
2181ffb34484SMateusz Guzik  * Callers are responsible for providing the reference for passed credentials
2182daf63fd2SMateusz Guzik  * and for freeing old ones.
2183daf63fd2SMateusz Guzik  *
2184daf63fd2SMateusz Guzik  * Process has to be locked except when it does not have credentials (as it
2185daf63fd2SMateusz Guzik  * should not be visible just yet) or when newcred is NULL (as this can be
2186daf63fd2SMateusz Guzik  * only used when the process is about to be freed, at which point it should
2187daf63fd2SMateusz Guzik  * not be visible anymore).
2188daf63fd2SMateusz Guzik  */
21896f836483SMateusz Guzik void
2190daf63fd2SMateusz Guzik proc_set_cred(struct proc *p, struct ucred *newcred)
2191daf63fd2SMateusz Guzik {
21921724c563SMateusz Guzik 	struct ucred *cr;
2193daf63fd2SMateusz Guzik 
21941724c563SMateusz Guzik 	cr = p->p_ucred;
21951724c563SMateusz Guzik 	MPASS(cr != NULL);
2196daf63fd2SMateusz Guzik 	PROC_LOCK_ASSERT(p, MA_OWNED);
21971724c563SMateusz Guzik 	KASSERT(newcred->cr_users == 0, ("%s: users %d not 0 on cred %p",
21981724c563SMateusz Guzik 	    __func__, newcred->cr_users, newcred));
21991724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
22001724c563SMateusz Guzik 	KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
22011724c563SMateusz Guzik 	    __func__, cr->cr_users, cr));
22021724c563SMateusz Guzik 	cr->cr_users--;
22031724c563SMateusz Guzik 	mtx_unlock(&cr->cr_mtx);
2204daf63fd2SMateusz Guzik 	p->p_ucred = newcred;
22051724c563SMateusz Guzik 	newcred->cr_users = 1;
22064ea6a9a2SMateusz Guzik 	PROC_UPDATE_COW(p);
2207daf63fd2SMateusz Guzik }
2208daf63fd2SMateusz Guzik 
22095a90435cSMateusz Guzik void
22105a90435cSMateusz Guzik proc_unset_cred(struct proc *p)
22115a90435cSMateusz Guzik {
22125a90435cSMateusz Guzik 	struct ucred *cr;
22135a90435cSMateusz Guzik 
22141724c563SMateusz Guzik 	MPASS(p->p_state == PRS_ZOMBIE || p->p_state == PRS_NEW);
22155a90435cSMateusz Guzik 	cr = p->p_ucred;
22165a90435cSMateusz Guzik 	p->p_ucred = NULL;
22171724c563SMateusz Guzik 	KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
22181724c563SMateusz Guzik 	    __func__, cr->cr_users, cr));
22191724c563SMateusz Guzik 	mtx_lock(&cr->cr_mtx);
22201724c563SMateusz Guzik 	cr->cr_users--;
22211724c563SMateusz Guzik 	if (cr->cr_users == 0)
222237337709SMateusz Guzik 		KASSERT(cr->cr_ref > 0, ("%s: ref %ld not > 0 on cred %p",
22231724c563SMateusz Guzik 		    __func__, cr->cr_ref, cr));
22241724c563SMateusz Guzik 	mtx_unlock(&cr->cr_mtx);
22255a90435cSMateusz Guzik 	crfree(cr);
22265a90435cSMateusz Guzik }
22275a90435cSMateusz Guzik 
2228838d9858SBrooks Davis struct ucred *
2229838d9858SBrooks Davis crcopysafe(struct proc *p, struct ucred *cr)
2230838d9858SBrooks Davis {
2231838d9858SBrooks Davis 	struct ucred *oldcred;
2232838d9858SBrooks Davis 	int groups;
2233838d9858SBrooks Davis 
2234838d9858SBrooks Davis 	PROC_LOCK_ASSERT(p, MA_OWNED);
2235838d9858SBrooks Davis 
2236838d9858SBrooks Davis 	oldcred = p->p_ucred;
2237838d9858SBrooks Davis 	while (cr->cr_agroups < oldcred->cr_agroups) {
2238838d9858SBrooks Davis 		groups = oldcred->cr_agroups;
2239838d9858SBrooks Davis 		PROC_UNLOCK(p);
2240838d9858SBrooks Davis 		crextend(cr, groups);
2241838d9858SBrooks Davis 		PROC_LOCK(p);
2242838d9858SBrooks Davis 		oldcred = p->p_ucred;
2243838d9858SBrooks Davis 	}
2244838d9858SBrooks Davis 	crcopy(cr, oldcred);
2245838d9858SBrooks Davis 
2246838d9858SBrooks Davis 	return (oldcred);
2247838d9858SBrooks Davis }
2248838d9858SBrooks Davis 
2249838d9858SBrooks Davis /*
2250838d9858SBrooks Davis  * Extend the passed in credential to hold n items.
2251838d9858SBrooks Davis  */
2252c8358c6eSGleb Smirnoff void
2253838d9858SBrooks Davis crextend(struct ucred *cr, int n)
2254838d9858SBrooks Davis {
2255838d9858SBrooks Davis 	int cnt;
2256838d9858SBrooks Davis 
2257838d9858SBrooks Davis 	/* Truncate? */
2258838d9858SBrooks Davis 	if (n <= cr->cr_agroups)
2259838d9858SBrooks Davis 		return;
2260838d9858SBrooks Davis 
2261838d9858SBrooks Davis 	/*
2262838d9858SBrooks Davis 	 * We extend by 2 each time since we're using a power of two
2263838d9858SBrooks Davis 	 * allocator until we need enough groups to fill a page.
2264838d9858SBrooks Davis 	 * Once we're allocating multiple pages, only allocate as many
2265838d9858SBrooks Davis 	 * as we actually need.  The case of processes needing a
2266838d9858SBrooks Davis 	 * non-power of two number of pages seems more likely than
2267838d9858SBrooks Davis 	 * a real world process that adds thousands of groups one at a
2268838d9858SBrooks Davis 	 * time.
2269838d9858SBrooks Davis 	 */
2270838d9858SBrooks Davis 	if ( n < PAGE_SIZE / sizeof(gid_t) ) {
2271838d9858SBrooks Davis 		if (cr->cr_agroups == 0)
227251871224SRyan Libby 			cnt = MAX(1, MINALLOCSIZE / sizeof(gid_t));
2273838d9858SBrooks Davis 		else
2274838d9858SBrooks Davis 			cnt = cr->cr_agroups * 2;
2275838d9858SBrooks Davis 
2276838d9858SBrooks Davis 		while (cnt < n)
2277838d9858SBrooks Davis 			cnt *= 2;
2278838d9858SBrooks Davis 	} else
2279838d9858SBrooks Davis 		cnt = roundup2(n, PAGE_SIZE / sizeof(gid_t));
2280838d9858SBrooks Davis 
2281838d9858SBrooks Davis 	/* Free the old array. */
2282a99500a9SMateusz Guzik 	if (cr->cr_groups != cr->cr_smallgroups)
2283838d9858SBrooks Davis 		free(cr->cr_groups, M_CRED);
2284838d9858SBrooks Davis 
2285838d9858SBrooks Davis 	cr->cr_groups = malloc(cnt * sizeof(gid_t), M_CRED, M_WAITOK | M_ZERO);
2286838d9858SBrooks Davis 	cr->cr_agroups = cnt;
2287838d9858SBrooks Davis }
2288838d9858SBrooks Davis 
2289838d9858SBrooks Davis /*
22907f92e578SBrooks Davis  * Copy groups in to a credential, preserving any necessary invariants.
22917f92e578SBrooks Davis  * Currently this includes the sorting of all supplemental gids.
22927f92e578SBrooks Davis  * crextend() must have been called before hand to ensure sufficient
22937f92e578SBrooks Davis  * space is available.
2294838d9858SBrooks Davis  */
2295838d9858SBrooks Davis static void
2296838d9858SBrooks Davis crsetgroups_locked(struct ucred *cr, int ngrp, gid_t *groups)
2297838d9858SBrooks Davis {
22987f92e578SBrooks Davis 	int i;
22997f92e578SBrooks Davis 	int j;
23007f92e578SBrooks Davis 	gid_t g;
2301838d9858SBrooks Davis 
2302838d9858SBrooks Davis 	KASSERT(cr->cr_agroups >= ngrp, ("cr_ngroups is too small"));
2303838d9858SBrooks Davis 
2304838d9858SBrooks Davis 	bcopy(groups, cr->cr_groups, ngrp * sizeof(gid_t));
2305838d9858SBrooks Davis 	cr->cr_ngroups = ngrp;
23067f92e578SBrooks Davis 
23077f92e578SBrooks Davis 	/*
23087f92e578SBrooks Davis 	 * Sort all groups except cr_groups[0] to allow groupmember to
23097f92e578SBrooks Davis 	 * perform a binary search.
23107f92e578SBrooks Davis 	 *
23117f92e578SBrooks Davis 	 * XXX: If large numbers of groups become common this should
23127f92e578SBrooks Davis 	 * be replaced with shell sort like linux uses or possibly
23137f92e578SBrooks Davis 	 * heap sort.
23147f92e578SBrooks Davis 	 */
23157f92e578SBrooks Davis 	for (i = 2; i < ngrp; i++) {
23167f92e578SBrooks Davis 		g = cr->cr_groups[i];
23177f92e578SBrooks Davis 		for (j = i-1; j >= 1 && g < cr->cr_groups[j]; j--)
23187f92e578SBrooks Davis 			cr->cr_groups[j + 1] = cr->cr_groups[j];
23197f92e578SBrooks Davis 		cr->cr_groups[j + 1] = g;
23207f92e578SBrooks Davis 	}
2321838d9858SBrooks Davis }
2322838d9858SBrooks Davis 
2323838d9858SBrooks Davis /*
2324838d9858SBrooks Davis  * Copy groups in to a credential after expanding it if required.
2325412f9500SBrooks Davis  * Truncate the list to (ngroups_max + 1) if it is too large.
2326838d9858SBrooks Davis  */
2327838d9858SBrooks Davis void
2328838d9858SBrooks Davis crsetgroups(struct ucred *cr, int ngrp, gid_t *groups)
2329838d9858SBrooks Davis {
2330838d9858SBrooks Davis 
2331412f9500SBrooks Davis 	if (ngrp > ngroups_max + 1)
2332412f9500SBrooks Davis 		ngrp = ngroups_max + 1;
2333838d9858SBrooks Davis 
2334838d9858SBrooks Davis 	crextend(cr, ngrp);
2335838d9858SBrooks Davis 	crsetgroups_locked(cr, ngrp, groups);
2336838d9858SBrooks Davis }
2337838d9858SBrooks Davis 
23382eb927e2SJulian Elischer /*
2339df8bae1dSRodney W. Grimes  * Get login name, if available.
2340df8bae1dSRodney W. Grimes  */
2341d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
2342df8bae1dSRodney W. Grimes struct getlogin_args {
2343df8bae1dSRodney W. Grimes 	char	*namebuf;
2344df8bae1dSRodney W. Grimes 	u_int	namelen;
2345df8bae1dSRodney W. Grimes };
2346d2d3e875SBruce Evans #endif
2347df8bae1dSRodney W. Grimes /* ARGSUSED */
234826f9a767SRodney W. Grimes int
23498451d0ddSKip Macy sys_getlogin(struct thread *td, struct getlogin_args *uap)
2350df8bae1dSRodney W. Grimes {
2351f591779bSSeigo Tanimura 	char login[MAXLOGNAME];
2352b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
2353bccb6d5aSDag-Erling Smørgrav 	size_t len;
2354df8bae1dSRodney W. Grimes 
235530cf3ac4SAndrey A. Chernov 	if (uap->namelen > MAXLOGNAME)
235653490b76SAndrey A. Chernov 		uap->namelen = MAXLOGNAME;
2357f591779bSSeigo Tanimura 	PROC_LOCK(p);
2358f591779bSSeigo Tanimura 	SESS_LOCK(p->p_session);
2359bccb6d5aSDag-Erling Smørgrav 	len = strlcpy(login, p->p_session->s_login, uap->namelen) + 1;
2360f591779bSSeigo Tanimura 	SESS_UNLOCK(p->p_session);
2361f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
2362bccb6d5aSDag-Erling Smørgrav 	if (len > uap->namelen)
23636f68699fSBaptiste Daroussin 		return (ERANGE);
2364bccb6d5aSDag-Erling Smørgrav 	return (copyout(login, uap->namebuf, len));
2365df8bae1dSRodney W. Grimes }
2366df8bae1dSRodney W. Grimes 
2367df8bae1dSRodney W. Grimes /*
2368df8bae1dSRodney W. Grimes  * Set login name.
2369df8bae1dSRodney W. Grimes  */
2370d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
2371df8bae1dSRodney W. Grimes struct setlogin_args {
2372df8bae1dSRodney W. Grimes 	char	*namebuf;
2373df8bae1dSRodney W. Grimes };
2374d2d3e875SBruce Evans #endif
2375df8bae1dSRodney W. Grimes /* ARGSUSED */
237626f9a767SRodney W. Grimes int
23778451d0ddSKip Macy sys_setlogin(struct thread *td, struct setlogin_args *uap)
2378df8bae1dSRodney W. Grimes {
2379b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
2380df8bae1dSRodney W. Grimes 	int error;
2381964ca0caSAndrey A. Chernov 	char logintmp[MAXLOGNAME];
2382df8bae1dSRodney W. Grimes 
2383bccb6d5aSDag-Erling Smørgrav 	CTASSERT(sizeof(p->p_session->s_login) >= sizeof(logintmp));
2384bccb6d5aSDag-Erling Smørgrav 
238532f9753cSRobert Watson 	error = priv_check(td, PRIV_PROC_SETLOGIN);
238607f3485dSJohn Baldwin 	if (error)
238707f3485dSJohn Baldwin 		return (error);
23887f05b035SAlfred Perlstein 	error = copyinstr(uap->namebuf, logintmp, sizeof(logintmp), NULL);
2389bccb6d5aSDag-Erling Smørgrav 	if (error != 0) {
2390eb725b4eSRobert Watson 		if (error == ENAMETOOLONG)
2391df8bae1dSRodney W. Grimes 			error = EINVAL;
2392bccb6d5aSDag-Erling Smørgrav 		return (error);
2393bccb6d5aSDag-Erling Smørgrav 	}
239470a98c11SRobert Watson 	AUDIT_ARG_LOGIN(logintmp);
2395f591779bSSeigo Tanimura 	PROC_LOCK(p);
2396f591779bSSeigo Tanimura 	SESS_LOCK(p->p_session);
2397bccb6d5aSDag-Erling Smørgrav 	strcpy(p->p_session->s_login, logintmp);
2398f591779bSSeigo Tanimura 	SESS_UNLOCK(p->p_session);
2399f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
2400bccb6d5aSDag-Erling Smørgrav 	return (0);
2401df8bae1dSRodney W. Grimes }
2402d5f81602SSean Eric Fagan 
2403d5f81602SSean Eric Fagan void
24044c44ad8eSJohn Baldwin setsugid(struct proc *p)
2405d5f81602SSean Eric Fagan {
2406f2102dadSAlfred Perlstein 
2407f2102dadSAlfred Perlstein 	PROC_LOCK_ASSERT(p, MA_OWNED);
2408d5f81602SSean Eric Fagan 	p->p_flag |= P_SUGID;
2409d5f81602SSean Eric Fagan }
2410f535380cSDon Lewis 
24111a996ed1SEdward Tomasz Napierala /*-
24127fd6a959SRobert Watson  * Change a process's effective uid.
2413b1fc0ec1SRobert Watson  * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified.
2414b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2415b1fc0ec1SRobert Watson  *             duration of the call.
2416f535380cSDon Lewis  */
2417f535380cSDon Lewis void
24181419eacbSAlfred Perlstein change_euid(struct ucred *newcred, struct uidinfo *euip)
2419f535380cSDon Lewis {
2420f535380cSDon Lewis 
24211419eacbSAlfred Perlstein 	newcred->cr_uid = euip->ui_uid;
24221419eacbSAlfred Perlstein 	uihold(euip);
2423b1fc0ec1SRobert Watson 	uifree(newcred->cr_uidinfo);
24241419eacbSAlfred Perlstein 	newcred->cr_uidinfo = euip;
2425f535380cSDon Lewis }
2426f535380cSDon Lewis 
24271a996ed1SEdward Tomasz Napierala /*-
24287fd6a959SRobert Watson  * Change a process's effective gid.
2429b1fc0ec1SRobert Watson  * Side effects: newcred->cr_gid will be modified.
2430b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2431b1fc0ec1SRobert Watson  *             duration of the call.
2432f535380cSDon Lewis  */
2433810bfc8eSAndrew Gallatin void
24344c44ad8eSJohn Baldwin change_egid(struct ucred *newcred, gid_t egid)
2435b1fc0ec1SRobert Watson {
2436b1fc0ec1SRobert Watson 
2437b1fc0ec1SRobert Watson 	newcred->cr_groups[0] = egid;
2438b1fc0ec1SRobert Watson }
2439b1fc0ec1SRobert Watson 
24401a996ed1SEdward Tomasz Napierala /*-
24417fd6a959SRobert Watson  * Change a process's real uid.
2442b1fc0ec1SRobert Watson  * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo
2443b1fc0ec1SRobert Watson  *               will be updated, and the old and new cr_ruidinfo proc
2444b1fc0ec1SRobert Watson  *               counts will be updated.
2445b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2446b1fc0ec1SRobert Watson  *             duration of the call.
2447b1fc0ec1SRobert Watson  */
2448b1fc0ec1SRobert Watson void
24491419eacbSAlfred Perlstein change_ruid(struct ucred *newcred, struct uidinfo *ruip)
2450f535380cSDon Lewis {
2451f535380cSDon Lewis 
2452b1fc0ec1SRobert Watson 	(void)chgproccnt(newcred->cr_ruidinfo, -1, 0);
24531419eacbSAlfred Perlstein 	newcred->cr_ruid = ruip->ui_uid;
24541419eacbSAlfred Perlstein 	uihold(ruip);
2455b1fc0ec1SRobert Watson 	uifree(newcred->cr_ruidinfo);
24561419eacbSAlfred Perlstein 	newcred->cr_ruidinfo = ruip;
2457b1fc0ec1SRobert Watson 	(void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
2458b1fc0ec1SRobert Watson }
2459b1fc0ec1SRobert Watson 
24601a996ed1SEdward Tomasz Napierala /*-
24617fd6a959SRobert Watson  * Change a process's real gid.
2462b1fc0ec1SRobert Watson  * Side effects: newcred->cr_rgid will be updated.
2463b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2464b1fc0ec1SRobert Watson  *             duration of the call.
2465b1fc0ec1SRobert Watson  */
2466b1fc0ec1SRobert Watson void
24674c44ad8eSJohn Baldwin change_rgid(struct ucred *newcred, gid_t rgid)
2468b1fc0ec1SRobert Watson {
2469b1fc0ec1SRobert Watson 
2470b1fc0ec1SRobert Watson 	newcred->cr_rgid = rgid;
2471b1fc0ec1SRobert Watson }
2472b1fc0ec1SRobert Watson 
24731a996ed1SEdward Tomasz Napierala /*-
24747fd6a959SRobert Watson  * Change a process's saved uid.
2475b1fc0ec1SRobert Watson  * Side effects: newcred->cr_svuid will be updated.
2476b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2477b1fc0ec1SRobert Watson  *             duration of the call.
2478b1fc0ec1SRobert Watson  */
2479b1fc0ec1SRobert Watson void
24804c44ad8eSJohn Baldwin change_svuid(struct ucred *newcred, uid_t svuid)
2481b1fc0ec1SRobert Watson {
2482b1fc0ec1SRobert Watson 
2483b1fc0ec1SRobert Watson 	newcred->cr_svuid = svuid;
2484b1fc0ec1SRobert Watson }
2485b1fc0ec1SRobert Watson 
24861a996ed1SEdward Tomasz Napierala /*-
24877fd6a959SRobert Watson  * Change a process's saved gid.
2488b1fc0ec1SRobert Watson  * Side effects: newcred->cr_svgid will be updated.
2489b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
2490b1fc0ec1SRobert Watson  *             duration of the call.
2491b1fc0ec1SRobert Watson  */
2492b1fc0ec1SRobert Watson void
24934c44ad8eSJohn Baldwin change_svgid(struct ucred *newcred, gid_t svgid)
2494b1fc0ec1SRobert Watson {
2495b1fc0ec1SRobert Watson 
2496b1fc0ec1SRobert Watson 	newcred->cr_svgid = svgid;
2497f535380cSDon Lewis }
2498fe6db727SKonstantin Belousov 
2499fe6db727SKonstantin Belousov bool allow_ptrace = true;
2500fe6db727SKonstantin Belousov SYSCTL_BOOL(_security_bsd, OID_AUTO, allow_ptrace, CTLFLAG_RWTUN,
2501fe6db727SKonstantin Belousov     &allow_ptrace, 0,
2502fe6db727SKonstantin Belousov     "Deny ptrace(2) use by returning ENOSYS");
2503