kern_prot.c revision 145147
1139804Simp/*- 21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * (c) UNIX System Laboratories, Inc. 51541Srgrimes * All or some portions of this file are derived from material licensed 61541Srgrimes * to the University of California by American Telephone and Telegraph 71541Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 81541Srgrimes * the permission of UNIX System Laboratories, Inc. 987218Srwatson * Copyright (c) 2000-2001 Robert N. M. Watson. All rights reserved. 101541Srgrimes * 111541Srgrimes * Redistribution and use in source and binary forms, with or without 121541Srgrimes * modification, are permitted provided that the following conditions 131541Srgrimes * are met: 141541Srgrimes * 1. Redistributions of source code must retain the above copyright 151541Srgrimes * notice, this list of conditions and the following disclaimer. 161541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 171541Srgrimes * notice, this list of conditions and the following disclaimer in the 181541Srgrimes * documentation and/or other materials provided with the distribution. 191541Srgrimes * 4. Neither the name of the University nor the names of its contributors 201541Srgrimes * may be used to endorse or promote products derived from this software 211541Srgrimes * without specific prior written permission. 221541Srgrimes * 231541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 241541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 251541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 261541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 271541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 281541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 291541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 301541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 311541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 321541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 331541Srgrimes * SUCH DAMAGE. 341541Srgrimes * 351541Srgrimes * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 361541Srgrimes */ 371541Srgrimes 381541Srgrimes/* 391541Srgrimes * System calls related to processes and protection 401541Srgrimes */ 411541Srgrimes 42116182Sobrien#include <sys/cdefs.h> 43116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_prot.c 145147 2005-04-16 13:29:15Z rwatson $"); 44116182Sobrien 4531778Seivind#include "opt_compat.h" 46101001Srwatson#include "opt_mac.h" 4731778Seivind 481541Srgrimes#include <sys/param.h> 4976166Smarkm#include <sys/systm.h> 501541Srgrimes#include <sys/acct.h> 51132548Srwatson#include <sys/kdb.h> 5241059Speter#include <sys/kernel.h> 5370317Sjake#include <sys/lock.h> 54101173Srwatson#include <sys/mac.h> 5591140Stanimura#include <sys/malloc.h> 5676166Smarkm#include <sys/mutex.h> 5791140Stanimura#include <sys/sx.h> 581541Srgrimes#include <sys/proc.h> 5976166Smarkm#include <sys/sysproto.h> 6087218Srwatson#include <sys/jail.h> 6131891Ssef#include <sys/pioctl.h> 6265495Struckman#include <sys/resourcevar.h> 6392976Srwatson#include <sys/socket.h> 6492976Srwatson#include <sys/socketvar.h> 6561287Srwatson#include <sys/sysctl.h> 661541Srgrimes 6730354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials"); 6830354Sphk 6989414SarrSYSCTL_DECL(_security); 7089414SarrSYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0, 7187138Srwatson "BSD security policy"); 7287138Srwatson 7312221Sbde#ifndef _SYS_SYSPROTO_H_ 7411332Sswallacestruct getpid_args { 751541Srgrimes int dummy; 761541Srgrimes}; 7712221Sbde#endif 7858717Sdillon/* 7982749Sdillon * MPSAFE 8082749Sdillon */ 811541Srgrimes/* ARGSUSED */ 821549Srgrimesint 8393580Sjhbgetpid(struct thread *td, struct getpid_args *uap) 841541Srgrimes{ 8583366Sjulian struct proc *p = td->td_proc; 861541Srgrimes 8783366Sjulian td->td_retval[0] = p->p_pid; 88130344Sphk#if defined(COMPAT_43) 8974728Sjhb PROC_LOCK(p); 9083366Sjulian td->td_retval[1] = p->p_pptr->p_pid; 9174728Sjhb PROC_UNLOCK(p); 921541Srgrimes#endif 931541Srgrimes return (0); 941541Srgrimes} 951541Srgrimes 9612221Sbde#ifndef _SYS_SYSPROTO_H_ 9711332Sswallacestruct getppid_args { 9811332Sswallace int dummy; 9911332Sswallace}; 10012221Sbde#endif 10182749Sdillon/* 10282749Sdillon * MPSAFE 10382749Sdillon */ 1041541Srgrimes/* ARGSUSED */ 1051549Srgrimesint 10693580Sjhbgetppid(struct thread *td, struct getppid_args *uap) 1071541Srgrimes{ 10883366Sjulian struct proc *p = td->td_proc; 1091541Srgrimes 11074728Sjhb PROC_LOCK(p); 11183366Sjulian td->td_retval[0] = p->p_pptr->p_pid; 11274728Sjhb PROC_UNLOCK(p); 1131541Srgrimes return (0); 1141541Srgrimes} 1151541Srgrimes 11687466Srwatson/* 11787218Srwatson * Get process group ID; note that POSIX getpgrp takes no parameter. 11858717Sdillon */ 11912221Sbde#ifndef _SYS_SYSPROTO_H_ 12011332Sswallacestruct getpgrp_args { 12111332Sswallace int dummy; 12211332Sswallace}; 12312221Sbde#endif 12482749Sdillon/* 12582749Sdillon * MPSAFE 12682749Sdillon */ 1271549Srgrimesint 12893580Sjhbgetpgrp(struct thread *td, struct getpgrp_args *uap) 1291541Srgrimes{ 13083366Sjulian struct proc *p = td->td_proc; 1311541Srgrimes 13291140Stanimura PROC_LOCK(p); 13383366Sjulian td->td_retval[0] = p->p_pgrp->pg_id; 13491140Stanimura PROC_UNLOCK(p); 1351541Srgrimes return (0); 1361541Srgrimes} 1371541Srgrimes 13828401Speter/* Get an arbitary pid's process group id */ 13912221Sbde#ifndef _SYS_SYSPROTO_H_ 14028401Speterstruct getpgid_args { 14128401Speter pid_t pid; 14228401Speter}; 14328401Speter#endif 14482749Sdillon/* 14582749Sdillon * MPSAFE 14682749Sdillon */ 14728401Speterint 14893580Sjhbgetpgid(struct thread *td, struct getpgid_args *uap) 14928401Speter{ 150114031Sjhb struct proc *p; 15192985Sjhb int error; 15241726Struckman 15391140Stanimura if (uap->pid == 0) { 154114031Sjhb p = td->td_proc; 15591140Stanimura PROC_LOCK(p); 156114031Sjhb } else { 157114031Sjhb p = pfind(uap->pid); 158114031Sjhb if (p == NULL) 159114031Sjhb return (ESRCH); 160114031Sjhb error = p_cansee(td, p); 161114031Sjhb if (error) { 162114031Sjhb PROC_UNLOCK(p); 163114031Sjhb return (error); 164114031Sjhb } 16575893Sjhb } 166114031Sjhb td->td_retval[0] = p->p_pgrp->pg_id; 167114031Sjhb PROC_UNLOCK(p); 168114031Sjhb return (0); 16928401Speter} 17028401Speter 17128401Speter/* 17228401Speter * Get an arbitary pid's session id. 17328401Speter */ 17428401Speter#ifndef _SYS_SYSPROTO_H_ 17528401Speterstruct getsid_args { 17628401Speter pid_t pid; 17728401Speter}; 17828401Speter#endif 17982749Sdillon/* 18082749Sdillon * MPSAFE 18182749Sdillon */ 18228401Speterint 18393580Sjhbgetsid(struct thread *td, struct getsid_args *uap) 18428401Speter{ 185114031Sjhb struct proc *p; 18687218Srwatson int error; 18741726Struckman 18891140Stanimura if (uap->pid == 0) { 189114031Sjhb p = td->td_proc; 19091140Stanimura PROC_LOCK(p); 191114031Sjhb } else { 192114031Sjhb p = pfind(uap->pid); 193114031Sjhb if (p == NULL) 194114031Sjhb return (ESRCH); 195114031Sjhb error = p_cansee(td, p); 196114031Sjhb if (error) { 197114031Sjhb PROC_UNLOCK(p); 198114031Sjhb return (error); 199114031Sjhb } 20075893Sjhb } 201114031Sjhb td->td_retval[0] = p->p_session->s_sid; 202114031Sjhb PROC_UNLOCK(p); 203114031Sjhb return (0); 20428401Speter} 20528401Speter 20628401Speter#ifndef _SYS_SYSPROTO_H_ 20711332Sswallacestruct getuid_args { 20811332Sswallace int dummy; 20911332Sswallace}; 21012221Sbde#endif 21182749Sdillon/* 21282749Sdillon * MPSAFE 21382749Sdillon */ 2141541Srgrimes/* ARGSUSED */ 2151549Srgrimesint 21693580Sjhbgetuid(struct thread *td, struct getuid_args *uap) 2171541Srgrimes{ 2181541Srgrimes 21992987Sjhb td->td_retval[0] = td->td_ucred->cr_ruid; 220130344Sphk#if defined(COMPAT_43) 22192987Sjhb td->td_retval[1] = td->td_ucred->cr_uid; 2221541Srgrimes#endif 2231541Srgrimes return (0); 2241541Srgrimes} 2251541Srgrimes 22612221Sbde#ifndef _SYS_SYSPROTO_H_ 22711332Sswallacestruct geteuid_args { 22811332Sswallace int dummy; 22911332Sswallace}; 23012221Sbde#endif 23187218Srwatson/* 23287218Srwatson * MPSAFE 23387218Srwatson */ 2341541Srgrimes/* ARGSUSED */ 2351549Srgrimesint 23693580Sjhbgeteuid(struct thread *td, struct geteuid_args *uap) 2371541Srgrimes{ 23892987Sjhb 23992987Sjhb td->td_retval[0] = td->td_ucred->cr_uid; 2401541Srgrimes return (0); 2411541Srgrimes} 2421541Srgrimes 24312221Sbde#ifndef _SYS_SYSPROTO_H_ 24411332Sswallacestruct getgid_args { 24511332Sswallace int dummy; 24611332Sswallace}; 24712221Sbde#endif 24882749Sdillon/* 24982749Sdillon * MPSAFE 25082749Sdillon */ 2511541Srgrimes/* ARGSUSED */ 2521549Srgrimesint 25393580Sjhbgetgid(struct thread *td, struct getgid_args *uap) 2541541Srgrimes{ 2551541Srgrimes 25692987Sjhb td->td_retval[0] = td->td_ucred->cr_rgid; 257130344Sphk#if defined(COMPAT_43) 25892987Sjhb td->td_retval[1] = td->td_ucred->cr_groups[0]; 2591541Srgrimes#endif 2601541Srgrimes return (0); 2611541Srgrimes} 2621541Srgrimes 2631541Srgrimes/* 2641541Srgrimes * Get effective group ID. The "egid" is groups[0], and could be obtained 2651541Srgrimes * via getgroups. This syscall exists because it is somewhat painful to do 2661541Srgrimes * correctly in a library function. 2671541Srgrimes */ 26812221Sbde#ifndef _SYS_SYSPROTO_H_ 26911332Sswallacestruct getegid_args { 27011332Sswallace int dummy; 27111332Sswallace}; 27212221Sbde#endif 27382749Sdillon/* 27482749Sdillon * MPSAFE 27582749Sdillon */ 2761541Srgrimes/* ARGSUSED */ 2771549Srgrimesint 27893580Sjhbgetegid(struct thread *td, struct getegid_args *uap) 2791541Srgrimes{ 2801541Srgrimes 28192987Sjhb td->td_retval[0] = td->td_ucred->cr_groups[0]; 2821541Srgrimes return (0); 2831541Srgrimes} 2841541Srgrimes 28512221Sbde#ifndef _SYS_SYSPROTO_H_ 2861541Srgrimesstruct getgroups_args { 2871541Srgrimes u_int gidsetsize; 2881541Srgrimes gid_t *gidset; 2891541Srgrimes}; 29012221Sbde#endif 29182749Sdillon/* 29282749Sdillon * MPSAFE 29382749Sdillon */ 2941549Srgrimesint 29593580Sjhbgetgroups(struct thread *td, register struct getgroups_args *uap) 2961541Srgrimes{ 29782749Sdillon struct ucred *cred; 29877183Srwatson u_int ngrp; 29987218Srwatson int error; 3001541Srgrimes 30192987Sjhb cred = td->td_ucred; 3021541Srgrimes if ((ngrp = uap->gidsetsize) == 0) { 30383366Sjulian td->td_retval[0] = cred->cr_ngroups; 30492987Sjhb return (0); 3051541Srgrimes } 30692987Sjhb if (ngrp < cred->cr_ngroups) 30792987Sjhb return (EINVAL); 30877183Srwatson ngrp = cred->cr_ngroups; 30999009Salfred error = copyout(cred->cr_groups, uap->gidset, ngrp * sizeof(gid_t)); 31093264Sdillon if (error == 0) 31193557Sjhb td->td_retval[0] = ngrp; 31293264Sdillon return (error); 3131541Srgrimes} 3141541Srgrimes 31512221Sbde#ifndef _SYS_SYSPROTO_H_ 31612207Sbdestruct setsid_args { 31711332Sswallace int dummy; 31811332Sswallace}; 31912221Sbde#endif 32082749Sdillon/* 32182749Sdillon * MPSAFE 32282749Sdillon */ 3231541Srgrimes/* ARGSUSED */ 3241549Srgrimesint 32593580Sjhbsetsid(register struct thread *td, struct setsid_args *uap) 3261541Srgrimes{ 32791140Stanimura struct pgrp *pgrp; 32882749Sdillon int error; 32983366Sjulian struct proc *p = td->td_proc; 33091140Stanimura struct pgrp *newpgrp; 33191140Stanimura struct session *newsess; 3321541Srgrimes 33391140Stanimura error = 0; 33491140Stanimura pgrp = NULL; 33591140Stanimura 336111119Simp MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); 337111119Simp MALLOC(newsess, struct session *, sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO); 33891140Stanimura 33994859Sjhb sx_xlock(&proctree_lock); 34091140Stanimura 34191140Stanimura if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) { 34291140Stanimura if (pgrp != NULL) 34391140Stanimura PGRP_UNLOCK(pgrp); 34482749Sdillon error = EPERM; 34591140Stanimura } else { 34691140Stanimura (void)enterpgrp(p, p->p_pid, newpgrp, newsess); 34783366Sjulian td->td_retval[0] = p->p_pid; 34894859Sjhb newpgrp = NULL; 34994859Sjhb newsess = NULL; 3501541Srgrimes } 35191140Stanimura 35294859Sjhb sx_xunlock(&proctree_lock); 35391140Stanimura 35495973Stanimura if (newpgrp != NULL) 35595973Stanimura FREE(newpgrp, M_PGRP); 35695973Stanimura if (newsess != NULL) 35795973Stanimura FREE(newsess, M_SESSION); 35891140Stanimura 35994859Sjhb return (error); 3601541Srgrimes} 3611541Srgrimes 3621541Srgrimes/* 3631541Srgrimes * set process group (setpgid/old setpgrp) 3641541Srgrimes * 3651541Srgrimes * caller does setpgid(targpid, targpgid) 3661541Srgrimes * 3671541Srgrimes * pid must be caller or child of caller (ESRCH) 3681541Srgrimes * if a child 3691541Srgrimes * pid must be in same session (EPERM) 3701541Srgrimes * pid can't have done an exec (EACCES) 3711541Srgrimes * if pgid != pid 3721541Srgrimes * there must exist some pid in same session having pgid (EPERM) 3731541Srgrimes * pid must not be session leader (EPERM) 3741541Srgrimes */ 37512221Sbde#ifndef _SYS_SYSPROTO_H_ 3761541Srgrimesstruct setpgid_args { 37787218Srwatson int pid; /* target process id */ 37887218Srwatson int pgid; /* target pgrp id */ 3791541Srgrimes}; 38012221Sbde#endif 38182749Sdillon/* 38282749Sdillon * MPSAFE 38382749Sdillon */ 3841541Srgrimes/* ARGSUSED */ 3851549Srgrimesint 38693580Sjhbsetpgid(struct thread *td, register struct setpgid_args *uap) 3871541Srgrimes{ 38883366Sjulian struct proc *curp = td->td_proc; 38987218Srwatson register struct proc *targp; /* target process */ 39087218Srwatson register struct pgrp *pgrp; /* target pgrp */ 39175448Srwatson int error; 39291140Stanimura struct pgrp *newpgrp; 3931541Srgrimes 39420677Sbde if (uap->pgid < 0) 39520677Sbde return (EINVAL); 39691140Stanimura 39791140Stanimura error = 0; 39891140Stanimura 399111119Simp MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); 40091140Stanimura 40194859Sjhb sx_xlock(&proctree_lock); 4021541Srgrimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 40391140Stanimura if ((targp = pfind(uap->pid)) == NULL) { 40482749Sdillon error = ESRCH; 40594859Sjhb goto done; 40675893Sjhb } 40791140Stanimura if (!inferior(targp)) { 40891140Stanimura PROC_UNLOCK(targp); 40991371Stanimura error = ESRCH; 41094859Sjhb goto done; 41191140Stanimura } 412132568Srwatson if ((error = p_cansee(td, targp))) { 41375893Sjhb PROC_UNLOCK(targp); 41494859Sjhb goto done; 41575893Sjhb } 41675893Sjhb if (targp->p_pgrp == NULL || 41775893Sjhb targp->p_session != curp->p_session) { 41875893Sjhb PROC_UNLOCK(targp); 41982749Sdillon error = EPERM; 42094859Sjhb goto done; 42175893Sjhb } 42275893Sjhb if (targp->p_flag & P_EXEC) { 42375893Sjhb PROC_UNLOCK(targp); 42482749Sdillon error = EACCES; 42594859Sjhb goto done; 42675893Sjhb } 42791140Stanimura PROC_UNLOCK(targp); 42891140Stanimura } else 4291541Srgrimes targp = curp; 43075893Sjhb if (SESS_LEADER(targp)) { 43182749Sdillon error = EPERM; 43294859Sjhb goto done; 43375893Sjhb } 43487218Srwatson if (uap->pgid == 0) 4351541Srgrimes uap->pgid = targp->p_pid; 436117214Scognet if ((pgrp = pgfind(uap->pgid)) == NULL) { 437117214Scognet if (uap->pgid == targp->p_pid) { 438117214Scognet error = enterpgrp(targp, uap->pgid, newpgrp, 439117214Scognet NULL); 440117214Scognet if (error == 0) 441117214Scognet newpgrp = NULL; 442117214Scognet } else 443117214Scognet error = EPERM; 44491140Stanimura } else { 445117214Scognet if (pgrp == targp->p_pgrp) { 446117214Scognet PGRP_UNLOCK(pgrp); 44794859Sjhb goto done; 44875893Sjhb } 449117214Scognet if (pgrp->pg_id != targp->p_pid && 450117214Scognet pgrp->pg_session != curp->p_session) { 45191140Stanimura PGRP_UNLOCK(pgrp); 452117214Scognet error = EPERM; 45391140Stanimura goto done; 45491140Stanimura } 45591140Stanimura PGRP_UNLOCK(pgrp); 45691140Stanimura error = enterthispgrp(targp, pgrp); 45782749Sdillon } 45891140Stanimuradone: 45994859Sjhb sx_xunlock(&proctree_lock); 46094859Sjhb KASSERT((error == 0) || (newpgrp != NULL), 46194859Sjhb ("setpgid failed and newpgrp is NULL")); 46295973Stanimura if (newpgrp != NULL) 46391140Stanimura FREE(newpgrp, M_PGRP); 46482749Sdillon return (error); 4651541Srgrimes} 4661541Srgrimes 46724448Speter/* 46824448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 46972093Sasmodai * compatible. It says that setting the uid/gid to euid/egid is a special 47024448Speter * case of "appropriate privilege". Once the rules are expanded out, this 47124448Speter * basically means that setuid(nnn) sets all three id's, in all permitted 47224448Speter * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 47324448Speter * does not set the saved id - this is dangerous for traditional BSD 47424448Speter * programs. For this reason, we *really* do not want to set 47524448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 47624448Speter */ 47724448Speter#define POSIX_APPENDIX_B_4_2_2 47824448Speter 47912221Sbde#ifndef _SYS_SYSPROTO_H_ 4801541Srgrimesstruct setuid_args { 4811541Srgrimes uid_t uid; 4821541Srgrimes}; 48312221Sbde#endif 48482749Sdillon/* 48582749Sdillon * MPSAFE 48682749Sdillon */ 4871541Srgrimes/* ARGSUSED */ 4881549Srgrimesint 48993580Sjhbsetuid(struct thread *td, struct setuid_args *uap) 4901541Srgrimes{ 49183366Sjulian struct proc *p = td->td_proc; 49277183Srwatson struct ucred *newcred, *oldcred; 49377183Srwatson uid_t uid; 49498417Salfred struct uidinfo *uip; 49587218Srwatson int error; 4961541Srgrimes 49777183Srwatson uid = uap->uid; 49894619Sjhb newcred = crget(); 49998417Salfred uip = uifind(uid); 50094619Sjhb PROC_LOCK(p); 50187219Srwatson oldcred = p->p_ucred; 50287466Srwatson 503145147Srwatson#ifdef MAC 504145147Srwatson error = mac_check_proc_setuid(p, oldcred, uid); 505145147Srwatson if (error) 506145147Srwatson goto fail; 507145147Srwatson#endif 508145147Srwatson 50924448Speter /* 51024448Speter * See if we have "permission" by POSIX 1003.1 rules. 51124448Speter * 51287218Srwatson * Note that setuid(geteuid()) is a special case of 51324448Speter * "appropriate privileges" in appendix B.4.2.2. We need 51472093Sasmodai * to use this clause to be compatible with traditional BSD 51524448Speter * semantics. Basically, it means that "setuid(xx)" sets all 51624448Speter * three id's (assuming you have privs). 51724448Speter * 51824448Speter * Notes on the logic. We do things in three steps. 51924448Speter * 1: We determine if the euid is going to change, and do EPERM 52024448Speter * right away. We unconditionally change the euid later if this 52124448Speter * test is satisfied, simplifying that part of the logic. 52287218Srwatson * 2: We determine if the real and/or saved uids are going to 52324448Speter * change. Determined by compile options. 52424448Speter * 3: Change euid last. (after tests in #2 for "appropriate privs") 52524448Speter */ 52677183Srwatson if (uid != oldcred->cr_ruid && /* allow setuid(getuid()) */ 52717994Sache#ifdef _POSIX_SAVED_IDS 52877183Srwatson uid != oldcred->cr_svuid && /* allow setuid(saved gid) */ 52917994Sache#endif 53024448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 53177183Srwatson uid != oldcred->cr_uid && /* allow setuid(geteuid()) */ 53224448Speter#endif 533145147Srwatson (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) 534145147Srwatson goto fail; 53524448Speter 53698417Salfred /* 53798417Salfred * Copy credentials so other references do not see our changes. 53898417Salfred */ 53994619Sjhb crcopy(newcred, oldcred); 54024448Speter#ifdef _POSIX_SAVED_IDS 5411541Srgrimes /* 54224448Speter * Do we have "appropriate privileges" (are we root or uid == euid) 54324448Speter * If so, we are changing the real uid and/or saved uid. 5441541Srgrimes */ 54517994Sache if ( 54624448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 54777183Srwatson uid == oldcred->cr_uid || 54817994Sache#endif 549132653Scperciva suser_cred(oldcred, SUSER_ALLOWJAIL) == 0) /* we are using privs */ 55017994Sache#endif 55124448Speter { 55224448Speter /* 55365495Struckman * Set the real uid and transfer proc count to new user. 55424448Speter */ 55577183Srwatson if (uid != oldcred->cr_ruid) { 55698417Salfred change_ruid(newcred, uip); 55765495Struckman setsugid(p); 55824448Speter } 55924448Speter /* 56024448Speter * Set saved uid 56124448Speter * 56224448Speter * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 56324448Speter * the security of seteuid() depends on it. B.4.2.2 says it 56424448Speter * is important that we should do this. 56524448Speter */ 56677183Srwatson if (uid != oldcred->cr_svuid) { 56777183Srwatson change_svuid(newcred, uid); 56831891Ssef setsugid(p); 56924448Speter } 5708141Sache } 57124448Speter 57224448Speter /* 57324448Speter * In all permitted cases, we are changing the euid. 57424448Speter */ 57577183Srwatson if (uid != oldcred->cr_uid) { 57698417Salfred change_euid(newcred, uip); 57731891Ssef setsugid(p); 57824448Speter } 57977183Srwatson p->p_ucred = newcred; 58094619Sjhb PROC_UNLOCK(p); 58198417Salfred uifree(uip); 58277183Srwatson crfree(oldcred); 58394619Sjhb return (0); 584145147Srwatson 585145147Srwatsonfail: 586145147Srwatson PROC_UNLOCK(p); 587145147Srwatson uifree(uip); 588145147Srwatson crfree(newcred); 589145147Srwatson return (error); 5901541Srgrimes} 5911541Srgrimes 59212221Sbde#ifndef _SYS_SYSPROTO_H_ 5931541Srgrimesstruct seteuid_args { 5941541Srgrimes uid_t euid; 5951541Srgrimes}; 59612221Sbde#endif 59782749Sdillon/* 59882749Sdillon * MPSAFE 59982749Sdillon */ 6001541Srgrimes/* ARGSUSED */ 6011549Srgrimesint 60293580Sjhbseteuid(struct thread *td, struct seteuid_args *uap) 6031541Srgrimes{ 60483366Sjulian struct proc *p = td->td_proc; 60577183Srwatson struct ucred *newcred, *oldcred; 60677183Srwatson uid_t euid; 60798417Salfred struct uidinfo *euip; 60887218Srwatson int error; 6091541Srgrimes 6101541Srgrimes euid = uap->euid; 61194619Sjhb newcred = crget(); 61298417Salfred euip = uifind(euid); 61394619Sjhb PROC_LOCK(p); 61477183Srwatson oldcred = p->p_ucred; 615145147Srwatson 616145147Srwatson#ifdef MAC 617145147Srwatson error = mac_check_proc_seteuid(p, oldcred, euid); 618145147Srwatson if (error) 619145147Srwatson goto fail; 620145147Srwatson#endif 621145147Srwatson 62277183Srwatson if (euid != oldcred->cr_ruid && /* allow seteuid(getuid()) */ 62377183Srwatson euid != oldcred->cr_svuid && /* allow seteuid(saved uid) */ 624145147Srwatson (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) 625145147Srwatson goto fail; 626145147Srwatson 6271541Srgrimes /* 6281541Srgrimes * Everything's okay, do it. Copy credentials so other references do 6291541Srgrimes * not see our changes. 6301541Srgrimes */ 63194619Sjhb crcopy(newcred, oldcred); 63277183Srwatson if (oldcred->cr_uid != euid) { 63398417Salfred change_euid(newcred, euip); 63431891Ssef setsugid(p); 63524449Speter } 63677183Srwatson p->p_ucred = newcred; 63794619Sjhb PROC_UNLOCK(p); 63898417Salfred uifree(euip); 63977183Srwatson crfree(oldcred); 64094619Sjhb return (0); 641145147Srwatson 642145147Srwatsonfail: 643145147Srwatson PROC_UNLOCK(p); 644145147Srwatson uifree(euip); 645145147Srwatson crfree(newcred); 646145147Srwatson return (error); 6471541Srgrimes} 6481541Srgrimes 64912221Sbde#ifndef _SYS_SYSPROTO_H_ 6501541Srgrimesstruct setgid_args { 6511541Srgrimes gid_t gid; 6521541Srgrimes}; 65312221Sbde#endif 65482749Sdillon/* 65582749Sdillon * MPSAFE 65682749Sdillon */ 6571541Srgrimes/* ARGSUSED */ 6581549Srgrimesint 65993580Sjhbsetgid(struct thread *td, struct setgid_args *uap) 6601541Srgrimes{ 66183366Sjulian struct proc *p = td->td_proc; 66277183Srwatson struct ucred *newcred, *oldcred; 66377183Srwatson gid_t gid; 66487218Srwatson int error; 6651541Srgrimes 66677183Srwatson gid = uap->gid; 66794619Sjhb newcred = crget(); 66894619Sjhb PROC_LOCK(p); 66977183Srwatson oldcred = p->p_ucred; 67087466Srwatson 671145147Srwatson#ifdef MAC 672145147Srwatson error = mac_check_proc_setgid(p, oldcred, gid); 673145147Srwatson if (error) 674145147Srwatson goto fail; 675145147Srwatson#endif 676145147Srwatson 67724448Speter /* 67824448Speter * See if we have "permission" by POSIX 1003.1 rules. 67924448Speter * 68024448Speter * Note that setgid(getegid()) is a special case of 68124448Speter * "appropriate privileges" in appendix B.4.2.2. We need 68272093Sasmodai * to use this clause to be compatible with traditional BSD 68324448Speter * semantics. Basically, it means that "setgid(xx)" sets all 68424448Speter * three id's (assuming you have privs). 68524448Speter * 68624448Speter * For notes on the logic here, see setuid() above. 68724448Speter */ 68877183Srwatson if (gid != oldcred->cr_rgid && /* allow setgid(getgid()) */ 68917994Sache#ifdef _POSIX_SAVED_IDS 69077183Srwatson gid != oldcred->cr_svgid && /* allow setgid(saved gid) */ 69117994Sache#endif 69224448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 69377183Srwatson gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */ 69424448Speter#endif 695145147Srwatson (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) 696145147Srwatson goto fail; 69724448Speter 69894619Sjhb crcopy(newcred, oldcred); 69917994Sache#ifdef _POSIX_SAVED_IDS 70024448Speter /* 70124448Speter * Do we have "appropriate privileges" (are we root or gid == egid) 70224448Speter * If so, we are changing the real uid and saved gid. 70324448Speter */ 70424448Speter if ( 70524448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 70677183Srwatson gid == oldcred->cr_groups[0] || 70717994Sache#endif 708132653Scperciva suser_cred(oldcred, SUSER_ALLOWJAIL) == 0) /* we are using privs */ 70924448Speter#endif 71024448Speter { 71124448Speter /* 71224448Speter * Set real gid 71324448Speter */ 71477183Srwatson if (oldcred->cr_rgid != gid) { 71577183Srwatson change_rgid(newcred, gid); 71631891Ssef setsugid(p); 71724448Speter } 71824448Speter /* 71924448Speter * Set saved gid 72024448Speter * 72124448Speter * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 72224448Speter * the security of setegid() depends on it. B.4.2.2 says it 72324448Speter * is important that we should do this. 72424448Speter */ 72577183Srwatson if (oldcred->cr_svgid != gid) { 72677183Srwatson change_svgid(newcred, gid); 72731891Ssef setsugid(p); 72824448Speter } 7298141Sache } 73024448Speter /* 73124448Speter * In all cases permitted cases, we are changing the egid. 73224448Speter * Copy credentials so other references do not see our changes. 73324448Speter */ 73477183Srwatson if (oldcred->cr_groups[0] != gid) { 73577183Srwatson change_egid(newcred, gid); 73631891Ssef setsugid(p); 73724448Speter } 73877183Srwatson p->p_ucred = newcred; 73994619Sjhb PROC_UNLOCK(p); 74077183Srwatson crfree(oldcred); 74194619Sjhb return (0); 742145147Srwatson 743145147Srwatsonfail: 744145147Srwatson PROC_UNLOCK(p); 745145147Srwatson crfree(newcred); 746145147Srwatson return (error); 7471541Srgrimes} 7481541Srgrimes 74912221Sbde#ifndef _SYS_SYSPROTO_H_ 7501541Srgrimesstruct setegid_args { 7511541Srgrimes gid_t egid; 7521541Srgrimes}; 75312221Sbde#endif 75482749Sdillon/* 75582749Sdillon * MPSAFE 75682749Sdillon */ 7571541Srgrimes/* ARGSUSED */ 7581549Srgrimesint 75993580Sjhbsetegid(struct thread *td, struct setegid_args *uap) 7601541Srgrimes{ 76183366Sjulian struct proc *p = td->td_proc; 76277183Srwatson struct ucred *newcred, *oldcred; 76377183Srwatson gid_t egid; 76487218Srwatson int error; 7651541Srgrimes 7661541Srgrimes egid = uap->egid; 76794619Sjhb newcred = crget(); 76894619Sjhb PROC_LOCK(p); 76977183Srwatson oldcred = p->p_ucred; 770145147Srwatson 771145147Srwatson#ifdef MAC 772145147Srwatson error = mac_check_proc_setegid(p, oldcred, egid); 773145147Srwatson if (error) 774145147Srwatson goto fail; 775145147Srwatson#endif 776145147Srwatson 77777183Srwatson if (egid != oldcred->cr_rgid && /* allow setegid(getgid()) */ 77877183Srwatson egid != oldcred->cr_svgid && /* allow setegid(saved gid) */ 779145147Srwatson (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) 780145147Srwatson goto fail; 781145147Srwatson 78294619Sjhb crcopy(newcred, oldcred); 78377183Srwatson if (oldcred->cr_groups[0] != egid) { 78477183Srwatson change_egid(newcred, egid); 78531891Ssef setsugid(p); 78624449Speter } 78777183Srwatson p->p_ucred = newcred; 78894619Sjhb PROC_UNLOCK(p); 78977183Srwatson crfree(oldcred); 79094619Sjhb return (0); 791145147Srwatson 792145147Srwatsonfail: 793145147Srwatson PROC_UNLOCK(p); 794145147Srwatson crfree(newcred); 795145147Srwatson return (error); 7961541Srgrimes} 7971541Srgrimes 79812221Sbde#ifndef _SYS_SYSPROTO_H_ 7991541Srgrimesstruct setgroups_args { 8001541Srgrimes u_int gidsetsize; 8011541Srgrimes gid_t *gidset; 8021541Srgrimes}; 80312221Sbde#endif 80482749Sdillon/* 80582749Sdillon * MPSAFE 80682749Sdillon */ 8071541Srgrimes/* ARGSUSED */ 8081549Srgrimesint 80993580Sjhbsetgroups(struct thread *td, struct setgroups_args *uap) 8101541Srgrimes{ 81183366Sjulian struct proc *p = td->td_proc; 81294619Sjhb struct ucred *newcred, *tempcred, *oldcred; 81377183Srwatson u_int ngrp; 8141541Srgrimes int error; 8151541Srgrimes 81687220Srwatson ngrp = uap->gidsetsize; 81794619Sjhb if (ngrp > NGROUPS) 81894619Sjhb return (EINVAL); 81994619Sjhb tempcred = crget(); 82099009Salfred error = copyin(uap->gidset, tempcred->cr_groups, ngrp * sizeof(gid_t)); 82194619Sjhb if (error != 0) { 82294619Sjhb crfree(tempcred); 82394619Sjhb return (error); 82494619Sjhb } 82594619Sjhb newcred = crget(); 82694619Sjhb PROC_LOCK(p); 82777183Srwatson oldcred = p->p_ucred; 828145147Srwatson 829145147Srwatson#ifdef MAC 830145147Srwatson error = mac_check_proc_setgroups(p, oldcred, ngrp, 831145147Srwatson tempcred->cr_groups); 832145147Srwatson if (error) 833145147Srwatson goto fail; 834145147Srwatson#endif 835145147Srwatson 836132653Scperciva error = suser_cred(oldcred, SUSER_ALLOWJAIL); 837145147Srwatson if (error) 838145147Srwatson goto fail; 839145147Srwatson 84024447Speter /* 84124447Speter * XXX A little bit lazy here. We could test if anything has 84224447Speter * changed before crcopy() and setting P_SUGID. 84324447Speter */ 84494619Sjhb crcopy(newcred, oldcred); 84524447Speter if (ngrp < 1) { 84624447Speter /* 84724447Speter * setgroups(0, NULL) is a legitimate way of clearing the 84824447Speter * groups vector on non-BSD systems (which generally do not 84924447Speter * have the egid in the groups[0]). We risk security holes 85024447Speter * when running non-BSD software if we do not do the same. 85124447Speter */ 85277183Srwatson newcred->cr_ngroups = 1; 85324447Speter } else { 85494619Sjhb bcopy(tempcred->cr_groups, newcred->cr_groups, 85594619Sjhb ngrp * sizeof(gid_t)); 85677183Srwatson newcred->cr_ngroups = ngrp; 85724447Speter } 85831891Ssef setsugid(p); 85977183Srwatson p->p_ucred = newcred; 86094619Sjhb PROC_UNLOCK(p); 86194619Sjhb crfree(tempcred); 86277183Srwatson crfree(oldcred); 86394619Sjhb return (0); 864145147Srwatson 865145147Srwatsonfail: 866145147Srwatson PROC_UNLOCK(p); 867145147Srwatson crfree(newcred); 868145147Srwatson crfree(tempcred); 869145147Srwatson return (error); 8701541Srgrimes} 8711541Srgrimes 87212221Sbde#ifndef _SYS_SYSPROTO_H_ 8731541Srgrimesstruct setreuid_args { 8749238Sache uid_t ruid; 8759238Sache uid_t euid; 8761541Srgrimes}; 87712221Sbde#endif 87882749Sdillon/* 87982749Sdillon * MPSAFE 88082749Sdillon */ 8811541Srgrimes/* ARGSUSED */ 8821549Srgrimesint 88393580Sjhbsetreuid(register struct thread *td, struct setreuid_args *uap) 8841541Srgrimes{ 88583366Sjulian struct proc *p = td->td_proc; 88677183Srwatson struct ucred *newcred, *oldcred; 88787218Srwatson uid_t euid, ruid; 88898417Salfred struct uidinfo *euip, *ruip; 88987218Srwatson int error; 8901541Srgrimes 89187218Srwatson euid = uap->euid; 8929238Sache ruid = uap->ruid; 89394619Sjhb newcred = crget(); 89498417Salfred euip = uifind(euid); 89598417Salfred ruip = uifind(ruid); 89694619Sjhb PROC_LOCK(p); 89777183Srwatson oldcred = p->p_ucred; 898145147Srwatson 899145147Srwatson#ifdef MAC 900145147Srwatson error = mac_check_proc_setreuid(p, oldcred, ruid, euid); 901145147Srwatson if (error) 902145147Srwatson goto fail; 903145147Srwatson#endif 904145147Srwatson 90577183Srwatson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 90677183Srwatson ruid != oldcred->cr_svuid) || 90777183Srwatson (euid != (uid_t)-1 && euid != oldcred->cr_uid && 90877183Srwatson euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) && 909145147Srwatson (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) 910145147Srwatson goto fail; 911145147Srwatson 91294619Sjhb crcopy(newcred, oldcred); 91377183Srwatson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 91498417Salfred change_euid(newcred, euip); 91531891Ssef setsugid(p); 91624450Speter } 91777183Srwatson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 91898417Salfred change_ruid(newcred, ruip); 91931891Ssef setsugid(p); 9208135Sache } 92177183Srwatson if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) && 92277183Srwatson newcred->cr_svuid != newcred->cr_uid) { 92377183Srwatson change_svuid(newcred, newcred->cr_uid); 92431891Ssef setsugid(p); 92524450Speter } 92677183Srwatson p->p_ucred = newcred; 92794619Sjhb PROC_UNLOCK(p); 92898417Salfred uifree(ruip); 92998417Salfred uifree(euip); 93077183Srwatson crfree(oldcred); 93194619Sjhb return (0); 932145147Srwatson 933145147Srwatsonfail: 934145147Srwatson PROC_UNLOCK(p); 935145147Srwatson uifree(ruip); 936145147Srwatson uifree(euip); 937145147Srwatson crfree(newcred); 938145147Srwatson return (error); 9391541Srgrimes} 9401541Srgrimes 94112221Sbde#ifndef _SYS_SYSPROTO_H_ 9421541Srgrimesstruct setregid_args { 9439238Sache gid_t rgid; 9449238Sache gid_t egid; 9451541Srgrimes}; 94612221Sbde#endif 94782749Sdillon/* 94882749Sdillon * MPSAFE 94982749Sdillon */ 9501541Srgrimes/* ARGSUSED */ 9511549Srgrimesint 95293580Sjhbsetregid(register struct thread *td, struct setregid_args *uap) 9531541Srgrimes{ 95483366Sjulian struct proc *p = td->td_proc; 95577183Srwatson struct ucred *newcred, *oldcred; 95687218Srwatson gid_t egid, rgid; 95787218Srwatson int error; 9581541Srgrimes 95987218Srwatson egid = uap->egid; 9609238Sache rgid = uap->rgid; 96194619Sjhb newcred = crget(); 96294619Sjhb PROC_LOCK(p); 96377183Srwatson oldcred = p->p_ucred; 964145147Srwatson 965145147Srwatson#ifdef MAC 966145147Srwatson error = mac_check_proc_setregid(p, oldcred, rgid, egid); 967145147Srwatson if (error) 968145147Srwatson goto fail; 969145147Srwatson#endif 970145147Srwatson 97177183Srwatson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 97277183Srwatson rgid != oldcred->cr_svgid) || 97377183Srwatson (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] && 97477183Srwatson egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) && 975145147Srwatson (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) 976145147Srwatson goto fail; 97794619Sjhb 97894619Sjhb crcopy(newcred, oldcred); 97977183Srwatson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 98077183Srwatson change_egid(newcred, egid); 98131891Ssef setsugid(p); 98224450Speter } 98377183Srwatson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 98477183Srwatson change_rgid(newcred, rgid); 98531891Ssef setsugid(p); 98624450Speter } 98777183Srwatson if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) && 98877183Srwatson newcred->cr_svgid != newcred->cr_groups[0]) { 98977183Srwatson change_svgid(newcred, newcred->cr_groups[0]); 99031891Ssef setsugid(p); 99124450Speter } 99277812Sru p->p_ucred = newcred; 99394619Sjhb PROC_UNLOCK(p); 99477812Sru crfree(oldcred); 99594619Sjhb return (0); 996145147Srwatson 997145147Srwatsonfail: 998145147Srwatson PROC_UNLOCK(p); 999145147Srwatson crfree(newcred); 1000145147Srwatson return (error); 10011541Srgrimes} 10021541Srgrimes 100356115Speter/* 100456115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the 100556115Speter * saved uid is explicit. 100656115Speter */ 100756115Speter 100824453Speter#ifndef _SYS_SYSPROTO_H_ 100956115Speterstruct setresuid_args { 101056115Speter uid_t ruid; 101156115Speter uid_t euid; 101256115Speter uid_t suid; 101356115Speter}; 101456115Speter#endif 101582749Sdillon/* 101682749Sdillon * MPSAFE 101782749Sdillon */ 101856115Speter/* ARGSUSED */ 101956115Speterint 102093580Sjhbsetresuid(register struct thread *td, struct setresuid_args *uap) 102156115Speter{ 102283366Sjulian struct proc *p = td->td_proc; 102377183Srwatson struct ucred *newcred, *oldcred; 102487218Srwatson uid_t euid, ruid, suid; 102598417Salfred struct uidinfo *euip, *ruip; 102656115Speter int error; 102756115Speter 102887218Srwatson euid = uap->euid; 102956115Speter ruid = uap->ruid; 103056115Speter suid = uap->suid; 103194619Sjhb newcred = crget(); 103298417Salfred euip = uifind(euid); 103398417Salfred ruip = uifind(ruid); 103494619Sjhb PROC_LOCK(p); 103577183Srwatson oldcred = p->p_ucred; 1036145147Srwatson 1037145147Srwatson#ifdef MAC 1038145147Srwatson error = mac_check_proc_setresuid(p, oldcred, ruid, euid, suid); 1039145147Srwatson if (error) 1040145147Srwatson goto fail; 1041145147Srwatson#endif 1042145147Srwatson 104377183Srwatson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 104477183Srwatson ruid != oldcred->cr_svuid && 104577183Srwatson ruid != oldcred->cr_uid) || 104677183Srwatson (euid != (uid_t)-1 && euid != oldcred->cr_ruid && 104777183Srwatson euid != oldcred->cr_svuid && 104877183Srwatson euid != oldcred->cr_uid) || 104977183Srwatson (suid != (uid_t)-1 && suid != oldcred->cr_ruid && 105077183Srwatson suid != oldcred->cr_svuid && 105177183Srwatson suid != oldcred->cr_uid)) && 1052145147Srwatson (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) 1053145147Srwatson goto fail; 105494619Sjhb 105594619Sjhb crcopy(newcred, oldcred); 105677183Srwatson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 105798417Salfred change_euid(newcred, euip); 105856115Speter setsugid(p); 105956115Speter } 106077183Srwatson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 106198417Salfred change_ruid(newcred, ruip); 106256115Speter setsugid(p); 106356115Speter } 106477183Srwatson if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) { 106577183Srwatson change_svuid(newcred, suid); 106656115Speter setsugid(p); 106756115Speter } 106877183Srwatson p->p_ucred = newcred; 106994619Sjhb PROC_UNLOCK(p); 107098417Salfred uifree(ruip); 107198417Salfred uifree(euip); 107277183Srwatson crfree(oldcred); 107394619Sjhb return (0); 1074145147Srwatson 1075145147Srwatsonfail: 1076145147Srwatson PROC_UNLOCK(p); 1077145147Srwatson uifree(ruip); 1078145147Srwatson uifree(euip); 1079145147Srwatson crfree(newcred); 1080145147Srwatson return (error); 1081145147Srwatson 108256115Speter} 108356115Speter 108456115Speter/* 108556115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the 108656115Speter * saved gid is explicit. 108756115Speter */ 108856115Speter 108956115Speter#ifndef _SYS_SYSPROTO_H_ 109056115Speterstruct setresgid_args { 109156115Speter gid_t rgid; 109256115Speter gid_t egid; 109356115Speter gid_t sgid; 109456115Speter}; 109556115Speter#endif 109687466Srwatson/* 109782749Sdillon * MPSAFE 109882749Sdillon */ 109956115Speter/* ARGSUSED */ 110056115Speterint 110193580Sjhbsetresgid(register struct thread *td, struct setresgid_args *uap) 110256115Speter{ 110383366Sjulian struct proc *p = td->td_proc; 110477183Srwatson struct ucred *newcred, *oldcred; 110587218Srwatson gid_t egid, rgid, sgid; 110656115Speter int error; 110756115Speter 110887218Srwatson egid = uap->egid; 110956115Speter rgid = uap->rgid; 111056115Speter sgid = uap->sgid; 111194619Sjhb newcred = crget(); 111294619Sjhb PROC_LOCK(p); 111377183Srwatson oldcred = p->p_ucred; 1114145147Srwatson 1115145147Srwatson#ifdef MAC 1116145147Srwatson error = mac_check_proc_setresgid(p, oldcred, rgid, egid, sgid); 1117145147Srwatson if (error) 1118145147Srwatson goto fail; 1119145147Srwatson#endif 1120145147Srwatson 112177183Srwatson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 112277183Srwatson rgid != oldcred->cr_svgid && 112377183Srwatson rgid != oldcred->cr_groups[0]) || 112477183Srwatson (egid != (gid_t)-1 && egid != oldcred->cr_rgid && 112577183Srwatson egid != oldcred->cr_svgid && 112677183Srwatson egid != oldcred->cr_groups[0]) || 112777183Srwatson (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid && 112877183Srwatson sgid != oldcred->cr_svgid && 112977183Srwatson sgid != oldcred->cr_groups[0])) && 1130145147Srwatson (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) 1131145147Srwatson goto fail; 113294619Sjhb 113394619Sjhb crcopy(newcred, oldcred); 113477183Srwatson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 113577183Srwatson change_egid(newcred, egid); 113656115Speter setsugid(p); 113756115Speter } 113877183Srwatson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 113977183Srwatson change_rgid(newcred, rgid); 114056115Speter setsugid(p); 114156115Speter } 114277183Srwatson if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) { 114377183Srwatson change_svgid(newcred, sgid); 114456115Speter setsugid(p); 114556115Speter } 114677183Srwatson p->p_ucred = newcred; 114794619Sjhb PROC_UNLOCK(p); 114877183Srwatson crfree(oldcred); 114994619Sjhb return (0); 1150145147Srwatson 1151145147Srwatsonfail: 1152145147Srwatson PROC_UNLOCK(p); 1153145147Srwatson crfree(newcred); 1154145147Srwatson return (error); 115556115Speter} 115656115Speter 115756115Speter#ifndef _SYS_SYSPROTO_H_ 115856115Speterstruct getresuid_args { 115956115Speter uid_t *ruid; 116056115Speter uid_t *euid; 116156115Speter uid_t *suid; 116256115Speter}; 116356115Speter#endif 116482749Sdillon/* 116582749Sdillon * MPSAFE 116682749Sdillon */ 116756115Speter/* ARGSUSED */ 116856115Speterint 116993580Sjhbgetresuid(register struct thread *td, struct getresuid_args *uap) 117056115Speter{ 117182749Sdillon struct ucred *cred; 117256115Speter int error1 = 0, error2 = 0, error3 = 0; 117356115Speter 117493264Sdillon cred = td->td_ucred; 117556115Speter if (uap->ruid) 117699009Salfred error1 = copyout(&cred->cr_ruid, 117799009Salfred uap->ruid, sizeof(cred->cr_ruid)); 117856115Speter if (uap->euid) 117999009Salfred error2 = copyout(&cred->cr_uid, 118099009Salfred uap->euid, sizeof(cred->cr_uid)); 118156115Speter if (uap->suid) 118299009Salfred error3 = copyout(&cred->cr_svuid, 118399009Salfred uap->suid, sizeof(cred->cr_svuid)); 118487218Srwatson return (error1 ? error1 : error2 ? error2 : error3); 118556115Speter} 118656115Speter 118756115Speter#ifndef _SYS_SYSPROTO_H_ 118856115Speterstruct getresgid_args { 118956115Speter gid_t *rgid; 119056115Speter gid_t *egid; 119156115Speter gid_t *sgid; 119256115Speter}; 119356115Speter#endif 119482749Sdillon/* 119582749Sdillon * MPSAFE 119682749Sdillon */ 119756115Speter/* ARGSUSED */ 119856115Speterint 119993580Sjhbgetresgid(register struct thread *td, struct getresgid_args *uap) 120056115Speter{ 120182749Sdillon struct ucred *cred; 120256115Speter int error1 = 0, error2 = 0, error3 = 0; 120356115Speter 120493264Sdillon cred = td->td_ucred; 120556115Speter if (uap->rgid) 120699009Salfred error1 = copyout(&cred->cr_rgid, 120799009Salfred uap->rgid, sizeof(cred->cr_rgid)); 120856115Speter if (uap->egid) 120999009Salfred error2 = copyout(&cred->cr_groups[0], 121099009Salfred uap->egid, sizeof(cred->cr_groups[0])); 121156115Speter if (uap->sgid) 121299009Salfred error3 = copyout(&cred->cr_svgid, 121399009Salfred uap->sgid, sizeof(cred->cr_svgid)); 121487218Srwatson return (error1 ? error1 : error2 ? error2 : error3); 121556115Speter} 121656115Speter 121756115Speter#ifndef _SYS_SYSPROTO_H_ 121824453Speterstruct issetugid_args { 121924453Speter int dummy; 122024453Speter}; 122124453Speter#endif 122287218Srwatson/* 1223116121Sjhb * MPSAFE 122487218Srwatson */ 122524453Speter/* ARGSUSED */ 122624453Speterint 122793580Sjhbissetugid(register struct thread *td, struct issetugid_args *uap) 122824453Speter{ 122983366Sjulian struct proc *p = td->td_proc; 123083366Sjulian 123124453Speter /* 123224453Speter * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 123324453Speter * we use P_SUGID because we consider changing the owners as 123424453Speter * "tainting" as well. 123524453Speter * This is significant for procs that start as root and "become" 123624453Speter * a user without an exec - programs cannot know *everything* 123724453Speter * that libc *might* have put in their data segment. 123824453Speter */ 123991140Stanimura PROC_LOCK(p); 124083366Sjulian td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 124191140Stanimura PROC_UNLOCK(p); 124224453Speter return (0); 124324453Speter} 124424453Speter 124582749Sdillon/* 124682749Sdillon * MPSAFE 124782749Sdillon */ 124875426Srwatsonint 124993580Sjhb__setugid(struct thread *td, struct __setugid_args *uap) 125075426Srwatson{ 125182749Sdillon#ifdef REGRESSION 125294619Sjhb struct proc *p; 125375426Srwatson 125494619Sjhb p = td->td_proc; 125575426Srwatson switch (uap->flag) { 125675426Srwatson case 0: 125794619Sjhb PROC_LOCK(p); 125894619Sjhb p->p_flag &= ~P_SUGID; 125994619Sjhb PROC_UNLOCK(p); 126094619Sjhb return (0); 126175426Srwatson case 1: 126294619Sjhb PROC_LOCK(p); 126394619Sjhb p->p_flag |= P_SUGID; 126494619Sjhb PROC_UNLOCK(p); 126594619Sjhb return (0); 126675426Srwatson default: 126794619Sjhb return (EINVAL); 126875426Srwatson } 126975426Srwatson#else /* !REGRESSION */ 127087218Srwatson 127175426Srwatson return (ENOSYS); 127287218Srwatson#endif /* REGRESSION */ 127375426Srwatson} 127475426Srwatson 12751541Srgrimes/* 12761541Srgrimes * Check if gid is a member of the group set. 127793264Sdillon * 127893264Sdillon * MPSAFE (cred must be held) 12791541Srgrimes */ 12801549Srgrimesint 128193580Sjhbgroupmember(gid_t gid, struct ucred *cred) 12821541Srgrimes{ 12831541Srgrimes register gid_t *gp; 12841541Srgrimes gid_t *egp; 12851541Srgrimes 12861541Srgrimes egp = &(cred->cr_groups[cred->cr_ngroups]); 12871541Srgrimes for (gp = cred->cr_groups; gp < egp; gp++) 12881541Srgrimes if (*gp == gid) 12891541Srgrimes return (1); 12901541Srgrimes return (0); 12911541Srgrimes} 12921541Srgrimes 129382424Srwatson/* 129489414Sarr * `suser_enabled' (which can be set by the security.suser_enabled 129582466Srwatson * sysctl) determines whether the system 'super-user' policy is in effect. 129682466Srwatson * If it is nonzero, an effective uid of 0 connotes special privilege, 129782466Srwatson * overriding many mandatory and discretionary protections. If it is zero, 129882466Srwatson * uid 0 is offered no special privilege in the kernel security policy. 129982466Srwatson * Setting it to zero may seriously impact the functionality of many 130082466Srwatson * existing userland programs, and should not be done without careful 130182466Srwatson * consideration of the consequences. 130282424Srwatson */ 130382693Srwatsonint suser_enabled = 1; 130489414SarrSYSCTL_INT(_security_bsd, OID_AUTO, suser_enabled, CTLFLAG_RW, 130582693Srwatson &suser_enabled, 0, "processes with uid 0 have privilege"); 130689414SarrTUNABLE_INT("security.bsd.suser_enabled", &suser_enabled); 130761287Srwatson 13081541Srgrimes/* 130982466Srwatson * Test whether the specified credentials imply "super-user" privilege. 1310132255Scperciva * Return 0 or EPERM. 13111541Srgrimes */ 13121549Srgrimesint 131393593Sjhbsuser_cred(struct ucred *cred, int flag) 131446112Sphk{ 131587218Srwatson 131682693Srwatson if (!suser_enabled) 131761282Srwatson return (EPERM); 1318132255Scperciva if (((flag & SUSER_RUID) ? cred->cr_ruid : cred->cr_uid) != 0) 131946155Sphk return (EPERM); 1320132653Scperciva if (jailed(cred) && !(flag & SUSER_ALLOWJAIL)) 132146155Sphk return (EPERM); 132246155Sphk return (0); 13231541Srgrimes} 13241541Srgrimes 132583639Srwatson/* 132693593Sjhb * Shortcut to hide contents of struct td and struct proc from the 132793593Sjhb * caller, promoting binary compatibility. 132893593Sjhb */ 132993593Sjhbint 133093593Sjhbsuser(struct thread *td) 133193593Sjhb{ 133293593Sjhb 1333132548Srwatson#ifdef INVARIANTS 1334132548Srwatson if (td != curthread) { 1335132548Srwatson printf("suser: thread %p (%d %s) != curthread %p (%d %s)\n", 1336132548Srwatson td, td->td_proc->p_pid, td->td_proc->p_comm, 1337132548Srwatson curthread, curthread->td_proc->p_pid, 1338132548Srwatson curthread->td_proc->p_comm); 1339132548Srwatson#ifdef KDB 1340132548Srwatson kdb_backtrace(); 1341132548Srwatson#endif 1342132548Srwatson } 1343132548Srwatson#endif 134493593Sjhb return (suser_cred(td->td_ucred, 0)); 134593593Sjhb} 134693593Sjhb 134793593Sjhb/* 134887218Srwatson * Test the active securelevel against a given level. securelevel_gt() 134987218Srwatson * implements (securelevel > level). securelevel_ge() implements 135087218Srwatson * (securelevel >= level). Note that the logic is inverted -- these 135187218Srwatson * functions return EPERM on "success" and 0 on "failure". 135283639Srwatson * 135393264Sdillon * MPSAFE 135483639Srwatson */ 135583639Srwatsonint 135683639Srwatsonsecurelevel_gt(struct ucred *cr, int level) 135783639Srwatson{ 135887218Srwatson int active_securelevel; 135983639Srwatson 136087218Srwatson active_securelevel = securelevel; 136193732Sjhb KASSERT(cr != NULL, ("securelevel_gt: null cr")); 1362140678Srwatson if (cr->cr_prison != NULL) 136387218Srwatson active_securelevel = imax(cr->cr_prison->pr_securelevel, 136487218Srwatson active_securelevel); 136587218Srwatson return (active_securelevel > level ? EPERM : 0); 136683639Srwatson} 136783639Srwatson 136883639Srwatsonint 136983639Srwatsonsecurelevel_ge(struct ucred *cr, int level) 137083639Srwatson{ 137187218Srwatson int active_securelevel; 137283639Srwatson 137387218Srwatson active_securelevel = securelevel; 137493732Sjhb KASSERT(cr != NULL, ("securelevel_ge: null cr")); 1375140678Srwatson if (cr->cr_prison != NULL) 137687218Srwatson active_securelevel = imax(cr->cr_prison->pr_securelevel, 137787218Srwatson active_securelevel); 137887218Srwatson return (active_securelevel >= level ? EPERM : 0); 137983639Srwatson} 138083639Srwatson 138184736Srwatson/* 138287144Srwatson * 'see_other_uids' determines whether or not visibility of processes 138387218Srwatson * and sockets with credentials holding different real uids is possible 138487138Srwatson * using a variety of system MIBs. 138587218Srwatson * XXX: data declarations should be together near the beginning of the file. 138684736Srwatson */ 138787144Srwatsonstatic int see_other_uids = 1; 138889414SarrSYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW, 138987218Srwatson &see_other_uids, 0, 139084736Srwatson "Unprivileged processes may see subjects/objects with different real uid"); 139184736Srwatson 139282466Srwatson/*- 139392923Srwatson * Determine if u1 "can see" the subject specified by u2, according to the 139492923Srwatson * 'see_other_uids' policy. 139592923Srwatson * Returns: 0 for permitted, ESRCH otherwise 139692923Srwatson * Locks: none 139792923Srwatson * References: *u1 and *u2 must not change during the call 139892923Srwatson * u1 may equal u2, in which case only one reference is required 139992923Srwatson */ 140092923Srwatsonstatic int 140192923Srwatsoncr_seeotheruids(struct ucred *u1, struct ucred *u2) 140292923Srwatson{ 140392923Srwatson 140492923Srwatson if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) { 1405132653Scperciva if (suser_cred(u1, SUSER_ALLOWJAIL) != 0) 140692923Srwatson return (ESRCH); 140792923Srwatson } 140892923Srwatson return (0); 140992923Srwatson} 141092923Srwatson 1411122869Srwatson/* 1412122869Srwatson * 'see_other_gids' determines whether or not visibility of processes 1413122869Srwatson * and sockets with credentials holding different real gids is possible 1414122869Srwatson * using a variety of system MIBs. 1415122869Srwatson * XXX: data declarations should be together near the beginning of the file. 1416122869Srwatson */ 1417122869Srwatsonstatic int see_other_gids = 1; 1418122869SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, see_other_gids, CTLFLAG_RW, 1419122869Srwatson &see_other_gids, 0, 1420122869Srwatson "Unprivileged processes may see subjects/objects with different real gid"); 1421122869Srwatson 1422122869Srwatson/* 1423122869Srwatson * Determine if u1 can "see" the subject specified by u2, according to the 1424122869Srwatson * 'see_other_gids' policy. 1425122869Srwatson * Returns: 0 for permitted, ESRCH otherwise 1426122869Srwatson * Locks: none 1427122869Srwatson * References: *u1 and *u2 must not change during the call 1428122869Srwatson * u1 may equal u2, in which case only one reference is required 1429122869Srwatson */ 1430122869Srwatsonstatic int 1431122869Srwatsoncr_seeothergids(struct ucred *u1, struct ucred *u2) 1432122869Srwatson{ 1433122869Srwatson int i, match; 1434122869Srwatson 1435122869Srwatson if (!see_other_gids) { 1436122869Srwatson match = 0; 1437122869Srwatson for (i = 0; i < u1->cr_ngroups; i++) { 1438122869Srwatson if (groupmember(u1->cr_groups[i], u2)) 1439122869Srwatson match = 1; 1440122869Srwatson if (match) 1441122869Srwatson break; 1442122869Srwatson } 1443122869Srwatson if (!match) { 1444132653Scperciva if (suser_cred(u1, SUSER_ALLOWJAIL) != 0) 1445122869Srwatson return (ESRCH); 1446122869Srwatson } 1447122869Srwatson } 1448122869Srwatson return (0); 1449122869Srwatson} 1450122869Srwatson 145192923Srwatson/*- 145282466Srwatson * Determine if u1 "can see" the subject specified by u2. 145374956Srwatson * Returns: 0 for permitted, an errno value otherwise 145474956Srwatson * Locks: none 145587218Srwatson * References: *u1 and *u2 must not change during the call 145674956Srwatson * u1 may equal u2, in which case only one reference is required 145774956Srwatson */ 145874956Srwatsonint 145983742Srwatsoncr_cansee(struct ucred *u1, struct ucred *u2) 146065237Srwatson{ 146172786Srwatson int error; 146253518Sphk 146374956Srwatson if ((error = prison_check(u1, u2))) 146472786Srwatson return (error); 1465101003Srwatson#ifdef MAC 1466101003Srwatson if ((error = mac_check_cred_visible(u1, u2))) 1467101003Srwatson return (error); 1468101003Srwatson#endif 146992923Srwatson if ((error = cr_seeotheruids(u1, u2))) 147092923Srwatson return (error); 1471122869Srwatson if ((error = cr_seeothergids(u1, u2))) 1472122869Srwatson return (error); 147365237Srwatson return (0); 147465237Srwatson} 147565237Srwatson 147682466Srwatson/*- 147796886Sjhb * Determine if td "can see" the subject specified by p. 147882424Srwatson * Returns: 0 for permitted, an errno value otherwise 147996886Sjhb * Locks: Sufficient locks to protect p->p_ucred must be held. td really 148096886Sjhb * should be curthread. 148196886Sjhb * References: td and p must be valid for the lifetime of the call 148282424Srwatson */ 148379335Srwatsonint 148496886Sjhbp_cansee(struct thread *td, struct proc *p) 148574956Srwatson{ 148674956Srwatson 148783742Srwatson /* Wrap cr_cansee() for all functionality. */ 148896886Sjhb KASSERT(td == curthread, ("%s: td not curthread", __func__)); 148996886Sjhb PROC_LOCK_ASSERT(p, MA_OWNED); 149096886Sjhb return (cr_cansee(td->td_ucred, p->p_ucred)); 149174956Srwatson} 149274956Srwatson 1493120052Srwatson/* 1494120052Srwatson * 'conservative_signals' prevents the delivery of a broad class of 1495120052Srwatson * signals by unprivileged processes to processes that have changed their 1496120052Srwatson * credentials since the last invocation of execve(). This can prevent 1497120052Srwatson * the leakage of cached information or retained privileges as a result 1498120052Srwatson * of a common class of signal-related vulnerabilities. However, this 1499120052Srwatson * may interfere with some applications that expect to be able to 1500120052Srwatson * deliver these signals to peer processes after having given up 1501120052Srwatson * privilege. 1502120052Srwatson */ 1503120052Srwatsonstatic int conservative_signals = 1; 1504120052SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, conservative_signals, CTLFLAG_RW, 1505120052Srwatson &conservative_signals, 0, "Unprivileged processes prevented from " 1506120052Srwatson "sending certain signals to processes whose credentials have changed"); 150782466Srwatson/*- 150888943Srwatson * Determine whether cred may deliver the specified signal to proc. 150988943Srwatson * Returns: 0 for permitted, an errno value otherwise. 151088943Srwatson * Locks: A lock must be held for proc. 151188943Srwatson * References: cred and proc must be valid for the lifetime of the call. 151275437Srwatson */ 151375437Srwatsonint 1514141815Ssobomaxcr_cansignal(struct ucred *cred, struct proc *proc, int signum) 151553518Sphk{ 151682466Srwatson int error; 151784826Sjhb 151896886Sjhb PROC_LOCK_ASSERT(proc, MA_OWNED); 151975437Srwatson /* 152088943Srwatson * Jail semantics limit the scope of signalling to proc in the 152188943Srwatson * same jail as cred, if cred is in jail. 152275437Srwatson */ 152388943Srwatson error = prison_check(cred, proc->p_ucred); 152488943Srwatson if (error) 152572786Srwatson return (error); 1526101003Srwatson#ifdef MAC 1527101003Srwatson if ((error = mac_check_proc_signal(cred, proc, signum))) 1528101003Srwatson return (error); 1529101003Srwatson#endif 1530122869Srwatson if ((error = cr_seeotheruids(cred, proc->p_ucred))) 153192923Srwatson return (error); 1532122869Srwatson if ((error = cr_seeothergids(cred, proc->p_ucred))) 1533122869Srwatson return (error); 153465237Srwatson 153565237Srwatson /* 153682424Srwatson * UNIX signal semantics depend on the status of the P_SUGID 153782424Srwatson * bit on the target process. If the bit is set, then additional 153882424Srwatson * restrictions are placed on the set of available signals. 153975437Srwatson */ 1540141815Ssobomax if (conservative_signals && (proc->p_flag & P_SUGID)) { 154175437Srwatson switch (signum) { 154275437Srwatson case 0: 154375437Srwatson case SIGKILL: 154475437Srwatson case SIGINT: 154575437Srwatson case SIGTERM: 1546120052Srwatson case SIGALRM: 154775437Srwatson case SIGSTOP: 154875437Srwatson case SIGTTIN: 154975437Srwatson case SIGTTOU: 155075437Srwatson case SIGTSTP: 155175437Srwatson case SIGHUP: 155275437Srwatson case SIGUSR1: 155375437Srwatson case SIGUSR2: 155482466Srwatson /* 155582466Srwatson * Generally, permit job and terminal control 155682466Srwatson * signals. 155782466Srwatson */ 155875437Srwatson break; 155975437Srwatson default: 156088943Srwatson /* Not permitted without privilege. */ 1561132653Scperciva error = suser_cred(cred, SUSER_ALLOWJAIL); 156275437Srwatson if (error) 156375437Srwatson return (error); 156475437Srwatson } 156565237Srwatson } 156665237Srwatson 156775480Srwatson /* 156882424Srwatson * Generally, the target credential's ruid or svuid must match the 156975480Srwatson * subject credential's ruid or euid. 157075480Srwatson */ 157188943Srwatson if (cred->cr_ruid != proc->p_ucred->cr_ruid && 157288943Srwatson cred->cr_ruid != proc->p_ucred->cr_svuid && 157388943Srwatson cred->cr_uid != proc->p_ucred->cr_ruid && 157488943Srwatson cred->cr_uid != proc->p_ucred->cr_svuid) { 157588943Srwatson /* Not permitted without privilege. */ 1576132653Scperciva error = suser_cred(cred, SUSER_ALLOWJAIL); 157775480Srwatson if (error) 157875480Srwatson return (error); 157975480Srwatson } 158075480Srwatson 158187218Srwatson return (0); 158253518Sphk} 158353518Sphk 158488943Srwatson 158582466Srwatson/*- 158696886Sjhb * Determine whether td may deliver the specified signal to p. 158788943Srwatson * Returns: 0 for permitted, an errno value otherwise 158896886Sjhb * Locks: Sufficient locks to protect various components of td and p 158996886Sjhb * must be held. td must be curthread, and a lock must be 159096886Sjhb * held for p. 159196886Sjhb * References: td and p must be valid for the lifetime of the call 159288943Srwatson */ 159388943Srwatsonint 1594141815Ssobomaxp_cansignal(struct thread *td, struct proc *p, int signum) 159588943Srwatson{ 159688943Srwatson 159796886Sjhb KASSERT(td == curthread, ("%s: td not curthread", __func__)); 159896886Sjhb PROC_LOCK_ASSERT(p, MA_OWNED); 159996886Sjhb if (td->td_proc == p) 160088943Srwatson return (0); 160188943Srwatson 160288943Srwatson /* 160388943Srwatson * UNIX signalling semantics require that processes in the same 160488943Srwatson * session always be able to deliver SIGCONT to one another, 160588943Srwatson * overriding the remaining protections. 160688943Srwatson */ 160796886Sjhb /* XXX: This will require an additional lock of some sort. */ 160896886Sjhb if (signum == SIGCONT && td->td_proc->p_session == p->p_session) 160988943Srwatson return (0); 1610143108Ssobomax /* 1611143800Ssobomax * Some compat layers use SIGTHR and higher signals for 1612143800Ssobomax * communication between different kernel threads of the same 1613143800Ssobomax * process, so that they expect that it's always possible to 1614143800Ssobomax * deliver them, even for suid applications where cr_cansignal() can 1615143108Ssobomax * deny such ability for security consideration. It should be 1616143108Ssobomax * pretty safe to do since the only way to create two processes 1617143108Ssobomax * with the same p_leader is via rfork(2). 1618143108Ssobomax */ 1619143805Ssobomax if (td->td_proc->p_leader != NULL && signum >= SIGTHR && 1620143805Ssobomax signum < SIGTHR + 4 && td->td_proc->p_leader == p->p_leader) 1621143108Ssobomax return (0); 162288943Srwatson 1623141815Ssobomax return (cr_cansignal(td->td_ucred, p, signum)); 162488943Srwatson} 162588943Srwatson 162688943Srwatson/*- 162796886Sjhb * Determine whether td may reschedule p. 162882466Srwatson * Returns: 0 for permitted, an errno value otherwise 162996886Sjhb * Locks: Sufficient locks to protect various components of td and p 163096886Sjhb * must be held. td must be curthread, and a lock must 163196886Sjhb * be held for p. 163296886Sjhb * References: td and p must be valid for the lifetime of the call 163382424Srwatson */ 163479335Srwatsonint 163596886Sjhbp_cansched(struct thread *td, struct proc *p) 163665237Srwatson{ 163772786Srwatson int error; 163865237Srwatson 163996886Sjhb KASSERT(td == curthread, ("%s: td not curthread", __func__)); 164096886Sjhb PROC_LOCK_ASSERT(p, MA_OWNED); 164196886Sjhb if (td->td_proc == p) 164265237Srwatson return (0); 164396886Sjhb if ((error = prison_check(td->td_ucred, p->p_ucred))) 164472786Srwatson return (error); 1645101003Srwatson#ifdef MAC 1646101003Srwatson if ((error = mac_check_proc_sched(td->td_ucred, p))) 1647101003Srwatson return (error); 1648101003Srwatson#endif 164996886Sjhb if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) 165092923Srwatson return (error); 1651122869Srwatson if ((error = cr_seeothergids(td->td_ucred, p->p_ucred))) 1652122869Srwatson return (error); 165396886Sjhb if (td->td_ucred->cr_ruid == p->p_ucred->cr_ruid) 165465237Srwatson return (0); 165596886Sjhb if (td->td_ucred->cr_uid == p->p_ucred->cr_ruid) 165665237Srwatson return (0); 1657132653Scperciva if (suser_cred(td->td_ucred, SUSER_ALLOWJAIL) == 0) 165865237Srwatson return (0); 165965237Srwatson 166065237Srwatson#ifdef CAPABILITIES 1661132653Scperciva if (!cap_check(NULL, td, CAP_SYS_NICE, SUSER_ALLOWJAIL)) 166265237Srwatson return (0); 166365237Srwatson#endif 166465237Srwatson 166565237Srwatson return (EPERM); 166665237Srwatson} 166765237Srwatson 166882424Srwatson/* 166987280Srwatson * The 'unprivileged_proc_debug' flag may be used to disable a variety of 167087280Srwatson * unprivileged inter-process debugging services, including some procfs 167187280Srwatson * functionality, ptrace(), and ktrace(). In the past, inter-process 167287280Srwatson * debugging has been involved in a variety of security problems, and sites 167387280Srwatson * not requiring the service might choose to disable it when hardening 167487280Srwatson * systems. 167582424Srwatson * 167682424Srwatson * XXX: Should modifying and reading this variable require locking? 167787218Srwatson * XXX: data declarations should be together near the beginning of the file. 167882424Srwatson */ 167987144Srwatsonstatic int unprivileged_proc_debug = 1; 168089414SarrSYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW, 168187218Srwatson &unprivileged_proc_debug, 0, 168280735Srwatson "Unprivileged processes may use process debugging facilities"); 168380735Srwatson 168482466Srwatson/*- 168596886Sjhb * Determine whether td may debug p. 168682466Srwatson * Returns: 0 for permitted, an errno value otherwise 168796886Sjhb * Locks: Sufficient locks to protect various components of td and p 168896886Sjhb * must be held. td must be curthread, and a lock must 168996886Sjhb * be held for p. 169096886Sjhb * References: td and p must be valid for the lifetime of the call 169182424Srwatson */ 169279335Srwatsonint 169396886Sjhbp_candebug(struct thread *td, struct proc *p) 169465237Srwatson{ 169587218Srwatson int credentialchanged, error, grpsubset, i, uidsubset; 169665237Srwatson 169796886Sjhb KASSERT(td == curthread, ("%s: td not curthread", __func__)); 169896886Sjhb PROC_LOCK_ASSERT(p, MA_OWNED); 169987144Srwatson if (!unprivileged_proc_debug) { 1700132653Scperciva error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL); 170184727Srwatson if (error) 170284727Srwatson return (error); 170384727Srwatson } 170496886Sjhb if (td->td_proc == p) 170584636Sdes return (0); 170696886Sjhb if ((error = prison_check(td->td_ucred, p->p_ucred))) 170772786Srwatson return (error); 1708101003Srwatson#ifdef MAC 1709101003Srwatson if ((error = mac_check_proc_debug(td->td_ucred, p))) 1710101003Srwatson return (error); 1711101003Srwatson#endif 171296886Sjhb if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) 171392923Srwatson return (error); 1714122869Srwatson if ((error = cr_seeothergids(td->td_ucred, p->p_ucred))) 1715122869Srwatson return (error); 171665237Srwatson 171782466Srwatson /* 171896886Sjhb * Is p's group set a subset of td's effective group set? This 171996886Sjhb * includes p's egid, group access list, rgid, and svgid. 172082466Srwatson */ 172185895Srwatson grpsubset = 1; 172296886Sjhb for (i = 0; i < p->p_ucred->cr_ngroups; i++) { 172396886Sjhb if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) { 172485895Srwatson grpsubset = 0; 172585895Srwatson break; 172685895Srwatson } 172785895Srwatson } 172885895Srwatson grpsubset = grpsubset && 172996886Sjhb groupmember(p->p_ucred->cr_rgid, td->td_ucred) && 173096886Sjhb groupmember(p->p_ucred->cr_svgid, td->td_ucred); 173185895Srwatson 173285895Srwatson /* 173396886Sjhb * Are the uids present in p's credential equal to td's 173496886Sjhb * effective uid? This includes p's euid, svuid, and ruid. 173585895Srwatson */ 173696886Sjhb uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid && 173796886Sjhb td->td_ucred->cr_uid == p->p_ucred->cr_svuid && 173896886Sjhb td->td_ucred->cr_uid == p->p_ucred->cr_ruid); 173985895Srwatson 174085895Srwatson /* 174185895Srwatson * Has the credential of the process changed since the last exec()? 174285895Srwatson */ 174396886Sjhb credentialchanged = (p->p_flag & P_SUGID); 174485895Srwatson 174585895Srwatson /* 174696886Sjhb * If p's gids aren't a subset, or the uids aren't a subset, 174785895Srwatson * or the credential has changed, require appropriate privilege 174896886Sjhb * for td to debug p. For POSIX.1e capabilities, this will 174985895Srwatson * require CAP_SYS_PTRACE. 175085895Srwatson */ 175185895Srwatson if (!grpsubset || !uidsubset || credentialchanged) { 1752132653Scperciva error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL); 175384727Srwatson if (error) 175465237Srwatson return (error); 175582466Srwatson } 175665237Srwatson 175787218Srwatson /* Can't trace init when securelevel > 0. */ 175896886Sjhb if (p == initproc) { 175996886Sjhb error = securelevel_gt(td->td_ucred, 0); 176083639Srwatson if (error) 176183639Srwatson return (error); 176283639Srwatson } 176365237Srwatson 176485880Srwatson /* 176585880Srwatson * Can't trace a process that's currently exec'ing. 176685880Srwatson * XXX: Note, this is not a security policy decision, it's a 176785880Srwatson * basic correctness/functionality decision. Therefore, this check 176885880Srwatson * should be moved to the caller's of p_candebug(). 176985880Srwatson */ 177096886Sjhb if ((p->p_flag & P_INEXEC) != 0) 177185598Sdes return (EAGAIN); 177287466Srwatson 177365237Srwatson return (0); 177465237Srwatson} 177565237Srwatson 177692976Srwatson/*- 177792976Srwatson * Determine whether the subject represented by cred can "see" a socket. 177892976Srwatson * Returns: 0 for permitted, ENOENT otherwise. 177992976Srwatson */ 178092976Srwatsonint 178192976Srwatsoncr_canseesocket(struct ucred *cred, struct socket *so) 178292976Srwatson{ 178392976Srwatson int error; 178492976Srwatson 178592976Srwatson error = prison_check(cred, so->so_cred); 178692976Srwatson if (error) 178792976Srwatson return (ENOENT); 1788101003Srwatson#ifdef MAC 1789130398Srwatson SOCK_LOCK(so); 1790101003Srwatson error = mac_check_socket_visible(cred, so); 1791130398Srwatson SOCK_UNLOCK(so); 1792101003Srwatson if (error) 1793101003Srwatson return (error); 1794101003Srwatson#endif 179592976Srwatson if (cr_seeotheruids(cred, so->so_cred)) 179692976Srwatson return (ENOENT); 1797122869Srwatson if (cr_seeothergids(cred, so->so_cred)) 1798122869Srwatson return (ENOENT); 179992976Srwatson 180092976Srwatson return (0); 180192976Srwatson} 180292976Srwatson 180353518Sphk/* 18041541Srgrimes * Allocate a zeroed cred structure. 1805116406Srwatson * MPSAFE 18061541Srgrimes */ 18071541Srgrimesstruct ucred * 180893580Sjhbcrget(void) 18091541Srgrimes{ 18101541Srgrimes register struct ucred *cr; 18111541Srgrimes 1812111119Simp MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK | M_ZERO); 18131541Srgrimes cr->cr_ref = 1; 1814117494Struckman cr->cr_mtxp = mtx_pool_find(mtxpool_sleep, cr); 1815101001Srwatson#ifdef MAC 1816101001Srwatson mac_init_cred(cr); 1817101001Srwatson#endif 18181541Srgrimes return (cr); 18191541Srgrimes} 18201541Srgrimes 18211541Srgrimes/* 182282466Srwatson * Claim another reference to a ucred structure. 1823116406Srwatson * MPSAFE 182469401Salfred */ 182584827Sjhbstruct ucred * 182693580Sjhbcrhold(struct ucred *cr) 182769401Salfred{ 182869401Salfred 182990756Sdillon mtx_lock(cr->cr_mtxp); 183069401Salfred cr->cr_ref++; 183190756Sdillon mtx_unlock(cr->cr_mtxp); 183284827Sjhb return (cr); 183369401Salfred} 183469401Salfred 183569401Salfred/* 18361541Srgrimes * Free a cred structure. 18371541Srgrimes * Throws away space when ref count gets to 0. 1838116406Srwatson * MPSAFE 18391541Srgrimes */ 18401549Srgrimesvoid 184193580Sjhbcrfree(struct ucred *cr) 18421541Srgrimes{ 184390756Sdillon struct mtx *mtxp = cr->cr_mtxp; 184469239Salfred 184590756Sdillon mtx_lock(mtxp); 184675632Salfred KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref)); 184765495Struckman if (--cr->cr_ref == 0) { 1848124884Srwatson mtx_unlock(mtxp); 184965495Struckman /* 185065495Struckman * Some callers of crget(), such as nfs_statfs(), 185165495Struckman * allocate a temporary credential, but don't 185265495Struckman * allocate a uidinfo structure. 185365495Struckman */ 185465495Struckman if (cr->cr_uidinfo != NULL) 185565495Struckman uifree(cr->cr_uidinfo); 185677277Srwatson if (cr->cr_ruidinfo != NULL) 185777277Srwatson uifree(cr->cr_ruidinfo); 185872786Srwatson /* 185972786Srwatson * Free a prison, if any. 186072786Srwatson */ 186172786Srwatson if (jailed(cr)) 186272786Srwatson prison_free(cr->cr_prison); 1863101001Srwatson#ifdef MAC 1864101001Srwatson mac_destroy_cred(cr); 1865101001Srwatson#endif 186699009Salfred FREE(cr, M_CRED); 186790756Sdillon } else { 186890756Sdillon mtx_unlock(mtxp); 186990756Sdillon } 18701541Srgrimes} 18711541Srgrimes 18721541Srgrimes/* 187384827Sjhb * Check to see if this ucred is shared. 1874116406Srwatson * MPSAFE 18751541Srgrimes */ 187684827Sjhbint 187793580Sjhbcrshared(struct ucred *cr) 18781541Srgrimes{ 187984827Sjhb int shared; 18801541Srgrimes 188190756Sdillon mtx_lock(cr->cr_mtxp); 188284827Sjhb shared = (cr->cr_ref > 1); 188390756Sdillon mtx_unlock(cr->cr_mtxp); 188484827Sjhb return (shared); 18851541Srgrimes} 18861541Srgrimes 18871541Srgrimes/* 188884827Sjhb * Copy a ucred's contents from a template. Does not block. 1889116406Srwatson * MPSAFE 189084827Sjhb */ 189184827Sjhbvoid 189293580Sjhbcrcopy(struct ucred *dest, struct ucred *src) 189384827Sjhb{ 189484827Sjhb 189584827Sjhb KASSERT(crshared(dest) == 0, ("crcopy of shared ucred")); 189684827Sjhb bcopy(&src->cr_startcopy, &dest->cr_startcopy, 189787218Srwatson (unsigned)((caddr_t)&src->cr_endcopy - 189884827Sjhb (caddr_t)&src->cr_startcopy)); 189984827Sjhb uihold(dest->cr_uidinfo); 190084827Sjhb uihold(dest->cr_ruidinfo); 190184827Sjhb if (jailed(dest)) 190284827Sjhb prison_hold(dest->cr_prison); 1903101001Srwatson#ifdef MAC 1904123173Srwatson mac_copy_cred(src, dest); 1905101001Srwatson#endif 190684827Sjhb} 190784827Sjhb 190884827Sjhb/* 19091541Srgrimes * Dup cred struct to a new held one. 1910116406Srwatson * MPSAFE 19111541Srgrimes */ 19121541Srgrimesstruct ucred * 191393580Sjhbcrdup(struct ucred *cr) 19141541Srgrimes{ 19151541Srgrimes struct ucred *newcr; 19161541Srgrimes 191784827Sjhb newcr = crget(); 191884827Sjhb crcopy(newcr, cr); 19191541Srgrimes return (newcr); 19201541Srgrimes} 19211541Srgrimes 19221541Srgrimes/* 192391354Sdd * Fill in a struct xucred based on a struct ucred. 1924116406Srwatson * MPSAFE 192591354Sdd */ 192691354Sddvoid 192793580Sjhbcru2x(struct ucred *cr, struct xucred *xcr) 192891354Sdd{ 192991354Sdd 193091354Sdd bzero(xcr, sizeof(*xcr)); 193191354Sdd xcr->cr_version = XUCRED_VERSION; 193291354Sdd xcr->cr_uid = cr->cr_uid; 193391354Sdd xcr->cr_ngroups = cr->cr_ngroups; 193491354Sdd bcopy(cr->cr_groups, xcr->cr_groups, sizeof(cr->cr_groups)); 193591354Sdd} 193691354Sdd 193791354Sdd/* 193890748Sjulian * small routine to swap a thread's current ucred for the correct one 193990748Sjulian * taken from the process. 1940116406Srwatson * MPSAFE 194190748Sjulian */ 194290748Sjulianvoid 194390748Sjuliancred_update_thread(struct thread *td) 194490748Sjulian{ 194590748Sjulian struct proc *p; 194691405Sjhb struct ucred *cred; 194790748Sjulian 194890748Sjulian p = td->td_proc; 194991405Sjhb cred = td->td_ucred; 195090748Sjulian PROC_LOCK(p); 195190748Sjulian td->td_ucred = crhold(p->p_ucred); 195290748Sjulian PROC_UNLOCK(p); 195391405Sjhb if (cred != NULL) 195491405Sjhb crfree(cred); 195590748Sjulian} 195690748Sjulian 195790748Sjulian/* 19581541Srgrimes * Get login name, if available. 19591541Srgrimes */ 196012221Sbde#ifndef _SYS_SYSPROTO_H_ 19611541Srgrimesstruct getlogin_args { 19621541Srgrimes char *namebuf; 19631541Srgrimes u_int namelen; 19641541Srgrimes}; 196512221Sbde#endif 196682749Sdillon/* 196782749Sdillon * MPSAFE 196882749Sdillon */ 19691541Srgrimes/* ARGSUSED */ 19701549Srgrimesint 197193580Sjhbgetlogin(struct thread *td, struct getlogin_args *uap) 19721541Srgrimes{ 197382749Sdillon int error; 197491140Stanimura char login[MAXLOGNAME]; 197583366Sjulian struct proc *p = td->td_proc; 19761541Srgrimes 197723358Sache if (uap->namelen > MAXLOGNAME) 197823359Sache uap->namelen = MAXLOGNAME; 197991140Stanimura PROC_LOCK(p); 198091140Stanimura SESS_LOCK(p->p_session); 198191140Stanimura bcopy(p->p_session->s_login, login, uap->namelen); 198291140Stanimura SESS_UNLOCK(p->p_session); 198391140Stanimura PROC_UNLOCK(p); 198499009Salfred error = copyout(login, uap->namebuf, uap->namelen); 198582749Sdillon return(error); 19861541Srgrimes} 19871541Srgrimes 19881541Srgrimes/* 19891541Srgrimes * Set login name. 19901541Srgrimes */ 199112221Sbde#ifndef _SYS_SYSPROTO_H_ 19921541Srgrimesstruct setlogin_args { 19931541Srgrimes char *namebuf; 19941541Srgrimes}; 199512221Sbde#endif 199682749Sdillon/* 199782749Sdillon * MPSAFE 199882749Sdillon */ 19991541Srgrimes/* ARGSUSED */ 20001549Srgrimesint 200193580Sjhbsetlogin(struct thread *td, struct setlogin_args *uap) 20021541Srgrimes{ 200383366Sjulian struct proc *p = td->td_proc; 20041541Srgrimes int error; 200523330Sache char logintmp[MAXLOGNAME]; 20061541Srgrimes 2007132653Scperciva error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL); 200894619Sjhb if (error) 200994619Sjhb return (error); 201099009Salfred error = copyinstr(uap->namebuf, logintmp, sizeof(logintmp), NULL); 201187218Srwatson if (error == ENAMETOOLONG) 20121541Srgrimes error = EINVAL; 201391140Stanimura else if (!error) { 201491140Stanimura PROC_LOCK(p); 201591140Stanimura SESS_LOCK(p->p_session); 201691140Stanimura (void) memcpy(p->p_session->s_login, logintmp, 201723330Sache sizeof(logintmp)); 201891140Stanimura SESS_UNLOCK(p->p_session); 201991140Stanimura PROC_UNLOCK(p); 202091140Stanimura } 20211541Srgrimes return (error); 20221541Srgrimes} 202331891Ssef 202431891Ssefvoid 202593580Sjhbsetsugid(struct proc *p) 202631891Ssef{ 202798403Salfred 202898403Salfred PROC_LOCK_ASSERT(p, MA_OWNED); 202931891Ssef p->p_flag |= P_SUGID; 203055707Ssef if (!(p->p_pfsflags & PF_ISUGID)) 203131891Ssef p->p_stops = 0; 203231891Ssef} 203365495Struckman 203482466Srwatson/*- 203582466Srwatson * Change a process's effective uid. 203677183Srwatson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified. 203777183Srwatson * References: newcred must be an exclusive credential reference for the 203877183Srwatson * duration of the call. 203965495Struckman */ 204065495Struckmanvoid 204198417Salfredchange_euid(struct ucred *newcred, struct uidinfo *euip) 204265495Struckman{ 204365495Struckman 204498417Salfred newcred->cr_uid = euip->ui_uid; 204598417Salfred uihold(euip); 204677183Srwatson uifree(newcred->cr_uidinfo); 204798417Salfred newcred->cr_uidinfo = euip; 204865495Struckman} 204965495Struckman 205082466Srwatson/*- 205182466Srwatson * Change a process's effective gid. 205277183Srwatson * Side effects: newcred->cr_gid will be modified. 205377183Srwatson * References: newcred must be an exclusive credential reference for the 205477183Srwatson * duration of the call. 205565495Struckman */ 205667629Sgallatinvoid 205793580Sjhbchange_egid(struct ucred *newcred, gid_t egid) 205865495Struckman{ 205965495Struckman 206077183Srwatson newcred->cr_groups[0] = egid; 206165495Struckman} 206277183Srwatson 206382466Srwatson/*- 206482466Srwatson * Change a process's real uid. 206577183Srwatson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo 206677183Srwatson * will be updated, and the old and new cr_ruidinfo proc 206777183Srwatson * counts will be updated. 206877183Srwatson * References: newcred must be an exclusive credential reference for the 206977183Srwatson * duration of the call. 207077183Srwatson */ 207177183Srwatsonvoid 207298417Salfredchange_ruid(struct ucred *newcred, struct uidinfo *ruip) 207377183Srwatson{ 207477183Srwatson 207577183Srwatson (void)chgproccnt(newcred->cr_ruidinfo, -1, 0); 207698417Salfred newcred->cr_ruid = ruip->ui_uid; 207798417Salfred uihold(ruip); 207877183Srwatson uifree(newcred->cr_ruidinfo); 207998417Salfred newcred->cr_ruidinfo = ruip; 208077183Srwatson (void)chgproccnt(newcred->cr_ruidinfo, 1, 0); 208177183Srwatson} 208277183Srwatson 208382466Srwatson/*- 208482466Srwatson * Change a process's real gid. 208577183Srwatson * Side effects: newcred->cr_rgid will be updated. 208677183Srwatson * References: newcred must be an exclusive credential reference for the 208777183Srwatson * duration of the call. 208877183Srwatson */ 208977183Srwatsonvoid 209093580Sjhbchange_rgid(struct ucred *newcred, gid_t rgid) 209177183Srwatson{ 209277183Srwatson 209377183Srwatson newcred->cr_rgid = rgid; 209477183Srwatson} 209577183Srwatson 209682466Srwatson/*- 209782466Srwatson * Change a process's saved uid. 209877183Srwatson * Side effects: newcred->cr_svuid will be updated. 209977183Srwatson * References: newcred must be an exclusive credential reference for the 210077183Srwatson * duration of the call. 210177183Srwatson */ 210277183Srwatsonvoid 210393580Sjhbchange_svuid(struct ucred *newcred, uid_t svuid) 210477183Srwatson{ 210577183Srwatson 210677183Srwatson newcred->cr_svuid = svuid; 210777183Srwatson} 210877183Srwatson 210982466Srwatson/*- 211082466Srwatson * Change a process's saved gid. 211177183Srwatson * Side effects: newcred->cr_svgid will be updated. 211277183Srwatson * References: newcred must be an exclusive credential reference for the 211377183Srwatson * duration of the call. 211477183Srwatson */ 211577183Srwatsonvoid 211693580Sjhbchange_svgid(struct ucred *newcred, gid_t svgid) 211777183Srwatson{ 211877183Srwatson 211977183Srwatson newcred->cr_svgid = svgid; 212077183Srwatson} 2121