kern_prot.c revision 139804
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 139804 2005-01-06 23:35:40Z imp $"); 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 50324448Speter /* 50424448Speter * See if we have "permission" by POSIX 1003.1 rules. 50524448Speter * 50687218Srwatson * Note that setuid(geteuid()) is a special case of 50724448Speter * "appropriate privileges" in appendix B.4.2.2. We need 50872093Sasmodai * to use this clause to be compatible with traditional BSD 50924448Speter * semantics. Basically, it means that "setuid(xx)" sets all 51024448Speter * three id's (assuming you have privs). 51124448Speter * 51224448Speter * Notes on the logic. We do things in three steps. 51324448Speter * 1: We determine if the euid is going to change, and do EPERM 51424448Speter * right away. We unconditionally change the euid later if this 51524448Speter * test is satisfied, simplifying that part of the logic. 51687218Srwatson * 2: We determine if the real and/or saved uids are going to 51724448Speter * change. Determined by compile options. 51824448Speter * 3: Change euid last. (after tests in #2 for "appropriate privs") 51924448Speter */ 52077183Srwatson if (uid != oldcred->cr_ruid && /* allow setuid(getuid()) */ 52117994Sache#ifdef _POSIX_SAVED_IDS 52277183Srwatson uid != oldcred->cr_svuid && /* allow setuid(saved gid) */ 52317994Sache#endif 52424448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 52577183Srwatson uid != oldcred->cr_uid && /* allow setuid(geteuid()) */ 52624448Speter#endif 527132653Scperciva (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) { 52894619Sjhb PROC_UNLOCK(p); 52998417Salfred uifree(uip); 53094619Sjhb crfree(newcred); 53194619Sjhb return (error); 53294619Sjhb } 53324448Speter 53498417Salfred /* 53598417Salfred * Copy credentials so other references do not see our changes. 53698417Salfred */ 53794619Sjhb crcopy(newcred, oldcred); 53824448Speter#ifdef _POSIX_SAVED_IDS 5391541Srgrimes /* 54024448Speter * Do we have "appropriate privileges" (are we root or uid == euid) 54124448Speter * If so, we are changing the real uid and/or saved uid. 5421541Srgrimes */ 54317994Sache if ( 54424448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 54577183Srwatson uid == oldcred->cr_uid || 54617994Sache#endif 547132653Scperciva suser_cred(oldcred, SUSER_ALLOWJAIL) == 0) /* we are using privs */ 54817994Sache#endif 54924448Speter { 55024448Speter /* 55165495Struckman * Set the real uid and transfer proc count to new user. 55224448Speter */ 55377183Srwatson if (uid != oldcred->cr_ruid) { 55498417Salfred change_ruid(newcred, uip); 55565495Struckman setsugid(p); 55624448Speter } 55724448Speter /* 55824448Speter * Set saved uid 55924448Speter * 56024448Speter * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 56124448Speter * the security of seteuid() depends on it. B.4.2.2 says it 56224448Speter * is important that we should do this. 56324448Speter */ 56477183Srwatson if (uid != oldcred->cr_svuid) { 56577183Srwatson change_svuid(newcred, uid); 56631891Ssef setsugid(p); 56724448Speter } 5688141Sache } 56924448Speter 57024448Speter /* 57124448Speter * In all permitted cases, we are changing the euid. 57224448Speter */ 57377183Srwatson if (uid != oldcred->cr_uid) { 57498417Salfred change_euid(newcred, uip); 57531891Ssef setsugid(p); 57624448Speter } 57777183Srwatson p->p_ucred = newcred; 57894619Sjhb PROC_UNLOCK(p); 57998417Salfred uifree(uip); 58077183Srwatson crfree(oldcred); 58194619Sjhb return (0); 5821541Srgrimes} 5831541Srgrimes 58412221Sbde#ifndef _SYS_SYSPROTO_H_ 5851541Srgrimesstruct seteuid_args { 5861541Srgrimes uid_t euid; 5871541Srgrimes}; 58812221Sbde#endif 58982749Sdillon/* 59082749Sdillon * MPSAFE 59182749Sdillon */ 5921541Srgrimes/* ARGSUSED */ 5931549Srgrimesint 59493580Sjhbseteuid(struct thread *td, struct seteuid_args *uap) 5951541Srgrimes{ 59683366Sjulian struct proc *p = td->td_proc; 59777183Srwatson struct ucred *newcred, *oldcred; 59877183Srwatson uid_t euid; 59998417Salfred struct uidinfo *euip; 60087218Srwatson int error; 6011541Srgrimes 6021541Srgrimes euid = uap->euid; 60394619Sjhb newcred = crget(); 60498417Salfred euip = uifind(euid); 60594619Sjhb PROC_LOCK(p); 60677183Srwatson oldcred = p->p_ucred; 60777183Srwatson if (euid != oldcred->cr_ruid && /* allow seteuid(getuid()) */ 60877183Srwatson euid != oldcred->cr_svuid && /* allow seteuid(saved uid) */ 609132653Scperciva (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) { 61094619Sjhb PROC_UNLOCK(p); 61198417Salfred uifree(euip); 61294619Sjhb crfree(newcred); 61394619Sjhb return (error); 61494619Sjhb } 6151541Srgrimes /* 6161541Srgrimes * Everything's okay, do it. Copy credentials so other references do 6171541Srgrimes * not see our changes. 6181541Srgrimes */ 61994619Sjhb crcopy(newcred, oldcred); 62077183Srwatson if (oldcred->cr_uid != euid) { 62198417Salfred change_euid(newcred, euip); 62231891Ssef setsugid(p); 62324449Speter } 62477183Srwatson p->p_ucred = newcred; 62594619Sjhb PROC_UNLOCK(p); 62698417Salfred uifree(euip); 62777183Srwatson crfree(oldcred); 62894619Sjhb return (0); 6291541Srgrimes} 6301541Srgrimes 63112221Sbde#ifndef _SYS_SYSPROTO_H_ 6321541Srgrimesstruct setgid_args { 6331541Srgrimes gid_t gid; 6341541Srgrimes}; 63512221Sbde#endif 63682749Sdillon/* 63782749Sdillon * MPSAFE 63882749Sdillon */ 6391541Srgrimes/* ARGSUSED */ 6401549Srgrimesint 64193580Sjhbsetgid(struct thread *td, struct setgid_args *uap) 6421541Srgrimes{ 64383366Sjulian struct proc *p = td->td_proc; 64477183Srwatson struct ucred *newcred, *oldcred; 64577183Srwatson gid_t gid; 64687218Srwatson int error; 6471541Srgrimes 64877183Srwatson gid = uap->gid; 64994619Sjhb newcred = crget(); 65094619Sjhb PROC_LOCK(p); 65177183Srwatson oldcred = p->p_ucred; 65287466Srwatson 65324448Speter /* 65424448Speter * See if we have "permission" by POSIX 1003.1 rules. 65524448Speter * 65624448Speter * Note that setgid(getegid()) is a special case of 65724448Speter * "appropriate privileges" in appendix B.4.2.2. We need 65872093Sasmodai * to use this clause to be compatible with traditional BSD 65924448Speter * semantics. Basically, it means that "setgid(xx)" sets all 66024448Speter * three id's (assuming you have privs). 66124448Speter * 66224448Speter * For notes on the logic here, see setuid() above. 66324448Speter */ 66477183Srwatson if (gid != oldcred->cr_rgid && /* allow setgid(getgid()) */ 66517994Sache#ifdef _POSIX_SAVED_IDS 66677183Srwatson gid != oldcred->cr_svgid && /* allow setgid(saved gid) */ 66717994Sache#endif 66824448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 66977183Srwatson gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */ 67024448Speter#endif 671132653Scperciva (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) { 67294619Sjhb PROC_UNLOCK(p); 67394619Sjhb crfree(newcred); 67494619Sjhb return (error); 67594619Sjhb } 67624448Speter 67794619Sjhb crcopy(newcred, oldcred); 67817994Sache#ifdef _POSIX_SAVED_IDS 67924448Speter /* 68024448Speter * Do we have "appropriate privileges" (are we root or gid == egid) 68124448Speter * If so, we are changing the real uid and saved gid. 68224448Speter */ 68324448Speter if ( 68424448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 68577183Srwatson gid == oldcred->cr_groups[0] || 68617994Sache#endif 687132653Scperciva suser_cred(oldcred, SUSER_ALLOWJAIL) == 0) /* we are using privs */ 68824448Speter#endif 68924448Speter { 69024448Speter /* 69124448Speter * Set real gid 69224448Speter */ 69377183Srwatson if (oldcred->cr_rgid != gid) { 69477183Srwatson change_rgid(newcred, gid); 69531891Ssef setsugid(p); 69624448Speter } 69724448Speter /* 69824448Speter * Set saved gid 69924448Speter * 70024448Speter * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 70124448Speter * the security of setegid() depends on it. B.4.2.2 says it 70224448Speter * is important that we should do this. 70324448Speter */ 70477183Srwatson if (oldcred->cr_svgid != gid) { 70577183Srwatson change_svgid(newcred, gid); 70631891Ssef setsugid(p); 70724448Speter } 7088141Sache } 70924448Speter /* 71024448Speter * In all cases permitted cases, we are changing the egid. 71124448Speter * Copy credentials so other references do not see our changes. 71224448Speter */ 71377183Srwatson if (oldcred->cr_groups[0] != gid) { 71477183Srwatson change_egid(newcred, gid); 71531891Ssef setsugid(p); 71624448Speter } 71777183Srwatson p->p_ucred = newcred; 71894619Sjhb PROC_UNLOCK(p); 71977183Srwatson crfree(oldcred); 72094619Sjhb return (0); 7211541Srgrimes} 7221541Srgrimes 72312221Sbde#ifndef _SYS_SYSPROTO_H_ 7241541Srgrimesstruct setegid_args { 7251541Srgrimes gid_t egid; 7261541Srgrimes}; 72712221Sbde#endif 72882749Sdillon/* 72982749Sdillon * MPSAFE 73082749Sdillon */ 7311541Srgrimes/* ARGSUSED */ 7321549Srgrimesint 73393580Sjhbsetegid(struct thread *td, struct setegid_args *uap) 7341541Srgrimes{ 73583366Sjulian struct proc *p = td->td_proc; 73677183Srwatson struct ucred *newcred, *oldcred; 73777183Srwatson gid_t egid; 73887218Srwatson int error; 7391541Srgrimes 7401541Srgrimes egid = uap->egid; 74194619Sjhb newcred = crget(); 74294619Sjhb PROC_LOCK(p); 74377183Srwatson oldcred = p->p_ucred; 74477183Srwatson if (egid != oldcred->cr_rgid && /* allow setegid(getgid()) */ 74577183Srwatson egid != oldcred->cr_svgid && /* allow setegid(saved gid) */ 746132653Scperciva (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) { 74794619Sjhb PROC_UNLOCK(p); 74894619Sjhb crfree(newcred); 74994619Sjhb return (error); 75094619Sjhb } 75194619Sjhb crcopy(newcred, oldcred); 75277183Srwatson if (oldcred->cr_groups[0] != egid) { 75377183Srwatson change_egid(newcred, egid); 75431891Ssef setsugid(p); 75524449Speter } 75677183Srwatson p->p_ucred = newcred; 75794619Sjhb PROC_UNLOCK(p); 75877183Srwatson crfree(oldcred); 75994619Sjhb return (0); 7601541Srgrimes} 7611541Srgrimes 76212221Sbde#ifndef _SYS_SYSPROTO_H_ 7631541Srgrimesstruct setgroups_args { 7641541Srgrimes u_int gidsetsize; 7651541Srgrimes gid_t *gidset; 7661541Srgrimes}; 76712221Sbde#endif 76882749Sdillon/* 76982749Sdillon * MPSAFE 77082749Sdillon */ 7711541Srgrimes/* ARGSUSED */ 7721549Srgrimesint 77393580Sjhbsetgroups(struct thread *td, struct setgroups_args *uap) 7741541Srgrimes{ 77583366Sjulian struct proc *p = td->td_proc; 77694619Sjhb struct ucred *newcred, *tempcred, *oldcred; 77777183Srwatson u_int ngrp; 7781541Srgrimes int error; 7791541Srgrimes 78087220Srwatson ngrp = uap->gidsetsize; 78194619Sjhb if (ngrp > NGROUPS) 78294619Sjhb return (EINVAL); 78394619Sjhb tempcred = crget(); 78499009Salfred error = copyin(uap->gidset, tempcred->cr_groups, ngrp * sizeof(gid_t)); 78594619Sjhb if (error != 0) { 78694619Sjhb crfree(tempcred); 78794619Sjhb return (error); 78894619Sjhb } 78994619Sjhb newcred = crget(); 79094619Sjhb PROC_LOCK(p); 79177183Srwatson oldcred = p->p_ucred; 792132653Scperciva error = suser_cred(oldcred, SUSER_ALLOWJAIL); 79394619Sjhb if (error) { 79494619Sjhb PROC_UNLOCK(p); 79594619Sjhb crfree(newcred); 79694619Sjhb crfree(tempcred); 79794619Sjhb return (error); 79882749Sdillon } 79994619Sjhb 80024447Speter /* 80124447Speter * XXX A little bit lazy here. We could test if anything has 80224447Speter * changed before crcopy() and setting P_SUGID. 80324447Speter */ 80494619Sjhb crcopy(newcred, oldcred); 80524447Speter if (ngrp < 1) { 80624447Speter /* 80724447Speter * setgroups(0, NULL) is a legitimate way of clearing the 80824447Speter * groups vector on non-BSD systems (which generally do not 80924447Speter * have the egid in the groups[0]). We risk security holes 81024447Speter * when running non-BSD software if we do not do the same. 81124447Speter */ 81277183Srwatson newcred->cr_ngroups = 1; 81324447Speter } else { 81494619Sjhb bcopy(tempcred->cr_groups, newcred->cr_groups, 81594619Sjhb ngrp * sizeof(gid_t)); 81677183Srwatson newcred->cr_ngroups = ngrp; 81724447Speter } 81831891Ssef setsugid(p); 81977183Srwatson p->p_ucred = newcred; 82094619Sjhb PROC_UNLOCK(p); 82194619Sjhb crfree(tempcred); 82277183Srwatson crfree(oldcred); 82394619Sjhb return (0); 8241541Srgrimes} 8251541Srgrimes 82612221Sbde#ifndef _SYS_SYSPROTO_H_ 8271541Srgrimesstruct setreuid_args { 8289238Sache uid_t ruid; 8299238Sache uid_t euid; 8301541Srgrimes}; 83112221Sbde#endif 83282749Sdillon/* 83382749Sdillon * MPSAFE 83482749Sdillon */ 8351541Srgrimes/* ARGSUSED */ 8361549Srgrimesint 83793580Sjhbsetreuid(register struct thread *td, struct setreuid_args *uap) 8381541Srgrimes{ 83983366Sjulian struct proc *p = td->td_proc; 84077183Srwatson struct ucred *newcred, *oldcred; 84187218Srwatson uid_t euid, ruid; 84298417Salfred struct uidinfo *euip, *ruip; 84387218Srwatson int error; 8441541Srgrimes 84587218Srwatson euid = uap->euid; 8469238Sache ruid = uap->ruid; 84794619Sjhb newcred = crget(); 84898417Salfred euip = uifind(euid); 84998417Salfred ruip = uifind(ruid); 85094619Sjhb PROC_LOCK(p); 85177183Srwatson oldcred = p->p_ucred; 85277183Srwatson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 85377183Srwatson ruid != oldcred->cr_svuid) || 85477183Srwatson (euid != (uid_t)-1 && euid != oldcred->cr_uid && 85577183Srwatson euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) && 856132653Scperciva (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) { 85794619Sjhb PROC_UNLOCK(p); 85898417Salfred uifree(ruip); 85998417Salfred uifree(euip); 86094619Sjhb crfree(newcred); 86194619Sjhb return (error); 86294619Sjhb } 86394619Sjhb crcopy(newcred, oldcred); 86477183Srwatson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 86598417Salfred change_euid(newcred, euip); 86631891Ssef setsugid(p); 86724450Speter } 86877183Srwatson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 86998417Salfred change_ruid(newcred, ruip); 87031891Ssef setsugid(p); 8718135Sache } 87277183Srwatson if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) && 87377183Srwatson newcred->cr_svuid != newcred->cr_uid) { 87477183Srwatson change_svuid(newcred, newcred->cr_uid); 87531891Ssef setsugid(p); 87624450Speter } 87777183Srwatson p->p_ucred = newcred; 87894619Sjhb PROC_UNLOCK(p); 87998417Salfred uifree(ruip); 88098417Salfred uifree(euip); 88177183Srwatson crfree(oldcred); 88294619Sjhb return (0); 8831541Srgrimes} 8841541Srgrimes 88512221Sbde#ifndef _SYS_SYSPROTO_H_ 8861541Srgrimesstruct setregid_args { 8879238Sache gid_t rgid; 8889238Sache gid_t egid; 8891541Srgrimes}; 89012221Sbde#endif 89182749Sdillon/* 89282749Sdillon * MPSAFE 89382749Sdillon */ 8941541Srgrimes/* ARGSUSED */ 8951549Srgrimesint 89693580Sjhbsetregid(register struct thread *td, struct setregid_args *uap) 8971541Srgrimes{ 89883366Sjulian struct proc *p = td->td_proc; 89977183Srwatson struct ucred *newcred, *oldcred; 90087218Srwatson gid_t egid, rgid; 90187218Srwatson int error; 9021541Srgrimes 90387218Srwatson egid = uap->egid; 9049238Sache rgid = uap->rgid; 90594619Sjhb newcred = crget(); 90694619Sjhb PROC_LOCK(p); 90777183Srwatson oldcred = p->p_ucred; 90877183Srwatson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 90977183Srwatson rgid != oldcred->cr_svgid) || 91077183Srwatson (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] && 91177183Srwatson egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) && 912132653Scperciva (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) { 91394619Sjhb PROC_UNLOCK(p); 91494619Sjhb crfree(newcred); 91594619Sjhb return (error); 91694619Sjhb } 91794619Sjhb 91894619Sjhb crcopy(newcred, oldcred); 91977183Srwatson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 92077183Srwatson change_egid(newcred, egid); 92131891Ssef setsugid(p); 92224450Speter } 92377183Srwatson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 92477183Srwatson change_rgid(newcred, rgid); 92531891Ssef setsugid(p); 92624450Speter } 92777183Srwatson if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) && 92877183Srwatson newcred->cr_svgid != newcred->cr_groups[0]) { 92977183Srwatson change_svgid(newcred, newcred->cr_groups[0]); 93031891Ssef setsugid(p); 93124450Speter } 93277812Sru p->p_ucred = newcred; 93394619Sjhb PROC_UNLOCK(p); 93477812Sru crfree(oldcred); 93594619Sjhb return (0); 9361541Srgrimes} 9371541Srgrimes 93856115Speter/* 93956115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the 94056115Speter * saved uid is explicit. 94156115Speter */ 94256115Speter 94324453Speter#ifndef _SYS_SYSPROTO_H_ 94456115Speterstruct setresuid_args { 94556115Speter uid_t ruid; 94656115Speter uid_t euid; 94756115Speter uid_t suid; 94856115Speter}; 94956115Speter#endif 95082749Sdillon/* 95182749Sdillon * MPSAFE 95282749Sdillon */ 95356115Speter/* ARGSUSED */ 95456115Speterint 95593580Sjhbsetresuid(register struct thread *td, struct setresuid_args *uap) 95656115Speter{ 95783366Sjulian struct proc *p = td->td_proc; 95877183Srwatson struct ucred *newcred, *oldcred; 95987218Srwatson uid_t euid, ruid, suid; 96098417Salfred struct uidinfo *euip, *ruip; 96156115Speter int error; 96256115Speter 96387218Srwatson euid = uap->euid; 96456115Speter ruid = uap->ruid; 96556115Speter suid = uap->suid; 96694619Sjhb newcred = crget(); 96798417Salfred euip = uifind(euid); 96898417Salfred ruip = uifind(ruid); 96994619Sjhb PROC_LOCK(p); 97077183Srwatson oldcred = p->p_ucred; 97177183Srwatson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 97277183Srwatson ruid != oldcred->cr_svuid && 97377183Srwatson ruid != oldcred->cr_uid) || 97477183Srwatson (euid != (uid_t)-1 && euid != oldcred->cr_ruid && 97577183Srwatson euid != oldcred->cr_svuid && 97677183Srwatson euid != oldcred->cr_uid) || 97777183Srwatson (suid != (uid_t)-1 && suid != oldcred->cr_ruid && 97877183Srwatson suid != oldcred->cr_svuid && 97977183Srwatson suid != oldcred->cr_uid)) && 980132653Scperciva (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) { 98194619Sjhb PROC_UNLOCK(p); 98298417Salfred uifree(ruip); 98398417Salfred uifree(euip); 98494619Sjhb crfree(newcred); 98594619Sjhb return (error); 98694619Sjhb } 98794619Sjhb 98894619Sjhb crcopy(newcred, oldcred); 98977183Srwatson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 99098417Salfred change_euid(newcred, euip); 99156115Speter setsugid(p); 99256115Speter } 99377183Srwatson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 99498417Salfred change_ruid(newcred, ruip); 99556115Speter setsugid(p); 99656115Speter } 99777183Srwatson if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) { 99877183Srwatson change_svuid(newcred, suid); 99956115Speter setsugid(p); 100056115Speter } 100177183Srwatson p->p_ucred = newcred; 100294619Sjhb PROC_UNLOCK(p); 100398417Salfred uifree(ruip); 100498417Salfred uifree(euip); 100577183Srwatson crfree(oldcred); 100694619Sjhb return (0); 100756115Speter} 100856115Speter 100956115Speter/* 101056115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the 101156115Speter * saved gid is explicit. 101256115Speter */ 101356115Speter 101456115Speter#ifndef _SYS_SYSPROTO_H_ 101556115Speterstruct setresgid_args { 101656115Speter gid_t rgid; 101756115Speter gid_t egid; 101856115Speter gid_t sgid; 101956115Speter}; 102056115Speter#endif 102187466Srwatson/* 102282749Sdillon * MPSAFE 102382749Sdillon */ 102456115Speter/* ARGSUSED */ 102556115Speterint 102693580Sjhbsetresgid(register struct thread *td, struct setresgid_args *uap) 102756115Speter{ 102883366Sjulian struct proc *p = td->td_proc; 102977183Srwatson struct ucred *newcred, *oldcred; 103087218Srwatson gid_t egid, rgid, sgid; 103156115Speter int error; 103256115Speter 103387218Srwatson egid = uap->egid; 103456115Speter rgid = uap->rgid; 103556115Speter sgid = uap->sgid; 103694619Sjhb newcred = crget(); 103794619Sjhb PROC_LOCK(p); 103877183Srwatson oldcred = p->p_ucred; 103977183Srwatson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 104077183Srwatson rgid != oldcred->cr_svgid && 104177183Srwatson rgid != oldcred->cr_groups[0]) || 104277183Srwatson (egid != (gid_t)-1 && egid != oldcred->cr_rgid && 104377183Srwatson egid != oldcred->cr_svgid && 104477183Srwatson egid != oldcred->cr_groups[0]) || 104577183Srwatson (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid && 104677183Srwatson sgid != oldcred->cr_svgid && 104777183Srwatson sgid != oldcred->cr_groups[0])) && 1048132653Scperciva (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) { 104994619Sjhb PROC_UNLOCK(p); 105094619Sjhb crfree(newcred); 105194619Sjhb return (error); 105294619Sjhb } 105394619Sjhb 105494619Sjhb crcopy(newcred, oldcred); 105577183Srwatson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 105677183Srwatson change_egid(newcred, egid); 105756115Speter setsugid(p); 105856115Speter } 105977183Srwatson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 106077183Srwatson change_rgid(newcred, rgid); 106156115Speter setsugid(p); 106256115Speter } 106377183Srwatson if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) { 106477183Srwatson change_svgid(newcred, sgid); 106556115Speter setsugid(p); 106656115Speter } 106777183Srwatson p->p_ucred = newcred; 106894619Sjhb PROC_UNLOCK(p); 106977183Srwatson crfree(oldcred); 107094619Sjhb return (0); 107156115Speter} 107256115Speter 107356115Speter#ifndef _SYS_SYSPROTO_H_ 107456115Speterstruct getresuid_args { 107556115Speter uid_t *ruid; 107656115Speter uid_t *euid; 107756115Speter uid_t *suid; 107856115Speter}; 107956115Speter#endif 108082749Sdillon/* 108182749Sdillon * MPSAFE 108282749Sdillon */ 108356115Speter/* ARGSUSED */ 108456115Speterint 108593580Sjhbgetresuid(register struct thread *td, struct getresuid_args *uap) 108656115Speter{ 108782749Sdillon struct ucred *cred; 108856115Speter int error1 = 0, error2 = 0, error3 = 0; 108956115Speter 109093264Sdillon cred = td->td_ucred; 109156115Speter if (uap->ruid) 109299009Salfred error1 = copyout(&cred->cr_ruid, 109399009Salfred uap->ruid, sizeof(cred->cr_ruid)); 109456115Speter if (uap->euid) 109599009Salfred error2 = copyout(&cred->cr_uid, 109699009Salfred uap->euid, sizeof(cred->cr_uid)); 109756115Speter if (uap->suid) 109899009Salfred error3 = copyout(&cred->cr_svuid, 109999009Salfred uap->suid, sizeof(cred->cr_svuid)); 110087218Srwatson return (error1 ? error1 : error2 ? error2 : error3); 110156115Speter} 110256115Speter 110356115Speter#ifndef _SYS_SYSPROTO_H_ 110456115Speterstruct getresgid_args { 110556115Speter gid_t *rgid; 110656115Speter gid_t *egid; 110756115Speter gid_t *sgid; 110856115Speter}; 110956115Speter#endif 111082749Sdillon/* 111182749Sdillon * MPSAFE 111282749Sdillon */ 111356115Speter/* ARGSUSED */ 111456115Speterint 111593580Sjhbgetresgid(register struct thread *td, struct getresgid_args *uap) 111656115Speter{ 111782749Sdillon struct ucred *cred; 111856115Speter int error1 = 0, error2 = 0, error3 = 0; 111956115Speter 112093264Sdillon cred = td->td_ucred; 112156115Speter if (uap->rgid) 112299009Salfred error1 = copyout(&cred->cr_rgid, 112399009Salfred uap->rgid, sizeof(cred->cr_rgid)); 112456115Speter if (uap->egid) 112599009Salfred error2 = copyout(&cred->cr_groups[0], 112699009Salfred uap->egid, sizeof(cred->cr_groups[0])); 112756115Speter if (uap->sgid) 112899009Salfred error3 = copyout(&cred->cr_svgid, 112999009Salfred uap->sgid, sizeof(cred->cr_svgid)); 113087218Srwatson return (error1 ? error1 : error2 ? error2 : error3); 113156115Speter} 113256115Speter 113356115Speter#ifndef _SYS_SYSPROTO_H_ 113424453Speterstruct issetugid_args { 113524453Speter int dummy; 113624453Speter}; 113724453Speter#endif 113887218Srwatson/* 1139116121Sjhb * MPSAFE 114087218Srwatson */ 114124453Speter/* ARGSUSED */ 114224453Speterint 114393580Sjhbissetugid(register struct thread *td, struct issetugid_args *uap) 114424453Speter{ 114583366Sjulian struct proc *p = td->td_proc; 114683366Sjulian 114724453Speter /* 114824453Speter * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 114924453Speter * we use P_SUGID because we consider changing the owners as 115024453Speter * "tainting" as well. 115124453Speter * This is significant for procs that start as root and "become" 115224453Speter * a user without an exec - programs cannot know *everything* 115324453Speter * that libc *might* have put in their data segment. 115424453Speter */ 115591140Stanimura PROC_LOCK(p); 115683366Sjulian td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 115791140Stanimura PROC_UNLOCK(p); 115824453Speter return (0); 115924453Speter} 116024453Speter 116182749Sdillon/* 116282749Sdillon * MPSAFE 116382749Sdillon */ 116475426Srwatsonint 116593580Sjhb__setugid(struct thread *td, struct __setugid_args *uap) 116675426Srwatson{ 116782749Sdillon#ifdef REGRESSION 116894619Sjhb struct proc *p; 116975426Srwatson 117094619Sjhb p = td->td_proc; 117175426Srwatson switch (uap->flag) { 117275426Srwatson case 0: 117394619Sjhb PROC_LOCK(p); 117494619Sjhb p->p_flag &= ~P_SUGID; 117594619Sjhb PROC_UNLOCK(p); 117694619Sjhb return (0); 117775426Srwatson case 1: 117894619Sjhb PROC_LOCK(p); 117994619Sjhb p->p_flag |= P_SUGID; 118094619Sjhb PROC_UNLOCK(p); 118194619Sjhb return (0); 118275426Srwatson default: 118394619Sjhb return (EINVAL); 118475426Srwatson } 118575426Srwatson#else /* !REGRESSION */ 118687218Srwatson 118775426Srwatson return (ENOSYS); 118887218Srwatson#endif /* REGRESSION */ 118975426Srwatson} 119075426Srwatson 11911541Srgrimes/* 11921541Srgrimes * Check if gid is a member of the group set. 119393264Sdillon * 119493264Sdillon * MPSAFE (cred must be held) 11951541Srgrimes */ 11961549Srgrimesint 119793580Sjhbgroupmember(gid_t gid, struct ucred *cred) 11981541Srgrimes{ 11991541Srgrimes register gid_t *gp; 12001541Srgrimes gid_t *egp; 12011541Srgrimes 12021541Srgrimes egp = &(cred->cr_groups[cred->cr_ngroups]); 12031541Srgrimes for (gp = cred->cr_groups; gp < egp; gp++) 12041541Srgrimes if (*gp == gid) 12051541Srgrimes return (1); 12061541Srgrimes return (0); 12071541Srgrimes} 12081541Srgrimes 120982424Srwatson/* 121089414Sarr * `suser_enabled' (which can be set by the security.suser_enabled 121182466Srwatson * sysctl) determines whether the system 'super-user' policy is in effect. 121282466Srwatson * If it is nonzero, an effective uid of 0 connotes special privilege, 121382466Srwatson * overriding many mandatory and discretionary protections. If it is zero, 121482466Srwatson * uid 0 is offered no special privilege in the kernel security policy. 121582466Srwatson * Setting it to zero may seriously impact the functionality of many 121682466Srwatson * existing userland programs, and should not be done without careful 121782466Srwatson * consideration of the consequences. 121882424Srwatson */ 121982693Srwatsonint suser_enabled = 1; 122089414SarrSYSCTL_INT(_security_bsd, OID_AUTO, suser_enabled, CTLFLAG_RW, 122182693Srwatson &suser_enabled, 0, "processes with uid 0 have privilege"); 122289414SarrTUNABLE_INT("security.bsd.suser_enabled", &suser_enabled); 122361287Srwatson 12241541Srgrimes/* 122582466Srwatson * Test whether the specified credentials imply "super-user" privilege. 1226132255Scperciva * Return 0 or EPERM. 12271541Srgrimes */ 12281549Srgrimesint 122993593Sjhbsuser_cred(struct ucred *cred, int flag) 123046112Sphk{ 123187218Srwatson 123282693Srwatson if (!suser_enabled) 123361282Srwatson return (EPERM); 1234132255Scperciva if (((flag & SUSER_RUID) ? cred->cr_ruid : cred->cr_uid) != 0) 123546155Sphk return (EPERM); 1236132653Scperciva if (jailed(cred) && !(flag & SUSER_ALLOWJAIL)) 123746155Sphk return (EPERM); 123846155Sphk return (0); 12391541Srgrimes} 12401541Srgrimes 124183639Srwatson/* 124293593Sjhb * Shortcut to hide contents of struct td and struct proc from the 124393593Sjhb * caller, promoting binary compatibility. 124493593Sjhb */ 124593593Sjhbint 124693593Sjhbsuser(struct thread *td) 124793593Sjhb{ 124893593Sjhb 1249132548Srwatson#ifdef INVARIANTS 1250132548Srwatson if (td != curthread) { 1251132548Srwatson printf("suser: thread %p (%d %s) != curthread %p (%d %s)\n", 1252132548Srwatson td, td->td_proc->p_pid, td->td_proc->p_comm, 1253132548Srwatson curthread, curthread->td_proc->p_pid, 1254132548Srwatson curthread->td_proc->p_comm); 1255132548Srwatson#ifdef KDB 1256132548Srwatson kdb_backtrace(); 1257132548Srwatson#endif 1258132548Srwatson } 1259132548Srwatson#endif 126093593Sjhb return (suser_cred(td->td_ucred, 0)); 126193593Sjhb} 126293593Sjhb 126393593Sjhb/* 126487218Srwatson * Test the active securelevel against a given level. securelevel_gt() 126587218Srwatson * implements (securelevel > level). securelevel_ge() implements 126687218Srwatson * (securelevel >= level). Note that the logic is inverted -- these 126787218Srwatson * functions return EPERM on "success" and 0 on "failure". 126883639Srwatson * 126993264Sdillon * MPSAFE 127083639Srwatson */ 127183639Srwatsonint 127283639Srwatsonsecurelevel_gt(struct ucred *cr, int level) 127383639Srwatson{ 127487218Srwatson int active_securelevel; 127583639Srwatson 127687218Srwatson active_securelevel = securelevel; 127793732Sjhb KASSERT(cr != NULL, ("securelevel_gt: null cr")); 127887275Srwatson if (cr->cr_prison != NULL) { 127987275Srwatson mtx_lock(&cr->cr_prison->pr_mtx); 128087218Srwatson active_securelevel = imax(cr->cr_prison->pr_securelevel, 128187218Srwatson active_securelevel); 128287275Srwatson mtx_unlock(&cr->cr_prison->pr_mtx); 128387275Srwatson } 128487218Srwatson return (active_securelevel > level ? EPERM : 0); 128583639Srwatson} 128683639Srwatson 128783639Srwatsonint 128883639Srwatsonsecurelevel_ge(struct ucred *cr, int level) 128983639Srwatson{ 129087218Srwatson int active_securelevel; 129183639Srwatson 129287218Srwatson active_securelevel = securelevel; 129393732Sjhb KASSERT(cr != NULL, ("securelevel_ge: null cr")); 129487275Srwatson if (cr->cr_prison != NULL) { 129587275Srwatson mtx_lock(&cr->cr_prison->pr_mtx); 129687218Srwatson active_securelevel = imax(cr->cr_prison->pr_securelevel, 129787218Srwatson active_securelevel); 129887275Srwatson mtx_unlock(&cr->cr_prison->pr_mtx); 129987275Srwatson } 130087218Srwatson return (active_securelevel >= level ? EPERM : 0); 130183639Srwatson} 130283639Srwatson 130384736Srwatson/* 130487144Srwatson * 'see_other_uids' determines whether or not visibility of processes 130587218Srwatson * and sockets with credentials holding different real uids is possible 130687138Srwatson * using a variety of system MIBs. 130787218Srwatson * XXX: data declarations should be together near the beginning of the file. 130884736Srwatson */ 130987144Srwatsonstatic int see_other_uids = 1; 131089414SarrSYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW, 131187218Srwatson &see_other_uids, 0, 131284736Srwatson "Unprivileged processes may see subjects/objects with different real uid"); 131384736Srwatson 131482466Srwatson/*- 131592923Srwatson * Determine if u1 "can see" the subject specified by u2, according to the 131692923Srwatson * 'see_other_uids' policy. 131792923Srwatson * Returns: 0 for permitted, ESRCH otherwise 131892923Srwatson * Locks: none 131992923Srwatson * References: *u1 and *u2 must not change during the call 132092923Srwatson * u1 may equal u2, in which case only one reference is required 132192923Srwatson */ 132292923Srwatsonstatic int 132392923Srwatsoncr_seeotheruids(struct ucred *u1, struct ucred *u2) 132492923Srwatson{ 132592923Srwatson 132692923Srwatson if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) { 1327132653Scperciva if (suser_cred(u1, SUSER_ALLOWJAIL) != 0) 132892923Srwatson return (ESRCH); 132992923Srwatson } 133092923Srwatson return (0); 133192923Srwatson} 133292923Srwatson 1333122869Srwatson/* 1334122869Srwatson * 'see_other_gids' determines whether or not visibility of processes 1335122869Srwatson * and sockets with credentials holding different real gids is possible 1336122869Srwatson * using a variety of system MIBs. 1337122869Srwatson * XXX: data declarations should be together near the beginning of the file. 1338122869Srwatson */ 1339122869Srwatsonstatic int see_other_gids = 1; 1340122869SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, see_other_gids, CTLFLAG_RW, 1341122869Srwatson &see_other_gids, 0, 1342122869Srwatson "Unprivileged processes may see subjects/objects with different real gid"); 1343122869Srwatson 1344122869Srwatson/* 1345122869Srwatson * Determine if u1 can "see" the subject specified by u2, according to the 1346122869Srwatson * 'see_other_gids' policy. 1347122869Srwatson * Returns: 0 for permitted, ESRCH otherwise 1348122869Srwatson * Locks: none 1349122869Srwatson * References: *u1 and *u2 must not change during the call 1350122869Srwatson * u1 may equal u2, in which case only one reference is required 1351122869Srwatson */ 1352122869Srwatsonstatic int 1353122869Srwatsoncr_seeothergids(struct ucred *u1, struct ucred *u2) 1354122869Srwatson{ 1355122869Srwatson int i, match; 1356122869Srwatson 1357122869Srwatson if (!see_other_gids) { 1358122869Srwatson match = 0; 1359122869Srwatson for (i = 0; i < u1->cr_ngroups; i++) { 1360122869Srwatson if (groupmember(u1->cr_groups[i], u2)) 1361122869Srwatson match = 1; 1362122869Srwatson if (match) 1363122869Srwatson break; 1364122869Srwatson } 1365122869Srwatson if (!match) { 1366132653Scperciva if (suser_cred(u1, SUSER_ALLOWJAIL) != 0) 1367122869Srwatson return (ESRCH); 1368122869Srwatson } 1369122869Srwatson } 1370122869Srwatson return (0); 1371122869Srwatson} 1372122869Srwatson 137392923Srwatson/*- 137482466Srwatson * Determine if u1 "can see" the subject specified by u2. 137574956Srwatson * Returns: 0 for permitted, an errno value otherwise 137674956Srwatson * Locks: none 137787218Srwatson * References: *u1 and *u2 must not change during the call 137874956Srwatson * u1 may equal u2, in which case only one reference is required 137974956Srwatson */ 138074956Srwatsonint 138183742Srwatsoncr_cansee(struct ucred *u1, struct ucred *u2) 138265237Srwatson{ 138372786Srwatson int error; 138453518Sphk 138574956Srwatson if ((error = prison_check(u1, u2))) 138672786Srwatson return (error); 1387101003Srwatson#ifdef MAC 1388101003Srwatson if ((error = mac_check_cred_visible(u1, u2))) 1389101003Srwatson return (error); 1390101003Srwatson#endif 139192923Srwatson if ((error = cr_seeotheruids(u1, u2))) 139292923Srwatson return (error); 1393122869Srwatson if ((error = cr_seeothergids(u1, u2))) 1394122869Srwatson return (error); 139565237Srwatson return (0); 139665237Srwatson} 139765237Srwatson 139882466Srwatson/*- 139996886Sjhb * Determine if td "can see" the subject specified by p. 140082424Srwatson * Returns: 0 for permitted, an errno value otherwise 140196886Sjhb * Locks: Sufficient locks to protect p->p_ucred must be held. td really 140296886Sjhb * should be curthread. 140396886Sjhb * References: td and p must be valid for the lifetime of the call 140482424Srwatson */ 140579335Srwatsonint 140696886Sjhbp_cansee(struct thread *td, struct proc *p) 140774956Srwatson{ 140874956Srwatson 140983742Srwatson /* Wrap cr_cansee() for all functionality. */ 141096886Sjhb KASSERT(td == curthread, ("%s: td not curthread", __func__)); 141196886Sjhb PROC_LOCK_ASSERT(p, MA_OWNED); 141296886Sjhb return (cr_cansee(td->td_ucred, p->p_ucred)); 141374956Srwatson} 141474956Srwatson 1415120052Srwatson/* 1416120052Srwatson * 'conservative_signals' prevents the delivery of a broad class of 1417120052Srwatson * signals by unprivileged processes to processes that have changed their 1418120052Srwatson * credentials since the last invocation of execve(). This can prevent 1419120052Srwatson * the leakage of cached information or retained privileges as a result 1420120052Srwatson * of a common class of signal-related vulnerabilities. However, this 1421120052Srwatson * may interfere with some applications that expect to be able to 1422120052Srwatson * deliver these signals to peer processes after having given up 1423120052Srwatson * privilege. 1424120052Srwatson */ 1425120052Srwatsonstatic int conservative_signals = 1; 1426120052SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, conservative_signals, CTLFLAG_RW, 1427120052Srwatson &conservative_signals, 0, "Unprivileged processes prevented from " 1428120052Srwatson "sending certain signals to processes whose credentials have changed"); 142982466Srwatson/*- 143088943Srwatson * Determine whether cred may deliver the specified signal to proc. 143188943Srwatson * Returns: 0 for permitted, an errno value otherwise. 143288943Srwatson * Locks: A lock must be held for proc. 143388943Srwatson * References: cred and proc must be valid for the lifetime of the call. 143475437Srwatson */ 143575437Srwatsonint 143688943Srwatsoncr_cansignal(struct ucred *cred, struct proc *proc, int signum) 143753518Sphk{ 143882466Srwatson int error; 143984826Sjhb 144096886Sjhb PROC_LOCK_ASSERT(proc, MA_OWNED); 144175437Srwatson /* 144288943Srwatson * Jail semantics limit the scope of signalling to proc in the 144388943Srwatson * same jail as cred, if cred is in jail. 144475437Srwatson */ 144588943Srwatson error = prison_check(cred, proc->p_ucred); 144688943Srwatson if (error) 144772786Srwatson return (error); 1448101003Srwatson#ifdef MAC 1449101003Srwatson if ((error = mac_check_proc_signal(cred, proc, signum))) 1450101003Srwatson return (error); 1451101003Srwatson#endif 1452122869Srwatson if ((error = cr_seeotheruids(cred, proc->p_ucred))) 145392923Srwatson return (error); 1454122869Srwatson if ((error = cr_seeothergids(cred, proc->p_ucred))) 1455122869Srwatson return (error); 145665237Srwatson 145765237Srwatson /* 145882424Srwatson * UNIX signal semantics depend on the status of the P_SUGID 145982424Srwatson * bit on the target process. If the bit is set, then additional 146082424Srwatson * restrictions are placed on the set of available signals. 146175437Srwatson */ 1462120052Srwatson if (conservative_signals && (proc->p_flag & P_SUGID)) { 146375437Srwatson switch (signum) { 146475437Srwatson case 0: 146575437Srwatson case SIGKILL: 146675437Srwatson case SIGINT: 146775437Srwatson case SIGTERM: 1468120052Srwatson case SIGALRM: 146975437Srwatson case SIGSTOP: 147075437Srwatson case SIGTTIN: 147175437Srwatson case SIGTTOU: 147275437Srwatson case SIGTSTP: 147375437Srwatson case SIGHUP: 147475437Srwatson case SIGUSR1: 147575437Srwatson case SIGUSR2: 147682466Srwatson /* 147782466Srwatson * Generally, permit job and terminal control 147882466Srwatson * signals. 147982466Srwatson */ 148075437Srwatson break; 148175437Srwatson default: 148288943Srwatson /* Not permitted without privilege. */ 1483132653Scperciva error = suser_cred(cred, SUSER_ALLOWJAIL); 148475437Srwatson if (error) 148575437Srwatson return (error); 148675437Srwatson } 148765237Srwatson } 148865237Srwatson 148975480Srwatson /* 149082424Srwatson * Generally, the target credential's ruid or svuid must match the 149175480Srwatson * subject credential's ruid or euid. 149275480Srwatson */ 149388943Srwatson if (cred->cr_ruid != proc->p_ucred->cr_ruid && 149488943Srwatson cred->cr_ruid != proc->p_ucred->cr_svuid && 149588943Srwatson cred->cr_uid != proc->p_ucred->cr_ruid && 149688943Srwatson cred->cr_uid != proc->p_ucred->cr_svuid) { 149788943Srwatson /* Not permitted without privilege. */ 1498132653Scperciva error = suser_cred(cred, SUSER_ALLOWJAIL); 149975480Srwatson if (error) 150075480Srwatson return (error); 150175480Srwatson } 150275480Srwatson 150387218Srwatson return (0); 150453518Sphk} 150553518Sphk 150688943Srwatson 150782466Srwatson/*- 150896886Sjhb * Determine whether td may deliver the specified signal to p. 150988943Srwatson * Returns: 0 for permitted, an errno value otherwise 151096886Sjhb * Locks: Sufficient locks to protect various components of td and p 151196886Sjhb * must be held. td must be curthread, and a lock must be 151296886Sjhb * held for p. 151396886Sjhb * References: td and p must be valid for the lifetime of the call 151488943Srwatson */ 151588943Srwatsonint 151696886Sjhbp_cansignal(struct thread *td, struct proc *p, int signum) 151788943Srwatson{ 151888943Srwatson 151996886Sjhb KASSERT(td == curthread, ("%s: td not curthread", __func__)); 152096886Sjhb PROC_LOCK_ASSERT(p, MA_OWNED); 152196886Sjhb if (td->td_proc == p) 152288943Srwatson return (0); 152388943Srwatson 152488943Srwatson /* 152588943Srwatson * UNIX signalling semantics require that processes in the same 152688943Srwatson * session always be able to deliver SIGCONT to one another, 152788943Srwatson * overriding the remaining protections. 152888943Srwatson */ 152996886Sjhb /* XXX: This will require an additional lock of some sort. */ 153096886Sjhb if (signum == SIGCONT && td->td_proc->p_session == p->p_session) 153188943Srwatson return (0); 153288943Srwatson 153396886Sjhb return (cr_cansignal(td->td_ucred, p, signum)); 153488943Srwatson} 153588943Srwatson 153688943Srwatson/*- 153796886Sjhb * Determine whether td may reschedule p. 153882466Srwatson * Returns: 0 for permitted, an errno value otherwise 153996886Sjhb * Locks: Sufficient locks to protect various components of td and p 154096886Sjhb * must be held. td must be curthread, and a lock must 154196886Sjhb * be held for p. 154296886Sjhb * References: td and p must be valid for the lifetime of the call 154382424Srwatson */ 154479335Srwatsonint 154596886Sjhbp_cansched(struct thread *td, struct proc *p) 154665237Srwatson{ 154772786Srwatson int error; 154865237Srwatson 154996886Sjhb KASSERT(td == curthread, ("%s: td not curthread", __func__)); 155096886Sjhb PROC_LOCK_ASSERT(p, MA_OWNED); 155196886Sjhb if (td->td_proc == p) 155265237Srwatson return (0); 155396886Sjhb if ((error = prison_check(td->td_ucred, p->p_ucred))) 155472786Srwatson return (error); 1555101003Srwatson#ifdef MAC 1556101003Srwatson if ((error = mac_check_proc_sched(td->td_ucred, p))) 1557101003Srwatson return (error); 1558101003Srwatson#endif 155996886Sjhb if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) 156092923Srwatson return (error); 1561122869Srwatson if ((error = cr_seeothergids(td->td_ucred, p->p_ucred))) 1562122869Srwatson return (error); 156396886Sjhb if (td->td_ucred->cr_ruid == p->p_ucred->cr_ruid) 156465237Srwatson return (0); 156596886Sjhb if (td->td_ucred->cr_uid == p->p_ucred->cr_ruid) 156665237Srwatson return (0); 1567132653Scperciva if (suser_cred(td->td_ucred, SUSER_ALLOWJAIL) == 0) 156865237Srwatson return (0); 156965237Srwatson 157065237Srwatson#ifdef CAPABILITIES 1571132653Scperciva if (!cap_check(NULL, td, CAP_SYS_NICE, SUSER_ALLOWJAIL)) 157265237Srwatson return (0); 157365237Srwatson#endif 157465237Srwatson 157565237Srwatson return (EPERM); 157665237Srwatson} 157765237Srwatson 157882424Srwatson/* 157987280Srwatson * The 'unprivileged_proc_debug' flag may be used to disable a variety of 158087280Srwatson * unprivileged inter-process debugging services, including some procfs 158187280Srwatson * functionality, ptrace(), and ktrace(). In the past, inter-process 158287280Srwatson * debugging has been involved in a variety of security problems, and sites 158387280Srwatson * not requiring the service might choose to disable it when hardening 158487280Srwatson * systems. 158582424Srwatson * 158682424Srwatson * XXX: Should modifying and reading this variable require locking? 158787218Srwatson * XXX: data declarations should be together near the beginning of the file. 158882424Srwatson */ 158987144Srwatsonstatic int unprivileged_proc_debug = 1; 159089414SarrSYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW, 159187218Srwatson &unprivileged_proc_debug, 0, 159280735Srwatson "Unprivileged processes may use process debugging facilities"); 159380735Srwatson 159482466Srwatson/*- 159596886Sjhb * Determine whether td may debug p. 159682466Srwatson * Returns: 0 for permitted, an errno value otherwise 159796886Sjhb * Locks: Sufficient locks to protect various components of td and p 159896886Sjhb * must be held. td must be curthread, and a lock must 159996886Sjhb * be held for p. 160096886Sjhb * References: td and p must be valid for the lifetime of the call 160182424Srwatson */ 160279335Srwatsonint 160396886Sjhbp_candebug(struct thread *td, struct proc *p) 160465237Srwatson{ 160587218Srwatson int credentialchanged, error, grpsubset, i, uidsubset; 160665237Srwatson 160796886Sjhb KASSERT(td == curthread, ("%s: td not curthread", __func__)); 160896886Sjhb PROC_LOCK_ASSERT(p, MA_OWNED); 160987144Srwatson if (!unprivileged_proc_debug) { 1610132653Scperciva error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL); 161184727Srwatson if (error) 161284727Srwatson return (error); 161384727Srwatson } 161496886Sjhb if (td->td_proc == p) 161584636Sdes return (0); 161696886Sjhb if ((error = prison_check(td->td_ucred, p->p_ucred))) 161772786Srwatson return (error); 1618101003Srwatson#ifdef MAC 1619101003Srwatson if ((error = mac_check_proc_debug(td->td_ucred, p))) 1620101003Srwatson return (error); 1621101003Srwatson#endif 162296886Sjhb if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) 162392923Srwatson return (error); 1624122869Srwatson if ((error = cr_seeothergids(td->td_ucred, p->p_ucred))) 1625122869Srwatson return (error); 162665237Srwatson 162782466Srwatson /* 162896886Sjhb * Is p's group set a subset of td's effective group set? This 162996886Sjhb * includes p's egid, group access list, rgid, and svgid. 163082466Srwatson */ 163185895Srwatson grpsubset = 1; 163296886Sjhb for (i = 0; i < p->p_ucred->cr_ngroups; i++) { 163396886Sjhb if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) { 163485895Srwatson grpsubset = 0; 163585895Srwatson break; 163685895Srwatson } 163785895Srwatson } 163885895Srwatson grpsubset = grpsubset && 163996886Sjhb groupmember(p->p_ucred->cr_rgid, td->td_ucred) && 164096886Sjhb groupmember(p->p_ucred->cr_svgid, td->td_ucred); 164185895Srwatson 164285895Srwatson /* 164396886Sjhb * Are the uids present in p's credential equal to td's 164496886Sjhb * effective uid? This includes p's euid, svuid, and ruid. 164585895Srwatson */ 164696886Sjhb uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid && 164796886Sjhb td->td_ucred->cr_uid == p->p_ucred->cr_svuid && 164896886Sjhb td->td_ucred->cr_uid == p->p_ucred->cr_ruid); 164985895Srwatson 165085895Srwatson /* 165185895Srwatson * Has the credential of the process changed since the last exec()? 165285895Srwatson */ 165396886Sjhb credentialchanged = (p->p_flag & P_SUGID); 165485895Srwatson 165585895Srwatson /* 165696886Sjhb * If p's gids aren't a subset, or the uids aren't a subset, 165785895Srwatson * or the credential has changed, require appropriate privilege 165896886Sjhb * for td to debug p. For POSIX.1e capabilities, this will 165985895Srwatson * require CAP_SYS_PTRACE. 166085895Srwatson */ 166185895Srwatson if (!grpsubset || !uidsubset || credentialchanged) { 1662132653Scperciva error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL); 166384727Srwatson if (error) 166465237Srwatson return (error); 166582466Srwatson } 166665237Srwatson 166787218Srwatson /* Can't trace init when securelevel > 0. */ 166896886Sjhb if (p == initproc) { 166996886Sjhb error = securelevel_gt(td->td_ucred, 0); 167083639Srwatson if (error) 167183639Srwatson return (error); 167283639Srwatson } 167365237Srwatson 167485880Srwatson /* 167585880Srwatson * Can't trace a process that's currently exec'ing. 167685880Srwatson * XXX: Note, this is not a security policy decision, it's a 167785880Srwatson * basic correctness/functionality decision. Therefore, this check 167885880Srwatson * should be moved to the caller's of p_candebug(). 167985880Srwatson */ 168096886Sjhb if ((p->p_flag & P_INEXEC) != 0) 168185598Sdes return (EAGAIN); 168287466Srwatson 168365237Srwatson return (0); 168465237Srwatson} 168565237Srwatson 168692976Srwatson/*- 168792976Srwatson * Determine whether the subject represented by cred can "see" a socket. 168892976Srwatson * Returns: 0 for permitted, ENOENT otherwise. 168992976Srwatson */ 169092976Srwatsonint 169192976Srwatsoncr_canseesocket(struct ucred *cred, struct socket *so) 169292976Srwatson{ 169392976Srwatson int error; 169492976Srwatson 169592976Srwatson error = prison_check(cred, so->so_cred); 169692976Srwatson if (error) 169792976Srwatson return (ENOENT); 1698101003Srwatson#ifdef MAC 1699130398Srwatson SOCK_LOCK(so); 1700101003Srwatson error = mac_check_socket_visible(cred, so); 1701130398Srwatson SOCK_UNLOCK(so); 1702101003Srwatson if (error) 1703101003Srwatson return (error); 1704101003Srwatson#endif 170592976Srwatson if (cr_seeotheruids(cred, so->so_cred)) 170692976Srwatson return (ENOENT); 1707122869Srwatson if (cr_seeothergids(cred, so->so_cred)) 1708122869Srwatson return (ENOENT); 170992976Srwatson 171092976Srwatson return (0); 171192976Srwatson} 171292976Srwatson 171353518Sphk/* 17141541Srgrimes * Allocate a zeroed cred structure. 1715116406Srwatson * MPSAFE 17161541Srgrimes */ 17171541Srgrimesstruct ucred * 171893580Sjhbcrget(void) 17191541Srgrimes{ 17201541Srgrimes register struct ucred *cr; 17211541Srgrimes 1722111119Simp MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK | M_ZERO); 17231541Srgrimes cr->cr_ref = 1; 1724117494Struckman cr->cr_mtxp = mtx_pool_find(mtxpool_sleep, cr); 1725101001Srwatson#ifdef MAC 1726101001Srwatson mac_init_cred(cr); 1727101001Srwatson#endif 17281541Srgrimes return (cr); 17291541Srgrimes} 17301541Srgrimes 17311541Srgrimes/* 173282466Srwatson * Claim another reference to a ucred structure. 1733116406Srwatson * MPSAFE 173469401Salfred */ 173584827Sjhbstruct ucred * 173693580Sjhbcrhold(struct ucred *cr) 173769401Salfred{ 173869401Salfred 173990756Sdillon mtx_lock(cr->cr_mtxp); 174069401Salfred cr->cr_ref++; 174190756Sdillon mtx_unlock(cr->cr_mtxp); 174284827Sjhb return (cr); 174369401Salfred} 174469401Salfred 174569401Salfred/* 17461541Srgrimes * Free a cred structure. 17471541Srgrimes * Throws away space when ref count gets to 0. 1748116406Srwatson * MPSAFE 17491541Srgrimes */ 17501549Srgrimesvoid 175193580Sjhbcrfree(struct ucred *cr) 17521541Srgrimes{ 175390756Sdillon struct mtx *mtxp = cr->cr_mtxp; 175469239Salfred 175590756Sdillon mtx_lock(mtxp); 175675632Salfred KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref)); 175765495Struckman if (--cr->cr_ref == 0) { 1758124884Srwatson mtx_unlock(mtxp); 175965495Struckman /* 176065495Struckman * Some callers of crget(), such as nfs_statfs(), 176165495Struckman * allocate a temporary credential, but don't 176265495Struckman * allocate a uidinfo structure. 176365495Struckman */ 176465495Struckman if (cr->cr_uidinfo != NULL) 176565495Struckman uifree(cr->cr_uidinfo); 176677277Srwatson if (cr->cr_ruidinfo != NULL) 176777277Srwatson uifree(cr->cr_ruidinfo); 176872786Srwatson /* 176972786Srwatson * Free a prison, if any. 177072786Srwatson */ 177172786Srwatson if (jailed(cr)) 177272786Srwatson prison_free(cr->cr_prison); 1773101001Srwatson#ifdef MAC 1774101001Srwatson mac_destroy_cred(cr); 1775101001Srwatson#endif 177699009Salfred FREE(cr, M_CRED); 177790756Sdillon } else { 177890756Sdillon mtx_unlock(mtxp); 177990756Sdillon } 17801541Srgrimes} 17811541Srgrimes 17821541Srgrimes/* 178384827Sjhb * Check to see if this ucred is shared. 1784116406Srwatson * MPSAFE 17851541Srgrimes */ 178684827Sjhbint 178793580Sjhbcrshared(struct ucred *cr) 17881541Srgrimes{ 178984827Sjhb int shared; 17901541Srgrimes 179190756Sdillon mtx_lock(cr->cr_mtxp); 179284827Sjhb shared = (cr->cr_ref > 1); 179390756Sdillon mtx_unlock(cr->cr_mtxp); 179484827Sjhb return (shared); 17951541Srgrimes} 17961541Srgrimes 17971541Srgrimes/* 179884827Sjhb * Copy a ucred's contents from a template. Does not block. 1799116406Srwatson * MPSAFE 180084827Sjhb */ 180184827Sjhbvoid 180293580Sjhbcrcopy(struct ucred *dest, struct ucred *src) 180384827Sjhb{ 180484827Sjhb 180584827Sjhb KASSERT(crshared(dest) == 0, ("crcopy of shared ucred")); 180684827Sjhb bcopy(&src->cr_startcopy, &dest->cr_startcopy, 180787218Srwatson (unsigned)((caddr_t)&src->cr_endcopy - 180884827Sjhb (caddr_t)&src->cr_startcopy)); 180984827Sjhb uihold(dest->cr_uidinfo); 181084827Sjhb uihold(dest->cr_ruidinfo); 181184827Sjhb if (jailed(dest)) 181284827Sjhb prison_hold(dest->cr_prison); 1813101001Srwatson#ifdef MAC 1814123173Srwatson mac_copy_cred(src, dest); 1815101001Srwatson#endif 181684827Sjhb} 181784827Sjhb 181884827Sjhb/* 18191541Srgrimes * Dup cred struct to a new held one. 1820116406Srwatson * MPSAFE 18211541Srgrimes */ 18221541Srgrimesstruct ucred * 182393580Sjhbcrdup(struct ucred *cr) 18241541Srgrimes{ 18251541Srgrimes struct ucred *newcr; 18261541Srgrimes 182784827Sjhb newcr = crget(); 182884827Sjhb crcopy(newcr, cr); 18291541Srgrimes return (newcr); 18301541Srgrimes} 18311541Srgrimes 18321541Srgrimes/* 183391354Sdd * Fill in a struct xucred based on a struct ucred. 1834116406Srwatson * MPSAFE 183591354Sdd */ 183691354Sddvoid 183793580Sjhbcru2x(struct ucred *cr, struct xucred *xcr) 183891354Sdd{ 183991354Sdd 184091354Sdd bzero(xcr, sizeof(*xcr)); 184191354Sdd xcr->cr_version = XUCRED_VERSION; 184291354Sdd xcr->cr_uid = cr->cr_uid; 184391354Sdd xcr->cr_ngroups = cr->cr_ngroups; 184491354Sdd bcopy(cr->cr_groups, xcr->cr_groups, sizeof(cr->cr_groups)); 184591354Sdd} 184691354Sdd 184791354Sdd/* 184890748Sjulian * small routine to swap a thread's current ucred for the correct one 184990748Sjulian * taken from the process. 1850116406Srwatson * MPSAFE 185190748Sjulian */ 185290748Sjulianvoid 185390748Sjuliancred_update_thread(struct thread *td) 185490748Sjulian{ 185590748Sjulian struct proc *p; 185691405Sjhb struct ucred *cred; 185790748Sjulian 185890748Sjulian p = td->td_proc; 185991405Sjhb cred = td->td_ucred; 186090748Sjulian PROC_LOCK(p); 186190748Sjulian td->td_ucred = crhold(p->p_ucred); 186290748Sjulian PROC_UNLOCK(p); 186391405Sjhb if (cred != NULL) 186491405Sjhb crfree(cred); 186590748Sjulian} 186690748Sjulian 186790748Sjulian/* 18681541Srgrimes * Get login name, if available. 18691541Srgrimes */ 187012221Sbde#ifndef _SYS_SYSPROTO_H_ 18711541Srgrimesstruct getlogin_args { 18721541Srgrimes char *namebuf; 18731541Srgrimes u_int namelen; 18741541Srgrimes}; 187512221Sbde#endif 187682749Sdillon/* 187782749Sdillon * MPSAFE 187882749Sdillon */ 18791541Srgrimes/* ARGSUSED */ 18801549Srgrimesint 188193580Sjhbgetlogin(struct thread *td, struct getlogin_args *uap) 18821541Srgrimes{ 188382749Sdillon int error; 188491140Stanimura char login[MAXLOGNAME]; 188583366Sjulian struct proc *p = td->td_proc; 18861541Srgrimes 188723358Sache if (uap->namelen > MAXLOGNAME) 188823359Sache uap->namelen = MAXLOGNAME; 188991140Stanimura PROC_LOCK(p); 189091140Stanimura SESS_LOCK(p->p_session); 189191140Stanimura bcopy(p->p_session->s_login, login, uap->namelen); 189291140Stanimura SESS_UNLOCK(p->p_session); 189391140Stanimura PROC_UNLOCK(p); 189499009Salfred error = copyout(login, uap->namebuf, uap->namelen); 189582749Sdillon return(error); 18961541Srgrimes} 18971541Srgrimes 18981541Srgrimes/* 18991541Srgrimes * Set login name. 19001541Srgrimes */ 190112221Sbde#ifndef _SYS_SYSPROTO_H_ 19021541Srgrimesstruct setlogin_args { 19031541Srgrimes char *namebuf; 19041541Srgrimes}; 190512221Sbde#endif 190682749Sdillon/* 190782749Sdillon * MPSAFE 190882749Sdillon */ 19091541Srgrimes/* ARGSUSED */ 19101549Srgrimesint 191193580Sjhbsetlogin(struct thread *td, struct setlogin_args *uap) 19121541Srgrimes{ 191383366Sjulian struct proc *p = td->td_proc; 19141541Srgrimes int error; 191523330Sache char logintmp[MAXLOGNAME]; 19161541Srgrimes 1917132653Scperciva error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL); 191894619Sjhb if (error) 191994619Sjhb return (error); 192099009Salfred error = copyinstr(uap->namebuf, logintmp, sizeof(logintmp), NULL); 192187218Srwatson if (error == ENAMETOOLONG) 19221541Srgrimes error = EINVAL; 192391140Stanimura else if (!error) { 192491140Stanimura PROC_LOCK(p); 192591140Stanimura SESS_LOCK(p->p_session); 192691140Stanimura (void) memcpy(p->p_session->s_login, logintmp, 192723330Sache sizeof(logintmp)); 192891140Stanimura SESS_UNLOCK(p->p_session); 192991140Stanimura PROC_UNLOCK(p); 193091140Stanimura } 19311541Srgrimes return (error); 19321541Srgrimes} 193331891Ssef 193431891Ssefvoid 193593580Sjhbsetsugid(struct proc *p) 193631891Ssef{ 193798403Salfred 193898403Salfred PROC_LOCK_ASSERT(p, MA_OWNED); 193931891Ssef p->p_flag |= P_SUGID; 194055707Ssef if (!(p->p_pfsflags & PF_ISUGID)) 194131891Ssef p->p_stops = 0; 194231891Ssef} 194365495Struckman 194482466Srwatson/*- 194582466Srwatson * Change a process's effective uid. 194677183Srwatson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified. 194777183Srwatson * References: newcred must be an exclusive credential reference for the 194877183Srwatson * duration of the call. 194965495Struckman */ 195065495Struckmanvoid 195198417Salfredchange_euid(struct ucred *newcred, struct uidinfo *euip) 195265495Struckman{ 195365495Struckman 195498417Salfred newcred->cr_uid = euip->ui_uid; 195598417Salfred uihold(euip); 195677183Srwatson uifree(newcred->cr_uidinfo); 195798417Salfred newcred->cr_uidinfo = euip; 195865495Struckman} 195965495Struckman 196082466Srwatson/*- 196182466Srwatson * Change a process's effective gid. 196277183Srwatson * Side effects: newcred->cr_gid will be modified. 196377183Srwatson * References: newcred must be an exclusive credential reference for the 196477183Srwatson * duration of the call. 196565495Struckman */ 196667629Sgallatinvoid 196793580Sjhbchange_egid(struct ucred *newcred, gid_t egid) 196865495Struckman{ 196965495Struckman 197077183Srwatson newcred->cr_groups[0] = egid; 197165495Struckman} 197277183Srwatson 197382466Srwatson/*- 197482466Srwatson * Change a process's real uid. 197577183Srwatson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo 197677183Srwatson * will be updated, and the old and new cr_ruidinfo proc 197777183Srwatson * counts will be updated. 197877183Srwatson * References: newcred must be an exclusive credential reference for the 197977183Srwatson * duration of the call. 198077183Srwatson */ 198177183Srwatsonvoid 198298417Salfredchange_ruid(struct ucred *newcred, struct uidinfo *ruip) 198377183Srwatson{ 198477183Srwatson 198577183Srwatson (void)chgproccnt(newcred->cr_ruidinfo, -1, 0); 198698417Salfred newcred->cr_ruid = ruip->ui_uid; 198798417Salfred uihold(ruip); 198877183Srwatson uifree(newcred->cr_ruidinfo); 198998417Salfred newcred->cr_ruidinfo = ruip; 199077183Srwatson (void)chgproccnt(newcred->cr_ruidinfo, 1, 0); 199177183Srwatson} 199277183Srwatson 199382466Srwatson/*- 199482466Srwatson * Change a process's real gid. 199577183Srwatson * Side effects: newcred->cr_rgid will be updated. 199677183Srwatson * References: newcred must be an exclusive credential reference for the 199777183Srwatson * duration of the call. 199877183Srwatson */ 199977183Srwatsonvoid 200093580Sjhbchange_rgid(struct ucred *newcred, gid_t rgid) 200177183Srwatson{ 200277183Srwatson 200377183Srwatson newcred->cr_rgid = rgid; 200477183Srwatson} 200577183Srwatson 200682466Srwatson/*- 200782466Srwatson * Change a process's saved uid. 200877183Srwatson * Side effects: newcred->cr_svuid will be updated. 200977183Srwatson * References: newcred must be an exclusive credential reference for the 201077183Srwatson * duration of the call. 201177183Srwatson */ 201277183Srwatsonvoid 201393580Sjhbchange_svuid(struct ucred *newcred, uid_t svuid) 201477183Srwatson{ 201577183Srwatson 201677183Srwatson newcred->cr_svuid = svuid; 201777183Srwatson} 201877183Srwatson 201982466Srwatson/*- 202082466Srwatson * Change a process's saved gid. 202177183Srwatson * Side effects: newcred->cr_svgid will be updated. 202277183Srwatson * References: newcred must be an exclusive credential reference for the 202377183Srwatson * duration of the call. 202477183Srwatson */ 202577183Srwatsonvoid 202693580Sjhbchange_svgid(struct ucred *newcred, gid_t svgid) 202777183Srwatson{ 202877183Srwatson 202977183Srwatson newcred->cr_svgid = svgid; 203077183Srwatson} 2031