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