19454b2d8SWarner Losh /*-
251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni *
4df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
5ef08c420SRobert Watson * The Regents of the University of California.
6df8bae1dSRodney W. Grimes * (c) UNIX System Laboratories, Inc.
7ef08c420SRobert Watson * Copyright (c) 2000-2001 Robert N. M. Watson.
8ef08c420SRobert Watson * All rights reserved.
9ef08c420SRobert Watson *
10df8bae1dSRodney W. Grimes * All or some portions of this file are derived from material licensed
11df8bae1dSRodney W. Grimes * to the University of California by American Telephone and Telegraph
12df8bae1dSRodney W. Grimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with
13df8bae1dSRodney W. Grimes * the permission of UNIX System Laboratories, Inc.
14df8bae1dSRodney W. Grimes *
15df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without
16df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions
17df8bae1dSRodney W. Grimes * are met:
18df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
19df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer.
20df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
21df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
22df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution.
2369a28758SEd Maste * 3. Neither the name of the University nor the names of its contributors
24df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software
25df8bae1dSRodney W. Grimes * without specific prior written permission.
26df8bae1dSRodney W. Grimes *
27df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37df8bae1dSRodney W. Grimes * SUCH DAMAGE.
38df8bae1dSRodney W. Grimes */
39df8bae1dSRodney W. Grimes
40df8bae1dSRodney W. Grimes /*
41df8bae1dSRodney W. Grimes * System calls related to processes and protection
42df8bae1dSRodney W. Grimes */
43df8bae1dSRodney W. Grimes
44677b542eSDavid E. O'Brien #include <sys/cdefs.h>
45f08ef6c5SBjoern A. Zeeb #include "opt_inet.h"
46f08ef6c5SBjoern A. Zeeb #include "opt_inet6.h"
475591b823SEivind Eklund
48df8bae1dSRodney W. Grimes #include <sys/param.h>
49df8bae1dSRodney W. Grimes #include <sys/systm.h>
50fb919e4dSMark Murray #include <sys/acct.h>
51df04411aSRobert Watson #include <sys/kdb.h>
521c5bb3eaSPeter Wemm #include <sys/kernel.h>
5337260547SOlivier Certner #include <sys/libkern.h>
5498f03f90SJake Burkholder #include <sys/lock.h>
552bfc50bcSEdward Tomasz Napierala #include <sys/loginclass.h>
56f9d0d524SRobert Watson #include <sys/malloc.h>
57fb919e4dSMark Murray #include <sys/mutex.h>
58fe6db727SKonstantin Belousov #include <sys/ptrace.h>
597e9e371fSJohn Baldwin #include <sys/refcount.h>
605b29d6e9SJohn Baldwin #include <sys/sx.h>
61800c9408SRobert Watson #include <sys/priv.h>
62f591779bSSeigo Tanimura #include <sys/proc.h>
6331d1b816SDmitry Chagin #ifdef COMPAT_43
647e097daaSKonstantin Belousov #include <sys/sysent.h>
6531d1b816SDmitry Chagin #endif
66fb919e4dSMark Murray #include <sys/sysproto.h>
67eb725b4eSRobert Watson #include <sys/jail.h>
68e4dcb704SEdward Tomasz Napierala #include <sys/racct.h>
69f87beb93SAndriy Gapon #include <sys/rctl.h>
70f535380cSDon Lewis #include <sys/resourcevar.h>
7129dc1288SRobert Watson #include <sys/socket.h>
7229dc1288SRobert Watson #include <sys/socketvar.h>
733cb83e71SJohn Baldwin #include <sys/syscallsubr.h>
74579f4eb4SRobert Watson #include <sys/sysctl.h>
75df8bae1dSRodney W. Grimes
766bb132baSBrooks Davis #include <vm/uma.h>
776bb132baSBrooks Davis
78de5b1952SAlexander Leidinger #ifdef REGRESSION
79de5b1952SAlexander Leidinger FEATURE(regression,
80ca54e1aeSHiroki Sato "Kernel support for interfaces necessary for regression testing (SECURITY RISK!)");
81de5b1952SAlexander Leidinger #endif
82de5b1952SAlexander Leidinger
832f8a46d5SWayne Salamon #include <security/audit/audit.h>
84aed55708SRobert Watson #include <security/mac/mac_framework.h>
852f8a46d5SWayne Salamon
86a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_CRED, "cred", "credentials");
87a1c995b6SPoul-Henning Kamp
887029da5cSPawel Biernacki SYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
897029da5cSPawel Biernacki "BSD security policy");
9048713bdcSRobert Watson
91f34a2f56SMateusz Guzik static void crfree_final(struct ucred *cr);
926d2efbb3SOlivier Certner
936d2efbb3SOlivier Certner static inline void
groups_check_positive_len(int ngrp)946d2efbb3SOlivier Certner groups_check_positive_len(int ngrp)
956d2efbb3SOlivier Certner {
966d2efbb3SOlivier Certner MPASS2(ngrp >= 0, "negative number of groups");
976d2efbb3SOlivier Certner MPASS2(ngrp != 0, "at least one group expected (effective GID)");
986d2efbb3SOlivier Certner }
996d2efbb3SOlivier Certner static inline void
groups_check_max_len(int ngrp)1006d2efbb3SOlivier Certner groups_check_max_len(int ngrp)
1016d2efbb3SOlivier Certner {
1026d2efbb3SOlivier Certner MPASS2(ngrp <= ngroups_max + 1, "too many groups");
1036d2efbb3SOlivier Certner }
1046d2efbb3SOlivier Certner
1056d2efbb3SOlivier Certner static void groups_normalize(int *ngrp, gid_t *groups);
1066d2efbb3SOlivier Certner static void crsetgroups_internal(struct ucred *cr, int ngrp,
1076d2efbb3SOlivier Certner const gid_t *groups);
108838d9858SBrooks Davis
10991e9d669SOlivier Certner static int cr_canseeotheruids(struct ucred *u1, struct ucred *u2);
11091e9d669SOlivier Certner static int cr_canseeothergids(struct ucred *u1, struct ucred *u2);
11191e9d669SOlivier Certner static int cr_canseejailproc(struct ucred *u1, struct ucred *u2);
11291e9d669SOlivier Certner
113d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
114ad7507e2SSteven Wallace struct getpid_args {
115df8bae1dSRodney W. Grimes int dummy;
116df8bae1dSRodney W. Grimes };
117d2d3e875SBruce Evans #endif
118df8bae1dSRodney W. Grimes /* ARGSUSED */
11926f9a767SRodney W. Grimes int
sys_getpid(struct thread * td,struct getpid_args * uap)1208451d0ddSKip Macy sys_getpid(struct thread *td, struct getpid_args *uap)
121df8bae1dSRodney W. Grimes {
122b40ce416SJulian Elischer struct proc *p = td->td_proc;
123df8bae1dSRodney W. Grimes
124b40ce416SJulian Elischer td->td_retval[0] = p->p_pid;
1251930e303SPoul-Henning Kamp #if defined(COMPAT_43)
1267e097daaSKonstantin Belousov if (SV_PROC_FLAG(p, SV_AOUT))
127abd386baSMateusz Guzik td->td_retval[1] = kern_getppid(td);
128df8bae1dSRodney W. Grimes #endif
129df8bae1dSRodney W. Grimes return (0);
130df8bae1dSRodney W. Grimes }
131df8bae1dSRodney W. Grimes
132d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
133ad7507e2SSteven Wallace struct getppid_args {
134ad7507e2SSteven Wallace int dummy;
135ad7507e2SSteven Wallace };
136d2d3e875SBruce Evans #endif
137df8bae1dSRodney W. Grimes /* ARGSUSED */
13826f9a767SRodney W. Grimes int
sys_getppid(struct thread * td,struct getppid_args * uap)1398451d0ddSKip Macy sys_getppid(struct thread *td, struct getppid_args *uap)
140df8bae1dSRodney W. Grimes {
141abd386baSMateusz Guzik
142abd386baSMateusz Guzik td->td_retval[0] = kern_getppid(td);
143abd386baSMateusz Guzik return (0);
144abd386baSMateusz Guzik }
145abd386baSMateusz Guzik
146abd386baSMateusz Guzik int
kern_getppid(struct thread * td)147abd386baSMateusz Guzik kern_getppid(struct thread *td)
148abd386baSMateusz Guzik {
149b40ce416SJulian Elischer struct proc *p = td->td_proc;
150df8bae1dSRodney W. Grimes
1512c054ce9SMateusz Guzik return (p->p_oppid);
152df8bae1dSRodney W. Grimes }
153df8bae1dSRodney W. Grimes
15436e9f877SMatthew Dillon /*
155eb725b4eSRobert Watson * Get process group ID; note that POSIX getpgrp takes no parameter.
15636e9f877SMatthew Dillon */
157d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
158ad7507e2SSteven Wallace struct getpgrp_args {
159ad7507e2SSteven Wallace int dummy;
160ad7507e2SSteven Wallace };
161d2d3e875SBruce Evans #endif
16226f9a767SRodney W. Grimes int
sys_getpgrp(struct thread * td,struct getpgrp_args * uap)1638451d0ddSKip Macy sys_getpgrp(struct thread *td, struct getpgrp_args *uap)
164df8bae1dSRodney W. Grimes {
165b40ce416SJulian Elischer struct proc *p = td->td_proc;
166df8bae1dSRodney W. Grimes
167f591779bSSeigo Tanimura PROC_LOCK(p);
168b40ce416SJulian Elischer td->td_retval[0] = p->p_pgrp->pg_id;
169f591779bSSeigo Tanimura PROC_UNLOCK(p);
170df8bae1dSRodney W. Grimes return (0);
171df8bae1dSRodney W. Grimes }
172df8bae1dSRodney W. Grimes
173e3043798SPedro F. Giffuni /* Get an arbitrary pid's process group id */
1741a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1751a5018a0SPeter Wemm struct getpgid_args {
1761a5018a0SPeter Wemm pid_t pid;
1771a5018a0SPeter Wemm };
1781a5018a0SPeter Wemm #endif
1791a5018a0SPeter Wemm int
sys_getpgid(struct thread * td,struct getpgid_args * uap)1808451d0ddSKip Macy sys_getpgid(struct thread *td, struct getpgid_args *uap)
1811a5018a0SPeter Wemm {
182a70a2b74SJohn Baldwin struct proc *p;
183f2ae7368SJohn Baldwin int error;
18465de0c7aSDon Lewis
185f591779bSSeigo Tanimura if (uap->pid == 0) {
186a70a2b74SJohn Baldwin p = td->td_proc;
187f591779bSSeigo Tanimura PROC_LOCK(p);
188a70a2b74SJohn Baldwin } else {
189a70a2b74SJohn Baldwin p = pfind(uap->pid);
190a70a2b74SJohn Baldwin if (p == NULL)
191a70a2b74SJohn Baldwin return (ESRCH);
192a70a2b74SJohn Baldwin error = p_cansee(td, p);
193a70a2b74SJohn Baldwin if (error) {
194a70a2b74SJohn Baldwin PROC_UNLOCK(p);
195a70a2b74SJohn Baldwin return (error);
196a70a2b74SJohn Baldwin }
197a70a2b74SJohn Baldwin }
198b40ce416SJulian Elischer td->td_retval[0] = p->p_pgrp->pg_id;
199f591779bSSeigo Tanimura PROC_UNLOCK(p);
200a70a2b74SJohn Baldwin return (0);
2011a5018a0SPeter Wemm }
2021a5018a0SPeter Wemm
2031a5018a0SPeter Wemm /*
204e3043798SPedro F. Giffuni * Get an arbitrary pid's session id.
2051a5018a0SPeter Wemm */
2061a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_
2071a5018a0SPeter Wemm struct getsid_args {
2081a5018a0SPeter Wemm pid_t pid;
2091a5018a0SPeter Wemm };
2101a5018a0SPeter Wemm #endif
2111a5018a0SPeter Wemm int
sys_getsid(struct thread * td,struct getsid_args * uap)2128451d0ddSKip Macy sys_getsid(struct thread *td, struct getsid_args *uap)
2131a5018a0SPeter Wemm {
214be2cfdbcSEdward Tomasz Napierala
215be2cfdbcSEdward Tomasz Napierala return (kern_getsid(td, uap->pid));
216be2cfdbcSEdward Tomasz Napierala }
217be2cfdbcSEdward Tomasz Napierala
218be2cfdbcSEdward Tomasz Napierala int
kern_getsid(struct thread * td,pid_t pid)219be2cfdbcSEdward Tomasz Napierala kern_getsid(struct thread *td, pid_t pid)
220be2cfdbcSEdward Tomasz Napierala {
221a70a2b74SJohn Baldwin struct proc *p;
222eb725b4eSRobert Watson int error;
22365de0c7aSDon Lewis
224be2cfdbcSEdward Tomasz Napierala if (pid == 0) {
225a70a2b74SJohn Baldwin p = td->td_proc;
226f591779bSSeigo Tanimura PROC_LOCK(p);
227a70a2b74SJohn Baldwin } else {
228be2cfdbcSEdward Tomasz Napierala p = pfind(pid);
229a70a2b74SJohn Baldwin if (p == NULL)
230a70a2b74SJohn Baldwin return (ESRCH);
231a70a2b74SJohn Baldwin error = p_cansee(td, p);
232a70a2b74SJohn Baldwin if (error) {
233a70a2b74SJohn Baldwin PROC_UNLOCK(p);
234a70a2b74SJohn Baldwin return (error);
235a70a2b74SJohn Baldwin }
236a70a2b74SJohn Baldwin }
237b40ce416SJulian Elischer td->td_retval[0] = p->p_session->s_sid;
238f591779bSSeigo Tanimura PROC_UNLOCK(p);
239a70a2b74SJohn Baldwin return (0);
2401a5018a0SPeter Wemm }
2411a5018a0SPeter Wemm
242d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
243ad7507e2SSteven Wallace struct getuid_args {
244ad7507e2SSteven Wallace int dummy;
245ad7507e2SSteven Wallace };
246d2d3e875SBruce Evans #endif
247df8bae1dSRodney W. Grimes /* ARGSUSED */
24826f9a767SRodney W. Grimes int
sys_getuid(struct thread * td,struct getuid_args * uap)2498451d0ddSKip Macy sys_getuid(struct thread *td, struct getuid_args *uap)
250df8bae1dSRodney W. Grimes {
251df8bae1dSRodney W. Grimes
252d846883bSJohn Baldwin td->td_retval[0] = td->td_ucred->cr_ruid;
2531930e303SPoul-Henning Kamp #if defined(COMPAT_43)
254d846883bSJohn Baldwin td->td_retval[1] = td->td_ucred->cr_uid;
255df8bae1dSRodney W. Grimes #endif
256df8bae1dSRodney W. Grimes return (0);
257df8bae1dSRodney W. Grimes }
258df8bae1dSRodney W. Grimes
259d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
260ad7507e2SSteven Wallace struct geteuid_args {
261ad7507e2SSteven Wallace int dummy;
262ad7507e2SSteven Wallace };
263d2d3e875SBruce Evans #endif
264df8bae1dSRodney W. Grimes /* ARGSUSED */
26526f9a767SRodney W. Grimes int
sys_geteuid(struct thread * td,struct geteuid_args * uap)2668451d0ddSKip Macy sys_geteuid(struct thread *td, struct geteuid_args *uap)
267df8bae1dSRodney W. Grimes {
268d846883bSJohn Baldwin
269d846883bSJohn Baldwin td->td_retval[0] = td->td_ucred->cr_uid;
270df8bae1dSRodney W. Grimes return (0);
271df8bae1dSRodney W. Grimes }
272df8bae1dSRodney W. Grimes
273d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
274ad7507e2SSteven Wallace struct getgid_args {
275ad7507e2SSteven Wallace int dummy;
276ad7507e2SSteven Wallace };
277d2d3e875SBruce Evans #endif
278df8bae1dSRodney W. Grimes /* ARGSUSED */
27926f9a767SRodney W. Grimes int
sys_getgid(struct thread * td,struct getgid_args * uap)2808451d0ddSKip Macy sys_getgid(struct thread *td, struct getgid_args *uap)
281df8bae1dSRodney W. Grimes {
282df8bae1dSRodney W. Grimes
283d846883bSJohn Baldwin td->td_retval[0] = td->td_ucred->cr_rgid;
2841930e303SPoul-Henning Kamp #if defined(COMPAT_43)
285d846883bSJohn Baldwin td->td_retval[1] = td->td_ucred->cr_groups[0];
286df8bae1dSRodney W. Grimes #endif
287df8bae1dSRodney W. Grimes return (0);
288df8bae1dSRodney W. Grimes }
289df8bae1dSRodney W. Grimes
290df8bae1dSRodney W. Grimes /*
291df8bae1dSRodney W. Grimes * Get effective group ID. The "egid" is groups[0], and could be obtained
292df8bae1dSRodney W. Grimes * via getgroups. This syscall exists because it is somewhat painful to do
293df8bae1dSRodney W. Grimes * correctly in a library function.
294df8bae1dSRodney W. Grimes */
295d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
296ad7507e2SSteven Wallace struct getegid_args {
297ad7507e2SSteven Wallace int dummy;
298ad7507e2SSteven Wallace };
299d2d3e875SBruce Evans #endif
300df8bae1dSRodney W. Grimes /* ARGSUSED */
30126f9a767SRodney W. Grimes int
sys_getegid(struct thread * td,struct getegid_args * uap)3028451d0ddSKip Macy sys_getegid(struct thread *td, struct getegid_args *uap)
303df8bae1dSRodney W. Grimes {
304df8bae1dSRodney W. Grimes
305d846883bSJohn Baldwin td->td_retval[0] = td->td_ucred->cr_groups[0];
306df8bae1dSRodney W. Grimes return (0);
307df8bae1dSRodney W. Grimes }
308df8bae1dSRodney W. Grimes
309d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
310df8bae1dSRodney W. Grimes struct getgroups_args {
3114bc2174aSMoritz Buhl int gidsetsize;
312df8bae1dSRodney W. Grimes gid_t *gidset;
313df8bae1dSRodney W. Grimes };
314d2d3e875SBruce Evans #endif
31526f9a767SRodney W. Grimes int
sys_getgroups(struct thread * td,struct getgroups_args * uap)3163e85b721SEd Maste sys_getgroups(struct thread *td, struct getgroups_args *uap)
317df8bae1dSRodney W. Grimes {
31807b384cbSMateusz Guzik struct ucred *cred;
3194bc2174aSMoritz Buhl int ngrp, error;
320df8bae1dSRodney W. Grimes
3213cb83e71SJohn Baldwin cred = td->td_ucred;
32207b384cbSMateusz Guzik ngrp = cred->cr_ngroups;
32307b384cbSMateusz Guzik
32407b384cbSMateusz Guzik if (uap->gidsetsize == 0) {
32507b384cbSMateusz Guzik error = 0;
32607b384cbSMateusz Guzik goto out;
3273cb83e71SJohn Baldwin }
32807b384cbSMateusz Guzik if (uap->gidsetsize < ngrp)
3293cb83e71SJohn Baldwin return (EINVAL);
33007b384cbSMateusz Guzik
33107b384cbSMateusz Guzik error = copyout(cred->cr_groups, uap->gidset, ngrp * sizeof(gid_t));
33207b384cbSMateusz Guzik out:
33307b384cbSMateusz Guzik td->td_retval[0] = ngrp;
33407b384cbSMateusz Guzik return (error);
3353cb83e71SJohn Baldwin }
3363cb83e71SJohn Baldwin
337d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
33882970b81SBruce Evans struct setsid_args {
339ad7507e2SSteven Wallace int dummy;
340ad7507e2SSteven Wallace };
341d2d3e875SBruce Evans #endif
342df8bae1dSRodney W. Grimes /* ARGSUSED */
34326f9a767SRodney W. Grimes int
sys_setsid(struct thread * td,struct setsid_args * uap)3443e85b721SEd Maste sys_setsid(struct thread *td, struct setsid_args *uap)
345df8bae1dSRodney W. Grimes {
346f591779bSSeigo Tanimura struct pgrp *pgrp;
347835a82eeSMatthew Dillon int error;
348b40ce416SJulian Elischer struct proc *p = td->td_proc;
349f591779bSSeigo Tanimura struct pgrp *newpgrp;
350f591779bSSeigo Tanimura struct session *newsess;
351f591779bSSeigo Tanimura
352f591779bSSeigo Tanimura pgrp = NULL;
353df8bae1dSRodney W. Grimes
354ef739c73SKonstantin Belousov newpgrp = uma_zalloc(pgrp_zone, M_WAITOK);
3551ede983cSDag-Erling Smørgrav newsess = malloc(sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO);
356f591779bSSeigo Tanimura
3573360b485SKonstantin Belousov again:
3583360b485SKonstantin Belousov error = 0;
359c8b1829dSJohn Baldwin sx_xlock(&proctree_lock);
360f591779bSSeigo Tanimura
361f591779bSSeigo Tanimura if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) {
362f591779bSSeigo Tanimura if (pgrp != NULL)
363f591779bSSeigo Tanimura PGRP_UNLOCK(pgrp);
364835a82eeSMatthew Dillon error = EPERM;
365f591779bSSeigo Tanimura } else {
3663360b485SKonstantin Belousov error = enterpgrp(p, p->p_pid, newpgrp, newsess);
3677a70f17aSKonstantin Belousov if (error == ERESTART)
3683360b485SKonstantin Belousov goto again;
3693360b485SKonstantin Belousov MPASS(error == 0);
370b40ce416SJulian Elischer td->td_retval[0] = p->p_pid;
371c8b1829dSJohn Baldwin newpgrp = NULL;
372c8b1829dSJohn Baldwin newsess = NULL;
373df8bae1dSRodney W. Grimes }
374f591779bSSeigo Tanimura
375c8b1829dSJohn Baldwin sx_xunlock(&proctree_lock);
376f591779bSSeigo Tanimura
377ef739c73SKonstantin Belousov uma_zfree(pgrp_zone, newpgrp);
3781ede983cSDag-Erling Smørgrav free(newsess, M_SESSION);
3791c2451c2SSeigo Tanimura
380c8b1829dSJohn Baldwin return (error);
381df8bae1dSRodney W. Grimes }
382df8bae1dSRodney W. Grimes
383df8bae1dSRodney W. Grimes /*
384df8bae1dSRodney W. Grimes * set process group (setpgid/old setpgrp)
385df8bae1dSRodney W. Grimes *
386df8bae1dSRodney W. Grimes * caller does setpgid(targpid, targpgid)
387df8bae1dSRodney W. Grimes *
388df8bae1dSRodney W. Grimes * pid must be caller or child of caller (ESRCH)
389df8bae1dSRodney W. Grimes * if a child
390df8bae1dSRodney W. Grimes * pid must be in same session (EPERM)
391df8bae1dSRodney W. Grimes * pid can't have done an exec (EACCES)
392df8bae1dSRodney W. Grimes * if pgid != pid
393df8bae1dSRodney W. Grimes * there must exist some pid in same session having pgid (EPERM)
394df8bae1dSRodney W. Grimes * pid must not be session leader (EPERM)
395df8bae1dSRodney W. Grimes */
396d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
397df8bae1dSRodney W. Grimes struct setpgid_args {
398df8bae1dSRodney W. Grimes int pid; /* target process id */
399df8bae1dSRodney W. Grimes int pgid; /* target pgrp id */
400df8bae1dSRodney W. Grimes };
401d2d3e875SBruce Evans #endif
402df8bae1dSRodney W. Grimes /* ARGSUSED */
40326f9a767SRodney W. Grimes int
sys_setpgid(struct thread * td,struct setpgid_args * uap)4043e85b721SEd Maste sys_setpgid(struct thread *td, struct setpgid_args *uap)
405df8bae1dSRodney W. Grimes {
406b40ce416SJulian Elischer struct proc *curp = td->td_proc;
4073e85b721SEd Maste struct proc *targp; /* target process */
4083e85b721SEd Maste struct pgrp *pgrp; /* target pgrp */
409eb9e5c1dSRobert Watson int error;
410f591779bSSeigo Tanimura struct pgrp *newpgrp;
411df8bae1dSRodney W. Grimes
41278f64bccSBruce Evans if (uap->pgid < 0)
41378f64bccSBruce Evans return (EINVAL);
414f591779bSSeigo Tanimura
415ef739c73SKonstantin Belousov newpgrp = uma_zalloc(pgrp_zone, M_WAITOK);
416f591779bSSeigo Tanimura
4173360b485SKonstantin Belousov again:
4183360b485SKonstantin Belousov error = 0;
4193360b485SKonstantin Belousov
420c8b1829dSJohn Baldwin sx_xlock(&proctree_lock);
421df8bae1dSRodney W. Grimes if (uap->pid != 0 && uap->pid != curp->p_pid) {
422f591779bSSeigo Tanimura if ((targp = pfind(uap->pid)) == NULL) {
423835a82eeSMatthew Dillon error = ESRCH;
424c8b1829dSJohn Baldwin goto done;
42533a9ed9dSJohn Baldwin }
426f591779bSSeigo Tanimura if (!inferior(targp)) {
427f591779bSSeigo Tanimura PROC_UNLOCK(targp);
4282f932587SSeigo Tanimura error = ESRCH;
429c8b1829dSJohn Baldwin goto done;
430f591779bSSeigo Tanimura }
43171a057bcSRobert Watson if ((error = p_cansee(td, targp))) {
43233a9ed9dSJohn Baldwin PROC_UNLOCK(targp);
433c8b1829dSJohn Baldwin goto done;
43433a9ed9dSJohn Baldwin }
43533a9ed9dSJohn Baldwin if (targp->p_pgrp == NULL ||
43633a9ed9dSJohn Baldwin targp->p_session != curp->p_session) {
43733a9ed9dSJohn Baldwin PROC_UNLOCK(targp);
438835a82eeSMatthew Dillon error = EPERM;
439c8b1829dSJohn Baldwin goto done;
44033a9ed9dSJohn Baldwin }
44133a9ed9dSJohn Baldwin if (targp->p_flag & P_EXEC) {
44233a9ed9dSJohn Baldwin PROC_UNLOCK(targp);
443835a82eeSMatthew Dillon error = EACCES;
444c8b1829dSJohn Baldwin goto done;
44533a9ed9dSJohn Baldwin }
44633a9ed9dSJohn Baldwin PROC_UNLOCK(targp);
447f591779bSSeigo Tanimura } else
448f591779bSSeigo Tanimura targp = curp;
449f591779bSSeigo Tanimura if (SESS_LEADER(targp)) {
450835a82eeSMatthew Dillon error = EPERM;
451c8b1829dSJohn Baldwin goto done;
45233a9ed9dSJohn Baldwin }
453eb725b4eSRobert Watson if (uap->pgid == 0)
454df8bae1dSRodney W. Grimes uap->pgid = targp->p_pid;
455a10d5f02SOlivier Houchard if ((pgrp = pgfind(uap->pgid)) == NULL) {
456f591779bSSeigo Tanimura if (uap->pgid == targp->p_pid) {
457a10d5f02SOlivier Houchard error = enterpgrp(targp, uap->pgid, newpgrp,
458a10d5f02SOlivier Houchard NULL);
459f591779bSSeigo Tanimura if (error == 0)
460f591779bSSeigo Tanimura newpgrp = NULL;
461a10d5f02SOlivier Houchard } else
462835a82eeSMatthew Dillon error = EPERM;
463a10d5f02SOlivier Houchard } else {
464f591779bSSeigo Tanimura if (pgrp == targp->p_pgrp) {
465f591779bSSeigo Tanimura PGRP_UNLOCK(pgrp);
466f591779bSSeigo Tanimura goto done;
46733a9ed9dSJohn Baldwin }
468a10d5f02SOlivier Houchard if (pgrp->pg_id != targp->p_pid &&
469a10d5f02SOlivier Houchard pgrp->pg_session != curp->p_session) {
470a10d5f02SOlivier Houchard PGRP_UNLOCK(pgrp);
471a10d5f02SOlivier Houchard error = EPERM;
472a10d5f02SOlivier Houchard goto done;
473a10d5f02SOlivier Houchard }
474f591779bSSeigo Tanimura PGRP_UNLOCK(pgrp);
475f591779bSSeigo Tanimura error = enterthispgrp(targp, pgrp);
476f591779bSSeigo Tanimura }
477f591779bSSeigo Tanimura done:
478ed84cb59SKonstantin Belousov KASSERT(error == 0 || newpgrp != NULL,
479c8b1829dSJohn Baldwin ("setpgid failed and newpgrp is NULL"));
4803360b485SKonstantin Belousov if (error == ERESTART)
4813360b485SKonstantin Belousov goto again;
4827a70f17aSKonstantin Belousov sx_xunlock(&proctree_lock);
483ef739c73SKonstantin Belousov uma_zfree(pgrp_zone, newpgrp);
484835a82eeSMatthew Dillon return (error);
485df8bae1dSRodney W. Grimes }
486df8bae1dSRodney W. Grimes
487a08f4bf6SPeter Wemm /*
488a08f4bf6SPeter Wemm * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
4892fa72ea7SJeroen Ruigrok van der Werven * compatible. It says that setting the uid/gid to euid/egid is a special
490a08f4bf6SPeter Wemm * case of "appropriate privilege". Once the rules are expanded out, this
491a08f4bf6SPeter Wemm * basically means that setuid(nnn) sets all three id's, in all permitted
492a08f4bf6SPeter Wemm * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid())
493a08f4bf6SPeter Wemm * does not set the saved id - this is dangerous for traditional BSD
494a08f4bf6SPeter Wemm * programs. For this reason, we *really* do not want to set
495a08f4bf6SPeter Wemm * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
496a08f4bf6SPeter Wemm */
497a08f4bf6SPeter Wemm #define POSIX_APPENDIX_B_4_2_2
498a08f4bf6SPeter Wemm
499d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
500df8bae1dSRodney W. Grimes struct setuid_args {
501df8bae1dSRodney W. Grimes uid_t uid;
502df8bae1dSRodney W. Grimes };
503d2d3e875SBruce Evans #endif
504df8bae1dSRodney W. Grimes /* ARGSUSED */
50526f9a767SRodney W. Grimes int
sys_setuid(struct thread * td,struct setuid_args * uap)5068451d0ddSKip Macy sys_setuid(struct thread *td, struct setuid_args *uap)
507df8bae1dSRodney W. Grimes {
508b40ce416SJulian Elischer struct proc *p = td->td_proc;
509b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred;
510b1fc0ec1SRobert Watson uid_t uid;
5111419eacbSAlfred Perlstein struct uidinfo *uip;
512eb725b4eSRobert Watson int error;
513df8bae1dSRodney W. Grimes
51407f3485dSJohn Baldwin uid = uap->uid;
51514961ba7SRobert Watson AUDIT_ARG_UID(uid);
51607f3485dSJohn Baldwin newcred = crget();
5171419eacbSAlfred Perlstein uip = uifind(uid);
51807f3485dSJohn Baldwin PROC_LOCK(p);
519838d9858SBrooks Davis /*
520838d9858SBrooks Davis * Copy credentials so other references do not see our changes.
521838d9858SBrooks Davis */
522838d9858SBrooks Davis oldcred = crcopysafe(p, newcred);
5235a92ee3cSRobert Watson
524030a28b3SRobert Watson #ifdef MAC
5256f6174a7SRobert Watson error = mac_cred_check_setuid(oldcred, uid);
526030a28b3SRobert Watson if (error)
527030a28b3SRobert Watson goto fail;
528030a28b3SRobert Watson #endif
529030a28b3SRobert Watson
530a08f4bf6SPeter Wemm /*
531a08f4bf6SPeter Wemm * See if we have "permission" by POSIX 1003.1 rules.
532a08f4bf6SPeter Wemm *
533a08f4bf6SPeter Wemm * Note that setuid(geteuid()) is a special case of
534a08f4bf6SPeter Wemm * "appropriate privileges" in appendix B.4.2.2. We need
5352fa72ea7SJeroen Ruigrok van der Werven * to use this clause to be compatible with traditional BSD
536a08f4bf6SPeter Wemm * semantics. Basically, it means that "setuid(xx)" sets all
537a08f4bf6SPeter Wemm * three id's (assuming you have privs).
538a08f4bf6SPeter Wemm *
539a08f4bf6SPeter Wemm * Notes on the logic. We do things in three steps.
540a08f4bf6SPeter Wemm * 1: We determine if the euid is going to change, and do EPERM
541a08f4bf6SPeter Wemm * right away. We unconditionally change the euid later if this
542a08f4bf6SPeter Wemm * test is satisfied, simplifying that part of the logic.
543eb725b4eSRobert Watson * 2: We determine if the real and/or saved uids are going to
544a08f4bf6SPeter Wemm * change. Determined by compile options.
545a08f4bf6SPeter Wemm * 3: Change euid last. (after tests in #2 for "appropriate privs")
546a08f4bf6SPeter Wemm */
547b1fc0ec1SRobert Watson if (uid != oldcred->cr_ruid && /* allow setuid(getuid()) */
5483f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS
549b1fc0ec1SRobert Watson uid != oldcred->cr_svuid && /* allow setuid(saved gid) */
550a08f4bf6SPeter Wemm #endif
551a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */
552b1fc0ec1SRobert Watson uid != oldcred->cr_uid && /* allow setuid(geteuid()) */
5533f246666SAndrey A. Chernov #endif
554cc426dd3SMateusz Guzik (error = priv_check_cred(oldcred, PRIV_CRED_SETUID)) != 0)
555030a28b3SRobert Watson goto fail;
556a08f4bf6SPeter Wemm
557a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS
558df8bae1dSRodney W. Grimes /*
559a08f4bf6SPeter Wemm * Do we have "appropriate privileges" (are we root or uid == euid)
560a08f4bf6SPeter Wemm * If so, we are changing the real uid and/or saved uid.
561df8bae1dSRodney W. Grimes */
5623f246666SAndrey A. Chernov if (
563a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */
564b1fc0ec1SRobert Watson uid == oldcred->cr_uid ||
5653f246666SAndrey A. Chernov #endif
566800c9408SRobert Watson /* We are using privs. */
567cc426dd3SMateusz Guzik priv_check_cred(oldcred, PRIV_CRED_SETUID) == 0)
568a08f4bf6SPeter Wemm #endif
569a08f4bf6SPeter Wemm {
570a08f4bf6SPeter Wemm /*
571f535380cSDon Lewis * Set the real uid and transfer proc count to new user.
572a08f4bf6SPeter Wemm */
573b1fc0ec1SRobert Watson if (uid != oldcred->cr_ruid) {
5741419eacbSAlfred Perlstein change_ruid(newcred, uip);
575f535380cSDon Lewis setsugid(p);
576d3cdb93dSAndrey A. Chernov }
577a08f4bf6SPeter Wemm /*
578a08f4bf6SPeter Wemm * Set saved uid
579a08f4bf6SPeter Wemm *
580a08f4bf6SPeter Wemm * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
581a08f4bf6SPeter Wemm * the security of seteuid() depends on it. B.4.2.2 says it
582a08f4bf6SPeter Wemm * is important that we should do this.
583a08f4bf6SPeter Wemm */
584b1fc0ec1SRobert Watson if (uid != oldcred->cr_svuid) {
585b1fc0ec1SRobert Watson change_svuid(newcred, uid);
586d5f81602SSean Eric Fagan setsugid(p);
587a08f4bf6SPeter Wemm }
588a08f4bf6SPeter Wemm }
589a08f4bf6SPeter Wemm
590a08f4bf6SPeter Wemm /*
591a08f4bf6SPeter Wemm * In all permitted cases, we are changing the euid.
592a08f4bf6SPeter Wemm */
593b1fc0ec1SRobert Watson if (uid != oldcred->cr_uid) {
5941419eacbSAlfred Perlstein change_euid(newcred, uip);
595d5f81602SSean Eric Fagan setsugid(p);
596a08f4bf6SPeter Wemm }
597daf63fd2SMateusz Guzik proc_set_cred(p, newcred);
598e4dcb704SEdward Tomasz Napierala #ifdef RACCT
599e4dcb704SEdward Tomasz Napierala racct_proc_ucred_changed(p, oldcred, newcred);
600f87beb93SAndriy Gapon crhold(newcred);
601f87beb93SAndriy Gapon #endif
602f87beb93SAndriy Gapon PROC_UNLOCK(p);
603f87beb93SAndriy Gapon #ifdef RCTL
604f87beb93SAndriy Gapon rctl_proc_ucred_changed(p, newcred);
605f87beb93SAndriy Gapon crfree(newcred);
606e4dcb704SEdward Tomasz Napierala #endif
6071419eacbSAlfred Perlstein uifree(uip);
608b1fc0ec1SRobert Watson crfree(oldcred);
60907f3485dSJohn Baldwin return (0);
610030a28b3SRobert Watson
611030a28b3SRobert Watson fail:
612030a28b3SRobert Watson PROC_UNLOCK(p);
613030a28b3SRobert Watson uifree(uip);
614030a28b3SRobert Watson crfree(newcred);
615030a28b3SRobert Watson return (error);
616df8bae1dSRodney W. Grimes }
617df8bae1dSRodney W. Grimes
618d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
619df8bae1dSRodney W. Grimes struct seteuid_args {
620df8bae1dSRodney W. Grimes uid_t euid;
621df8bae1dSRodney W. Grimes };
622d2d3e875SBruce Evans #endif
623df8bae1dSRodney W. Grimes /* ARGSUSED */
62426f9a767SRodney W. Grimes int
sys_seteuid(struct thread * td,struct seteuid_args * uap)6258451d0ddSKip Macy sys_seteuid(struct thread *td, struct seteuid_args *uap)
626df8bae1dSRodney W. Grimes {
627b40ce416SJulian Elischer struct proc *p = td->td_proc;
628b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred;
629b1fc0ec1SRobert Watson uid_t euid;
6301419eacbSAlfred Perlstein struct uidinfo *euip;
631eb725b4eSRobert Watson int error;
632df8bae1dSRodney W. Grimes
633df8bae1dSRodney W. Grimes euid = uap->euid;
63414961ba7SRobert Watson AUDIT_ARG_EUID(euid);
63507f3485dSJohn Baldwin newcred = crget();
6361419eacbSAlfred Perlstein euip = uifind(euid);
63707f3485dSJohn Baldwin PROC_LOCK(p);
638838d9858SBrooks Davis /*
639838d9858SBrooks Davis * Copy credentials so other references do not see our changes.
640838d9858SBrooks Davis */
641838d9858SBrooks Davis oldcred = crcopysafe(p, newcred);
642030a28b3SRobert Watson
643030a28b3SRobert Watson #ifdef MAC
6446f6174a7SRobert Watson error = mac_cred_check_seteuid(oldcred, euid);
645030a28b3SRobert Watson if (error)
646030a28b3SRobert Watson goto fail;
647030a28b3SRobert Watson #endif
648030a28b3SRobert Watson
649b1fc0ec1SRobert Watson if (euid != oldcred->cr_ruid && /* allow seteuid(getuid()) */
650b1fc0ec1SRobert Watson euid != oldcred->cr_svuid && /* allow seteuid(saved uid) */
651cc426dd3SMateusz Guzik (error = priv_check_cred(oldcred, PRIV_CRED_SETEUID)) != 0)
652030a28b3SRobert Watson goto fail;
653030a28b3SRobert Watson
654df8bae1dSRodney W. Grimes /*
655838d9858SBrooks Davis * Everything's okay, do it.
656df8bae1dSRodney W. Grimes */
657b1fc0ec1SRobert Watson if (oldcred->cr_uid != euid) {
6581419eacbSAlfred Perlstein change_euid(newcred, euip);
659d5f81602SSean Eric Fagan setsugid(p);
660229a15f0SPeter Wemm }
661daf63fd2SMateusz Guzik proc_set_cred(p, newcred);
66207f3485dSJohn Baldwin PROC_UNLOCK(p);
6631419eacbSAlfred Perlstein uifree(euip);
664b1fc0ec1SRobert Watson crfree(oldcred);
66507f3485dSJohn Baldwin return (0);
666030a28b3SRobert Watson
667030a28b3SRobert Watson fail:
668030a28b3SRobert Watson PROC_UNLOCK(p);
669030a28b3SRobert Watson uifree(euip);
670030a28b3SRobert Watson crfree(newcred);
671030a28b3SRobert Watson return (error);
672df8bae1dSRodney W. Grimes }
673df8bae1dSRodney W. Grimes
674d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
675df8bae1dSRodney W. Grimes struct setgid_args {
676df8bae1dSRodney W. Grimes gid_t gid;
677df8bae1dSRodney W. Grimes };
678d2d3e875SBruce Evans #endif
679df8bae1dSRodney W. Grimes /* ARGSUSED */
68026f9a767SRodney W. Grimes int
sys_setgid(struct thread * td,struct setgid_args * uap)6818451d0ddSKip Macy sys_setgid(struct thread *td, struct setgid_args *uap)
682df8bae1dSRodney W. Grimes {
683b40ce416SJulian Elischer struct proc *p = td->td_proc;
684b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred;
685b1fc0ec1SRobert Watson gid_t gid;
686eb725b4eSRobert Watson int error;
687df8bae1dSRodney W. Grimes
688b1fc0ec1SRobert Watson gid = uap->gid;
68914961ba7SRobert Watson AUDIT_ARG_GID(gid);
69007f3485dSJohn Baldwin newcred = crget();
69107f3485dSJohn Baldwin PROC_LOCK(p);
692838d9858SBrooks Davis oldcred = crcopysafe(p, newcred);
6935a92ee3cSRobert Watson
694030a28b3SRobert Watson #ifdef MAC
6956f6174a7SRobert Watson error = mac_cred_check_setgid(oldcred, gid);
696030a28b3SRobert Watson if (error)
697030a28b3SRobert Watson goto fail;
698030a28b3SRobert Watson #endif
699030a28b3SRobert Watson
700a08f4bf6SPeter Wemm /*
701a08f4bf6SPeter Wemm * See if we have "permission" by POSIX 1003.1 rules.
702a08f4bf6SPeter Wemm *
703a08f4bf6SPeter Wemm * Note that setgid(getegid()) is a special case of
704a08f4bf6SPeter Wemm * "appropriate privileges" in appendix B.4.2.2. We need
7052fa72ea7SJeroen Ruigrok van der Werven * to use this clause to be compatible with traditional BSD
706a08f4bf6SPeter Wemm * semantics. Basically, it means that "setgid(xx)" sets all
707a08f4bf6SPeter Wemm * three id's (assuming you have privs).
708a08f4bf6SPeter Wemm *
709a08f4bf6SPeter Wemm * For notes on the logic here, see setuid() above.
710a08f4bf6SPeter Wemm */
711b1fc0ec1SRobert Watson if (gid != oldcred->cr_rgid && /* allow setgid(getgid()) */
7123f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS
713b1fc0ec1SRobert Watson gid != oldcred->cr_svgid && /* allow setgid(saved gid) */
714a08f4bf6SPeter Wemm #endif
715a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */
716b1fc0ec1SRobert Watson gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */
7173f246666SAndrey A. Chernov #endif
718cc426dd3SMateusz Guzik (error = priv_check_cred(oldcred, PRIV_CRED_SETGID)) != 0)
719030a28b3SRobert Watson goto fail;
720a08f4bf6SPeter Wemm
721a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS
722a08f4bf6SPeter Wemm /*
723a08f4bf6SPeter Wemm * Do we have "appropriate privileges" (are we root or gid == egid)
724a08f4bf6SPeter Wemm * If so, we are changing the real uid and saved gid.
725a08f4bf6SPeter Wemm */
726a08f4bf6SPeter Wemm if (
727a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */
728b1fc0ec1SRobert Watson gid == oldcred->cr_groups[0] ||
729a08f4bf6SPeter Wemm #endif
730800c9408SRobert Watson /* We are using privs. */
731cc426dd3SMateusz Guzik priv_check_cred(oldcred, PRIV_CRED_SETGID) == 0)
732a08f4bf6SPeter Wemm #endif
733a08f4bf6SPeter Wemm {
734a08f4bf6SPeter Wemm /*
735a08f4bf6SPeter Wemm * Set real gid
736a08f4bf6SPeter Wemm */
737b1fc0ec1SRobert Watson if (oldcred->cr_rgid != gid) {
738b1fc0ec1SRobert Watson change_rgid(newcred, gid);
739d5f81602SSean Eric Fagan setsugid(p);
740a08f4bf6SPeter Wemm }
741a08f4bf6SPeter Wemm /*
742a08f4bf6SPeter Wemm * Set saved gid
743a08f4bf6SPeter Wemm *
744a08f4bf6SPeter Wemm * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
745a08f4bf6SPeter Wemm * the security of setegid() depends on it. B.4.2.2 says it
746a08f4bf6SPeter Wemm * is important that we should do this.
747a08f4bf6SPeter Wemm */
748b1fc0ec1SRobert Watson if (oldcred->cr_svgid != gid) {
749b1fc0ec1SRobert Watson change_svgid(newcred, gid);
750d5f81602SSean Eric Fagan setsugid(p);
751a08f4bf6SPeter Wemm }
752a08f4bf6SPeter Wemm }
753a08f4bf6SPeter Wemm /*
754a08f4bf6SPeter Wemm * In all cases permitted cases, we are changing the egid.
755a08f4bf6SPeter Wemm * Copy credentials so other references do not see our changes.
756a08f4bf6SPeter Wemm */
757b1fc0ec1SRobert Watson if (oldcred->cr_groups[0] != gid) {
758b1fc0ec1SRobert Watson change_egid(newcred, gid);
759d5f81602SSean Eric Fagan setsugid(p);
760a08f4bf6SPeter Wemm }
761daf63fd2SMateusz Guzik proc_set_cred(p, newcred);
76207f3485dSJohn Baldwin PROC_UNLOCK(p);
763b1fc0ec1SRobert Watson crfree(oldcred);
76407f3485dSJohn Baldwin return (0);
765030a28b3SRobert Watson
766030a28b3SRobert Watson fail:
767030a28b3SRobert Watson PROC_UNLOCK(p);
768030a28b3SRobert Watson crfree(newcred);
769030a28b3SRobert Watson return (error);
770df8bae1dSRodney W. Grimes }
771df8bae1dSRodney W. Grimes
772d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
773df8bae1dSRodney W. Grimes struct setegid_args {
774df8bae1dSRodney W. Grimes gid_t egid;
775df8bae1dSRodney W. Grimes };
776d2d3e875SBruce Evans #endif
777df8bae1dSRodney W. Grimes /* ARGSUSED */
77826f9a767SRodney W. Grimes int
sys_setegid(struct thread * td,struct setegid_args * uap)7798451d0ddSKip Macy sys_setegid(struct thread *td, struct setegid_args *uap)
780df8bae1dSRodney W. Grimes {
781b40ce416SJulian Elischer struct proc *p = td->td_proc;
782b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred;
783b1fc0ec1SRobert Watson gid_t egid;
784eb725b4eSRobert Watson int error;
785df8bae1dSRodney W. Grimes
786df8bae1dSRodney W. Grimes egid = uap->egid;
78714961ba7SRobert Watson AUDIT_ARG_EGID(egid);
78807f3485dSJohn Baldwin newcred = crget();
78907f3485dSJohn Baldwin PROC_LOCK(p);
790838d9858SBrooks Davis oldcred = crcopysafe(p, newcred);
791030a28b3SRobert Watson
792030a28b3SRobert Watson #ifdef MAC
7936f6174a7SRobert Watson error = mac_cred_check_setegid(oldcred, egid);
794030a28b3SRobert Watson if (error)
795030a28b3SRobert Watson goto fail;
796030a28b3SRobert Watson #endif
797030a28b3SRobert Watson
798b1fc0ec1SRobert Watson if (egid != oldcred->cr_rgid && /* allow setegid(getgid()) */
799b1fc0ec1SRobert Watson egid != oldcred->cr_svgid && /* allow setegid(saved gid) */
800cc426dd3SMateusz Guzik (error = priv_check_cred(oldcred, PRIV_CRED_SETEGID)) != 0)
801030a28b3SRobert Watson goto fail;
802030a28b3SRobert Watson
803b1fc0ec1SRobert Watson if (oldcred->cr_groups[0] != egid) {
804b1fc0ec1SRobert Watson change_egid(newcred, egid);
805d5f81602SSean Eric Fagan setsugid(p);
806229a15f0SPeter Wemm }
807daf63fd2SMateusz Guzik proc_set_cred(p, newcred);
80807f3485dSJohn Baldwin PROC_UNLOCK(p);
809b1fc0ec1SRobert Watson crfree(oldcred);
81007f3485dSJohn Baldwin return (0);
811030a28b3SRobert Watson
812030a28b3SRobert Watson fail:
813030a28b3SRobert Watson PROC_UNLOCK(p);
814030a28b3SRobert Watson crfree(newcred);
815030a28b3SRobert Watson return (error);
816df8bae1dSRodney W. Grimes }
817df8bae1dSRodney W. Grimes
818d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
819df8bae1dSRodney W. Grimes struct setgroups_args {
8204bc2174aSMoritz Buhl int gidsetsize;
821df8bae1dSRodney W. Grimes gid_t *gidset;
822df8bae1dSRodney W. Grimes };
823d2d3e875SBruce Evans #endif
824df8bae1dSRodney W. Grimes /* ARGSUSED */
82526f9a767SRodney W. Grimes int
sys_setgroups(struct thread * td,struct setgroups_args * uap)8268451d0ddSKip Macy sys_setgroups(struct thread *td, struct setgroups_args *uap)
827df8bae1dSRodney W. Grimes {
828664b9fcbSOlivier Certner gid_t smallgroups[CRED_SMALLGROUPS_NB];
8297e9a456aSMateusz Guzik gid_t *groups;
8304bc2174aSMoritz Buhl int gidsetsize, error;
831df8bae1dSRodney W. Grimes
832abd39811SOlivier Certner /*
833abd39811SOlivier Certner * Sanity check size now to avoid passing too big a value to copyin(),
834abd39811SOlivier Certner * even if kern_setgroups() will do it again.
835abd39811SOlivier Certner *
836abd39811SOlivier Certner * Ideally, the 'gidsetsize' argument should have been a 'u_int' (and it
837abd39811SOlivier Certner * was, in this implementation, for a long time), but POSIX standardized
838abd39811SOlivier Certner * getgroups() to take an 'int' and it would be quite entrapping to have
839abd39811SOlivier Certner * setgroups() differ.
840abd39811SOlivier Certner */
84192b064f4SMateusz Guzik gidsetsize = uap->gidsetsize;
8424bc2174aSMoritz Buhl if (gidsetsize > ngroups_max + 1 || gidsetsize < 0)
8433cb83e71SJohn Baldwin return (EINVAL);
8447e9a456aSMateusz Guzik
845664b9fcbSOlivier Certner if (gidsetsize > CRED_SMALLGROUPS_NB)
84692b064f4SMateusz Guzik groups = malloc(gidsetsize * sizeof(gid_t), M_TEMP, M_WAITOK);
84792b064f4SMateusz Guzik else
84892b064f4SMateusz Guzik groups = smallgroups;
8497e9a456aSMateusz Guzik
85092b064f4SMateusz Guzik error = copyin(uap->gidset, groups, gidsetsize * sizeof(gid_t));
8517e9a456aSMateusz Guzik if (error == 0)
8526d2efbb3SOlivier Certner error = kern_setgroups(td, &gidsetsize, groups);
8537e9a456aSMateusz Guzik
8546d2efbb3SOlivier Certner if (groups != smallgroups)
855838d9858SBrooks Davis free(groups, M_TEMP);
8563cb83e71SJohn Baldwin return (error);
8573cb83e71SJohn Baldwin }
8583cb83e71SJohn Baldwin
85937260547SOlivier Certner static int
gidp_cmp(const void * p1,const void * p2)86037260547SOlivier Certner gidp_cmp(const void *p1, const void *p2)
86137260547SOlivier Certner {
86237260547SOlivier Certner const gid_t g1 = *(const gid_t *)p1;
86337260547SOlivier Certner const gid_t g2 = *(const gid_t *)p2;
86437260547SOlivier Certner
86537260547SOlivier Certner return ((g1 > g2) - (g1 < g2));
86637260547SOlivier Certner }
86737260547SOlivier Certner
8686d2efbb3SOlivier Certner /*
8696d2efbb3SOlivier Certner * CAUTION: This function normalizes 'groups', possibly also changing the value
8706d2efbb3SOlivier Certner * of '*ngrpp' as a consequence.
8716d2efbb3SOlivier Certner */
8723cb83e71SJohn Baldwin int
kern_setgroups(struct thread * td,int * ngrpp,gid_t * groups)8736d2efbb3SOlivier Certner kern_setgroups(struct thread *td, int *ngrpp, gid_t *groups)
8743cb83e71SJohn Baldwin {
8753cb83e71SJohn Baldwin struct proc *p = td->td_proc;
8763cb83e71SJohn Baldwin struct ucred *newcred, *oldcred;
8776d2efbb3SOlivier Certner int ngrp, error;
8783cb83e71SJohn Baldwin
8796d2efbb3SOlivier Certner ngrp = *ngrpp;
880abd39811SOlivier Certner /* Sanity check size. */
881abd39811SOlivier Certner if (ngrp < 0 || ngrp > ngroups_max + 1)
882abd39811SOlivier Certner return (EINVAL);
883abd39811SOlivier Certner
88414961ba7SRobert Watson AUDIT_ARG_GROUPSET(groups, ngrp);
8856d2efbb3SOlivier Certner if (ngrp != 0) {
8866d2efbb3SOlivier Certner /* We allow and treat 0 specially below. */
8876d2efbb3SOlivier Certner groups_normalize(ngrpp, groups);
8886d2efbb3SOlivier Certner ngrp = *ngrpp;
8896d2efbb3SOlivier Certner }
89007f3485dSJohn Baldwin newcred = crget();
891ea26c0e7SOlivier Certner if (ngrp != 0)
892838d9858SBrooks Davis crextend(newcred, ngrp);
89307f3485dSJohn Baldwin PROC_LOCK(p);
894838d9858SBrooks Davis oldcred = crcopysafe(p, newcred);
895030a28b3SRobert Watson
896030a28b3SRobert Watson #ifdef MAC
8976d2efbb3SOlivier Certner error = ngrp == 0 ?
8986d2efbb3SOlivier Certner /* If 'ngrp' is 0, we'll keep just the current effective GID. */
8996d2efbb3SOlivier Certner mac_cred_check_setgroups(oldcred, 1, oldcred->cr_groups) :
9006d2efbb3SOlivier Certner mac_cred_check_setgroups(oldcred, ngrp, groups);
901030a28b3SRobert Watson if (error)
902030a28b3SRobert Watson goto fail;
903030a28b3SRobert Watson #endif
904030a28b3SRobert Watson
905cc426dd3SMateusz Guzik error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS);
906030a28b3SRobert Watson if (error)
907030a28b3SRobert Watson goto fail;
90807f3485dSJohn Baldwin
9097e9a456aSMateusz Guzik if (ngrp == 0) {
9108a5d815aSPeter Wemm /*
9118a5d815aSPeter Wemm * setgroups(0, NULL) is a legitimate way of clearing the
9128a5d815aSPeter Wemm * groups vector on non-BSD systems (which generally do not
9138a5d815aSPeter Wemm * have the egid in the groups[0]). We risk security holes
9148a5d815aSPeter Wemm * when running non-BSD software if we do not do the same.
9158a5d815aSPeter Wemm */
916b1fc0ec1SRobert Watson newcred->cr_ngroups = 1;
9176d2efbb3SOlivier Certner } else
9186d2efbb3SOlivier Certner crsetgroups_internal(newcred, ngrp, groups);
9196d2efbb3SOlivier Certner
920d5f81602SSean Eric Fagan setsugid(p);
921daf63fd2SMateusz Guzik proc_set_cred(p, newcred);
92207f3485dSJohn Baldwin PROC_UNLOCK(p);
923b1fc0ec1SRobert Watson crfree(oldcred);
92407f3485dSJohn Baldwin return (0);
925030a28b3SRobert Watson
926030a28b3SRobert Watson fail:
927030a28b3SRobert Watson PROC_UNLOCK(p);
928030a28b3SRobert Watson crfree(newcred);
929030a28b3SRobert Watson return (error);
930df8bae1dSRodney W. Grimes }
931df8bae1dSRodney W. Grimes
932d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
933df8bae1dSRodney W. Grimes struct setreuid_args {
93400999cd6SAndrey A. Chernov uid_t ruid;
93500999cd6SAndrey A. Chernov uid_t euid;
936df8bae1dSRodney W. Grimes };
937d2d3e875SBruce Evans #endif
938df8bae1dSRodney W. Grimes /* ARGSUSED */
93926f9a767SRodney W. Grimes int
sys_setreuid(struct thread * td,struct setreuid_args * uap)9403e85b721SEd Maste sys_setreuid(struct thread *td, struct setreuid_args *uap)
941df8bae1dSRodney W. Grimes {
942b40ce416SJulian Elischer struct proc *p = td->td_proc;
943b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred;
944eb725b4eSRobert Watson uid_t euid, ruid;
9451419eacbSAlfred Perlstein struct uidinfo *euip, *ruip;
946eb725b4eSRobert Watson int error;
947df8bae1dSRodney W. Grimes
94800999cd6SAndrey A. Chernov euid = uap->euid;
949eb725b4eSRobert Watson ruid = uap->ruid;
95014961ba7SRobert Watson AUDIT_ARG_EUID(euid);
95114961ba7SRobert Watson AUDIT_ARG_RUID(ruid);
95207f3485dSJohn Baldwin newcred = crget();
9531419eacbSAlfred Perlstein euip = uifind(euid);
9541419eacbSAlfred Perlstein ruip = uifind(ruid);
95507f3485dSJohn Baldwin PROC_LOCK(p);
956838d9858SBrooks Davis oldcred = crcopysafe(p, newcred);
957030a28b3SRobert Watson
958030a28b3SRobert Watson #ifdef MAC
9596f6174a7SRobert Watson error = mac_cred_check_setreuid(oldcred, ruid, euid);
960030a28b3SRobert Watson if (error)
961030a28b3SRobert Watson goto fail;
962030a28b3SRobert Watson #endif
963030a28b3SRobert Watson
964b1fc0ec1SRobert Watson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
965b1fc0ec1SRobert Watson ruid != oldcred->cr_svuid) ||
966b1fc0ec1SRobert Watson (euid != (uid_t)-1 && euid != oldcred->cr_uid &&
967b1fc0ec1SRobert Watson euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) &&
968cc426dd3SMateusz Guzik (error = priv_check_cred(oldcred, PRIV_CRED_SETREUID)) != 0)
969030a28b3SRobert Watson goto fail;
970030a28b3SRobert Watson
971b1fc0ec1SRobert Watson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
9721419eacbSAlfred Perlstein change_euid(newcred, euip);
973d5f81602SSean Eric Fagan setsugid(p);
974a89a5370SPeter Wemm }
975b1fc0ec1SRobert Watson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
9761419eacbSAlfred Perlstein change_ruid(newcred, ruip);
977d5f81602SSean Eric Fagan setsugid(p);
97800999cd6SAndrey A. Chernov }
979b1fc0ec1SRobert Watson if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) &&
980b1fc0ec1SRobert Watson newcred->cr_svuid != newcred->cr_uid) {
981b1fc0ec1SRobert Watson change_svuid(newcred, newcred->cr_uid);
982d5f81602SSean Eric Fagan setsugid(p);
983a89a5370SPeter Wemm }
984daf63fd2SMateusz Guzik proc_set_cred(p, newcred);
985e4dcb704SEdward Tomasz Napierala #ifdef RACCT
986e4dcb704SEdward Tomasz Napierala racct_proc_ucred_changed(p, oldcred, newcred);
987f87beb93SAndriy Gapon crhold(newcred);
988f87beb93SAndriy Gapon #endif
989f87beb93SAndriy Gapon PROC_UNLOCK(p);
990f87beb93SAndriy Gapon #ifdef RCTL
991f87beb93SAndriy Gapon rctl_proc_ucred_changed(p, newcred);
992f87beb93SAndriy Gapon crfree(newcred);
993e4dcb704SEdward Tomasz Napierala #endif
9941419eacbSAlfred Perlstein uifree(ruip);
9951419eacbSAlfred Perlstein uifree(euip);
996b1fc0ec1SRobert Watson crfree(oldcred);
99707f3485dSJohn Baldwin return (0);
998030a28b3SRobert Watson
999030a28b3SRobert Watson fail:
1000030a28b3SRobert Watson PROC_UNLOCK(p);
1001030a28b3SRobert Watson uifree(ruip);
1002030a28b3SRobert Watson uifree(euip);
1003030a28b3SRobert Watson crfree(newcred);
1004030a28b3SRobert Watson return (error);
1005df8bae1dSRodney W. Grimes }
1006df8bae1dSRodney W. Grimes
1007d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
1008df8bae1dSRodney W. Grimes struct setregid_args {
100900999cd6SAndrey A. Chernov gid_t rgid;
101000999cd6SAndrey A. Chernov gid_t egid;
1011df8bae1dSRodney W. Grimes };
1012d2d3e875SBruce Evans #endif
1013df8bae1dSRodney W. Grimes /* ARGSUSED */
101426f9a767SRodney W. Grimes int
sys_setregid(struct thread * td,struct setregid_args * uap)10153e85b721SEd Maste sys_setregid(struct thread *td, struct setregid_args *uap)
1016df8bae1dSRodney W. Grimes {
1017b40ce416SJulian Elischer struct proc *p = td->td_proc;
1018b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred;
1019eb725b4eSRobert Watson gid_t egid, rgid;
1020eb725b4eSRobert Watson int error;
1021df8bae1dSRodney W. Grimes
102200999cd6SAndrey A. Chernov egid = uap->egid;
1023eb725b4eSRobert Watson rgid = uap->rgid;
102414961ba7SRobert Watson AUDIT_ARG_EGID(egid);
102514961ba7SRobert Watson AUDIT_ARG_RGID(rgid);
102607f3485dSJohn Baldwin newcred = crget();
102707f3485dSJohn Baldwin PROC_LOCK(p);
1028838d9858SBrooks Davis oldcred = crcopysafe(p, newcred);
1029030a28b3SRobert Watson
1030030a28b3SRobert Watson #ifdef MAC
10316f6174a7SRobert Watson error = mac_cred_check_setregid(oldcred, rgid, egid);
1032030a28b3SRobert Watson if (error)
1033030a28b3SRobert Watson goto fail;
1034030a28b3SRobert Watson #endif
1035030a28b3SRobert Watson
1036b1fc0ec1SRobert Watson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
1037b1fc0ec1SRobert Watson rgid != oldcred->cr_svgid) ||
1038b1fc0ec1SRobert Watson (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] &&
1039b1fc0ec1SRobert Watson egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) &&
1040cc426dd3SMateusz Guzik (error = priv_check_cred(oldcred, PRIV_CRED_SETREGID)) != 0)
1041030a28b3SRobert Watson goto fail;
104207f3485dSJohn Baldwin
1043b1fc0ec1SRobert Watson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
1044b1fc0ec1SRobert Watson change_egid(newcred, egid);
1045d5f81602SSean Eric Fagan setsugid(p);
1046a89a5370SPeter Wemm }
1047b1fc0ec1SRobert Watson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
1048b1fc0ec1SRobert Watson change_rgid(newcred, rgid);
1049d5f81602SSean Eric Fagan setsugid(p);
1050a89a5370SPeter Wemm }
1051b1fc0ec1SRobert Watson if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) &&
1052b1fc0ec1SRobert Watson newcred->cr_svgid != newcred->cr_groups[0]) {
1053b1fc0ec1SRobert Watson change_svgid(newcred, newcred->cr_groups[0]);
1054d5f81602SSean Eric Fagan setsugid(p);
1055a89a5370SPeter Wemm }
1056daf63fd2SMateusz Guzik proc_set_cred(p, newcred);
105707f3485dSJohn Baldwin PROC_UNLOCK(p);
10584589be70SRuslan Ermilov crfree(oldcred);
105907f3485dSJohn Baldwin return (0);
1060030a28b3SRobert Watson
1061030a28b3SRobert Watson fail:
1062030a28b3SRobert Watson PROC_UNLOCK(p);
1063030a28b3SRobert Watson crfree(newcred);
1064030a28b3SRobert Watson return (error);
1065df8bae1dSRodney W. Grimes }
1066df8bae1dSRodney W. Grimes
10678ccd6334SPeter Wemm /*
1068873fbcd7SRobert Watson * setresuid(ruid, euid, suid) is like setreuid except control over the saved
1069873fbcd7SRobert Watson * uid is explicit.
10708ccd6334SPeter Wemm */
10718ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
10728ccd6334SPeter Wemm struct setresuid_args {
10738ccd6334SPeter Wemm uid_t ruid;
10748ccd6334SPeter Wemm uid_t euid;
10758ccd6334SPeter Wemm uid_t suid;
10768ccd6334SPeter Wemm };
10778ccd6334SPeter Wemm #endif
10788ccd6334SPeter Wemm /* ARGSUSED */
10798ccd6334SPeter Wemm int
sys_setresuid(struct thread * td,struct setresuid_args * uap)10803e85b721SEd Maste sys_setresuid(struct thread *td, struct setresuid_args *uap)
10818ccd6334SPeter Wemm {
1082b40ce416SJulian Elischer struct proc *p = td->td_proc;
1083b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred;
1084eb725b4eSRobert Watson uid_t euid, ruid, suid;
10851419eacbSAlfred Perlstein struct uidinfo *euip, *ruip;
10868ccd6334SPeter Wemm int error;
10878ccd6334SPeter Wemm
10888ccd6334SPeter Wemm euid = uap->euid;
1089eb725b4eSRobert Watson ruid = uap->ruid;
10908ccd6334SPeter Wemm suid = uap->suid;
109114961ba7SRobert Watson AUDIT_ARG_EUID(euid);
109214961ba7SRobert Watson AUDIT_ARG_RUID(ruid);
109314961ba7SRobert Watson AUDIT_ARG_SUID(suid);
109407f3485dSJohn Baldwin newcred = crget();
10951419eacbSAlfred Perlstein euip = uifind(euid);
10961419eacbSAlfred Perlstein ruip = uifind(ruid);
109707f3485dSJohn Baldwin PROC_LOCK(p);
1098838d9858SBrooks Davis oldcred = crcopysafe(p, newcred);
1099030a28b3SRobert Watson
1100030a28b3SRobert Watson #ifdef MAC
11016f6174a7SRobert Watson error = mac_cred_check_setresuid(oldcred, ruid, euid, suid);
1102030a28b3SRobert Watson if (error)
1103030a28b3SRobert Watson goto fail;
1104030a28b3SRobert Watson #endif
1105030a28b3SRobert Watson
1106b1fc0ec1SRobert Watson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
1107b1fc0ec1SRobert Watson ruid != oldcred->cr_svuid &&
1108b1fc0ec1SRobert Watson ruid != oldcred->cr_uid) ||
1109b1fc0ec1SRobert Watson (euid != (uid_t)-1 && euid != oldcred->cr_ruid &&
1110b1fc0ec1SRobert Watson euid != oldcred->cr_svuid &&
1111b1fc0ec1SRobert Watson euid != oldcred->cr_uid) ||
1112b1fc0ec1SRobert Watson (suid != (uid_t)-1 && suid != oldcred->cr_ruid &&
1113b1fc0ec1SRobert Watson suid != oldcred->cr_svuid &&
1114b1fc0ec1SRobert Watson suid != oldcred->cr_uid)) &&
1115cc426dd3SMateusz Guzik (error = priv_check_cred(oldcred, PRIV_CRED_SETRESUID)) != 0)
1116030a28b3SRobert Watson goto fail;
111707f3485dSJohn Baldwin
1118b1fc0ec1SRobert Watson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
11191419eacbSAlfred Perlstein change_euid(newcred, euip);
11208ccd6334SPeter Wemm setsugid(p);
11218ccd6334SPeter Wemm }
1122b1fc0ec1SRobert Watson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
11231419eacbSAlfred Perlstein change_ruid(newcred, ruip);
11248ccd6334SPeter Wemm setsugid(p);
11258ccd6334SPeter Wemm }
1126b1fc0ec1SRobert Watson if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) {
1127b1fc0ec1SRobert Watson change_svuid(newcred, suid);
11288ccd6334SPeter Wemm setsugid(p);
11298ccd6334SPeter Wemm }
1130daf63fd2SMateusz Guzik proc_set_cred(p, newcred);
1131e4dcb704SEdward Tomasz Napierala #ifdef RACCT
1132e4dcb704SEdward Tomasz Napierala racct_proc_ucred_changed(p, oldcred, newcred);
1133f87beb93SAndriy Gapon crhold(newcred);
1134f87beb93SAndriy Gapon #endif
1135f87beb93SAndriy Gapon PROC_UNLOCK(p);
1136f87beb93SAndriy Gapon #ifdef RCTL
1137f87beb93SAndriy Gapon rctl_proc_ucred_changed(p, newcred);
1138f87beb93SAndriy Gapon crfree(newcred);
1139e4dcb704SEdward Tomasz Napierala #endif
11401419eacbSAlfred Perlstein uifree(ruip);
11411419eacbSAlfred Perlstein uifree(euip);
1142b1fc0ec1SRobert Watson crfree(oldcred);
114307f3485dSJohn Baldwin return (0);
1144030a28b3SRobert Watson
1145030a28b3SRobert Watson fail:
1146030a28b3SRobert Watson PROC_UNLOCK(p);
1147030a28b3SRobert Watson uifree(ruip);
1148030a28b3SRobert Watson uifree(euip);
1149030a28b3SRobert Watson crfree(newcred);
1150030a28b3SRobert Watson return (error);
1151030a28b3SRobert Watson
11528ccd6334SPeter Wemm }
11538ccd6334SPeter Wemm
11548ccd6334SPeter Wemm /*
1155873fbcd7SRobert Watson * setresgid(rgid, egid, sgid) is like setregid except control over the saved
1156873fbcd7SRobert Watson * gid is explicit.
11578ccd6334SPeter Wemm */
11588ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
11598ccd6334SPeter Wemm struct setresgid_args {
11608ccd6334SPeter Wemm gid_t rgid;
11618ccd6334SPeter Wemm gid_t egid;
11628ccd6334SPeter Wemm gid_t sgid;
11638ccd6334SPeter Wemm };
11648ccd6334SPeter Wemm #endif
11658ccd6334SPeter Wemm /* ARGSUSED */
11668ccd6334SPeter Wemm int
sys_setresgid(struct thread * td,struct setresgid_args * uap)11673e85b721SEd Maste sys_setresgid(struct thread *td, struct setresgid_args *uap)
11688ccd6334SPeter Wemm {
1169b40ce416SJulian Elischer struct proc *p = td->td_proc;
1170b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred;
1171eb725b4eSRobert Watson gid_t egid, rgid, sgid;
11728ccd6334SPeter Wemm int error;
11738ccd6334SPeter Wemm
11748ccd6334SPeter Wemm egid = uap->egid;
1175eb725b4eSRobert Watson rgid = uap->rgid;
11768ccd6334SPeter Wemm sgid = uap->sgid;
117714961ba7SRobert Watson AUDIT_ARG_EGID(egid);
117814961ba7SRobert Watson AUDIT_ARG_RGID(rgid);
117914961ba7SRobert Watson AUDIT_ARG_SGID(sgid);
118007f3485dSJohn Baldwin newcred = crget();
118107f3485dSJohn Baldwin PROC_LOCK(p);
1182838d9858SBrooks Davis oldcred = crcopysafe(p, newcred);
1183030a28b3SRobert Watson
1184030a28b3SRobert Watson #ifdef MAC
11856f6174a7SRobert Watson error = mac_cred_check_setresgid(oldcred, rgid, egid, sgid);
1186030a28b3SRobert Watson if (error)
1187030a28b3SRobert Watson goto fail;
1188030a28b3SRobert Watson #endif
1189030a28b3SRobert Watson
1190b1fc0ec1SRobert Watson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
1191b1fc0ec1SRobert Watson rgid != oldcred->cr_svgid &&
1192b1fc0ec1SRobert Watson rgid != oldcred->cr_groups[0]) ||
1193b1fc0ec1SRobert Watson (egid != (gid_t)-1 && egid != oldcred->cr_rgid &&
1194b1fc0ec1SRobert Watson egid != oldcred->cr_svgid &&
1195b1fc0ec1SRobert Watson egid != oldcred->cr_groups[0]) ||
1196b1fc0ec1SRobert Watson (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid &&
1197b1fc0ec1SRobert Watson sgid != oldcred->cr_svgid &&
1198b1fc0ec1SRobert Watson sgid != oldcred->cr_groups[0])) &&
1199cc426dd3SMateusz Guzik (error = priv_check_cred(oldcred, PRIV_CRED_SETRESGID)) != 0)
1200030a28b3SRobert Watson goto fail;
120107f3485dSJohn Baldwin
1202b1fc0ec1SRobert Watson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
1203b1fc0ec1SRobert Watson change_egid(newcred, egid);
12048ccd6334SPeter Wemm setsugid(p);
12058ccd6334SPeter Wemm }
1206b1fc0ec1SRobert Watson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
1207b1fc0ec1SRobert Watson change_rgid(newcred, rgid);
12088ccd6334SPeter Wemm setsugid(p);
12098ccd6334SPeter Wemm }
1210b1fc0ec1SRobert Watson if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) {
1211b1fc0ec1SRobert Watson change_svgid(newcred, sgid);
12128ccd6334SPeter Wemm setsugid(p);
12138ccd6334SPeter Wemm }
1214daf63fd2SMateusz Guzik proc_set_cred(p, newcred);
121507f3485dSJohn Baldwin PROC_UNLOCK(p);
1216b1fc0ec1SRobert Watson crfree(oldcred);
121707f3485dSJohn Baldwin return (0);
1218030a28b3SRobert Watson
1219030a28b3SRobert Watson fail:
1220030a28b3SRobert Watson PROC_UNLOCK(p);
1221030a28b3SRobert Watson crfree(newcred);
1222030a28b3SRobert Watson return (error);
12238ccd6334SPeter Wemm }
12248ccd6334SPeter Wemm
12258ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
12268ccd6334SPeter Wemm struct getresuid_args {
12278ccd6334SPeter Wemm uid_t *ruid;
12288ccd6334SPeter Wemm uid_t *euid;
12298ccd6334SPeter Wemm uid_t *suid;
12308ccd6334SPeter Wemm };
12318ccd6334SPeter Wemm #endif
12328ccd6334SPeter Wemm /* ARGSUSED */
12338ccd6334SPeter Wemm int
sys_getresuid(struct thread * td,struct getresuid_args * uap)12343e85b721SEd Maste sys_getresuid(struct thread *td, struct getresuid_args *uap)
12358ccd6334SPeter Wemm {
1236835a82eeSMatthew Dillon struct ucred *cred;
12378ccd6334SPeter Wemm int error1 = 0, error2 = 0, error3 = 0;
12388ccd6334SPeter Wemm
1239d74ac681SMatthew Dillon cred = td->td_ucred;
12408ccd6334SPeter Wemm if (uap->ruid)
12417f05b035SAlfred Perlstein error1 = copyout(&cred->cr_ruid,
12427f05b035SAlfred Perlstein uap->ruid, sizeof(cred->cr_ruid));
12438ccd6334SPeter Wemm if (uap->euid)
12447f05b035SAlfred Perlstein error2 = copyout(&cred->cr_uid,
12457f05b035SAlfred Perlstein uap->euid, sizeof(cred->cr_uid));
12468ccd6334SPeter Wemm if (uap->suid)
12477f05b035SAlfred Perlstein error3 = copyout(&cred->cr_svuid,
12487f05b035SAlfred Perlstein uap->suid, sizeof(cred->cr_svuid));
1249eb725b4eSRobert Watson return (error1 ? error1 : error2 ? error2 : error3);
12508ccd6334SPeter Wemm }
12518ccd6334SPeter Wemm
12528ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
12538ccd6334SPeter Wemm struct getresgid_args {
12548ccd6334SPeter Wemm gid_t *rgid;
12558ccd6334SPeter Wemm gid_t *egid;
12568ccd6334SPeter Wemm gid_t *sgid;
12578ccd6334SPeter Wemm };
12588ccd6334SPeter Wemm #endif
12598ccd6334SPeter Wemm /* ARGSUSED */
12608ccd6334SPeter Wemm int
sys_getresgid(struct thread * td,struct getresgid_args * uap)12613e85b721SEd Maste sys_getresgid(struct thread *td, struct getresgid_args *uap)
12628ccd6334SPeter Wemm {
1263835a82eeSMatthew Dillon struct ucred *cred;
12648ccd6334SPeter Wemm int error1 = 0, error2 = 0, error3 = 0;
12658ccd6334SPeter Wemm
1266d74ac681SMatthew Dillon cred = td->td_ucred;
12678ccd6334SPeter Wemm if (uap->rgid)
12687f05b035SAlfred Perlstein error1 = copyout(&cred->cr_rgid,
12697f05b035SAlfred Perlstein uap->rgid, sizeof(cred->cr_rgid));
12708ccd6334SPeter Wemm if (uap->egid)
12717f05b035SAlfred Perlstein error2 = copyout(&cred->cr_groups[0],
12727f05b035SAlfred Perlstein uap->egid, sizeof(cred->cr_groups[0]));
12738ccd6334SPeter Wemm if (uap->sgid)
12747f05b035SAlfred Perlstein error3 = copyout(&cred->cr_svgid,
12757f05b035SAlfred Perlstein uap->sgid, sizeof(cred->cr_svgid));
1276eb725b4eSRobert Watson return (error1 ? error1 : error2 ? error2 : error3);
12778ccd6334SPeter Wemm }
12788ccd6334SPeter Wemm
1279b67cbc65SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1280b67cbc65SPeter Wemm struct issetugid_args {
1281b67cbc65SPeter Wemm int dummy;
1282b67cbc65SPeter Wemm };
1283b67cbc65SPeter Wemm #endif
1284b67cbc65SPeter Wemm /* ARGSUSED */
1285b67cbc65SPeter Wemm int
sys_issetugid(struct thread * td,struct issetugid_args * uap)12863e85b721SEd Maste sys_issetugid(struct thread *td, struct issetugid_args *uap)
1287b67cbc65SPeter Wemm {
1288b40ce416SJulian Elischer struct proc *p = td->td_proc;
1289b40ce416SJulian Elischer
1290b67cbc65SPeter Wemm /*
1291b67cbc65SPeter Wemm * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
1292b67cbc65SPeter Wemm * we use P_SUGID because we consider changing the owners as
1293b67cbc65SPeter Wemm * "tainting" as well.
1294b67cbc65SPeter Wemm * This is significant for procs that start as root and "become"
1295b67cbc65SPeter Wemm * a user without an exec - programs cannot know *everything*
1296b67cbc65SPeter Wemm * that libc *might* have put in their data segment.
1297b67cbc65SPeter Wemm */
1298b40ce416SJulian Elischer td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
1299b67cbc65SPeter Wemm return (0);
1300b67cbc65SPeter Wemm }
1301b67cbc65SPeter Wemm
1302130d0157SRobert Watson int
sys___setugid(struct thread * td,struct __setugid_args * uap)13038451d0ddSKip Macy sys___setugid(struct thread *td, struct __setugid_args *uap)
1304130d0157SRobert Watson {
1305130d0157SRobert Watson #ifdef REGRESSION
130607f3485dSJohn Baldwin struct proc *p;
1307835a82eeSMatthew Dillon
130807f3485dSJohn Baldwin p = td->td_proc;
1309130d0157SRobert Watson switch (uap->flag) {
1310130d0157SRobert Watson case 0:
131107f3485dSJohn Baldwin PROC_LOCK(p);
131207f3485dSJohn Baldwin p->p_flag &= ~P_SUGID;
131307f3485dSJohn Baldwin PROC_UNLOCK(p);
131407f3485dSJohn Baldwin return (0);
131507f3485dSJohn Baldwin case 1:
131607f3485dSJohn Baldwin PROC_LOCK(p);
131707f3485dSJohn Baldwin p->p_flag |= P_SUGID;
131807f3485dSJohn Baldwin PROC_UNLOCK(p);
131907f3485dSJohn Baldwin return (0);
132007f3485dSJohn Baldwin default:
132107f3485dSJohn Baldwin return (EINVAL);
132207f3485dSJohn Baldwin }
1323130d0157SRobert Watson #else /* !REGRESSION */
1324eb725b4eSRobert Watson
1325130d0157SRobert Watson return (ENOSYS);
1326eb725b4eSRobert Watson #endif /* REGRESSION */
1327130d0157SRobert Watson }
1328130d0157SRobert Watson
13296d2efbb3SOlivier Certner #ifdef INVARIANTS
13306d2efbb3SOlivier Certner static void
groups_check_normalized(int ngrp,const gid_t * groups)13316d2efbb3SOlivier Certner groups_check_normalized(int ngrp, const gid_t *groups)
13326d2efbb3SOlivier Certner {
13336d2efbb3SOlivier Certner gid_t prev_g;
13346d2efbb3SOlivier Certner
13356d2efbb3SOlivier Certner groups_check_positive_len(ngrp);
13366d2efbb3SOlivier Certner groups_check_max_len(ngrp);
13376d2efbb3SOlivier Certner
13386d2efbb3SOlivier Certner if (ngrp == 1)
13396d2efbb3SOlivier Certner return;
13406d2efbb3SOlivier Certner
13416d2efbb3SOlivier Certner prev_g = groups[1];
13426d2efbb3SOlivier Certner for (int i = 2; i < ngrp; ++i) {
13436d2efbb3SOlivier Certner const gid_t g = groups[i];
13446d2efbb3SOlivier Certner
13456d2efbb3SOlivier Certner if (prev_g >= g)
13466d2efbb3SOlivier Certner panic("%s: groups[%d] (%u) >= groups[%d] (%u)",
13476d2efbb3SOlivier Certner __func__, i - 1, prev_g, i, g);
13486d2efbb3SOlivier Certner prev_g = g;
13496d2efbb3SOlivier Certner }
13506d2efbb3SOlivier Certner }
13516d2efbb3SOlivier Certner #else
13526d2efbb3SOlivier Certner #define groups_check_normalized(...)
13536d2efbb3SOlivier Certner #endif
13546d2efbb3SOlivier Certner
1355df8bae1dSRodney W. Grimes /*
1356b725f232SOlivier Certner * Returns whether gid designates a supplementary group in cred.
1357df8bae1dSRodney W. Grimes */
135863695442SOlivier Certner bool
group_is_supplementary(const gid_t gid,const struct ucred * const cred)13592e031fd0SOlivier Certner group_is_supplementary(const gid_t gid, const struct ucred *const cred)
1360df8bae1dSRodney W. Grimes {
13617f92e578SBrooks Davis
136263467506SOlivier Certner groups_check_normalized(cred->cr_ngroups, cred->cr_groups);
136363467506SOlivier Certner
13647f92e578SBrooks Davis /*
13652e031fd0SOlivier Certner * Perform a binary search of the supplementary groups. This is
13662e031fd0SOlivier Certner * possible because we sort the groups in crsetgroups().
13677f92e578SBrooks Davis */
136837260547SOlivier Certner return (bsearch(&gid, cred->cr_groups + 1, cred->cr_ngroups - 1,
136937260547SOlivier Certner sizeof(gid), gidp_cmp) != NULL);
1370b725f232SOlivier Certner }
1371b725f232SOlivier Certner
1372b725f232SOlivier Certner /*
1373b725f232SOlivier Certner * Check if gid is a member of the (effective) group set (i.e., effective and
1374b725f232SOlivier Certner * supplementary groups).
1375b725f232SOlivier Certner */
1376ffd3ef8eSOlivier Certner bool
groupmember(gid_t gid,const struct ucred * cred)1377b15110fbSOlivier Certner groupmember(gid_t gid, const struct ucred *cred)
1378b725f232SOlivier Certner {
1379b725f232SOlivier Certner
138063467506SOlivier Certner groups_check_positive_len(cred->cr_ngroups);
138163467506SOlivier Certner
1382ffd3ef8eSOlivier Certner if (gid == cred->cr_groups[0])
1383ffd3ef8eSOlivier Certner return (true);
13847f92e578SBrooks Davis
13852e031fd0SOlivier Certner return (group_is_supplementary(gid, cred));
1386df8bae1dSRodney W. Grimes }
1387df8bae1dSRodney W. Grimes
13883b243b72SRobert Watson /*
13892a2bfa6aSOlivier Certner * Check if gid is a member of the real group set (i.e., real and supplementary
13902a2bfa6aSOlivier Certner * groups).
13912a2bfa6aSOlivier Certner */
1392ffd3ef8eSOlivier Certner bool
realgroupmember(gid_t gid,const struct ucred * cred)1393b15110fbSOlivier Certner realgroupmember(gid_t gid, const struct ucred *cred)
13942a2bfa6aSOlivier Certner {
139563467506SOlivier Certner /*
139663467506SOlivier Certner * Although the equality test on 'cr_rgid' below doesn't access
139763467506SOlivier Certner * 'cr_groups', we check for the latter's length here as we assume that,
139863467506SOlivier Certner * if 'cr_ngroups' is 0, the passed 'struct ucred' is invalid, and
139963467506SOlivier Certner * 'cr_rgid' may not have been filled.
140063467506SOlivier Certner */
140163467506SOlivier Certner groups_check_positive_len(cred->cr_ngroups);
140263467506SOlivier Certner
14032a2bfa6aSOlivier Certner if (gid == cred->cr_rgid)
1404ffd3ef8eSOlivier Certner return (true);
14052a2bfa6aSOlivier Certner
14062e031fd0SOlivier Certner return (group_is_supplementary(gid, cred));
14072a2bfa6aSOlivier Certner }
14082a2bfa6aSOlivier Certner
14092a2bfa6aSOlivier Certner /*
1410eb725b4eSRobert Watson * Test the active securelevel against a given level. securelevel_gt()
1411eb725b4eSRobert Watson * implements (securelevel > level). securelevel_ge() implements
1412eb725b4eSRobert Watson * (securelevel >= level). Note that the logic is inverted -- these
1413eb725b4eSRobert Watson * functions return EPERM on "success" and 0 on "failure".
14143ca719f1SRobert Watson *
14150304c731SJamie Gritton * Due to care taken when setting the securelevel, we know that no jail will
14160304c731SJamie Gritton * be less secure that its parent (or the physical system), so it is sufficient
14170304c731SJamie Gritton * to test the current jail only.
14180304c731SJamie Gritton *
1419800c9408SRobert Watson * XXXRW: Possibly since this has to do with privilege, it should move to
1420800c9408SRobert Watson * kern_priv.c.
14213ca719f1SRobert Watson */
14223ca719f1SRobert Watson int
securelevel_gt(struct ucred * cr,int level)14233ca719f1SRobert Watson securelevel_gt(struct ucred *cr, int level)
14243ca719f1SRobert Watson {
14253ca719f1SRobert Watson
14260304c731SJamie Gritton return (cr->cr_prison->pr_securelevel > level ? EPERM : 0);
14273ca719f1SRobert Watson }
14283ca719f1SRobert Watson
14293ca719f1SRobert Watson int
securelevel_ge(struct ucred * cr,int level)14303ca719f1SRobert Watson securelevel_ge(struct ucred *cr, int level)
14313ca719f1SRobert Watson {
14323ca719f1SRobert Watson
14330304c731SJamie Gritton return (cr->cr_prison->pr_securelevel >= level ? EPERM : 0);
14343ca719f1SRobert Watson }
14353ca719f1SRobert Watson
14368a7d8cc6SRobert Watson /*
1437e409590dSRobert Watson * 'see_other_uids' determines whether or not visibility of processes
1438eb725b4eSRobert Watson * and sockets with credentials holding different real uids is possible
143948713bdcSRobert Watson * using a variety of system MIBs.
1440eb725b4eSRobert Watson * XXX: data declarations should be together near the beginning of the file.
14418a7d8cc6SRobert Watson */
1442e409590dSRobert Watson static int see_other_uids = 1;
1443d0615c64SAndrew R. Reiter SYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW,
1444eb725b4eSRobert Watson &see_other_uids, 0,
14458a7d8cc6SRobert Watson "Unprivileged processes may see subjects/objects with different real uid");
14468a7d8cc6SRobert Watson
14471a996ed1SEdward Tomasz Napierala /*-
14481b350b45SRobert Watson * Determine if u1 "can see" the subject specified by u2, according to the
14491b350b45SRobert Watson * 'see_other_uids' policy.
14501b350b45SRobert Watson * Returns: 0 for permitted, ESRCH otherwise
14511b350b45SRobert Watson * Locks: none
14521b350b45SRobert Watson * References: *u1 and *u2 must not change during the call
14531b350b45SRobert Watson * u1 may equal u2, in which case only one reference is required
14541b350b45SRobert Watson */
145591e9d669SOlivier Certner static int
cr_canseeotheruids(struct ucred * u1,struct ucred * u2)14564ac21b4fSStephen J. Kiernan cr_canseeotheruids(struct ucred *u1, struct ucred *u2)
14571b350b45SRobert Watson {
14581b350b45SRobert Watson
14591b350b45SRobert Watson if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) {
1460cc426dd3SMateusz Guzik if (priv_check_cred(u1, PRIV_SEEOTHERUIDS) != 0)
14611b350b45SRobert Watson return (ESRCH);
14621b350b45SRobert Watson }
14631b350b45SRobert Watson return (0);
14641b350b45SRobert Watson }
14651b350b45SRobert Watson
146664d19c2eSRobert Watson /*
146764d19c2eSRobert Watson * 'see_other_gids' determines whether or not visibility of processes
146864d19c2eSRobert Watson * and sockets with credentials holding different real gids is possible
146964d19c2eSRobert Watson * using a variety of system MIBs.
147064d19c2eSRobert Watson * XXX: data declarations should be together near the beginning of the file.
147164d19c2eSRobert Watson */
147264d19c2eSRobert Watson static int see_other_gids = 1;
147364d19c2eSRobert Watson SYSCTL_INT(_security_bsd, OID_AUTO, see_other_gids, CTLFLAG_RW,
147464d19c2eSRobert Watson &see_other_gids, 0,
147564d19c2eSRobert Watson "Unprivileged processes may see subjects/objects with different real gid");
147664d19c2eSRobert Watson
147764d19c2eSRobert Watson /*
147864d19c2eSRobert Watson * Determine if u1 can "see" the subject specified by u2, according to the
147964d19c2eSRobert Watson * 'see_other_gids' policy.
148064d19c2eSRobert Watson * Returns: 0 for permitted, ESRCH otherwise
148164d19c2eSRobert Watson * Locks: none
148264d19c2eSRobert Watson * References: *u1 and *u2 must not change during the call
148364d19c2eSRobert Watson * u1 may equal u2, in which case only one reference is required
148464d19c2eSRobert Watson */
148591e9d669SOlivier Certner static int
cr_canseeothergids(struct ucred * u1,struct ucred * u2)14864ac21b4fSStephen J. Kiernan cr_canseeothergids(struct ucred *u1, struct ucred *u2)
148764d19c2eSRobert Watson {
148864d19c2eSRobert Watson if (!see_other_gids) {
148991658080SOlivier Certner if (realgroupmember(u1->cr_rgid, u2))
149091658080SOlivier Certner return (0);
149191658080SOlivier Certner
149291658080SOlivier Certner for (int i = 1; i < u1->cr_ngroups; i++)
149391658080SOlivier Certner if (realgroupmember(u1->cr_groups[i], u2))
149491658080SOlivier Certner return (0);
149591658080SOlivier Certner
1496cc426dd3SMateusz Guzik if (priv_check_cred(u1, PRIV_SEEOTHERGIDS) != 0)
149764d19c2eSRobert Watson return (ESRCH);
149864d19c2eSRobert Watson }
149991658080SOlivier Certner
150064d19c2eSRobert Watson return (0);
150164d19c2eSRobert Watson }
150264d19c2eSRobert Watson
1503a4aaba3bSSteve Wills /*
1504a4aaba3bSSteve Wills * 'see_jail_proc' determines whether or not visibility of processes and
1505a4aaba3bSSteve Wills * sockets with credentials holding different jail ids is possible using a
1506a4aaba3bSSteve Wills * variety of system MIBs.
1507a4aaba3bSSteve Wills *
1508a4aaba3bSSteve Wills * XXX: data declarations should be together near the beginning of the file.
1509a4aaba3bSSteve Wills */
1510a4aaba3bSSteve Wills
1511a4aaba3bSSteve Wills static int see_jail_proc = 1;
1512a4aaba3bSSteve Wills SYSCTL_INT(_security_bsd, OID_AUTO, see_jail_proc, CTLFLAG_RW,
1513a4aaba3bSSteve Wills &see_jail_proc, 0,
1514a4aaba3bSSteve Wills "Unprivileged processes may see subjects/objects with different jail ids");
1515a4aaba3bSSteve Wills
1516a4aaba3bSSteve Wills /*-
1517a4aaba3bSSteve Wills * Determine if u1 "can see" the subject specified by u2, according to the
1518a4aaba3bSSteve Wills * 'see_jail_proc' policy.
1519a4aaba3bSSteve Wills * Returns: 0 for permitted, ESRCH otherwise
1520a4aaba3bSSteve Wills * Locks: none
1521a4aaba3bSSteve Wills * References: *u1 and *u2 must not change during the call
1522a4aaba3bSSteve Wills * u1 may equal u2, in which case only one reference is required
1523a4aaba3bSSteve Wills */
152491e9d669SOlivier Certner static int
cr_canseejailproc(struct ucred * u1,struct ucred * u2)1525a4aaba3bSSteve Wills cr_canseejailproc(struct ucred *u1, struct ucred *u2)
1526a4aaba3bSSteve Wills {
15277974ca1cSOlivier Certner if (see_jail_proc || /* Policy deactivated. */
15287974ca1cSOlivier Certner u1->cr_prison == u2->cr_prison || /* Same jail. */
15297974ca1cSOlivier Certner priv_check_cred(u1, PRIV_SEEJAILPROC) == 0) /* Privileged. */
1530a4aaba3bSSteve Wills return (0);
15317974ca1cSOlivier Certner
15327974ca1cSOlivier Certner return (ESRCH);
1533a4aaba3bSSteve Wills }
1534a4aaba3bSSteve Wills
1535e4a7b4f9SOlivier Certner /*
1536e4a7b4f9SOlivier Certner * Helper for cr_cansee*() functions to abide by system-wide security.bsd.see_*
1537e4a7b4f9SOlivier Certner * policies. Determines if u1 "can see" u2 according to these policies.
1538e4a7b4f9SOlivier Certner * Returns: 0 for permitted, ESRCH otherwise
1539e4a7b4f9SOlivier Certner */
1540e4a7b4f9SOlivier Certner int
cr_bsd_visible(struct ucred * u1,struct ucred * u2)1541e4a7b4f9SOlivier Certner cr_bsd_visible(struct ucred *u1, struct ucred *u2)
1542e4a7b4f9SOlivier Certner {
1543e4a7b4f9SOlivier Certner int error;
1544e4a7b4f9SOlivier Certner
1545a1e37bebSOlivier Certner error = cr_canseeotheruids(u1, u2);
1546a1e37bebSOlivier Certner if (error != 0)
1547e4a7b4f9SOlivier Certner return (error);
1548a1e37bebSOlivier Certner error = cr_canseeothergids(u1, u2);
1549a1e37bebSOlivier Certner if (error != 0)
1550e4a7b4f9SOlivier Certner return (error);
1551a1e37bebSOlivier Certner error = cr_canseejailproc(u1, u2);
1552a1e37bebSOlivier Certner if (error != 0)
1553e4a7b4f9SOlivier Certner return (error);
1554e4a7b4f9SOlivier Certner return (0);
1555e4a7b4f9SOlivier Certner }
1556e4a7b4f9SOlivier Certner
15571a996ed1SEdward Tomasz Napierala /*-
15587fd6a959SRobert Watson * Determine if u1 "can see" the subject specified by u2.
1559ed639720SRobert Watson * Returns: 0 for permitted, an errno value otherwise
1560ed639720SRobert Watson * Locks: none
1561eb725b4eSRobert Watson * References: *u1 and *u2 must not change during the call
1562ed639720SRobert Watson * u1 may equal u2, in which case only one reference is required
1563ed639720SRobert Watson */
1564ed639720SRobert Watson int
cr_cansee(struct ucred * u1,struct ucred * u2)156594088977SRobert Watson cr_cansee(struct ucred *u1, struct ucred *u2)
1566a9e0361bSPoul-Henning Kamp {
156791421ba2SRobert Watson int error;
1568a9e0361bSPoul-Henning Kamp
1569ed639720SRobert Watson if ((error = prison_check(u1, u2)))
157091421ba2SRobert Watson return (error);
15718a1d977dSRobert Watson #ifdef MAC
157230d239bcSRobert Watson if ((error = mac_cred_check_visible(u1, u2)))
15738a1d977dSRobert Watson return (error);
15748a1d977dSRobert Watson #endif
15755817169bSOlivier Certner if ((error = cr_bsd_visible(u1, u2)))
1576a4aaba3bSSteve Wills return (error);
1577387d2c03SRobert Watson return (0);
1578387d2c03SRobert Watson }
1579387d2c03SRobert Watson
15801a996ed1SEdward Tomasz Napierala /*-
1581f44d9e24SJohn Baldwin * Determine if td "can see" the subject specified by p.
15823b243b72SRobert Watson * Returns: 0 for permitted, an errno value otherwise
1583f44d9e24SJohn Baldwin * Locks: Sufficient locks to protect p->p_ucred must be held. td really
1584f44d9e24SJohn Baldwin * should be curthread.
1585f44d9e24SJohn Baldwin * References: td and p must be valid for the lifetime of the call
15863b243b72SRobert Watson */
1587a0f75161SRobert Watson int
p_cansee(struct thread * td,struct proc * p)1588f44d9e24SJohn Baldwin p_cansee(struct thread *td, struct proc *p)
1589ed639720SRobert Watson {
159094088977SRobert Watson /* Wrap cr_cansee() for all functionality. */
1591f44d9e24SJohn Baldwin KASSERT(td == curthread, ("%s: td not curthread", __func__));
1592f44d9e24SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED);
159355a0aa21SKonstantin Belousov
159455a0aa21SKonstantin Belousov if (td->td_proc == p)
159555a0aa21SKonstantin Belousov return (0);
1596f44d9e24SJohn Baldwin return (cr_cansee(td->td_ucred, p->p_ucred));
1597ed639720SRobert Watson }
1598ed639720SRobert Watson
159962c45ef4SRobert Watson /*
160062c45ef4SRobert Watson * 'conservative_signals' prevents the delivery of a broad class of
160162c45ef4SRobert Watson * signals by unprivileged processes to processes that have changed their
160262c45ef4SRobert Watson * credentials since the last invocation of execve(). This can prevent
160362c45ef4SRobert Watson * the leakage of cached information or retained privileges as a result
160462c45ef4SRobert Watson * of a common class of signal-related vulnerabilities. However, this
160562c45ef4SRobert Watson * may interfere with some applications that expect to be able to
160662c45ef4SRobert Watson * deliver these signals to peer processes after having given up
160762c45ef4SRobert Watson * privilege.
160862c45ef4SRobert Watson */
160962c45ef4SRobert Watson static int conservative_signals = 1;
161062c45ef4SRobert Watson SYSCTL_INT(_security_bsd, OID_AUTO, conservative_signals, CTLFLAG_RW,
161162c45ef4SRobert Watson &conservative_signals, 0, "Unprivileged processes prevented from "
161262c45ef4SRobert Watson "sending certain signals to processes whose credentials have changed");
16131a996ed1SEdward Tomasz Napierala /*-
1614c83f8015SRobert Watson * Determine whether cred may deliver the specified signal to proc.
1615c83f8015SRobert Watson * Returns: 0 for permitted, an errno value otherwise.
1616c83f8015SRobert Watson * Locks: A lock must be held for proc.
1617c83f8015SRobert Watson * References: cred and proc must be valid for the lifetime of the call.
16184c5eb9c3SRobert Watson */
16194c5eb9c3SRobert Watson int
cr_cansignal(struct ucred * cred,struct proc * proc,int signum)16201a88a252SMaxim Sobolev cr_cansignal(struct ucred *cred, struct proc *proc, int signum)
1621387d2c03SRobert Watson {
162291421ba2SRobert Watson int error;
1623387d2c03SRobert Watson
1624f44d9e24SJohn Baldwin PROC_LOCK_ASSERT(proc, MA_OWNED);
16254c5eb9c3SRobert Watson /*
1626c83f8015SRobert Watson * Jail semantics limit the scope of signalling to proc in the
1627c83f8015SRobert Watson * same jail as cred, if cred is in jail.
16284c5eb9c3SRobert Watson */
1629c83f8015SRobert Watson error = prison_check(cred, proc->p_ucred);
1630c83f8015SRobert Watson if (error)
163191421ba2SRobert Watson return (error);
16328a1d977dSRobert Watson #ifdef MAC
163330d239bcSRobert Watson if ((error = mac_proc_check_signal(cred, proc, signum)))
16348a1d977dSRobert Watson return (error);
16358a1d977dSRobert Watson #endif
16365817169bSOlivier Certner if ((error = cr_bsd_visible(cred, proc->p_ucred)))
16371b350b45SRobert Watson return (error);
1638387d2c03SRobert Watson
1639387d2c03SRobert Watson /*
16403b243b72SRobert Watson * UNIX signal semantics depend on the status of the P_SUGID
16413b243b72SRobert Watson * bit on the target process. If the bit is set, then additional
16423b243b72SRobert Watson * restrictions are placed on the set of available signals.
16434c5eb9c3SRobert Watson */
16441a88a252SMaxim Sobolev if (conservative_signals && (proc->p_flag & P_SUGID)) {
16454c5eb9c3SRobert Watson switch (signum) {
16464c5eb9c3SRobert Watson case 0:
16474c5eb9c3SRobert Watson case SIGKILL:
16484c5eb9c3SRobert Watson case SIGINT:
16494c5eb9c3SRobert Watson case SIGTERM:
165062c45ef4SRobert Watson case SIGALRM:
16514c5eb9c3SRobert Watson case SIGSTOP:
16524c5eb9c3SRobert Watson case SIGTTIN:
16534c5eb9c3SRobert Watson case SIGTTOU:
16544c5eb9c3SRobert Watson case SIGTSTP:
16554c5eb9c3SRobert Watson case SIGHUP:
16564c5eb9c3SRobert Watson case SIGUSR1:
16574c5eb9c3SRobert Watson case SIGUSR2:
16587fd6a959SRobert Watson /*
16597fd6a959SRobert Watson * Generally, permit job and terminal control
16607fd6a959SRobert Watson * signals.
16617fd6a959SRobert Watson */
16624c5eb9c3SRobert Watson break;
16634c5eb9c3SRobert Watson default:
1664c83f8015SRobert Watson /* Not permitted without privilege. */
1665cc426dd3SMateusz Guzik error = priv_check_cred(cred, PRIV_SIGNAL_SUGID);
16664c5eb9c3SRobert Watson if (error)
16674c5eb9c3SRobert Watson return (error);
16684c5eb9c3SRobert Watson }
1669e9e7ff5bSRobert Watson }
1670e9e7ff5bSRobert Watson
16714c5eb9c3SRobert Watson /*
16723b243b72SRobert Watson * Generally, the target credential's ruid or svuid must match the
1673e9e7ff5bSRobert Watson * subject credential's ruid or euid.
16744c5eb9c3SRobert Watson */
1675c83f8015SRobert Watson if (cred->cr_ruid != proc->p_ucred->cr_ruid &&
1676c83f8015SRobert Watson cred->cr_ruid != proc->p_ucred->cr_svuid &&
1677c83f8015SRobert Watson cred->cr_uid != proc->p_ucred->cr_ruid &&
1678c83f8015SRobert Watson cred->cr_uid != proc->p_ucred->cr_svuid) {
1679cc426dd3SMateusz Guzik error = priv_check_cred(cred, PRIV_SIGNAL_DIFFCRED);
16804c5eb9c3SRobert Watson if (error)
16814c5eb9c3SRobert Watson return (error);
16824c5eb9c3SRobert Watson }
1683387d2c03SRobert Watson
1684387d2c03SRobert Watson return (0);
1685387d2c03SRobert Watson }
1686a9e0361bSPoul-Henning Kamp
16871a996ed1SEdward Tomasz Napierala /*-
1688f44d9e24SJohn Baldwin * Determine whether td may deliver the specified signal to p.
1689c83f8015SRobert Watson * Returns: 0 for permitted, an errno value otherwise
1690f44d9e24SJohn Baldwin * Locks: Sufficient locks to protect various components of td and p
1691f44d9e24SJohn Baldwin * must be held. td must be curthread, and a lock must be
1692f44d9e24SJohn Baldwin * held for p.
1693f44d9e24SJohn Baldwin * References: td and p must be valid for the lifetime of the call
1694c83f8015SRobert Watson */
1695c83f8015SRobert Watson int
p_cansignal(struct thread * td,struct proc * p,int signum)16961a88a252SMaxim Sobolev p_cansignal(struct thread *td, struct proc *p, int signum)
1697c83f8015SRobert Watson {
1698c83f8015SRobert Watson
1699f44d9e24SJohn Baldwin KASSERT(td == curthread, ("%s: td not curthread", __func__));
1700f44d9e24SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED);
1701f44d9e24SJohn Baldwin if (td->td_proc == p)
1702c83f8015SRobert Watson return (0);
1703c83f8015SRobert Watson
1704c83f8015SRobert Watson /*
1705c83f8015SRobert Watson * UNIX signalling semantics require that processes in the same
1706c83f8015SRobert Watson * session always be able to deliver SIGCONT to one another,
1707c83f8015SRobert Watson * overriding the remaining protections.
1708c83f8015SRobert Watson */
1709f44d9e24SJohn Baldwin /* XXX: This will require an additional lock of some sort. */
1710f44d9e24SJohn Baldwin if (signum == SIGCONT && td->td_proc->p_session == p->p_session)
1711c83f8015SRobert Watson return (0);
17124b178336SMaxim Sobolev /*
1713f9cd63d4SMaxim Sobolev * Some compat layers use SIGTHR and higher signals for
1714f9cd63d4SMaxim Sobolev * communication between different kernel threads of the same
1715f9cd63d4SMaxim Sobolev * process, so that they expect that it's always possible to
1716f9cd63d4SMaxim Sobolev * deliver them, even for suid applications where cr_cansignal() can
17174b178336SMaxim Sobolev * deny such ability for security consideration. It should be
17184b178336SMaxim Sobolev * pretty safe to do since the only way to create two processes
17194b178336SMaxim Sobolev * with the same p_leader is via rfork(2).
17204b178336SMaxim Sobolev */
17212322a0a7SMaxim Sobolev if (td->td_proc->p_leader != NULL && signum >= SIGTHR &&
17222322a0a7SMaxim Sobolev signum < SIGTHR + 4 && td->td_proc->p_leader == p->p_leader)
17234b178336SMaxim Sobolev return (0);
1724c83f8015SRobert Watson
17251a88a252SMaxim Sobolev return (cr_cansignal(td->td_ucred, p, signum));
1726c83f8015SRobert Watson }
1727c83f8015SRobert Watson
17281a996ed1SEdward Tomasz Napierala /*-
1729f44d9e24SJohn Baldwin * Determine whether td may reschedule p.
17307fd6a959SRobert Watson * Returns: 0 for permitted, an errno value otherwise
1731f44d9e24SJohn Baldwin * Locks: Sufficient locks to protect various components of td and p
1732f44d9e24SJohn Baldwin * must be held. td must be curthread, and a lock must
1733f44d9e24SJohn Baldwin * be held for p.
1734f44d9e24SJohn Baldwin * References: td and p must be valid for the lifetime of the call
17353b243b72SRobert Watson */
1736a0f75161SRobert Watson int
p_cansched(struct thread * td,struct proc * p)1737f44d9e24SJohn Baldwin p_cansched(struct thread *td, struct proc *p)
1738387d2c03SRobert Watson {
173991421ba2SRobert Watson int error;
1740387d2c03SRobert Watson
1741f44d9e24SJohn Baldwin KASSERT(td == curthread, ("%s: td not curthread", __func__));
1742f44d9e24SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED);
1743f44d9e24SJohn Baldwin if (td->td_proc == p)
1744387d2c03SRobert Watson return (0);
1745f44d9e24SJohn Baldwin if ((error = prison_check(td->td_ucred, p->p_ucred)))
174691421ba2SRobert Watson return (error);
17478a1d977dSRobert Watson #ifdef MAC
174830d239bcSRobert Watson if ((error = mac_proc_check_sched(td->td_ucred, p)))
17498a1d977dSRobert Watson return (error);
17508a1d977dSRobert Watson #endif
17515817169bSOlivier Certner if ((error = cr_bsd_visible(td->td_ucred, p->p_ucred)))
17521b350b45SRobert Watson return (error);
17535817169bSOlivier Certner
1754800c9408SRobert Watson if (td->td_ucred->cr_ruid != p->p_ucred->cr_ruid &&
1755800c9408SRobert Watson td->td_ucred->cr_uid != p->p_ucred->cr_ruid) {
175632f9753cSRobert Watson error = priv_check(td, PRIV_SCHED_DIFFCRED);
1757800c9408SRobert Watson if (error)
1758800c9408SRobert Watson return (error);
1759800c9408SRobert Watson }
1760387d2c03SRobert Watson return (0);
1761387d2c03SRobert Watson }
1762387d2c03SRobert Watson
17633b243b72SRobert Watson /*
1764b3079544SJamie Gritton * Handle getting or setting the prison's unprivileged_proc_debug
1765b3079544SJamie Gritton * value.
1766b3079544SJamie Gritton */
1767b3079544SJamie Gritton static int
sysctl_unprivileged_proc_debug(SYSCTL_HANDLER_ARGS)1768b3079544SJamie Gritton sysctl_unprivileged_proc_debug(SYSCTL_HANDLER_ARGS)
1769b3079544SJamie Gritton {
1770b3079544SJamie Gritton int error, val;
1771b3079544SJamie Gritton
17720fe74ae6SJamie Gritton val = prison_allow(req->td->td_ucred, PR_ALLOW_UNPRIV_DEBUG);
1773b3079544SJamie Gritton error = sysctl_handle_int(oidp, &val, 0, req);
1774b3079544SJamie Gritton if (error != 0 || req->newptr == NULL)
1775b3079544SJamie Gritton return (error);
17760fe74ae6SJamie Gritton if (val != 0 && val != 1)
17770fe74ae6SJamie Gritton return (EINVAL);
17780fe74ae6SJamie Gritton prison_set_allow(req->td->td_ucred, PR_ALLOW_UNPRIV_DEBUG, val);
17790fe74ae6SJamie Gritton return (0);
1780b3079544SJamie Gritton }
1781b3079544SJamie Gritton
1782b3079544SJamie Gritton /*
17835d476e73SRobert Watson * The 'unprivileged_proc_debug' flag may be used to disable a variety of
17845d476e73SRobert Watson * unprivileged inter-process debugging services, including some procfs
17855d476e73SRobert Watson * functionality, ptrace(), and ktrace(). In the past, inter-process
17865d476e73SRobert Watson * debugging has been involved in a variety of security problems, and sites
17875d476e73SRobert Watson * not requiring the service might choose to disable it when hardening
17885d476e73SRobert Watson * systems.
17893b243b72SRobert Watson */
1790b3079544SJamie Gritton SYSCTL_PROC(_security_bsd, OID_AUTO, unprivileged_proc_debug,
17917029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_SECURE |
17927029da5cSPawel Biernacki CTLFLAG_MPSAFE, 0, 0, sysctl_unprivileged_proc_debug, "I",
17930ef5652eSRobert Watson "Unprivileged processes may use process debugging facilities");
17940ef5652eSRobert Watson
17951a996ed1SEdward Tomasz Napierala /*-
1796f44d9e24SJohn Baldwin * Determine whether td may debug p.
17977fd6a959SRobert Watson * Returns: 0 for permitted, an errno value otherwise
1798f44d9e24SJohn Baldwin * Locks: Sufficient locks to protect various components of td and p
1799f44d9e24SJohn Baldwin * must be held. td must be curthread, and a lock must
1800f44d9e24SJohn Baldwin * be held for p.
1801f44d9e24SJohn Baldwin * References: td and p must be valid for the lifetime of the call
18023b243b72SRobert Watson */
1803a0f75161SRobert Watson int
p_candebug(struct thread * td,struct proc * p)1804f44d9e24SJohn Baldwin p_candebug(struct thread *td, struct proc *p)
1805387d2c03SRobert Watson {
1806c54d240eSPawel Jakub Dawidek int error, grpsubset, i, uidsubset;
1807387d2c03SRobert Watson
1808f44d9e24SJohn Baldwin KASSERT(td == curthread, ("%s: td not curthread", __func__));
1809f44d9e24SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED);
1810f44d9e24SJohn Baldwin if (td->td_proc == p)
181123fad5b6SDag-Erling Smørgrav return (0);
181255a0aa21SKonstantin Belousov if ((error = priv_check(td, PRIV_DEBUG_UNPRIV)))
181355a0aa21SKonstantin Belousov return (error);
1814f44d9e24SJohn Baldwin if ((error = prison_check(td->td_ucred, p->p_ucred)))
181591421ba2SRobert Watson return (error);
18168a1d977dSRobert Watson #ifdef MAC
181730d239bcSRobert Watson if ((error = mac_proc_check_debug(td->td_ucred, p)))
18188a1d977dSRobert Watson return (error);
18198a1d977dSRobert Watson #endif
18205817169bSOlivier Certner if ((error = cr_bsd_visible(td->td_ucred, p->p_ucred)))
182164d19c2eSRobert Watson return (error);
1822387d2c03SRobert Watson
18237fd6a959SRobert Watson /*
1824f44d9e24SJohn Baldwin * Is p's group set a subset of td's effective group set? This
1825f44d9e24SJohn Baldwin * includes p's egid, group access list, rgid, and svgid.
18267fd6a959SRobert Watson */
1827db42a33dSRobert Watson grpsubset = 1;
1828f44d9e24SJohn Baldwin for (i = 0; i < p->p_ucred->cr_ngroups; i++) {
1829f44d9e24SJohn Baldwin if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) {
1830db42a33dSRobert Watson grpsubset = 0;
1831db42a33dSRobert Watson break;
1832db42a33dSRobert Watson }
1833db42a33dSRobert Watson }
1834db42a33dSRobert Watson grpsubset = grpsubset &&
1835f44d9e24SJohn Baldwin groupmember(p->p_ucred->cr_rgid, td->td_ucred) &&
1836f44d9e24SJohn Baldwin groupmember(p->p_ucred->cr_svgid, td->td_ucred);
1837db42a33dSRobert Watson
1838db42a33dSRobert Watson /*
1839f44d9e24SJohn Baldwin * Are the uids present in p's credential equal to td's
1840f44d9e24SJohn Baldwin * effective uid? This includes p's euid, svuid, and ruid.
1841db42a33dSRobert Watson */
1842f44d9e24SJohn Baldwin uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid &&
1843f44d9e24SJohn Baldwin td->td_ucred->cr_uid == p->p_ucred->cr_svuid &&
1844f44d9e24SJohn Baldwin td->td_ucred->cr_uid == p->p_ucred->cr_ruid);
1845db42a33dSRobert Watson
1846db42a33dSRobert Watson /*
1847f44d9e24SJohn Baldwin * If p's gids aren't a subset, or the uids aren't a subset,
1848db42a33dSRobert Watson * or the credential has changed, require appropriate privilege
1849800c9408SRobert Watson * for td to debug p.
1850db42a33dSRobert Watson */
1851800c9408SRobert Watson if (!grpsubset || !uidsubset) {
185232f9753cSRobert Watson error = priv_check(td, PRIV_DEBUG_DIFFCRED);
1853800c9408SRobert Watson if (error)
1854800c9408SRobert Watson return (error);
1855800c9408SRobert Watson }
1856800c9408SRobert Watson
1857c54d240eSPawel Jakub Dawidek /*
1858c54d240eSPawel Jakub Dawidek * Has the credential of the process changed since the last exec()?
1859c54d240eSPawel Jakub Dawidek */
1860c54d240eSPawel Jakub Dawidek if ((p->p_flag & P_SUGID) != 0) {
186132f9753cSRobert Watson error = priv_check(td, PRIV_DEBUG_SUGID);
186232d18604SRobert Watson if (error)
1863387d2c03SRobert Watson return (error);
18647fd6a959SRobert Watson }
1865387d2c03SRobert Watson
1866eb725b4eSRobert Watson /* Can't trace init when securelevel > 0. */
1867f44d9e24SJohn Baldwin if (p == initproc) {
1868f44d9e24SJohn Baldwin error = securelevel_gt(td->td_ucred, 0);
18693ca719f1SRobert Watson if (error)
18703ca719f1SRobert Watson return (error);
18713ca719f1SRobert Watson }
1872387d2c03SRobert Watson
18735fab7614SRobert Watson /*
18745fab7614SRobert Watson * Can't trace a process that's currently exec'ing.
1875800c9408SRobert Watson *
18765fab7614SRobert Watson * XXX: Note, this is not a security policy decision, it's a
18775fab7614SRobert Watson * basic correctness/functionality decision. Therefore, this check
18785fab7614SRobert Watson * should be moved to the caller's of p_candebug().
18795fab7614SRobert Watson */
1880f44d9e24SJohn Baldwin if ((p->p_flag & P_INEXEC) != 0)
1881af80b2c9SKonstantin Belousov return (EBUSY);
18829ca45e81SDag-Erling Smørgrav
1883768f9b8bSGordon Bergling /* Denied explicitly */
1884677258f7SKonstantin Belousov if ((p->p_flag2 & P2_NOTRACE) != 0) {
1885677258f7SKonstantin Belousov error = priv_check(td, PRIV_DEBUG_DENIED);
1886677258f7SKonstantin Belousov if (error != 0)
1887677258f7SKonstantin Belousov return (error);
1888677258f7SKonstantin Belousov }
1889677258f7SKonstantin Belousov
1890387d2c03SRobert Watson return (0);
1891387d2c03SRobert Watson }
1892387d2c03SRobert Watson
18931a996ed1SEdward Tomasz Napierala /*-
189429dc1288SRobert Watson * Determine whether the subject represented by cred can "see" a socket.
189529dc1288SRobert Watson * Returns: 0 for permitted, ENOENT otherwise.
189629dc1288SRobert Watson */
189729dc1288SRobert Watson int
cr_canseesocket(struct ucred * cred,struct socket * so)189829dc1288SRobert Watson cr_canseesocket(struct ucred *cred, struct socket *so)
189929dc1288SRobert Watson {
190029dc1288SRobert Watson int error;
190129dc1288SRobert Watson
190229dc1288SRobert Watson error = prison_check(cred, so->so_cred);
190329dc1288SRobert Watson if (error)
190429dc1288SRobert Watson return (ENOENT);
19058a1d977dSRobert Watson #ifdef MAC
190630d239bcSRobert Watson error = mac_socket_check_visible(cred, so);
19078a1d977dSRobert Watson if (error)
19088a1d977dSRobert Watson return (error);
19098a1d977dSRobert Watson #endif
19105817169bSOlivier Certner if (cr_bsd_visible(cred, so->so_cred))
191164d19c2eSRobert Watson return (ENOENT);
191229dc1288SRobert Watson
191329dc1288SRobert Watson return (0);
191429dc1288SRobert Watson }
191529dc1288SRobert Watson
19161a996ed1SEdward Tomasz Napierala /*-
1917babe9a2bSRobert Watson * Determine whether td can wait for the exit of p.
1918babe9a2bSRobert Watson * Returns: 0 for permitted, an errno value otherwise
1919babe9a2bSRobert Watson * Locks: Sufficient locks to protect various components of td and p
1920babe9a2bSRobert Watson * must be held. td must be curthread, and a lock must
1921babe9a2bSRobert Watson * be held for p.
1922babe9a2bSRobert Watson * References: td and p must be valid for the lifetime of the call
1923babe9a2bSRobert Watson
1924babe9a2bSRobert Watson */
1925babe9a2bSRobert Watson int
p_canwait(struct thread * td,struct proc * p)1926babe9a2bSRobert Watson p_canwait(struct thread *td, struct proc *p)
1927babe9a2bSRobert Watson {
1928babe9a2bSRobert Watson int error;
1929babe9a2bSRobert Watson
1930babe9a2bSRobert Watson KASSERT(td == curthread, ("%s: td not curthread", __func__));
1931babe9a2bSRobert Watson PROC_LOCK_ASSERT(p, MA_OWNED);
19327afcbc18SJamie Gritton if ((error = prison_check(td->td_ucred, p->p_ucred)))
1933babe9a2bSRobert Watson return (error);
1934babe9a2bSRobert Watson #ifdef MAC
193530d239bcSRobert Watson if ((error = mac_proc_check_wait(td->td_ucred, p)))
1936babe9a2bSRobert Watson return (error);
1937babe9a2bSRobert Watson #endif
1938babe9a2bSRobert Watson #if 0
1939babe9a2bSRobert Watson /* XXXMAC: This could have odd effects on some shells. */
19405817169bSOlivier Certner if ((error = cr_bsd_visible(td->td_ucred, p->p_ucred)))
1941babe9a2bSRobert Watson return (error);
1942babe9a2bSRobert Watson #endif
1943babe9a2bSRobert Watson
1944babe9a2bSRobert Watson return (0);
1945babe9a2bSRobert Watson }
1946babe9a2bSRobert Watson
1947a9e0361bSPoul-Henning Kamp /*
19481724c563SMateusz Guzik * Credential management.
19491724c563SMateusz Guzik *
19501724c563SMateusz Guzik * struct ucred objects are rarely allocated but gain and lose references all
19511724c563SMateusz Guzik * the time (e.g., on struct file alloc/dealloc) turning refcount updates into
19521724c563SMateusz Guzik * a significant source of cache-line ping ponging. Common cases are worked
19531724c563SMateusz Guzik * around by modifying thread-local counter instead if the cred to operate on
19541724c563SMateusz Guzik * matches td_realucred.
19551724c563SMateusz Guzik *
19561724c563SMateusz Guzik * The counter is split into 2 parts:
19571724c563SMateusz Guzik * - cr_users -- total count of all struct proc and struct thread objects
19581724c563SMateusz Guzik * which have given cred in p_ucred and td_ucred respectively
19591724c563SMateusz Guzik * - cr_ref -- the actual ref count, only valid if cr_users == 0
19601724c563SMateusz Guzik *
19611724c563SMateusz Guzik * If users == 0 then cr_ref behaves similarly to refcount(9), in particular if
19621724c563SMateusz Guzik * the count reaches 0 the object is freeable.
19631724c563SMateusz Guzik * If users > 0 and curthread->td_realucred == cred, then updates are performed
19641724c563SMateusz Guzik * against td_ucredref.
19651724c563SMateusz Guzik * In other cases updates are performed against cr_ref.
19661724c563SMateusz Guzik *
19671724c563SMateusz Guzik * Changing td_realucred into something else decrements cr_users and transfers
19681724c563SMateusz Guzik * accumulated updates.
19691724c563SMateusz Guzik */
19701724c563SMateusz Guzik struct ucred *
crcowget(struct ucred * cr)19711724c563SMateusz Guzik crcowget(struct ucred *cr)
19721724c563SMateusz Guzik {
19731724c563SMateusz Guzik
19741724c563SMateusz Guzik mtx_lock(&cr->cr_mtx);
19751724c563SMateusz Guzik KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
19761724c563SMateusz Guzik __func__, cr->cr_users, cr));
19771724c563SMateusz Guzik cr->cr_users++;
19781724c563SMateusz Guzik cr->cr_ref++;
19791724c563SMateusz Guzik mtx_unlock(&cr->cr_mtx);
19801724c563SMateusz Guzik return (cr);
19811724c563SMateusz Guzik }
19821724c563SMateusz Guzik
19831724c563SMateusz Guzik static struct ucred *
crunuse(struct thread * td)19841724c563SMateusz Guzik crunuse(struct thread *td)
19851724c563SMateusz Guzik {
19861724c563SMateusz Guzik struct ucred *cr, *crold;
19871724c563SMateusz Guzik
1988936c24faSMateusz Guzik MPASS(td->td_realucred == td->td_ucred);
1989936c24faSMateusz Guzik cr = td->td_realucred;
19901724c563SMateusz Guzik mtx_lock(&cr->cr_mtx);
19911724c563SMateusz Guzik cr->cr_ref += td->td_ucredref;
19921724c563SMateusz Guzik td->td_ucredref = 0;
19931724c563SMateusz Guzik KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
19941724c563SMateusz Guzik __func__, cr->cr_users, cr));
19951724c563SMateusz Guzik cr->cr_users--;
19961724c563SMateusz Guzik if (cr->cr_users == 0) {
199737337709SMateusz Guzik KASSERT(cr->cr_ref > 0, ("%s: ref %ld not > 0 on cred %p",
19981724c563SMateusz Guzik __func__, cr->cr_ref, cr));
19991724c563SMateusz Guzik crold = cr;
20001724c563SMateusz Guzik } else {
20011724c563SMateusz Guzik cr->cr_ref--;
20021724c563SMateusz Guzik crold = NULL;
20031724c563SMateusz Guzik }
20041724c563SMateusz Guzik mtx_unlock(&cr->cr_mtx);
2005936c24faSMateusz Guzik td->td_realucred = NULL;
20061724c563SMateusz Guzik return (crold);
20071724c563SMateusz Guzik }
20081724c563SMateusz Guzik
2009f34a2f56SMateusz Guzik static void
crunusebatch(struct ucred * cr,int users,int ref)2010f34a2f56SMateusz Guzik crunusebatch(struct ucred *cr, int users, int ref)
2011f34a2f56SMateusz Guzik {
2012f34a2f56SMateusz Guzik
2013f34a2f56SMateusz Guzik KASSERT(users > 0, ("%s: passed users %d not > 0 ; cred %p",
2014f34a2f56SMateusz Guzik __func__, users, cr));
2015f34a2f56SMateusz Guzik mtx_lock(&cr->cr_mtx);
2016f34a2f56SMateusz Guzik KASSERT(cr->cr_users >= users, ("%s: users %d not > %d on cred %p",
2017f34a2f56SMateusz Guzik __func__, cr->cr_users, users, cr));
2018f34a2f56SMateusz Guzik cr->cr_users -= users;
2019f34a2f56SMateusz Guzik cr->cr_ref += ref;
2020f34a2f56SMateusz Guzik cr->cr_ref -= users;
2021f34a2f56SMateusz Guzik if (cr->cr_users > 0) {
2022f34a2f56SMateusz Guzik mtx_unlock(&cr->cr_mtx);
2023f34a2f56SMateusz Guzik return;
2024f34a2f56SMateusz Guzik }
202537337709SMateusz Guzik KASSERT(cr->cr_ref >= 0, ("%s: ref %ld not >= 0 on cred %p",
2026f34a2f56SMateusz Guzik __func__, cr->cr_ref, cr));
2027f34a2f56SMateusz Guzik if (cr->cr_ref > 0) {
2028f34a2f56SMateusz Guzik mtx_unlock(&cr->cr_mtx);
2029f34a2f56SMateusz Guzik return;
2030f34a2f56SMateusz Guzik }
2031f34a2f56SMateusz Guzik crfree_final(cr);
2032f34a2f56SMateusz Guzik }
2033f34a2f56SMateusz Guzik
20341724c563SMateusz Guzik void
crcowfree(struct thread * td)20351724c563SMateusz Guzik crcowfree(struct thread *td)
20361724c563SMateusz Guzik {
20371724c563SMateusz Guzik struct ucred *cr;
20381724c563SMateusz Guzik
20391724c563SMateusz Guzik cr = crunuse(td);
20401724c563SMateusz Guzik if (cr != NULL)
20411724c563SMateusz Guzik crfree(cr);
20421724c563SMateusz Guzik }
20431724c563SMateusz Guzik
20441724c563SMateusz Guzik struct ucred *
crcowsync(void)20451724c563SMateusz Guzik crcowsync(void)
20461724c563SMateusz Guzik {
20471724c563SMateusz Guzik struct thread *td;
20481724c563SMateusz Guzik struct proc *p;
20491724c563SMateusz Guzik struct ucred *crnew, *crold;
20501724c563SMateusz Guzik
20511724c563SMateusz Guzik td = curthread;
20521724c563SMateusz Guzik p = td->td_proc;
20531724c563SMateusz Guzik PROC_LOCK_ASSERT(p, MA_OWNED);
20541724c563SMateusz Guzik
20551724c563SMateusz Guzik MPASS(td->td_realucred == td->td_ucred);
20561724c563SMateusz Guzik if (td->td_realucred == p->p_ucred)
20571724c563SMateusz Guzik return (NULL);
20581724c563SMateusz Guzik
20591724c563SMateusz Guzik crnew = crcowget(p->p_ucred);
20601724c563SMateusz Guzik crold = crunuse(td);
20611724c563SMateusz Guzik td->td_realucred = crnew;
20621724c563SMateusz Guzik td->td_ucred = td->td_realucred;
20631724c563SMateusz Guzik return (crold);
20641724c563SMateusz Guzik }
20651724c563SMateusz Guzik
20661724c563SMateusz Guzik /*
2067f34a2f56SMateusz Guzik * Batching.
2068f34a2f56SMateusz Guzik */
2069f34a2f56SMateusz Guzik void
credbatch_add(struct credbatch * crb,struct thread * td)2070f34a2f56SMateusz Guzik credbatch_add(struct credbatch *crb, struct thread *td)
2071f34a2f56SMateusz Guzik {
2072f34a2f56SMateusz Guzik struct ucred *cr;
2073f34a2f56SMateusz Guzik
2074f34a2f56SMateusz Guzik MPASS(td->td_realucred != NULL);
2075f34a2f56SMateusz Guzik MPASS(td->td_realucred == td->td_ucred);
2076fa2528acSAlex Richardson MPASS(TD_GET_STATE(td) == TDS_INACTIVE);
2077f34a2f56SMateusz Guzik cr = td->td_realucred;
2078f34a2f56SMateusz Guzik KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
2079f34a2f56SMateusz Guzik __func__, cr->cr_users, cr));
2080f34a2f56SMateusz Guzik if (crb->cred != cr) {
2081f34a2f56SMateusz Guzik if (crb->users > 0) {
2082f34a2f56SMateusz Guzik MPASS(crb->cred != NULL);
2083f34a2f56SMateusz Guzik crunusebatch(crb->cred, crb->users, crb->ref);
2084f34a2f56SMateusz Guzik crb->users = 0;
2085f34a2f56SMateusz Guzik crb->ref = 0;
2086f34a2f56SMateusz Guzik }
2087f34a2f56SMateusz Guzik }
2088f34a2f56SMateusz Guzik crb->cred = cr;
2089f34a2f56SMateusz Guzik crb->users++;
2090f34a2f56SMateusz Guzik crb->ref += td->td_ucredref;
2091f34a2f56SMateusz Guzik td->td_ucredref = 0;
2092f34a2f56SMateusz Guzik td->td_realucred = NULL;
2093f34a2f56SMateusz Guzik }
2094f34a2f56SMateusz Guzik
2095f34a2f56SMateusz Guzik void
credbatch_final(struct credbatch * crb)2096f34a2f56SMateusz Guzik credbatch_final(struct credbatch *crb)
2097f34a2f56SMateusz Guzik {
2098f34a2f56SMateusz Guzik
2099f34a2f56SMateusz Guzik MPASS(crb->cred != NULL);
2100f34a2f56SMateusz Guzik MPASS(crb->users > 0);
2101f34a2f56SMateusz Guzik crunusebatch(crb->cred, crb->users, crb->ref);
2102f34a2f56SMateusz Guzik }
2103f34a2f56SMateusz Guzik
2104f34a2f56SMateusz Guzik /*
2105df8bae1dSRodney W. Grimes * Allocate a zeroed cred structure.
2106df8bae1dSRodney W. Grimes */
2107df8bae1dSRodney W. Grimes struct ucred *
crget(void)21084c44ad8eSJohn Baldwin crget(void)
2109df8bae1dSRodney W. Grimes {
21103e85b721SEd Maste struct ucred *cr;
2111df8bae1dSRodney W. Grimes
21121ede983cSDag-Erling Smørgrav cr = malloc(sizeof(*cr), M_CRED, M_WAITOK | M_ZERO);
21131724c563SMateusz Guzik mtx_init(&cr->cr_mtx, "cred", NULL, MTX_DEF);
21141724c563SMateusz Guzik cr->cr_ref = 1;
2115faef5371SRobert Watson #ifdef AUDIT
2116faef5371SRobert Watson audit_cred_init(cr);
2117faef5371SRobert Watson #endif
211840244964SRobert Watson #ifdef MAC
211930d239bcSRobert Watson mac_cred_init(cr);
212040244964SRobert Watson #endif
2121a99500a9SMateusz Guzik cr->cr_groups = cr->cr_smallgroups;
2122a99500a9SMateusz Guzik cr->cr_agroups =
2123a99500a9SMateusz Guzik sizeof(cr->cr_smallgroups) / sizeof(cr->cr_smallgroups[0]);
2124df8bae1dSRodney W. Grimes return (cr);
2125df8bae1dSRodney W. Grimes }
2126df8bae1dSRodney W. Grimes
2127df8bae1dSRodney W. Grimes /*
21287fd6a959SRobert Watson * Claim another reference to a ucred structure.
21295c3f70d7SAlfred Perlstein */
2130bd78ceceSJohn Baldwin struct ucred *
crhold(struct ucred * cr)21314c44ad8eSJohn Baldwin crhold(struct ucred *cr)
21325c3f70d7SAlfred Perlstein {
21331724c563SMateusz Guzik struct thread *td;
21345c3f70d7SAlfred Perlstein
21351724c563SMateusz Guzik td = curthread;
21361724c563SMateusz Guzik if (__predict_true(td->td_realucred == cr)) {
21371724c563SMateusz Guzik KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
21381724c563SMateusz Guzik __func__, cr->cr_users, cr));
21391724c563SMateusz Guzik td->td_ucredref++;
21401724c563SMateusz Guzik return (cr);
21411724c563SMateusz Guzik }
21421724c563SMateusz Guzik mtx_lock(&cr->cr_mtx);
21431724c563SMateusz Guzik cr->cr_ref++;
21441724c563SMateusz Guzik mtx_unlock(&cr->cr_mtx);
2145bd78ceceSJohn Baldwin return (cr);
21465c3f70d7SAlfred Perlstein }
21475c3f70d7SAlfred Perlstein
21485c3f70d7SAlfred Perlstein /*
21490c14ff0eSRobert Watson * Free a cred structure. Throws away space when ref count gets to 0.
2150df8bae1dSRodney W. Grimes */
215126f9a767SRodney W. Grimes void
crfree(struct ucred * cr)21524c44ad8eSJohn Baldwin crfree(struct ucred *cr)
2153df8bae1dSRodney W. Grimes {
21541724c563SMateusz Guzik struct thread *td;
21551e5d626aSAlfred Perlstein
21561724c563SMateusz Guzik td = curthread;
2157a2de789eSMateusz Guzik if (__predict_true(td->td_realucred == cr)) {
21581724c563SMateusz Guzik KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
21591724c563SMateusz Guzik __func__, cr->cr_users, cr));
21601724c563SMateusz Guzik td->td_ucredref--;
21611724c563SMateusz Guzik return;
21621724c563SMateusz Guzik }
21631724c563SMateusz Guzik mtx_lock(&cr->cr_mtx);
21641724c563SMateusz Guzik KASSERT(cr->cr_users >= 0, ("%s: users %d not >= 0 on cred %p",
21651724c563SMateusz Guzik __func__, cr->cr_users, cr));
21661724c563SMateusz Guzik cr->cr_ref--;
21671724c563SMateusz Guzik if (cr->cr_users > 0) {
21681724c563SMateusz Guzik mtx_unlock(&cr->cr_mtx);
21691724c563SMateusz Guzik return;
21701724c563SMateusz Guzik }
217137337709SMateusz Guzik KASSERT(cr->cr_ref >= 0, ("%s: ref %ld not >= 0 on cred %p",
21721724c563SMateusz Guzik __func__, cr->cr_ref, cr));
21731724c563SMateusz Guzik if (cr->cr_ref > 0) {
21741724c563SMateusz Guzik mtx_unlock(&cr->cr_mtx);
21751724c563SMateusz Guzik return;
21761724c563SMateusz Guzik }
2177f34a2f56SMateusz Guzik crfree_final(cr);
2178f34a2f56SMateusz Guzik }
2179f34a2f56SMateusz Guzik
2180f34a2f56SMateusz Guzik static void
crfree_final(struct ucred * cr)2181f34a2f56SMateusz Guzik crfree_final(struct ucred *cr)
2182f34a2f56SMateusz Guzik {
2183f34a2f56SMateusz Guzik
2184f34a2f56SMateusz Guzik KASSERT(cr->cr_users == 0, ("%s: users %d not == 0 on cred %p",
2185f34a2f56SMateusz Guzik __func__, cr->cr_users, cr));
218637337709SMateusz Guzik KASSERT(cr->cr_ref == 0, ("%s: ref %ld not == 0 on cred %p",
2187f34a2f56SMateusz Guzik __func__, cr->cr_ref, cr));
21882f5b0b48SMateusz Guzik
2189f535380cSDon Lewis /*
21901724c563SMateusz Guzik * Some callers of crget(), such as nfs_statfs(), allocate a temporary
21911724c563SMateusz Guzik * credential, but don't allocate a uidinfo structure.
2192f535380cSDon Lewis */
2193f535380cSDon Lewis if (cr->cr_uidinfo != NULL)
2194f535380cSDon Lewis uifree(cr->cr_uidinfo);
2195823c224eSRobert Watson if (cr->cr_ruidinfo != NULL)
2196823c224eSRobert Watson uifree(cr->cr_ruidinfo);
21970304c731SJamie Gritton if (cr->cr_prison != NULL)
219891421ba2SRobert Watson prison_free(cr->cr_prison);
21992bfc50bcSEdward Tomasz Napierala if (cr->cr_loginclass != NULL)
22002bfc50bcSEdward Tomasz Napierala loginclass_free(cr->cr_loginclass);
2201faef5371SRobert Watson #ifdef AUDIT
2202faef5371SRobert Watson audit_cred_destroy(cr);
2203faef5371SRobert Watson #endif
220440244964SRobert Watson #ifdef MAC
220530d239bcSRobert Watson mac_cred_destroy(cr);
220640244964SRobert Watson #endif
22071724c563SMateusz Guzik mtx_destroy(&cr->cr_mtx);
2208a99500a9SMateusz Guzik if (cr->cr_groups != cr->cr_smallgroups)
2209838d9858SBrooks Davis free(cr->cr_groups, M_CRED);
22101ede983cSDag-Erling Smørgrav free(cr, M_CRED);
2211e1bca29fSMatthew Dillon }
2212df8bae1dSRodney W. Grimes
2213df8bae1dSRodney W. Grimes /*
2214bd78ceceSJohn Baldwin * Copy a ucred's contents from a template. Does not block.
2215bd78ceceSJohn Baldwin */
2216bd78ceceSJohn Baldwin void
crcopy(struct ucred * dest,struct ucred * src)22174c44ad8eSJohn Baldwin crcopy(struct ucred *dest, struct ucred *src)
2218bd78ceceSJohn Baldwin {
2219bd78ceceSJohn Baldwin
2220*169a1085SOlivier Certner /*
2221*169a1085SOlivier Certner * Ideally, 'cr_ngroups' should be moved out of 'struct ucred''s bcopied
2222*169a1085SOlivier Certner * area, but this would break the ABI, so is deferred until there is
2223*169a1085SOlivier Certner * a compelling need to change it.
2224*169a1085SOlivier Certner */
2225bd78ceceSJohn Baldwin bcopy(&src->cr_startcopy, &dest->cr_startcopy,
2226bd78ceceSJohn Baldwin (unsigned)((caddr_t)&src->cr_endcopy -
2227bd78ceceSJohn Baldwin (caddr_t)&src->cr_startcopy));
222837337709SMateusz Guzik dest->cr_flags = src->cr_flags;
2229838d9858SBrooks Davis crsetgroups(dest, src->cr_ngroups, src->cr_groups);
2230bd78ceceSJohn Baldwin uihold(dest->cr_uidinfo);
2231bd78ceceSJohn Baldwin uihold(dest->cr_ruidinfo);
2232bd78ceceSJohn Baldwin prison_hold(dest->cr_prison);
22332bfc50bcSEdward Tomasz Napierala loginclass_hold(dest->cr_loginclass);
2234faef5371SRobert Watson #ifdef AUDIT
2235faef5371SRobert Watson audit_cred_copy(src, dest);
2236faef5371SRobert Watson #endif
223740244964SRobert Watson #ifdef MAC
223830d239bcSRobert Watson mac_cred_copy(src, dest);
223940244964SRobert Watson #endif
2240df8bae1dSRodney W. Grimes }
2241df8bae1dSRodney W. Grimes
2242df8bae1dSRodney W. Grimes /*
2243df8bae1dSRodney W. Grimes * Dup cred struct to a new held one.
2244df8bae1dSRodney W. Grimes */
2245df8bae1dSRodney W. Grimes struct ucred *
crdup(struct ucred * cr)22464c44ad8eSJohn Baldwin crdup(struct ucred *cr)
2247df8bae1dSRodney W. Grimes {
2248df8bae1dSRodney W. Grimes struct ucred *newcr;
2249df8bae1dSRodney W. Grimes
2250bd78ceceSJohn Baldwin newcr = crget();
2251bd78ceceSJohn Baldwin crcopy(newcr, cr);
2252df8bae1dSRodney W. Grimes return (newcr);
2253df8bae1dSRodney W. Grimes }
2254df8bae1dSRodney W. Grimes
2255df8bae1dSRodney W. Grimes /*
225676183f34SDima Dorfman * Fill in a struct xucred based on a struct ucred.
225776183f34SDima Dorfman */
225876183f34SDima Dorfman void
cru2x(struct ucred * cr,struct xucred * xcr)22594c44ad8eSJohn Baldwin cru2x(struct ucred *cr, struct xucred *xcr)
226076183f34SDima Dorfman {
2261838d9858SBrooks Davis int ngroups;
226276183f34SDima Dorfman
226376183f34SDima Dorfman bzero(xcr, sizeof(*xcr));
226476183f34SDima Dorfman xcr->cr_version = XUCRED_VERSION;
226576183f34SDima Dorfman xcr->cr_uid = cr->cr_uid;
2266838d9858SBrooks Davis
2267838d9858SBrooks Davis ngroups = MIN(cr->cr_ngroups, XU_NGROUPS);
2268838d9858SBrooks Davis xcr->cr_ngroups = ngroups;
2269838d9858SBrooks Davis bcopy(cr->cr_groups, xcr->cr_groups,
2270838d9858SBrooks Davis ngroups * sizeof(*cr->cr_groups));
227176183f34SDima Dorfman }
227276183f34SDima Dorfman
2273c8124e20SDmitry Chagin void
cru2xt(struct thread * td,struct xucred * xcr)2274c5afec6eSDmitry Chagin cru2xt(struct thread *td, struct xucred *xcr)
2275c5afec6eSDmitry Chagin {
2276c5afec6eSDmitry Chagin
2277c5afec6eSDmitry Chagin cru2x(td->td_ucred, xcr);
2278c5afec6eSDmitry Chagin xcr->cr_pid = td->td_proc->p_pid;
2279c5afec6eSDmitry Chagin }
2280c5afec6eSDmitry Chagin
228176183f34SDima Dorfman /*
2282daf63fd2SMateusz Guzik * Change process credentials.
2283ffb34484SMateusz Guzik * Callers are responsible for providing the reference for passed credentials
2284daf63fd2SMateusz Guzik * and for freeing old ones.
2285daf63fd2SMateusz Guzik *
2286daf63fd2SMateusz Guzik * Process has to be locked except when it does not have credentials (as it
2287daf63fd2SMateusz Guzik * should not be visible just yet) or when newcred is NULL (as this can be
2288daf63fd2SMateusz Guzik * only used when the process is about to be freed, at which point it should
2289daf63fd2SMateusz Guzik * not be visible anymore).
2290daf63fd2SMateusz Guzik */
22916f836483SMateusz Guzik void
proc_set_cred(struct proc * p,struct ucred * newcred)2292daf63fd2SMateusz Guzik proc_set_cred(struct proc *p, struct ucred *newcred)
2293daf63fd2SMateusz Guzik {
22941724c563SMateusz Guzik struct ucred *cr;
2295daf63fd2SMateusz Guzik
22961724c563SMateusz Guzik cr = p->p_ucred;
22971724c563SMateusz Guzik MPASS(cr != NULL);
2298daf63fd2SMateusz Guzik PROC_LOCK_ASSERT(p, MA_OWNED);
22991724c563SMateusz Guzik KASSERT(newcred->cr_users == 0, ("%s: users %d not 0 on cred %p",
23001724c563SMateusz Guzik __func__, newcred->cr_users, newcred));
23011724c563SMateusz Guzik mtx_lock(&cr->cr_mtx);
23021724c563SMateusz Guzik KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
23031724c563SMateusz Guzik __func__, cr->cr_users, cr));
23041724c563SMateusz Guzik cr->cr_users--;
23051724c563SMateusz Guzik mtx_unlock(&cr->cr_mtx);
2306daf63fd2SMateusz Guzik p->p_ucred = newcred;
23071724c563SMateusz Guzik newcred->cr_users = 1;
23084ea6a9a2SMateusz Guzik PROC_UPDATE_COW(p);
2309daf63fd2SMateusz Guzik }
2310daf63fd2SMateusz Guzik
23115a90435cSMateusz Guzik void
proc_unset_cred(struct proc * p)23125a90435cSMateusz Guzik proc_unset_cred(struct proc *p)
23135a90435cSMateusz Guzik {
23145a90435cSMateusz Guzik struct ucred *cr;
23155a90435cSMateusz Guzik
23161724c563SMateusz Guzik MPASS(p->p_state == PRS_ZOMBIE || p->p_state == PRS_NEW);
23175a90435cSMateusz Guzik cr = p->p_ucred;
23185a90435cSMateusz Guzik p->p_ucred = NULL;
23191724c563SMateusz Guzik KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
23201724c563SMateusz Guzik __func__, cr->cr_users, cr));
23211724c563SMateusz Guzik mtx_lock(&cr->cr_mtx);
23221724c563SMateusz Guzik cr->cr_users--;
23231724c563SMateusz Guzik if (cr->cr_users == 0)
232437337709SMateusz Guzik KASSERT(cr->cr_ref > 0, ("%s: ref %ld not > 0 on cred %p",
23251724c563SMateusz Guzik __func__, cr->cr_ref, cr));
23261724c563SMateusz Guzik mtx_unlock(&cr->cr_mtx);
23275a90435cSMateusz Guzik crfree(cr);
23285a90435cSMateusz Guzik }
23295a90435cSMateusz Guzik
2330838d9858SBrooks Davis struct ucred *
crcopysafe(struct proc * p,struct ucred * cr)2331838d9858SBrooks Davis crcopysafe(struct proc *p, struct ucred *cr)
2332838d9858SBrooks Davis {
2333838d9858SBrooks Davis struct ucred *oldcred;
2334838d9858SBrooks Davis int groups;
2335838d9858SBrooks Davis
2336838d9858SBrooks Davis PROC_LOCK_ASSERT(p, MA_OWNED);
2337838d9858SBrooks Davis
2338838d9858SBrooks Davis oldcred = p->p_ucred;
2339838d9858SBrooks Davis while (cr->cr_agroups < oldcred->cr_agroups) {
2340838d9858SBrooks Davis groups = oldcred->cr_agroups;
2341838d9858SBrooks Davis PROC_UNLOCK(p);
2342838d9858SBrooks Davis crextend(cr, groups);
2343838d9858SBrooks Davis PROC_LOCK(p);
2344838d9858SBrooks Davis oldcred = p->p_ucred;
2345838d9858SBrooks Davis }
2346838d9858SBrooks Davis crcopy(cr, oldcred);
2347838d9858SBrooks Davis
2348838d9858SBrooks Davis return (oldcred);
2349838d9858SBrooks Davis }
2350838d9858SBrooks Davis
2351838d9858SBrooks Davis /*
2352ea26c0e7SOlivier Certner * Extend the passed-in credentials to hold n groups.
2353ea26c0e7SOlivier Certner *
2354ea26c0e7SOlivier Certner * Must not be called after groups have been set.
2355838d9858SBrooks Davis */
2356c8358c6eSGleb Smirnoff void
crextend(struct ucred * cr,int n)2357838d9858SBrooks Davis crextend(struct ucred *cr, int n)
2358838d9858SBrooks Davis {
2359ea26c0e7SOlivier Certner size_t nbytes;
2360838d9858SBrooks Davis
23616d2efbb3SOlivier Certner MPASS2(cr->cr_ref == 1, "'cr_ref' must be 1 (referenced, unshared)");
2362ea26c0e7SOlivier Certner MPASS2(cr->cr_ngroups == 0, "groups on 'cr' already set!");
2363ea26c0e7SOlivier Certner groups_check_positive_len(n);
2364ea26c0e7SOlivier Certner groups_check_max_len(n);
23656d2efbb3SOlivier Certner
2366838d9858SBrooks Davis if (n <= cr->cr_agroups)
2367838d9858SBrooks Davis return;
2368838d9858SBrooks Davis
2369ea26c0e7SOlivier Certner nbytes = n * sizeof(gid_t);
2370ea26c0e7SOlivier Certner if (nbytes < n)
2371ea26c0e7SOlivier Certner panic("Too many groups (memory size overflow)! "
2372ea26c0e7SOlivier Certner "Computation of 'kern.ngroups' should have prevented this, "
2373ea26c0e7SOlivier Certner "please fix it. In the meantime, reduce 'kern.ngroups'.");
2374838d9858SBrooks Davis
2375ea26c0e7SOlivier Certner /*
2376ea26c0e7SOlivier Certner * We allocate a power of 2 larger than 'nbytes', except when that
2377ea26c0e7SOlivier Certner * exceeds PAGE_SIZE, in which case we allocate the right multiple of
2378ea26c0e7SOlivier Certner * pages. We assume PAGE_SIZE is a power of 2 (the call to roundup2()
2379ea26c0e7SOlivier Certner * below) but do not need to for sizeof(gid_t).
2380ea26c0e7SOlivier Certner */
2381ea26c0e7SOlivier Certner if (nbytes < PAGE_SIZE) {
2382ea26c0e7SOlivier Certner if (!powerof2(nbytes))
2383ea26c0e7SOlivier Certner /* fls*() return a bit index starting at 1. */
2384ea26c0e7SOlivier Certner nbytes = 1 << flsl(nbytes);
2385838d9858SBrooks Davis } else
2386ea26c0e7SOlivier Certner nbytes = roundup2(nbytes, PAGE_SIZE);
2387838d9858SBrooks Davis
2388838d9858SBrooks Davis /* Free the old array. */
2389a99500a9SMateusz Guzik if (cr->cr_groups != cr->cr_smallgroups)
2390838d9858SBrooks Davis free(cr->cr_groups, M_CRED);
2391838d9858SBrooks Davis
2392ea26c0e7SOlivier Certner cr->cr_groups = malloc(nbytes, M_CRED, M_WAITOK | M_ZERO);
2393ea26c0e7SOlivier Certner cr->cr_agroups = nbytes / sizeof(gid_t);
2394838d9858SBrooks Davis }
2395838d9858SBrooks Davis
2396838d9858SBrooks Davis /*
23976d2efbb3SOlivier Certner * Normalizes a set of groups to be applied to a 'struct ucred'.
23986d2efbb3SOlivier Certner *
23996d2efbb3SOlivier Certner * The set of groups is an array that must comprise the effective GID as its
24006d2efbb3SOlivier Certner * first element (so its length cannot be 0).
24016d2efbb3SOlivier Certner *
24026d2efbb3SOlivier Certner * Normalization ensures that elements after the first, which stand for the
24036d2efbb3SOlivier Certner * supplementary groups, are sorted in ascending order and do not contain
24046d2efbb3SOlivier Certner * duplicates.
2405838d9858SBrooks Davis */
2406838d9858SBrooks Davis static void
groups_normalize(int * ngrp,gid_t * groups)24076d2efbb3SOlivier Certner groups_normalize(int *ngrp, gid_t *groups)
2408838d9858SBrooks Davis {
24096d2efbb3SOlivier Certner gid_t prev_g;
24106d2efbb3SOlivier Certner int ins_idx;
2411838d9858SBrooks Davis
24126d2efbb3SOlivier Certner groups_check_positive_len(*ngrp);
24136d2efbb3SOlivier Certner groups_check_max_len(*ngrp);
24146d2efbb3SOlivier Certner
24156d2efbb3SOlivier Certner if (*ngrp == 1)
24166d2efbb3SOlivier Certner return;
24176d2efbb3SOlivier Certner
24186d2efbb3SOlivier Certner qsort(groups + 1, *ngrp - 1, sizeof(*groups), gidp_cmp);
24196d2efbb3SOlivier Certner
24206d2efbb3SOlivier Certner /* Remove duplicates. */
24216d2efbb3SOlivier Certner prev_g = groups[1];
24226d2efbb3SOlivier Certner ins_idx = 2;
24236d2efbb3SOlivier Certner for (int i = 2; i < *ngrp; ++i) {
24246d2efbb3SOlivier Certner const gid_t g = groups[i];
24256d2efbb3SOlivier Certner
24266d2efbb3SOlivier Certner if (g != prev_g) {
24276d2efbb3SOlivier Certner if (i != ins_idx)
24286d2efbb3SOlivier Certner groups[ins_idx] = g;
24296d2efbb3SOlivier Certner ++ins_idx;
24306d2efbb3SOlivier Certner prev_g = g;
24316d2efbb3SOlivier Certner }
24326d2efbb3SOlivier Certner }
24336d2efbb3SOlivier Certner *ngrp = ins_idx;
24346d2efbb3SOlivier Certner
24356d2efbb3SOlivier Certner groups_check_normalized(*ngrp, groups);
24366d2efbb3SOlivier Certner }
24376d2efbb3SOlivier Certner
24386d2efbb3SOlivier Certner /*
24396d2efbb3SOlivier Certner * Internal function copying groups into a credential.
24406d2efbb3SOlivier Certner *
24416d2efbb3SOlivier Certner * 'ngrp' must be strictly positive. Either the passed 'groups' array must have
24426d2efbb3SOlivier Certner * been normalized in advance (see groups_normalize()), else it must be so
24436d2efbb3SOlivier Certner * before the structure is to be used again.
24446d2efbb3SOlivier Certner *
24456d2efbb3SOlivier Certner * This function is suitable to be used under any lock (it doesn't take any lock
24466d2efbb3SOlivier Certner * itself nor sleep, and in particular doesn't allocate memory). crextend()
24476d2efbb3SOlivier Certner * must have been called beforehand to ensure sufficient space is available.
24486d2efbb3SOlivier Certner * See also crsetgroups(), which handles that.
24496d2efbb3SOlivier Certner */
24506d2efbb3SOlivier Certner static void
crsetgroups_internal(struct ucred * cr,int ngrp,const gid_t * groups)24516d2efbb3SOlivier Certner crsetgroups_internal(struct ucred *cr, int ngrp, const gid_t *groups)
24526d2efbb3SOlivier Certner {
24536d2efbb3SOlivier Certner
24546d2efbb3SOlivier Certner MPASS2(cr->cr_ref == 1, "'cr_ref' must be 1 (referenced, unshared)");
24556d2efbb3SOlivier Certner MPASS2(cr->cr_agroups >= ngrp, "'cr_agroups' too small");
24566d2efbb3SOlivier Certner groups_check_positive_len(ngrp);
2457838d9858SBrooks Davis
2458838d9858SBrooks Davis bcopy(groups, cr->cr_groups, ngrp * sizeof(gid_t));
2459838d9858SBrooks Davis cr->cr_ngroups = ngrp;
2460838d9858SBrooks Davis }
2461838d9858SBrooks Davis
2462838d9858SBrooks Davis /*
2463838d9858SBrooks Davis * Copy groups in to a credential after expanding it if required.
24646d2efbb3SOlivier Certner *
24656d2efbb3SOlivier Certner * May sleep in order to allocate memory (except if, e.g., crextend() was called
24666d2efbb3SOlivier Certner * before with 'ngrp' or greater). Truncates the list to (ngroups_max + 1) if
24676d2efbb3SOlivier Certner * it is too large. Array 'groups' doesn't need to be sorted. 'ngrp' must be
24686d2efbb3SOlivier Certner * strictly positive.
2469838d9858SBrooks Davis */
2470838d9858SBrooks Davis void
crsetgroups(struct ucred * cr,int ngrp,const gid_t * groups)24716d2efbb3SOlivier Certner crsetgroups(struct ucred *cr, int ngrp, const gid_t *groups)
2472838d9858SBrooks Davis {
2473838d9858SBrooks Davis
2474412f9500SBrooks Davis if (ngrp > ngroups_max + 1)
2475412f9500SBrooks Davis ngrp = ngroups_max + 1;
2476*169a1085SOlivier Certner /*
2477*169a1085SOlivier Certner * crextend() asserts that groups are not set, as it may allocate a new
2478*169a1085SOlivier Certner * backing storage without copying the content of the old one. Since we
2479*169a1085SOlivier Certner * are going to install a completely new set anyway, signal that we
2480*169a1085SOlivier Certner * consider the old ones thrown away.
2481*169a1085SOlivier Certner */
2482*169a1085SOlivier Certner cr->cr_ngroups = 0;
2483838d9858SBrooks Davis crextend(cr, ngrp);
24846d2efbb3SOlivier Certner crsetgroups_internal(cr, ngrp, groups);
24856d2efbb3SOlivier Certner groups_normalize(&cr->cr_ngroups, cr->cr_groups);
2486838d9858SBrooks Davis }
2487838d9858SBrooks Davis
24882eb927e2SJulian Elischer /*
2489d4e0d4d9SOlivier Certner * Same as crsetgroups() but accepts an empty groups array.
2490d4e0d4d9SOlivier Certner *
2491d4e0d4d9SOlivier Certner * This function ensures that an effective GID is always present in credentials.
2492d4e0d4d9SOlivier Certner * An empty array is treated as a one-size one holding the passed effective GID
2493d4e0d4d9SOlivier Certner * fallback.
2494d4e0d4d9SOlivier Certner */
2495d4e0d4d9SOlivier Certner void
crsetgroups_fallback(struct ucred * cr,int ngrp,const gid_t * groups,const gid_t fallback)2496d4e0d4d9SOlivier Certner crsetgroups_fallback(struct ucred *cr, int ngrp, const gid_t *groups,
2497d4e0d4d9SOlivier Certner const gid_t fallback)
2498d4e0d4d9SOlivier Certner {
2499d4e0d4d9SOlivier Certner if (ngrp == 0)
2500d4e0d4d9SOlivier Certner /* Shortcut. */
2501d4e0d4d9SOlivier Certner crsetgroups_internal(cr, 1, &fallback);
2502d4e0d4d9SOlivier Certner else
2503d4e0d4d9SOlivier Certner crsetgroups(cr, ngrp, groups);
2504d4e0d4d9SOlivier Certner }
2505d4e0d4d9SOlivier Certner
2506d4e0d4d9SOlivier Certner /*
2507df8bae1dSRodney W. Grimes * Get login name, if available.
2508df8bae1dSRodney W. Grimes */
2509d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
2510df8bae1dSRodney W. Grimes struct getlogin_args {
2511df8bae1dSRodney W. Grimes char *namebuf;
2512df8bae1dSRodney W. Grimes u_int namelen;
2513df8bae1dSRodney W. Grimes };
2514d2d3e875SBruce Evans #endif
2515df8bae1dSRodney W. Grimes /* ARGSUSED */
251626f9a767SRodney W. Grimes int
sys_getlogin(struct thread * td,struct getlogin_args * uap)25178451d0ddSKip Macy sys_getlogin(struct thread *td, struct getlogin_args *uap)
2518df8bae1dSRodney W. Grimes {
2519f591779bSSeigo Tanimura char login[MAXLOGNAME];
2520b40ce416SJulian Elischer struct proc *p = td->td_proc;
2521bccb6d5aSDag-Erling Smørgrav size_t len;
2522df8bae1dSRodney W. Grimes
252330cf3ac4SAndrey A. Chernov if (uap->namelen > MAXLOGNAME)
252453490b76SAndrey A. Chernov uap->namelen = MAXLOGNAME;
2525f591779bSSeigo Tanimura PROC_LOCK(p);
2526f591779bSSeigo Tanimura SESS_LOCK(p->p_session);
2527bccb6d5aSDag-Erling Smørgrav len = strlcpy(login, p->p_session->s_login, uap->namelen) + 1;
2528f591779bSSeigo Tanimura SESS_UNLOCK(p->p_session);
2529f591779bSSeigo Tanimura PROC_UNLOCK(p);
2530bccb6d5aSDag-Erling Smørgrav if (len > uap->namelen)
25316f68699fSBaptiste Daroussin return (ERANGE);
2532bccb6d5aSDag-Erling Smørgrav return (copyout(login, uap->namebuf, len));
2533df8bae1dSRodney W. Grimes }
2534df8bae1dSRodney W. Grimes
2535df8bae1dSRodney W. Grimes /*
2536df8bae1dSRodney W. Grimes * Set login name.
2537df8bae1dSRodney W. Grimes */
2538d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
2539df8bae1dSRodney W. Grimes struct setlogin_args {
2540df8bae1dSRodney W. Grimes char *namebuf;
2541df8bae1dSRodney W. Grimes };
2542d2d3e875SBruce Evans #endif
2543df8bae1dSRodney W. Grimes /* ARGSUSED */
254426f9a767SRodney W. Grimes int
sys_setlogin(struct thread * td,struct setlogin_args * uap)25458451d0ddSKip Macy sys_setlogin(struct thread *td, struct setlogin_args *uap)
2546df8bae1dSRodney W. Grimes {
2547b40ce416SJulian Elischer struct proc *p = td->td_proc;
2548df8bae1dSRodney W. Grimes int error;
2549964ca0caSAndrey A. Chernov char logintmp[MAXLOGNAME];
2550df8bae1dSRodney W. Grimes
2551bccb6d5aSDag-Erling Smørgrav CTASSERT(sizeof(p->p_session->s_login) >= sizeof(logintmp));
2552bccb6d5aSDag-Erling Smørgrav
255332f9753cSRobert Watson error = priv_check(td, PRIV_PROC_SETLOGIN);
255407f3485dSJohn Baldwin if (error)
255507f3485dSJohn Baldwin return (error);
25567f05b035SAlfred Perlstein error = copyinstr(uap->namebuf, logintmp, sizeof(logintmp), NULL);
2557bccb6d5aSDag-Erling Smørgrav if (error != 0) {
2558eb725b4eSRobert Watson if (error == ENAMETOOLONG)
2559df8bae1dSRodney W. Grimes error = EINVAL;
2560bccb6d5aSDag-Erling Smørgrav return (error);
2561bccb6d5aSDag-Erling Smørgrav }
256270a98c11SRobert Watson AUDIT_ARG_LOGIN(logintmp);
2563f591779bSSeigo Tanimura PROC_LOCK(p);
2564f591779bSSeigo Tanimura SESS_LOCK(p->p_session);
2565bccb6d5aSDag-Erling Smørgrav strcpy(p->p_session->s_login, logintmp);
2566f591779bSSeigo Tanimura SESS_UNLOCK(p->p_session);
2567f591779bSSeigo Tanimura PROC_UNLOCK(p);
2568bccb6d5aSDag-Erling Smørgrav return (0);
2569df8bae1dSRodney W. Grimes }
2570d5f81602SSean Eric Fagan
2571d5f81602SSean Eric Fagan void
setsugid(struct proc * p)25724c44ad8eSJohn Baldwin setsugid(struct proc *p)
2573d5f81602SSean Eric Fagan {
2574f2102dadSAlfred Perlstein
2575f2102dadSAlfred Perlstein PROC_LOCK_ASSERT(p, MA_OWNED);
2576d5f81602SSean Eric Fagan p->p_flag |= P_SUGID;
2577d5f81602SSean Eric Fagan }
2578f535380cSDon Lewis
25791a996ed1SEdward Tomasz Napierala /*-
25807fd6a959SRobert Watson * Change a process's effective uid.
2581b1fc0ec1SRobert Watson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified.
2582b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the
2583b1fc0ec1SRobert Watson * duration of the call.
2584f535380cSDon Lewis */
2585f535380cSDon Lewis void
change_euid(struct ucred * newcred,struct uidinfo * euip)25861419eacbSAlfred Perlstein change_euid(struct ucred *newcred, struct uidinfo *euip)
2587f535380cSDon Lewis {
2588f535380cSDon Lewis
25891419eacbSAlfred Perlstein newcred->cr_uid = euip->ui_uid;
25901419eacbSAlfred Perlstein uihold(euip);
2591b1fc0ec1SRobert Watson uifree(newcred->cr_uidinfo);
25921419eacbSAlfred Perlstein newcred->cr_uidinfo = euip;
2593f535380cSDon Lewis }
2594f535380cSDon Lewis
25951a996ed1SEdward Tomasz Napierala /*-
25967fd6a959SRobert Watson * Change a process's effective gid.
2597b1fc0ec1SRobert Watson * Side effects: newcred->cr_gid will be modified.
2598b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the
2599b1fc0ec1SRobert Watson * duration of the call.
2600f535380cSDon Lewis */
2601810bfc8eSAndrew Gallatin void
change_egid(struct ucred * newcred,gid_t egid)26024c44ad8eSJohn Baldwin change_egid(struct ucred *newcred, gid_t egid)
2603b1fc0ec1SRobert Watson {
2604b1fc0ec1SRobert Watson
2605b1fc0ec1SRobert Watson newcred->cr_groups[0] = egid;
2606b1fc0ec1SRobert Watson }
2607b1fc0ec1SRobert Watson
26081a996ed1SEdward Tomasz Napierala /*-
26097fd6a959SRobert Watson * Change a process's real uid.
2610b1fc0ec1SRobert Watson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo
2611b1fc0ec1SRobert Watson * will be updated, and the old and new cr_ruidinfo proc
2612b1fc0ec1SRobert Watson * counts will be updated.
2613b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the
2614b1fc0ec1SRobert Watson * duration of the call.
2615b1fc0ec1SRobert Watson */
2616b1fc0ec1SRobert Watson void
change_ruid(struct ucred * newcred,struct uidinfo * ruip)26171419eacbSAlfred Perlstein change_ruid(struct ucred *newcred, struct uidinfo *ruip)
2618f535380cSDon Lewis {
2619f535380cSDon Lewis
2620b1fc0ec1SRobert Watson (void)chgproccnt(newcred->cr_ruidinfo, -1, 0);
26211419eacbSAlfred Perlstein newcred->cr_ruid = ruip->ui_uid;
26221419eacbSAlfred Perlstein uihold(ruip);
2623b1fc0ec1SRobert Watson uifree(newcred->cr_ruidinfo);
26241419eacbSAlfred Perlstein newcred->cr_ruidinfo = ruip;
2625b1fc0ec1SRobert Watson (void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
2626b1fc0ec1SRobert Watson }
2627b1fc0ec1SRobert Watson
26281a996ed1SEdward Tomasz Napierala /*-
26297fd6a959SRobert Watson * Change a process's real gid.
2630b1fc0ec1SRobert Watson * Side effects: newcred->cr_rgid will be updated.
2631b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the
2632b1fc0ec1SRobert Watson * duration of the call.
2633b1fc0ec1SRobert Watson */
2634b1fc0ec1SRobert Watson void
change_rgid(struct ucred * newcred,gid_t rgid)26354c44ad8eSJohn Baldwin change_rgid(struct ucred *newcred, gid_t rgid)
2636b1fc0ec1SRobert Watson {
2637b1fc0ec1SRobert Watson
2638b1fc0ec1SRobert Watson newcred->cr_rgid = rgid;
2639b1fc0ec1SRobert Watson }
2640b1fc0ec1SRobert Watson
26411a996ed1SEdward Tomasz Napierala /*-
26427fd6a959SRobert Watson * Change a process's saved uid.
2643b1fc0ec1SRobert Watson * Side effects: newcred->cr_svuid will be updated.
2644b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the
2645b1fc0ec1SRobert Watson * duration of the call.
2646b1fc0ec1SRobert Watson */
2647b1fc0ec1SRobert Watson void
change_svuid(struct ucred * newcred,uid_t svuid)26484c44ad8eSJohn Baldwin change_svuid(struct ucred *newcred, uid_t svuid)
2649b1fc0ec1SRobert Watson {
2650b1fc0ec1SRobert Watson
2651b1fc0ec1SRobert Watson newcred->cr_svuid = svuid;
2652b1fc0ec1SRobert Watson }
2653b1fc0ec1SRobert Watson
26541a996ed1SEdward Tomasz Napierala /*-
26557fd6a959SRobert Watson * Change a process's saved gid.
2656b1fc0ec1SRobert Watson * Side effects: newcred->cr_svgid will be updated.
2657b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the
2658b1fc0ec1SRobert Watson * duration of the call.
2659b1fc0ec1SRobert Watson */
2660b1fc0ec1SRobert Watson void
change_svgid(struct ucred * newcred,gid_t svgid)26614c44ad8eSJohn Baldwin change_svgid(struct ucred *newcred, gid_t svgid)
2662b1fc0ec1SRobert Watson {
2663b1fc0ec1SRobert Watson
2664b1fc0ec1SRobert Watson newcred->cr_svgid = svgid;
2665f535380cSDon Lewis }
2666fe6db727SKonstantin Belousov
2667fe6db727SKonstantin Belousov bool allow_ptrace = true;
2668fe6db727SKonstantin Belousov SYSCTL_BOOL(_security_bsd, OID_AUTO, allow_ptrace, CTLFLAG_RWTUN,
2669fe6db727SKonstantin Belousov &allow_ptrace, 0,
2670fe6db727SKonstantin Belousov "Deny ptrace(2) use by returning ENOSYS");
2671