kern_prot.c revision 92987
11541Srgrimes/* 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 * 3. All advertising materials mentioning features or use of this software 201541Srgrimes * must display the following acknowledgement: 211541Srgrimes * This product includes software developed by the University of 221541Srgrimes * California, Berkeley and its contributors. 231541Srgrimes * 4. Neither the name of the University nor the names of its contributors 241541Srgrimes * may be used to endorse or promote products derived from this software 251541Srgrimes * without specific prior written permission. 261541Srgrimes * 271541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 281541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 291541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 301541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 311541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 321541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 331541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 341541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 351541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 361541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 371541Srgrimes * SUCH DAMAGE. 381541Srgrimes * 391541Srgrimes * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 4050477Speter * $FreeBSD: head/sys/kern/kern_prot.c 92987 2002-03-22 22:32:04Z jhb $ 411541Srgrimes */ 421541Srgrimes 431541Srgrimes/* 441541Srgrimes * System calls related to processes and protection 451541Srgrimes */ 461541Srgrimes 4731778Seivind#include "opt_compat.h" 4831778Seivind 491541Srgrimes#include <sys/param.h> 5076166Smarkm#include <sys/systm.h> 511541Srgrimes#include <sys/acct.h> 5241059Speter#include <sys/kernel.h> 5370317Sjake#include <sys/lock.h> 5491140Stanimura#include <sys/malloc.h> 5576166Smarkm#include <sys/mutex.h> 5691140Stanimura#include <sys/sx.h> 571541Srgrimes#include <sys/proc.h> 5876166Smarkm#include <sys/sysproto.h> 5987218Srwatson#include <sys/jail.h> 6031891Ssef#include <sys/pioctl.h> 6165495Struckman#include <sys/resourcevar.h> 6292976Srwatson#include <sys/socket.h> 6392976Srwatson#include <sys/socketvar.h> 6461287Srwatson#include <sys/sysctl.h> 651541Srgrimes 6630354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials"); 6730354Sphk 6889414SarrSYSCTL_DECL(_security); 6989414SarrSYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0, 7087138Srwatson "BSD security policy"); 7187138Srwatson 7212221Sbde#ifndef _SYS_SYSPROTO_H_ 7311332Sswallacestruct getpid_args { 741541Srgrimes int dummy; 751541Srgrimes}; 7612221Sbde#endif 7758717Sdillon/* 7882749Sdillon * MPSAFE 7982749Sdillon */ 801541Srgrimes/* ARGSUSED */ 811549Srgrimesint 8283366Sjuliangetpid(td, uap) 8383366Sjulian struct thread *td; 8411332Sswallace struct getpid_args *uap; 851541Srgrimes{ 8683366Sjulian struct proc *p = td->td_proc; 8785564Sdillon int s; 881541Srgrimes 8985564Sdillon s = mtx_lock_giant(kern_giant_proc); 9083366Sjulian td->td_retval[0] = p->p_pid; 911541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 9274728Sjhb PROC_LOCK(p); 9383366Sjulian td->td_retval[1] = p->p_pptr->p_pid; 9474728Sjhb PROC_UNLOCK(p); 951541Srgrimes#endif 9685564Sdillon mtx_unlock_giant(s); 971541Srgrimes return (0); 981541Srgrimes} 991541Srgrimes 10012221Sbde#ifndef _SYS_SYSPROTO_H_ 10111332Sswallacestruct getppid_args { 10211332Sswallace int dummy; 10311332Sswallace}; 10412221Sbde#endif 10582749Sdillon/* 10682749Sdillon * MPSAFE 10782749Sdillon */ 1081541Srgrimes/* ARGSUSED */ 1091549Srgrimesint 11083366Sjuliangetppid(td, uap) 11183366Sjulian struct thread *td; 11211332Sswallace struct getppid_args *uap; 1131541Srgrimes{ 11483366Sjulian struct proc *p = td->td_proc; 11585564Sdillon int s; 1161541Srgrimes 11785564Sdillon s = mtx_lock_giant(kern_giant_proc); 11874728Sjhb PROC_LOCK(p); 11983366Sjulian td->td_retval[0] = p->p_pptr->p_pid; 12074728Sjhb PROC_UNLOCK(p); 12185564Sdillon mtx_unlock_giant(s); 1221541Srgrimes return (0); 1231541Srgrimes} 1241541Srgrimes 12587466Srwatson/* 12687218Srwatson * Get process group ID; note that POSIX getpgrp takes no parameter. 12758717Sdillon */ 12812221Sbde#ifndef _SYS_SYSPROTO_H_ 12911332Sswallacestruct getpgrp_args { 13011332Sswallace int dummy; 13111332Sswallace}; 13212221Sbde#endif 13382749Sdillon/* 13482749Sdillon * MPSAFE 13582749Sdillon */ 1361549Srgrimesint 13783366Sjuliangetpgrp(td, uap) 13883366Sjulian struct thread *td; 13911332Sswallace struct getpgrp_args *uap; 1401541Srgrimes{ 14183366Sjulian struct proc *p = td->td_proc; 14291140Stanimura int s; 1431541Srgrimes 14491140Stanimura s = mtx_lock_giant(kern_giant_proc); 14591140Stanimura PROC_LOCK(p); 14683366Sjulian td->td_retval[0] = p->p_pgrp->pg_id; 14791140Stanimura PROC_UNLOCK(p); 14891140Stanimura mtx_unlock_giant(s); 1491541Srgrimes return (0); 1501541Srgrimes} 1511541Srgrimes 15228401Speter/* Get an arbitary pid's process group id */ 15312221Sbde#ifndef _SYS_SYSPROTO_H_ 15428401Speterstruct getpgid_args { 15528401Speter pid_t pid; 15628401Speter}; 15728401Speter#endif 15882749Sdillon/* 15982749Sdillon * MPSAFE 16082749Sdillon */ 16128401Speterint 16283366Sjuliangetpgid(td, uap) 16383366Sjulian struct thread *td; 16428401Speter struct getpgid_args *uap; 16528401Speter{ 16683366Sjulian struct proc *p = td->td_proc; 16741726Struckman struct proc *pt; 16892985Sjhb int error; 16941726Struckman 17092985Sjhb mtx_lock(&Giant); 17187218Srwatson error = 0; 17291140Stanimura if (uap->pid == 0) { 17391140Stanimura PROC_LOCK(p); 17483366Sjulian td->td_retval[0] = p->p_pgrp->pg_id; 17591140Stanimura PROC_UNLOCK(p); 17691140Stanimura } else if ((pt = pfind(uap->pid)) == NULL) 17784825Sjhb error = ESRCH; 17875893Sjhb else { 17984825Sjhb error = p_cansee(p, pt); 18084825Sjhb if (error == 0) 18184825Sjhb td->td_retval[0] = pt->p_pgrp->pg_id; 18275893Sjhb PROC_UNLOCK(pt); 18375893Sjhb } 18492985Sjhb mtx_unlock(&Giant); 18582749Sdillon return (error); 18628401Speter} 18728401Speter 18828401Speter/* 18928401Speter * Get an arbitary pid's session id. 19028401Speter */ 19128401Speter#ifndef _SYS_SYSPROTO_H_ 19228401Speterstruct getsid_args { 19328401Speter pid_t pid; 19428401Speter}; 19528401Speter#endif 19682749Sdillon/* 19782749Sdillon * MPSAFE 19882749Sdillon */ 19928401Speterint 20083366Sjuliangetsid(td, uap) 20183366Sjulian struct thread *td; 20228401Speter struct getsid_args *uap; 20328401Speter{ 20483366Sjulian struct proc *p = td->td_proc; 20541726Struckman struct proc *pt; 20687218Srwatson int error; 20741726Struckman 20892985Sjhb mtx_lock(&Giant); 20987218Srwatson error = 0; 21091140Stanimura if (uap->pid == 0) { 21191140Stanimura PROC_LOCK(p); 21283366Sjulian td->td_retval[0] = p->p_session->s_sid; 21391140Stanimura PROC_UNLOCK(p); 21491140Stanimura } else if ((pt = pfind(uap->pid)) == NULL) 21584825Sjhb error = ESRCH; 21684825Sjhb else { 21784825Sjhb error = p_cansee(p, pt); 21884825Sjhb if (error == 0) 21984825Sjhb td->td_retval[0] = pt->p_session->s_sid; 22075893Sjhb PROC_UNLOCK(pt); 22175893Sjhb } 22292985Sjhb mtx_unlock(&Giant); 22382749Sdillon return (error); 22428401Speter} 22528401Speter 22628401Speter#ifndef _SYS_SYSPROTO_H_ 22711332Sswallacestruct getuid_args { 22811332Sswallace int dummy; 22911332Sswallace}; 23012221Sbde#endif 23182749Sdillon/* 23282749Sdillon * MPSAFE 23382749Sdillon */ 2341541Srgrimes/* ARGSUSED */ 2351549Srgrimesint 23683366Sjuliangetuid(td, uap) 23783366Sjulian struct thread *td; 23811332Sswallace struct getuid_args *uap; 2391541Srgrimes{ 2401541Srgrimes 24192987Sjhb td->td_retval[0] = td->td_ucred->cr_ruid; 2421541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 24392987Sjhb td->td_retval[1] = td->td_ucred->cr_uid; 2441541Srgrimes#endif 2451541Srgrimes return (0); 2461541Srgrimes} 2471541Srgrimes 24812221Sbde#ifndef _SYS_SYSPROTO_H_ 24911332Sswallacestruct geteuid_args { 25011332Sswallace int dummy; 25111332Sswallace}; 25212221Sbde#endif 25387218Srwatson/* 25487218Srwatson * MPSAFE 25587218Srwatson */ 2561541Srgrimes/* ARGSUSED */ 2571549Srgrimesint 25883366Sjuliangeteuid(td, uap) 25983366Sjulian struct thread *td; 26011332Sswallace struct geteuid_args *uap; 2611541Srgrimes{ 26292987Sjhb 26392987Sjhb td->td_retval[0] = td->td_ucred->cr_uid; 2641541Srgrimes return (0); 2651541Srgrimes} 2661541Srgrimes 26712221Sbde#ifndef _SYS_SYSPROTO_H_ 26811332Sswallacestruct getgid_args { 26911332Sswallace int dummy; 27011332Sswallace}; 27112221Sbde#endif 27282749Sdillon/* 27382749Sdillon * MPSAFE 27482749Sdillon */ 2751541Srgrimes/* ARGSUSED */ 2761549Srgrimesint 27783366Sjuliangetgid(td, uap) 27883366Sjulian struct thread *td; 27911332Sswallace struct getgid_args *uap; 2801541Srgrimes{ 2811541Srgrimes 28292987Sjhb td->td_retval[0] = td->td_ucred->cr_rgid; 2831541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 28492987Sjhb td->td_retval[1] = td->td_ucred->cr_groups[0]; 2851541Srgrimes#endif 2861541Srgrimes return (0); 2871541Srgrimes} 2881541Srgrimes 2891541Srgrimes/* 2901541Srgrimes * Get effective group ID. The "egid" is groups[0], and could be obtained 2911541Srgrimes * via getgroups. This syscall exists because it is somewhat painful to do 2921541Srgrimes * correctly in a library function. 2931541Srgrimes */ 29412221Sbde#ifndef _SYS_SYSPROTO_H_ 29511332Sswallacestruct getegid_args { 29611332Sswallace int dummy; 29711332Sswallace}; 29812221Sbde#endif 29982749Sdillon/* 30082749Sdillon * MPSAFE 30182749Sdillon */ 3021541Srgrimes/* ARGSUSED */ 3031549Srgrimesint 30483366Sjuliangetegid(td, uap) 30583366Sjulian struct thread *td; 30611332Sswallace struct getegid_args *uap; 3071541Srgrimes{ 3081541Srgrimes 30992987Sjhb td->td_retval[0] = td->td_ucred->cr_groups[0]; 3101541Srgrimes return (0); 3111541Srgrimes} 3121541Srgrimes 31312221Sbde#ifndef _SYS_SYSPROTO_H_ 3141541Srgrimesstruct getgroups_args { 3151541Srgrimes u_int gidsetsize; 3161541Srgrimes gid_t *gidset; 3171541Srgrimes}; 31812221Sbde#endif 31982749Sdillon/* 32082749Sdillon * MPSAFE 32182749Sdillon */ 3221549Srgrimesint 32383366Sjuliangetgroups(td, uap) 32483366Sjulian struct thread *td; 32587218Srwatson register struct getgroups_args *uap; 3261541Srgrimes{ 32782749Sdillon struct ucred *cred; 32877183Srwatson u_int ngrp; 32987218Srwatson int error; 3301541Srgrimes 33192987Sjhb cred = td->td_ucred; 3321541Srgrimes if ((ngrp = uap->gidsetsize) == 0) { 33383366Sjulian td->td_retval[0] = cred->cr_ngroups; 33492987Sjhb return (0); 3351541Srgrimes } 33692987Sjhb if (ngrp < cred->cr_ngroups) 33792987Sjhb return (EINVAL); 33877183Srwatson ngrp = cred->cr_ngroups; 33992987Sjhb error = copyout((caddr_t)cred->cr_groups, (caddr_t)uap->gidset, 34092987Sjhb ngrp * sizeof(gid_t)); 34192987Sjhb if (error) 34292987Sjhb return (error); 34383366Sjulian td->td_retval[0] = ngrp; 34492987Sjhb return (0); 3451541Srgrimes} 3461541Srgrimes 34712221Sbde#ifndef _SYS_SYSPROTO_H_ 34812207Sbdestruct setsid_args { 34911332Sswallace int dummy; 35011332Sswallace}; 35112221Sbde#endif 35282749Sdillon/* 35382749Sdillon * MPSAFE 35482749Sdillon */ 3551541Srgrimes/* ARGSUSED */ 3561549Srgrimesint 35783366Sjuliansetsid(td, uap) 35883366Sjulian register struct thread *td; 35912207Sbde struct setsid_args *uap; 3601541Srgrimes{ 36191140Stanimura struct pgrp *pgrp; 36282749Sdillon int error; 36383366Sjulian struct proc *p = td->td_proc; 36491140Stanimura struct pgrp *newpgrp; 36591140Stanimura struct session *newsess; 3661541Srgrimes 36791140Stanimura error = 0; 36891140Stanimura pgrp = NULL; 36991140Stanimura 37082749Sdillon mtx_lock(&Giant); 37191140Stanimura 37291140Stanimura MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); 37391140Stanimura MALLOC(newsess, struct session *, sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO); 37491140Stanimura 37591140Stanimura PGRPSESS_XLOCK(); 37691140Stanimura 37791140Stanimura if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) { 37891140Stanimura if (pgrp != NULL) 37991140Stanimura PGRP_UNLOCK(pgrp); 38082749Sdillon error = EPERM; 38191140Stanimura goto fail; 38291140Stanimura } else { 38391140Stanimura (void)enterpgrp(p, p->p_pid, newpgrp, newsess); 38483366Sjulian td->td_retval[0] = p->p_pid; 38582749Sdillon error = 0; 3861541Srgrimes } 38791140Stanimura PGRPSESS_XUNLOCK(); 38882749Sdillon mtx_unlock(&Giant); 38991140Stanimura return (0); 39091140Stanimura 39191140Stanimurafail: 39291140Stanimura PGRPSESS_XUNLOCK(); 39391140Stanimura 39491140Stanimura FREE(newpgrp, M_PGRP); 39591140Stanimura FREE(newsess, M_SESSION); 39691140Stanimura 39791140Stanimura mtx_unlock(&Giant); 39891140Stanimura return (0); 3991541Srgrimes} 4001541Srgrimes 4011541Srgrimes/* 4021541Srgrimes * set process group (setpgid/old setpgrp) 4031541Srgrimes * 4041541Srgrimes * caller does setpgid(targpid, targpgid) 4051541Srgrimes * 4061541Srgrimes * pid must be caller or child of caller (ESRCH) 4071541Srgrimes * if a child 4081541Srgrimes * pid must be in same session (EPERM) 4091541Srgrimes * pid can't have done an exec (EACCES) 4101541Srgrimes * if pgid != pid 4111541Srgrimes * there must exist some pid in same session having pgid (EPERM) 4121541Srgrimes * pid must not be session leader (EPERM) 4131541Srgrimes */ 41412221Sbde#ifndef _SYS_SYSPROTO_H_ 4151541Srgrimesstruct setpgid_args { 41687218Srwatson int pid; /* target process id */ 41787218Srwatson int pgid; /* target pgrp id */ 4181541Srgrimes}; 41912221Sbde#endif 42082749Sdillon/* 42182749Sdillon * MPSAFE 42282749Sdillon */ 4231541Srgrimes/* ARGSUSED */ 4241549Srgrimesint 42583366Sjuliansetpgid(td, uap) 42683366Sjulian struct thread *td; 4271541Srgrimes register struct setpgid_args *uap; 4281541Srgrimes{ 42983366Sjulian struct proc *curp = td->td_proc; 43087218Srwatson register struct proc *targp; /* target process */ 43187218Srwatson register struct pgrp *pgrp; /* target pgrp */ 43275448Srwatson int error; 43391140Stanimura struct pgrp *newpgrp; 4341541Srgrimes 43520677Sbde if (uap->pgid < 0) 43620677Sbde return (EINVAL); 43791140Stanimura 43891140Stanimura error = 0; 43991140Stanimura 44082749Sdillon mtx_lock(&Giant); 44191140Stanimura 44291140Stanimura MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); 44391140Stanimura 44491140Stanimura PGRPSESS_XLOCK(); 44591140Stanimura 4461541Srgrimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 44791140Stanimura sx_slock(&proctree_lock); 44891140Stanimura if ((targp = pfind(uap->pid)) == NULL) { 44975893Sjhb if (targp) 45075893Sjhb PROC_UNLOCK(targp); 45191140Stanimura sx_sunlock(&proctree_lock); 45282749Sdillon error = ESRCH; 45391140Stanimura goto fail; 45475893Sjhb } 45591140Stanimura if (!inferior(targp)) { 45691140Stanimura PROC_UNLOCK(targp); 45791140Stanimura sx_sunlock(&proctree_lock); 45891371Stanimura error = ESRCH; 45991140Stanimura goto fail; 46091140Stanimura } 46191140Stanimura sx_sunlock(&proctree_lock); 46279335Srwatson if ((error = p_cansee(curproc, targp))) { 46375893Sjhb PROC_UNLOCK(targp); 46491140Stanimura goto fail; 46575893Sjhb } 46675893Sjhb if (targp->p_pgrp == NULL || 46775893Sjhb targp->p_session != curp->p_session) { 46875893Sjhb PROC_UNLOCK(targp); 46982749Sdillon error = EPERM; 47091140Stanimura goto fail; 47175893Sjhb } 47275893Sjhb if (targp->p_flag & P_EXEC) { 47375893Sjhb PROC_UNLOCK(targp); 47482749Sdillon error = EACCES; 47591140Stanimura goto fail; 47675893Sjhb } 47791140Stanimura PROC_UNLOCK(targp); 47891140Stanimura } else 4791541Srgrimes targp = curp; 48075893Sjhb if (SESS_LEADER(targp)) { 48182749Sdillon error = EPERM; 48291140Stanimura goto fail; 48375893Sjhb } 48487218Srwatson if (uap->pgid == 0) 4851541Srgrimes uap->pgid = targp->p_pid; 48691140Stanimura if (uap->pgid == targp->p_pid) { 48791140Stanimura if (targp->p_pgid == uap->pgid) 48891140Stanimura goto done; 48991140Stanimura error = enterpgrp(targp, uap->pgid, newpgrp, NULL); 49091140Stanimura if (error == 0) 49191140Stanimura newpgrp = NULL; 49291140Stanimura } else { 49391140Stanimura if ((pgrp = pgfind(uap->pgid)) == NULL || 49487218Srwatson pgrp->pg_session != curp->p_session) { 49591140Stanimura if (pgrp != NULL) 49691140Stanimura PGRP_UNLOCK(pgrp); 49782749Sdillon error = EPERM; 49891140Stanimura goto fail; 49975893Sjhb } 50091140Stanimura if (pgrp == targp->p_pgrp) { 50191140Stanimura PGRP_UNLOCK(pgrp); 50291140Stanimura goto done; 50391140Stanimura } 50491140Stanimura PGRP_UNLOCK(pgrp); 50591140Stanimura error = enterthispgrp(targp, pgrp); 50682749Sdillon } 50791140Stanimuradone: 50891140Stanimura PGRPSESS_XUNLOCK(); 50991140Stanimura if (newpgrp != NULL) 51091140Stanimura FREE(newpgrp, M_PGRP); 51182749Sdillon mtx_unlock(&Giant); 51291140Stanimura return (0); 51391140Stanimura 51491140Stanimurafail: 51591140Stanimura PGRPSESS_XUNLOCK(); 51691140Stanimura 51791140Stanimura KASSERT(newpgrp != NULL, ("setpgid failed and newpgrp is null.")); 51891371Stanimura KASSERT(error != 0, ("setpgid successfully failed?")); 51991140Stanimura FREE(newpgrp, M_PGRP); 52091140Stanimura 52191140Stanimura mtx_unlock(&Giant); 52282749Sdillon return (error); 5231541Srgrimes} 5241541Srgrimes 52524448Speter/* 52624448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 52772093Sasmodai * compatible. It says that setting the uid/gid to euid/egid is a special 52824448Speter * case of "appropriate privilege". Once the rules are expanded out, this 52924448Speter * basically means that setuid(nnn) sets all three id's, in all permitted 53024448Speter * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 53124448Speter * does not set the saved id - this is dangerous for traditional BSD 53224448Speter * programs. For this reason, we *really* do not want to set 53324448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 53424448Speter */ 53524448Speter#define POSIX_APPENDIX_B_4_2_2 53624448Speter 53712221Sbde#ifndef _SYS_SYSPROTO_H_ 5381541Srgrimesstruct setuid_args { 5391541Srgrimes uid_t uid; 5401541Srgrimes}; 54112221Sbde#endif 54282749Sdillon/* 54382749Sdillon * MPSAFE 54482749Sdillon */ 5451541Srgrimes/* ARGSUSED */ 5461549Srgrimesint 54783366Sjuliansetuid(td, uap) 54883366Sjulian struct thread *td; 5491541Srgrimes struct setuid_args *uap; 5501541Srgrimes{ 55183366Sjulian struct proc *p = td->td_proc; 55277183Srwatson struct ucred *newcred, *oldcred; 55377183Srwatson uid_t uid; 55487218Srwatson int error; 5551541Srgrimes 55677183Srwatson uid = uap->uid; 55782749Sdillon mtx_lock(&Giant); 55887218Srwatson error = 0; 55987219Srwatson oldcred = p->p_ucred; 56087466Srwatson 56124448Speter /* 56224448Speter * See if we have "permission" by POSIX 1003.1 rules. 56324448Speter * 56487218Srwatson * Note that setuid(geteuid()) is a special case of 56524448Speter * "appropriate privileges" in appendix B.4.2.2. We need 56672093Sasmodai * to use this clause to be compatible with traditional BSD 56724448Speter * semantics. Basically, it means that "setuid(xx)" sets all 56824448Speter * three id's (assuming you have privs). 56924448Speter * 57024448Speter * Notes on the logic. We do things in three steps. 57124448Speter * 1: We determine if the euid is going to change, and do EPERM 57224448Speter * right away. We unconditionally change the euid later if this 57324448Speter * test is satisfied, simplifying that part of the logic. 57487218Srwatson * 2: We determine if the real and/or saved uids are going to 57524448Speter * change. Determined by compile options. 57624448Speter * 3: Change euid last. (after tests in #2 for "appropriate privs") 57724448Speter */ 57877183Srwatson if (uid != oldcred->cr_ruid && /* allow setuid(getuid()) */ 57917994Sache#ifdef _POSIX_SAVED_IDS 58077183Srwatson uid != oldcred->cr_svuid && /* allow setuid(saved gid) */ 58117994Sache#endif 58224448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 58377183Srwatson uid != oldcred->cr_uid && /* allow setuid(geteuid()) */ 58424448Speter#endif 58587218Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 58682749Sdillon goto done2; 58724448Speter 58877183Srwatson newcred = crdup(oldcred); 58924448Speter#ifdef _POSIX_SAVED_IDS 5901541Srgrimes /* 59124448Speter * Do we have "appropriate privileges" (are we root or uid == euid) 59224448Speter * If so, we are changing the real uid and/or saved uid. 5931541Srgrimes */ 59417994Sache if ( 59524448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 59677183Srwatson uid == oldcred->cr_uid || 59717994Sache#endif 59877183Srwatson suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */ 59917994Sache#endif 60024448Speter { 60124448Speter /* 60265495Struckman * Set the real uid and transfer proc count to new user. 60324448Speter */ 60477183Srwatson if (uid != oldcred->cr_ruid) { 60577183Srwatson change_ruid(newcred, uid); 60665495Struckman setsugid(p); 60724448Speter } 60824448Speter /* 60924448Speter * Set saved uid 61024448Speter * 61124448Speter * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 61224448Speter * the security of seteuid() depends on it. B.4.2.2 says it 61324448Speter * is important that we should do this. 61424448Speter */ 61577183Srwatson if (uid != oldcred->cr_svuid) { 61677183Srwatson change_svuid(newcred, uid); 61731891Ssef setsugid(p); 61824448Speter } 6198141Sache } 62024448Speter 62124448Speter /* 62224448Speter * In all permitted cases, we are changing the euid. 62324448Speter * Copy credentials so other references do not see our changes. 62424448Speter */ 62577183Srwatson if (uid != oldcred->cr_uid) { 62677183Srwatson change_euid(newcred, uid); 62731891Ssef setsugid(p); 62824448Speter } 62977183Srwatson p->p_ucred = newcred; 63077183Srwatson crfree(oldcred); 63182749Sdillondone2: 63282749Sdillon mtx_unlock(&Giant); 63382749Sdillon return (error); 6341541Srgrimes} 6351541Srgrimes 63612221Sbde#ifndef _SYS_SYSPROTO_H_ 6371541Srgrimesstruct seteuid_args { 6381541Srgrimes uid_t euid; 6391541Srgrimes}; 64012221Sbde#endif 64182749Sdillon/* 64282749Sdillon * MPSAFE 64382749Sdillon */ 6441541Srgrimes/* ARGSUSED */ 6451549Srgrimesint 64683366Sjulianseteuid(td, uap) 64783366Sjulian struct thread *td; 6481541Srgrimes struct seteuid_args *uap; 6491541Srgrimes{ 65083366Sjulian struct proc *p = td->td_proc; 65177183Srwatson struct ucred *newcred, *oldcred; 65277183Srwatson uid_t euid; 65387218Srwatson int error; 6541541Srgrimes 6551541Srgrimes euid = uap->euid; 65682749Sdillon mtx_lock(&Giant); 65787218Srwatson error = 0; 65877183Srwatson oldcred = p->p_ucred; 65977183Srwatson if (euid != oldcred->cr_ruid && /* allow seteuid(getuid()) */ 66077183Srwatson euid != oldcred->cr_svuid && /* allow seteuid(saved uid) */ 66187218Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 66282749Sdillon goto done2; 6631541Srgrimes /* 6641541Srgrimes * Everything's okay, do it. Copy credentials so other references do 6651541Srgrimes * not see our changes. 6661541Srgrimes */ 66777183Srwatson newcred = crdup(oldcred); 66877183Srwatson if (oldcred->cr_uid != euid) { 66977183Srwatson change_euid(newcred, euid); 67031891Ssef setsugid(p); 67124449Speter } 67277183Srwatson p->p_ucred = newcred; 67377183Srwatson crfree(oldcred); 67482749Sdillondone2: 67582749Sdillon mtx_unlock(&Giant); 67682749Sdillon return (error); 6771541Srgrimes} 6781541Srgrimes 67912221Sbde#ifndef _SYS_SYSPROTO_H_ 6801541Srgrimesstruct setgid_args { 6811541Srgrimes gid_t gid; 6821541Srgrimes}; 68312221Sbde#endif 68482749Sdillon/* 68582749Sdillon * MPSAFE 68682749Sdillon */ 6871541Srgrimes/* ARGSUSED */ 6881549Srgrimesint 68983366Sjuliansetgid(td, uap) 69083366Sjulian struct thread *td; 6911541Srgrimes struct setgid_args *uap; 6921541Srgrimes{ 69383366Sjulian struct proc *p = td->td_proc; 69477183Srwatson struct ucred *newcred, *oldcred; 69577183Srwatson gid_t gid; 69687218Srwatson int error; 6971541Srgrimes 69877183Srwatson gid = uap->gid; 69982749Sdillon mtx_lock(&Giant); 70087218Srwatson error = 0; 70177183Srwatson oldcred = p->p_ucred; 70287466Srwatson 70324448Speter /* 70424448Speter * See if we have "permission" by POSIX 1003.1 rules. 70524448Speter * 70624448Speter * Note that setgid(getegid()) is a special case of 70724448Speter * "appropriate privileges" in appendix B.4.2.2. We need 70872093Sasmodai * to use this clause to be compatible with traditional BSD 70924448Speter * semantics. Basically, it means that "setgid(xx)" sets all 71024448Speter * three id's (assuming you have privs). 71124448Speter * 71224448Speter * For notes on the logic here, see setuid() above. 71324448Speter */ 71477183Srwatson if (gid != oldcred->cr_rgid && /* allow setgid(getgid()) */ 71517994Sache#ifdef _POSIX_SAVED_IDS 71677183Srwatson gid != oldcred->cr_svgid && /* allow setgid(saved gid) */ 71717994Sache#endif 71824448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 71977183Srwatson gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */ 72024448Speter#endif 72187218Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 72282749Sdillon goto done2; 72324448Speter 72477183Srwatson newcred = crdup(oldcred); 72517994Sache#ifdef _POSIX_SAVED_IDS 72624448Speter /* 72724448Speter * Do we have "appropriate privileges" (are we root or gid == egid) 72824448Speter * If so, we are changing the real uid and saved gid. 72924448Speter */ 73024448Speter if ( 73124448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 73277183Srwatson gid == oldcred->cr_groups[0] || 73317994Sache#endif 73477183Srwatson suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */ 73524448Speter#endif 73624448Speter { 73724448Speter /* 73824448Speter * Set real gid 73924448Speter */ 74077183Srwatson if (oldcred->cr_rgid != gid) { 74177183Srwatson change_rgid(newcred, gid); 74231891Ssef setsugid(p); 74324448Speter } 74424448Speter /* 74524448Speter * Set saved gid 74624448Speter * 74724448Speter * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 74824448Speter * the security of setegid() depends on it. B.4.2.2 says it 74924448Speter * is important that we should do this. 75024448Speter */ 75177183Srwatson if (oldcred->cr_svgid != gid) { 75277183Srwatson change_svgid(newcred, gid); 75331891Ssef setsugid(p); 75424448Speter } 7558141Sache } 75624448Speter /* 75724448Speter * In all cases permitted cases, we are changing the egid. 75824448Speter * Copy credentials so other references do not see our changes. 75924448Speter */ 76077183Srwatson if (oldcred->cr_groups[0] != gid) { 76177183Srwatson change_egid(newcred, gid); 76231891Ssef setsugid(p); 76324448Speter } 76477183Srwatson p->p_ucred = newcred; 76577183Srwatson crfree(oldcred); 76682749Sdillondone2: 76782749Sdillon mtx_unlock(&Giant); 76882749Sdillon return (error); 7691541Srgrimes} 7701541Srgrimes 77112221Sbde#ifndef _SYS_SYSPROTO_H_ 7721541Srgrimesstruct setegid_args { 7731541Srgrimes gid_t egid; 7741541Srgrimes}; 77512221Sbde#endif 77682749Sdillon/* 77782749Sdillon * MPSAFE 77882749Sdillon */ 7791541Srgrimes/* ARGSUSED */ 7801549Srgrimesint 78183366Sjuliansetegid(td, uap) 78283366Sjulian struct thread *td; 7831541Srgrimes struct setegid_args *uap; 7841541Srgrimes{ 78583366Sjulian struct proc *p = td->td_proc; 78677183Srwatson struct ucred *newcred, *oldcred; 78777183Srwatson gid_t egid; 78887218Srwatson int error; 7891541Srgrimes 7901541Srgrimes egid = uap->egid; 79182749Sdillon mtx_lock(&Giant); 79287218Srwatson error = 0; 79377183Srwatson oldcred = p->p_ucred; 79477183Srwatson if (egid != oldcred->cr_rgid && /* allow setegid(getgid()) */ 79577183Srwatson egid != oldcred->cr_svgid && /* allow setegid(saved gid) */ 79687218Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 79782749Sdillon goto done2; 79877183Srwatson newcred = crdup(oldcred); 79977183Srwatson if (oldcred->cr_groups[0] != egid) { 80077183Srwatson change_egid(newcred, egid); 80131891Ssef setsugid(p); 80224449Speter } 80377183Srwatson p->p_ucred = newcred; 80477183Srwatson crfree(oldcred); 80582749Sdillondone2: 80682749Sdillon mtx_unlock(&Giant); 80782749Sdillon return (error); 8081541Srgrimes} 8091541Srgrimes 81012221Sbde#ifndef _SYS_SYSPROTO_H_ 8111541Srgrimesstruct setgroups_args { 8121541Srgrimes u_int gidsetsize; 8131541Srgrimes gid_t *gidset; 8141541Srgrimes}; 81512221Sbde#endif 81682749Sdillon/* 81782749Sdillon * MPSAFE 81882749Sdillon */ 8191541Srgrimes/* ARGSUSED */ 8201549Srgrimesint 82183366Sjuliansetgroups(td, uap) 82283366Sjulian struct thread *td; 8231541Srgrimes struct setgroups_args *uap; 8241541Srgrimes{ 82583366Sjulian struct proc *p = td->td_proc; 82677183Srwatson struct ucred *newcred, *oldcred; 82777183Srwatson u_int ngrp; 8281541Srgrimes int error; 8291541Srgrimes 83087220Srwatson ngrp = uap->gidsetsize; 83182749Sdillon mtx_lock(&Giant); 83277183Srwatson oldcred = p->p_ucred; 83387218Srwatson if ((error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 83482749Sdillon goto done2; 83582749Sdillon if (ngrp > NGROUPS) { 83682749Sdillon error = EINVAL; 83782749Sdillon goto done2; 83882749Sdillon } 83924447Speter /* 84024447Speter * XXX A little bit lazy here. We could test if anything has 84124447Speter * changed before crcopy() and setting P_SUGID. 84224447Speter */ 84377183Srwatson newcred = crdup(oldcred); 84424447Speter if (ngrp < 1) { 84524447Speter /* 84624447Speter * setgroups(0, NULL) is a legitimate way of clearing the 84724447Speter * groups vector on non-BSD systems (which generally do not 84824447Speter * have the egid in the groups[0]). We risk security holes 84924447Speter * when running non-BSD software if we do not do the same. 85024447Speter */ 85177183Srwatson newcred->cr_ngroups = 1; 85224447Speter } else { 85324447Speter if ((error = copyin((caddr_t)uap->gidset, 85477183Srwatson (caddr_t)newcred->cr_groups, ngrp * sizeof(gid_t)))) { 85577183Srwatson crfree(newcred); 85682749Sdillon goto done2; 85777183Srwatson } 85877183Srwatson newcred->cr_ngroups = ngrp; 85924447Speter } 86031891Ssef setsugid(p); 86177183Srwatson p->p_ucred = newcred; 86277183Srwatson crfree(oldcred); 86382749Sdillondone2: 86482749Sdillon mtx_unlock(&Giant); 86582749Sdillon return (error); 8661541Srgrimes} 8671541Srgrimes 86812221Sbde#ifndef _SYS_SYSPROTO_H_ 8691541Srgrimesstruct setreuid_args { 8709238Sache uid_t ruid; 8719238Sache uid_t euid; 8721541Srgrimes}; 87312221Sbde#endif 87482749Sdillon/* 87582749Sdillon * MPSAFE 87682749Sdillon */ 8771541Srgrimes/* ARGSUSED */ 8781549Srgrimesint 87983366Sjuliansetreuid(td, uap) 88083366Sjulian register struct thread *td; 8811541Srgrimes struct setreuid_args *uap; 8821541Srgrimes{ 88383366Sjulian struct proc *p = td->td_proc; 88477183Srwatson struct ucred *newcred, *oldcred; 88587218Srwatson uid_t euid, ruid; 88687218Srwatson int error; 8871541Srgrimes 88887218Srwatson euid = uap->euid; 8899238Sache ruid = uap->ruid; 89082749Sdillon mtx_lock(&Giant); 89187218Srwatson error = 0; 89277183Srwatson oldcred = p->p_ucred; 89377183Srwatson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 89477183Srwatson ruid != oldcred->cr_svuid) || 89577183Srwatson (euid != (uid_t)-1 && euid != oldcred->cr_uid && 89677183Srwatson euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) && 89787218Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 89882749Sdillon goto done2; 89977183Srwatson newcred = crdup(oldcred); 90077183Srwatson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 90177183Srwatson change_euid(newcred, euid); 90231891Ssef setsugid(p); 90324450Speter } 90477183Srwatson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 90577183Srwatson change_ruid(newcred, ruid); 90631891Ssef setsugid(p); 9078135Sache } 90877183Srwatson if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) && 90977183Srwatson newcred->cr_svuid != newcred->cr_uid) { 91077183Srwatson change_svuid(newcred, newcred->cr_uid); 91131891Ssef setsugid(p); 91224450Speter } 91377183Srwatson p->p_ucred = newcred; 91477183Srwatson crfree(oldcred); 91582749Sdillondone2: 91682749Sdillon mtx_unlock(&Giant); 91782749Sdillon return (error); 9181541Srgrimes} 9191541Srgrimes 92012221Sbde#ifndef _SYS_SYSPROTO_H_ 9211541Srgrimesstruct setregid_args { 9229238Sache gid_t rgid; 9239238Sache gid_t egid; 9241541Srgrimes}; 92512221Sbde#endif 92682749Sdillon/* 92782749Sdillon * MPSAFE 92882749Sdillon */ 9291541Srgrimes/* ARGSUSED */ 9301549Srgrimesint 93183366Sjuliansetregid(td, uap) 93283366Sjulian register struct thread *td; 9331541Srgrimes struct setregid_args *uap; 9341541Srgrimes{ 93583366Sjulian struct proc *p = td->td_proc; 93677183Srwatson struct ucred *newcred, *oldcred; 93787218Srwatson gid_t egid, rgid; 93887218Srwatson int error; 9391541Srgrimes 94087218Srwatson egid = uap->egid; 9419238Sache rgid = uap->rgid; 94282749Sdillon mtx_lock(&Giant); 94387218Srwatson error = 0; 94477183Srwatson oldcred = p->p_ucred; 94577183Srwatson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 94677183Srwatson rgid != oldcred->cr_svgid) || 94777183Srwatson (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] && 94877183Srwatson egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) && 94987218Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 95082749Sdillon goto done2; 95177183Srwatson newcred = crdup(oldcred); 95277183Srwatson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 95377183Srwatson change_egid(newcred, egid); 95431891Ssef setsugid(p); 95524450Speter } 95677183Srwatson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 95777183Srwatson change_rgid(newcred, rgid); 95831891Ssef setsugid(p); 95924450Speter } 96077183Srwatson if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) && 96177183Srwatson newcred->cr_svgid != newcred->cr_groups[0]) { 96277183Srwatson change_svgid(newcred, newcred->cr_groups[0]); 96331891Ssef setsugid(p); 96424450Speter } 96577812Sru p->p_ucred = newcred; 96677812Sru crfree(oldcred); 96782749Sdillondone2: 96882749Sdillon mtx_unlock(&Giant); 96982749Sdillon return (error); 9701541Srgrimes} 9711541Srgrimes 97256115Speter/* 97356115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the 97456115Speter * saved uid is explicit. 97556115Speter */ 97656115Speter 97724453Speter#ifndef _SYS_SYSPROTO_H_ 97856115Speterstruct setresuid_args { 97956115Speter uid_t ruid; 98056115Speter uid_t euid; 98156115Speter uid_t suid; 98256115Speter}; 98356115Speter#endif 98482749Sdillon/* 98582749Sdillon * MPSAFE 98682749Sdillon */ 98756115Speter/* ARGSUSED */ 98856115Speterint 98983366Sjuliansetresuid(td, uap) 99083366Sjulian register struct thread *td; 99156115Speter struct setresuid_args *uap; 99256115Speter{ 99383366Sjulian struct proc *p = td->td_proc; 99477183Srwatson struct ucred *newcred, *oldcred; 99587218Srwatson uid_t euid, ruid, suid; 99656115Speter int error; 99756115Speter 99887218Srwatson euid = uap->euid; 99956115Speter ruid = uap->ruid; 100056115Speter suid = uap->suid; 100182749Sdillon mtx_lock(&Giant); 100277183Srwatson oldcred = p->p_ucred; 100377183Srwatson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 100477183Srwatson ruid != oldcred->cr_svuid && 100577183Srwatson ruid != oldcred->cr_uid) || 100677183Srwatson (euid != (uid_t)-1 && euid != oldcred->cr_ruid && 100777183Srwatson euid != oldcred->cr_svuid && 100877183Srwatson euid != oldcred->cr_uid) || 100977183Srwatson (suid != (uid_t)-1 && suid != oldcred->cr_ruid && 101077183Srwatson suid != oldcred->cr_svuid && 101177183Srwatson suid != oldcred->cr_uid)) && 101287218Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 101382749Sdillon goto done2; 101477183Srwatson newcred = crdup(oldcred); 101577183Srwatson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 101677183Srwatson change_euid(newcred, euid); 101756115Speter setsugid(p); 101856115Speter } 101977183Srwatson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 102077183Srwatson change_ruid(newcred, ruid); 102156115Speter setsugid(p); 102256115Speter } 102377183Srwatson if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) { 102477183Srwatson change_svuid(newcred, suid); 102556115Speter setsugid(p); 102656115Speter } 102777183Srwatson p->p_ucred = newcred; 102877183Srwatson crfree(oldcred); 102982749Sdillon error = 0; 103082749Sdillondone2: 103182749Sdillon mtx_unlock(&Giant); 103282749Sdillon return (error); 103356115Speter} 103456115Speter 103556115Speter/* 103656115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the 103756115Speter * saved gid is explicit. 103856115Speter */ 103956115Speter 104056115Speter#ifndef _SYS_SYSPROTO_H_ 104156115Speterstruct setresgid_args { 104256115Speter gid_t rgid; 104356115Speter gid_t egid; 104456115Speter gid_t sgid; 104556115Speter}; 104656115Speter#endif 104787466Srwatson/* 104882749Sdillon * MPSAFE 104982749Sdillon */ 105056115Speter/* ARGSUSED */ 105156115Speterint 105283366Sjuliansetresgid(td, uap) 105383366Sjulian register struct thread *td; 105456115Speter struct setresgid_args *uap; 105556115Speter{ 105683366Sjulian struct proc *p = td->td_proc; 105777183Srwatson struct ucred *newcred, *oldcred; 105887218Srwatson gid_t egid, rgid, sgid; 105956115Speter int error; 106056115Speter 106187218Srwatson egid = uap->egid; 106256115Speter rgid = uap->rgid; 106356115Speter sgid = uap->sgid; 106482749Sdillon mtx_lock(&Giant); 106577183Srwatson oldcred = p->p_ucred; 106677183Srwatson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 106777183Srwatson rgid != oldcred->cr_svgid && 106877183Srwatson rgid != oldcred->cr_groups[0]) || 106977183Srwatson (egid != (gid_t)-1 && egid != oldcred->cr_rgid && 107077183Srwatson egid != oldcred->cr_svgid && 107177183Srwatson egid != oldcred->cr_groups[0]) || 107277183Srwatson (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid && 107377183Srwatson sgid != oldcred->cr_svgid && 107477183Srwatson sgid != oldcred->cr_groups[0])) && 107587466Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 107682749Sdillon goto done2; 107777183Srwatson newcred = crdup(oldcred); 107877183Srwatson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 107977183Srwatson change_egid(newcred, egid); 108056115Speter setsugid(p); 108156115Speter } 108277183Srwatson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 108377183Srwatson change_rgid(newcred, rgid); 108456115Speter setsugid(p); 108556115Speter } 108677183Srwatson if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) { 108777183Srwatson change_svgid(newcred, sgid); 108856115Speter setsugid(p); 108956115Speter } 109077183Srwatson p->p_ucred = newcred; 109177183Srwatson crfree(oldcred); 109282749Sdillon error = 0; 109382749Sdillondone2: 109482749Sdillon mtx_unlock(&Giant); 109582749Sdillon return (error); 109656115Speter} 109756115Speter 109856115Speter#ifndef _SYS_SYSPROTO_H_ 109956115Speterstruct getresuid_args { 110056115Speter uid_t *ruid; 110156115Speter uid_t *euid; 110256115Speter uid_t *suid; 110356115Speter}; 110456115Speter#endif 110582749Sdillon/* 110682749Sdillon * MPSAFE 110782749Sdillon */ 110856115Speter/* ARGSUSED */ 110956115Speterint 111083366Sjuliangetresuid(td, uap) 111183366Sjulian register struct thread *td; 111256115Speter struct getresuid_args *uap; 111356115Speter{ 111482749Sdillon struct ucred *cred; 111583366Sjulian struct proc *p = td->td_proc; 111656115Speter int error1 = 0, error2 = 0, error3 = 0; 111756115Speter 111882749Sdillon mtx_lock(&Giant); 111982749Sdillon cred = p->p_ucred; 112056115Speter if (uap->ruid) 112177183Srwatson error1 = copyout((caddr_t)&cred->cr_ruid, 112277183Srwatson (caddr_t)uap->ruid, sizeof(cred->cr_ruid)); 112356115Speter if (uap->euid) 112477183Srwatson error2 = copyout((caddr_t)&cred->cr_uid, 112577183Srwatson (caddr_t)uap->euid, sizeof(cred->cr_uid)); 112656115Speter if (uap->suid) 112777183Srwatson error3 = copyout((caddr_t)&cred->cr_svuid, 112877183Srwatson (caddr_t)uap->suid, sizeof(cred->cr_svuid)); 112982749Sdillon mtx_unlock(&Giant); 113087218Srwatson return (error1 ? error1 : error2 ? error2 : error3); 113156115Speter} 113256115Speter 113356115Speter#ifndef _SYS_SYSPROTO_H_ 113456115Speterstruct getresgid_args { 113556115Speter gid_t *rgid; 113656115Speter gid_t *egid; 113756115Speter gid_t *sgid; 113856115Speter}; 113956115Speter#endif 114082749Sdillon/* 114182749Sdillon * MPSAFE 114282749Sdillon */ 114356115Speter/* ARGSUSED */ 114456115Speterint 114583366Sjuliangetresgid(td, uap) 114683366Sjulian register struct thread *td; 114756115Speter struct getresgid_args *uap; 114856115Speter{ 114982749Sdillon struct ucred *cred; 115083366Sjulian struct proc *p = td->td_proc; 115156115Speter int error1 = 0, error2 = 0, error3 = 0; 115256115Speter 115382749Sdillon mtx_lock(&Giant); 115482749Sdillon cred = p->p_ucred; 115556115Speter if (uap->rgid) 115677183Srwatson error1 = copyout((caddr_t)&cred->cr_rgid, 115777183Srwatson (caddr_t)uap->rgid, sizeof(cred->cr_rgid)); 115856115Speter if (uap->egid) 115977183Srwatson error2 = copyout((caddr_t)&cred->cr_groups[0], 116077183Srwatson (caddr_t)uap->egid, sizeof(cred->cr_groups[0])); 116156115Speter if (uap->sgid) 116277183Srwatson error3 = copyout((caddr_t)&cred->cr_svgid, 116377183Srwatson (caddr_t)uap->sgid, sizeof(cred->cr_svgid)); 116482749Sdillon mtx_unlock(&Giant); 116587218Srwatson return (error1 ? error1 : error2 ? error2 : error3); 116656115Speter} 116756115Speter 116856115Speter#ifndef _SYS_SYSPROTO_H_ 116924453Speterstruct issetugid_args { 117024453Speter int dummy; 117124453Speter}; 117224453Speter#endif 117387218Srwatson/* 117487218Srwatson * NOT MPSAFE? 117587218Srwatson */ 117624453Speter/* ARGSUSED */ 117724453Speterint 117883366Sjulianissetugid(td, uap) 117983366Sjulian register struct thread *td; 118024453Speter struct issetugid_args *uap; 118124453Speter{ 118283366Sjulian struct proc *p = td->td_proc; 118383366Sjulian 118424453Speter /* 118524453Speter * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 118624453Speter * we use P_SUGID because we consider changing the owners as 118724453Speter * "tainting" as well. 118824453Speter * This is significant for procs that start as root and "become" 118924453Speter * a user without an exec - programs cannot know *everything* 119024453Speter * that libc *might* have put in their data segment. 119124453Speter */ 119291140Stanimura PROC_LOCK(p); 119383366Sjulian td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 119491140Stanimura PROC_UNLOCK(p); 119524453Speter return (0); 119624453Speter} 119724453Speter 119882749Sdillon/* 119982749Sdillon * MPSAFE 120082749Sdillon */ 120175426Srwatsonint 120283366Sjulian__setugid(td, uap) 120383366Sjulian struct thread *td; 120475426Srwatson struct __setugid_args *uap; 120575426Srwatson{ 120682749Sdillon#ifdef REGRESSION 120787218Srwatson int error; 120875426Srwatson 120982749Sdillon mtx_lock(&Giant); 121087218Srwatson error = 0; 121175426Srwatson switch (uap->flag) { 121275426Srwatson case 0: 121391140Stanimura PROC_LOCK(td->td_proc); 121483366Sjulian td->td_proc->p_flag &= ~P_SUGID; 121591140Stanimura PROC_UNLOCK(td->td_proc); 121682749Sdillon break; 121775426Srwatson case 1: 121891140Stanimura PROC_LOCK(td->td_proc); 121983366Sjulian td->td_proc->p_flag |= P_SUGID; 122091140Stanimura PROC_UNLOCK(td->td_proc); 122182749Sdillon break; 122275426Srwatson default: 122382749Sdillon error = EINVAL; 122482749Sdillon break; 122575426Srwatson } 122682749Sdillon mtx_unlock(&Giant); 122782749Sdillon return (error); 122875426Srwatson#else /* !REGRESSION */ 122987218Srwatson 123075426Srwatson return (ENOSYS); 123187218Srwatson#endif /* REGRESSION */ 123275426Srwatson} 123375426Srwatson 12341541Srgrimes/* 12351541Srgrimes * Check if gid is a member of the group set. 12361541Srgrimes */ 12371549Srgrimesint 12381541Srgrimesgroupmember(gid, cred) 12391541Srgrimes gid_t gid; 124077183Srwatson struct ucred *cred; 12411541Srgrimes{ 12421541Srgrimes register gid_t *gp; 12431541Srgrimes gid_t *egp; 12441541Srgrimes 12451541Srgrimes egp = &(cred->cr_groups[cred->cr_ngroups]); 12461541Srgrimes for (gp = cred->cr_groups; gp < egp; gp++) 12471541Srgrimes if (*gp == gid) 12481541Srgrimes return (1); 12491541Srgrimes return (0); 12501541Srgrimes} 12511541Srgrimes 125282424Srwatson/* 125389414Sarr * `suser_enabled' (which can be set by the security.suser_enabled 125482466Srwatson * sysctl) determines whether the system 'super-user' policy is in effect. 125582466Srwatson * If it is nonzero, an effective uid of 0 connotes special privilege, 125682466Srwatson * overriding many mandatory and discretionary protections. If it is zero, 125782466Srwatson * uid 0 is offered no special privilege in the kernel security policy. 125882466Srwatson * Setting it to zero may seriously impact the functionality of many 125982466Srwatson * existing userland programs, and should not be done without careful 126082466Srwatson * consideration of the consequences. 126182424Srwatson */ 126282693Srwatsonint suser_enabled = 1; 126389414SarrSYSCTL_INT(_security_bsd, OID_AUTO, suser_enabled, CTLFLAG_RW, 126482693Srwatson &suser_enabled, 0, "processes with uid 0 have privilege"); 126589414SarrTUNABLE_INT("security.bsd.suser_enabled", &suser_enabled); 126661287Srwatson 12671541Srgrimes/* 126882466Srwatson * Test whether the specified credentials imply "super-user" privilege. 126982466Srwatson * Return 0 or EPERM. 12701541Srgrimes */ 12711549Srgrimesint 127246112Sphksuser(p) 127372786Srwatson struct proc *p; 127446112Sphk{ 127587218Srwatson 127687218Srwatson return (suser_xxx(0, p, 0)); 127746112Sphk} 127846112Sphk 127983366Sjulian/* 128083366Sjulian * version for when the thread pointer is available and not the proc. 128183366Sjulian * (saves having to include proc.h into every file that needs to do the change.) 128283366Sjulian */ 128346112Sphkint 128483366Sjuliansuser_td(td) 128583366Sjulian struct thread *td; 128683366Sjulian{ 128787466Srwatson return (suser_xxx(0, td->td_proc, 0)); 128883366Sjulian} 128983366Sjulian 129083366Sjulian/* 129183366Sjulian * wrapper to use if you have the thread on hand but not the proc. 129283366Sjulian */ 129383366Sjulianint 129483366Sjuliansuser_xxx_td(cred, td, flag) 129583366Sjulian struct ucred *cred; 129683366Sjulian struct thread *td; 129783366Sjulian int flag; 129883366Sjulian{ 129983366Sjulian return(suser_xxx(cred, td->td_proc, flag)); 130083366Sjulian} 130183366Sjulian 130283366Sjulianint 130346155Sphksuser_xxx(cred, proc, flag) 130472786Srwatson struct ucred *cred; 130572786Srwatson struct proc *proc; 130646155Sphk int flag; 13071541Srgrimes{ 130882693Srwatson if (!suser_enabled) 130961282Srwatson return (EPERM); 131046155Sphk if (!cred && !proc) { 131146155Sphk printf("suser_xxx(): THINK!\n"); 131246155Sphk return (EPERM); 13131541Srgrimes } 131487218Srwatson if (cred == NULL) 131546155Sphk cred = proc->p_ucred; 131687218Srwatson if (cred->cr_uid != 0) 131746155Sphk return (EPERM); 131872786Srwatson if (jailed(cred) && !(flag & PRISON_ROOT)) 131946155Sphk return (EPERM); 132046155Sphk return (0); 13211541Srgrimes} 13221541Srgrimes 132383639Srwatson/* 132487218Srwatson * Test the active securelevel against a given level. securelevel_gt() 132587218Srwatson * implements (securelevel > level). securelevel_ge() implements 132687218Srwatson * (securelevel >= level). Note that the logic is inverted -- these 132787218Srwatson * functions return EPERM on "success" and 0 on "failure". 132883639Srwatson * 132983639Srwatson * cr is permitted to be NULL for the time being, as there were some 133083639Srwatson * existing securelevel checks that occurred without a process/credential 133187218Srwatson * context. In the future this will be disallowed, so a kernel message 133287218Srwatson * is displayed. 133383639Srwatson */ 133483639Srwatsonint 133583639Srwatsonsecurelevel_gt(struct ucred *cr, int level) 133683639Srwatson{ 133787218Srwatson int active_securelevel; 133883639Srwatson 133987218Srwatson active_securelevel = securelevel; 134087218Srwatson if (cr == NULL) 134192951Srwatson panic("securelevel_gt: cr is NULL\n"); 134287275Srwatson if (cr->cr_prison != NULL) { 134387275Srwatson mtx_lock(&cr->cr_prison->pr_mtx); 134487218Srwatson active_securelevel = imax(cr->cr_prison->pr_securelevel, 134587218Srwatson active_securelevel); 134687275Srwatson mtx_unlock(&cr->cr_prison->pr_mtx); 134787275Srwatson } 134887218Srwatson return (active_securelevel > level ? EPERM : 0); 134983639Srwatson} 135083639Srwatson 135183639Srwatsonint 135283639Srwatsonsecurelevel_ge(struct ucred *cr, int level) 135383639Srwatson{ 135487218Srwatson int active_securelevel; 135583639Srwatson 135687218Srwatson active_securelevel = securelevel; 135787218Srwatson if (cr == NULL) 135892951Srwatson panic("securelevel_gt: cr is NULL\n"); 135987275Srwatson if (cr->cr_prison != NULL) { 136087275Srwatson mtx_lock(&cr->cr_prison->pr_mtx); 136187218Srwatson active_securelevel = imax(cr->cr_prison->pr_securelevel, 136287218Srwatson active_securelevel); 136387275Srwatson mtx_unlock(&cr->cr_prison->pr_mtx); 136487275Srwatson } 136587218Srwatson return (active_securelevel >= level ? EPERM : 0); 136683639Srwatson} 136783639Srwatson 136884736Srwatson/* 136987144Srwatson * 'see_other_uids' determines whether or not visibility of processes 137087218Srwatson * and sockets with credentials holding different real uids is possible 137187138Srwatson * using a variety of system MIBs. 137287218Srwatson * XXX: data declarations should be together near the beginning of the file. 137384736Srwatson */ 137487144Srwatsonstatic int see_other_uids = 1; 137589414SarrSYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW, 137687218Srwatson &see_other_uids, 0, 137784736Srwatson "Unprivileged processes may see subjects/objects with different real uid"); 137884736Srwatson 137982466Srwatson/*- 138092923Srwatson * Determine if u1 "can see" the subject specified by u2, according to the 138192923Srwatson * 'see_other_uids' policy. 138292923Srwatson * Returns: 0 for permitted, ESRCH otherwise 138392923Srwatson * Locks: none 138492923Srwatson * References: *u1 and *u2 must not change during the call 138592923Srwatson * u1 may equal u2, in which case only one reference is required 138692923Srwatson */ 138792923Srwatsonstatic int 138892923Srwatsoncr_seeotheruids(struct ucred *u1, struct ucred *u2) 138992923Srwatson{ 139092923Srwatson 139192923Srwatson if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) { 139292923Srwatson if (suser_xxx(u1, NULL, PRISON_ROOT) != 0) 139392923Srwatson return (ESRCH); 139492923Srwatson } 139592923Srwatson return (0); 139692923Srwatson} 139792923Srwatson 139892923Srwatson/*- 139982466Srwatson * Determine if u1 "can see" the subject specified by u2. 140074956Srwatson * Returns: 0 for permitted, an errno value otherwise 140174956Srwatson * Locks: none 140287218Srwatson * References: *u1 and *u2 must not change during the call 140374956Srwatson * u1 may equal u2, in which case only one reference is required 140474956Srwatson */ 140574956Srwatsonint 140683742Srwatsoncr_cansee(struct ucred *u1, struct ucred *u2) 140765237Srwatson{ 140872786Srwatson int error; 140953518Sphk 141074956Srwatson if ((error = prison_check(u1, u2))) 141172786Srwatson return (error); 141292923Srwatson if ((error = cr_seeotheruids(u1, u2))) 141392923Srwatson return (error); 141465237Srwatson return (0); 141565237Srwatson} 141665237Srwatson 141782466Srwatson/*- 141882466Srwatson * Determine if p1 "can see" the subject specified by p2. 141982424Srwatson * Returns: 0 for permitted, an errno value otherwise 142082466Srwatson * Locks: Sufficient locks to protect p1->p_ucred and p2->p_ucred must 142182424Srwatson * be held. Normally, p1 will be curproc, and a lock must be held 142282424Srwatson * for p2. 142382424Srwatson * References: p1 and p2 must be valid for the lifetime of the call 142482424Srwatson */ 142579335Srwatsonint 142679335Srwatsonp_cansee(struct proc *p1, struct proc *p2) 142774956Srwatson{ 142874956Srwatson 142983742Srwatson /* Wrap cr_cansee() for all functionality. */ 143083742Srwatson return (cr_cansee(p1->p_ucred, p2->p_ucred)); 143174956Srwatson} 143274956Srwatson 143382466Srwatson/*- 143488943Srwatson * Determine whether cred may deliver the specified signal to proc. 143588943Srwatson * Returns: 0 for permitted, an errno value otherwise. 143688943Srwatson * Locks: A lock must be held for proc. 143788943Srwatson * References: cred and proc must be valid for the lifetime of the call. 143875437Srwatson */ 143975437Srwatsonint 144088943Srwatsoncr_cansignal(struct ucred *cred, struct proc *proc, int signum) 144153518Sphk{ 144282466Srwatson int error; 144384826Sjhb 144475437Srwatson /* 144588943Srwatson * Jail semantics limit the scope of signalling to proc in the 144688943Srwatson * same jail as cred, if cred is in jail. 144775437Srwatson */ 144888943Srwatson error = prison_check(cred, proc->p_ucred); 144988943Srwatson if (error) 145072786Srwatson return (error); 145192923Srwatson error = cr_seeotheruids(cred, proc->p_ucred); 145292923Srwatson if (error) 145392923Srwatson return (error); 145465237Srwatson 145565237Srwatson /* 145682424Srwatson * UNIX signal semantics depend on the status of the P_SUGID 145782424Srwatson * bit on the target process. If the bit is set, then additional 145882424Srwatson * restrictions are placed on the set of available signals. 145975437Srwatson */ 146088943Srwatson if (proc->p_flag & P_SUGID) { 146175437Srwatson switch (signum) { 146275437Srwatson case 0: 146375437Srwatson case SIGKILL: 146475437Srwatson case SIGINT: 146575437Srwatson case SIGTERM: 146675437Srwatson case SIGSTOP: 146775437Srwatson case SIGTTIN: 146875437Srwatson case SIGTTOU: 146975437Srwatson case SIGTSTP: 147075437Srwatson case SIGHUP: 147175437Srwatson case SIGUSR1: 147275437Srwatson case SIGUSR2: 147382466Srwatson /* 147482466Srwatson * Generally, permit job and terminal control 147582466Srwatson * signals. 147682466Srwatson */ 147775437Srwatson break; 147875437Srwatson default: 147988943Srwatson /* Not permitted without privilege. */ 148088943Srwatson error = suser_xxx(cred, NULL, PRISON_ROOT); 148175437Srwatson if (error) 148275437Srwatson return (error); 148375437Srwatson } 148465237Srwatson } 148565237Srwatson 148675480Srwatson /* 148782424Srwatson * Generally, the target credential's ruid or svuid must match the 148875480Srwatson * subject credential's ruid or euid. 148975480Srwatson */ 149088943Srwatson if (cred->cr_ruid != proc->p_ucred->cr_ruid && 149188943Srwatson cred->cr_ruid != proc->p_ucred->cr_svuid && 149288943Srwatson cred->cr_uid != proc->p_ucred->cr_ruid && 149388943Srwatson cred->cr_uid != proc->p_ucred->cr_svuid) { 149488943Srwatson /* Not permitted without privilege. */ 149588943Srwatson error = suser_xxx(cred, NULL, PRISON_ROOT); 149675480Srwatson if (error) 149775480Srwatson return (error); 149875480Srwatson } 149975480Srwatson 150087218Srwatson return (0); 150153518Sphk} 150253518Sphk 150388943Srwatson 150482466Srwatson/*- 150588943Srwatson * Determine whether p1 may deliver the specified signal to p2. 150688943Srwatson * Returns: 0 for permitted, an errno value otherwise 150788943Srwatson * Locks: Sufficient locks to protect various components of p1 and p2 150888943Srwatson * must be held. Normally, p1 will be curproc, and a lock must 150988943Srwatson * be held for p2. 151088943Srwatson * References: p1 and p2 must be valid for the lifetime of the call 151188943Srwatson */ 151288943Srwatsonint 151388943Srwatsonp_cansignal(struct proc *p1, struct proc *p2, int signum) 151488943Srwatson{ 151588943Srwatson 151688943Srwatson if (p1 == p2) 151788943Srwatson return (0); 151888943Srwatson 151988943Srwatson /* 152088943Srwatson * UNIX signalling semantics require that processes in the same 152188943Srwatson * session always be able to deliver SIGCONT to one another, 152288943Srwatson * overriding the remaining protections. 152388943Srwatson */ 152488943Srwatson if (signum == SIGCONT && p1->p_session == p2->p_session) 152588943Srwatson return (0); 152688943Srwatson 152788943Srwatson return (cr_cansignal(p1->p_ucred, p2, signum)); 152888943Srwatson} 152988943Srwatson 153088943Srwatson/*- 153187218Srwatson * Determine whether p1 may reschedule p2. 153282466Srwatson * Returns: 0 for permitted, an errno value otherwise 153382424Srwatson * Locks: Sufficient locks to protect various components of p1 and p2 153482424Srwatson * must be held. Normally, p1 will be curproc, and a lock must 153582466Srwatson * be held for p2. 153682424Srwatson * References: p1 and p2 must be valid for the lifetime of the call 153782424Srwatson */ 153879335Srwatsonint 153979335Srwatsonp_cansched(struct proc *p1, struct proc *p2) 154065237Srwatson{ 154172786Srwatson int error; 154265237Srwatson 154365237Srwatson if (p1 == p2) 154465237Srwatson return (0); 154572786Srwatson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 154672786Srwatson return (error); 154792923Srwatson if ((error = cr_seeotheruids(p1->p_ucred, p2->p_ucred))) 154892923Srwatson return (error); 154977183Srwatson if (p1->p_ucred->cr_ruid == p2->p_ucred->cr_ruid) 155065237Srwatson return (0); 155177183Srwatson if (p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid) 155265237Srwatson return (0); 155382466Srwatson if (suser_xxx(0, p1, PRISON_ROOT) == 0) 155465237Srwatson return (0); 155565237Srwatson 155665237Srwatson#ifdef CAPABILITIES 155785874Srwatson if (!cap_check(NULL, p1, CAP_SYS_NICE, PRISON_ROOT)) 155865237Srwatson return (0); 155965237Srwatson#endif 156065237Srwatson 156165237Srwatson return (EPERM); 156265237Srwatson} 156365237Srwatson 156482424Srwatson/* 156587280Srwatson * The 'unprivileged_proc_debug' flag may be used to disable a variety of 156687280Srwatson * unprivileged inter-process debugging services, including some procfs 156787280Srwatson * functionality, ptrace(), and ktrace(). In the past, inter-process 156887280Srwatson * debugging has been involved in a variety of security problems, and sites 156987280Srwatson * not requiring the service might choose to disable it when hardening 157087280Srwatson * systems. 157182424Srwatson * 157282424Srwatson * XXX: Should modifying and reading this variable require locking? 157387218Srwatson * XXX: data declarations should be together near the beginning of the file. 157482424Srwatson */ 157587144Srwatsonstatic int unprivileged_proc_debug = 1; 157689414SarrSYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW, 157787218Srwatson &unprivileged_proc_debug, 0, 157880735Srwatson "Unprivileged processes may use process debugging facilities"); 157980735Srwatson 158082466Srwatson/*- 158182466Srwatson * Determine whether p1 may debug p2. 158282466Srwatson * Returns: 0 for permitted, an errno value otherwise 158382466Srwatson * Locks: Sufficient locks to protect various components of p1 and p2 158482466Srwatson * must be held. Normally, p1 will be curproc, and a lock must 158582466Srwatson * be held for p2. 158682424Srwatson * References: p1 and p2 must be valid for the lifetime of the call 158782424Srwatson */ 158879335Srwatsonint 158979335Srwatsonp_candebug(struct proc *p1, struct proc *p2) 159065237Srwatson{ 159187218Srwatson int credentialchanged, error, grpsubset, i, uidsubset; 159265237Srwatson 159387144Srwatson if (!unprivileged_proc_debug) { 159484727Srwatson error = suser_xxx(NULL, p1, PRISON_ROOT); 159584727Srwatson if (error) 159684727Srwatson return (error); 159784727Srwatson } 159884636Sdes if (p1 == p2) 159984636Sdes return (0); 160072786Srwatson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 160172786Srwatson return (error); 160292923Srwatson if ((error = cr_seeotheruids(p1->p_ucred, p2->p_ucred))) 160392923Srwatson return (error); 160465237Srwatson 160582466Srwatson /* 160685895Srwatson * Is p2's group set a subset of p1's effective group set? This 160785895Srwatson * includes p2's egid, group access list, rgid, and svgid. 160882466Srwatson */ 160985895Srwatson grpsubset = 1; 161085895Srwatson for (i = 0; i < p2->p_ucred->cr_ngroups; i++) { 161185895Srwatson if (!groupmember(p2->p_ucred->cr_groups[i], p1->p_ucred)) { 161285895Srwatson grpsubset = 0; 161385895Srwatson break; 161485895Srwatson } 161585895Srwatson } 161685895Srwatson grpsubset = grpsubset && 161785895Srwatson groupmember(p2->p_ucred->cr_rgid, p1->p_ucred) && 161885895Srwatson groupmember(p2->p_ucred->cr_svgid, p1->p_ucred); 161985895Srwatson 162085895Srwatson /* 162185895Srwatson * Are the uids present in p2's credential equal to p1's 162285895Srwatson * effective uid? This includes p2's euid, svuid, and ruid. 162385895Srwatson */ 162485895Srwatson uidsubset = (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid && 162585895Srwatson p1->p_ucred->cr_uid == p2->p_ucred->cr_svuid && 162685895Srwatson p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid); 162785895Srwatson 162885895Srwatson /* 162985895Srwatson * Has the credential of the process changed since the last exec()? 163085895Srwatson */ 163185895Srwatson credentialchanged = (p2->p_flag & P_SUGID); 163285895Srwatson 163385895Srwatson /* 163485895Srwatson * If p2's gids aren't a subset, or the uids aren't a subset, 163585895Srwatson * or the credential has changed, require appropriate privilege 163685895Srwatson * for p1 to debug p2. For POSIX.1e capabilities, this will 163785895Srwatson * require CAP_SYS_PTRACE. 163885895Srwatson */ 163985895Srwatson if (!grpsubset || !uidsubset || credentialchanged) { 164084727Srwatson error = suser_xxx(NULL, p1, PRISON_ROOT); 164184727Srwatson if (error) 164265237Srwatson return (error); 164382466Srwatson } 164465237Srwatson 164587218Srwatson /* Can't trace init when securelevel > 0. */ 164687218Srwatson if (p2 == initproc) { 164783639Srwatson error = securelevel_gt(p1->p_ucred, 0); 164883639Srwatson if (error) 164983639Srwatson return (error); 165083639Srwatson } 165165237Srwatson 165285880Srwatson /* 165385880Srwatson * Can't trace a process that's currently exec'ing. 165485880Srwatson * XXX: Note, this is not a security policy decision, it's a 165585880Srwatson * basic correctness/functionality decision. Therefore, this check 165685880Srwatson * should be moved to the caller's of p_candebug(). 165785880Srwatson */ 165885598Sdes if ((p2->p_flag & P_INEXEC) != 0) 165985598Sdes return (EAGAIN); 166087466Srwatson 166165237Srwatson return (0); 166265237Srwatson} 166365237Srwatson 166492976Srwatson/*- 166592976Srwatson * Determine whether the subject represented by cred can "see" a socket. 166692976Srwatson * Returns: 0 for permitted, ENOENT otherwise. 166792976Srwatson */ 166892976Srwatsonint 166992976Srwatsoncr_canseesocket(struct ucred *cred, struct socket *so) 167092976Srwatson{ 167192976Srwatson int error; 167292976Srwatson 167392976Srwatson error = prison_check(cred, so->so_cred); 167492976Srwatson if (error) 167592976Srwatson return (ENOENT); 167692976Srwatson if (cr_seeotheruids(cred, so->so_cred)) 167792976Srwatson return (ENOENT); 167892976Srwatson#ifdef MAC 167992976Srwatson /* XXX: error = mac_cred_check_seesocket() here. */ 168092976Srwatson#endif 168192976Srwatson 168292976Srwatson return (0); 168392976Srwatson} 168492976Srwatson 168553518Sphk/* 16861541Srgrimes * Allocate a zeroed cred structure. 16871541Srgrimes */ 16881541Srgrimesstruct ucred * 16891541Srgrimescrget() 16901541Srgrimes{ 16911541Srgrimes register struct ucred *cr; 16921541Srgrimes 169384826Sjhb MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK | M_ZERO); 16941541Srgrimes cr->cr_ref = 1; 169590756Sdillon cr->cr_mtxp = mtx_pool_find(cr); 16961541Srgrimes return (cr); 16971541Srgrimes} 16981541Srgrimes 16991541Srgrimes/* 170082466Srwatson * Claim another reference to a ucred structure. 170169401Salfred */ 170284827Sjhbstruct ucred * 170369401Salfredcrhold(cr) 170469401Salfred struct ucred *cr; 170569401Salfred{ 170669401Salfred 170790756Sdillon mtx_lock(cr->cr_mtxp); 170869401Salfred cr->cr_ref++; 170990756Sdillon mtx_unlock(cr->cr_mtxp); 171084827Sjhb return (cr); 171169401Salfred} 171269401Salfred 171369401Salfred/* 17141541Srgrimes * Free a cred structure. 17151541Srgrimes * Throws away space when ref count gets to 0. 17161541Srgrimes */ 17171549Srgrimesvoid 17181541Srgrimescrfree(cr) 17191541Srgrimes struct ucred *cr; 17201541Srgrimes{ 172190756Sdillon struct mtx *mtxp = cr->cr_mtxp; 172269239Salfred 172390756Sdillon mtx_lock(mtxp); 172475632Salfred KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref)); 172565495Struckman if (--cr->cr_ref == 0) { 172665495Struckman /* 172765495Struckman * Some callers of crget(), such as nfs_statfs(), 172865495Struckman * allocate a temporary credential, but don't 172965495Struckman * allocate a uidinfo structure. 173065495Struckman */ 173190756Sdillon mtx_unlock(mtxp); 173292823Sjhb mtx_lock(&Giant); 173365495Struckman if (cr->cr_uidinfo != NULL) 173465495Struckman uifree(cr->cr_uidinfo); 173577277Srwatson if (cr->cr_ruidinfo != NULL) 173677277Srwatson uifree(cr->cr_ruidinfo); 173772786Srwatson /* 173872786Srwatson * Free a prison, if any. 173972786Srwatson */ 174072786Srwatson if (jailed(cr)) 174172786Srwatson prison_free(cr->cr_prison); 17421541Srgrimes FREE((caddr_t)cr, M_CRED); 174392823Sjhb mtx_unlock(&Giant); 174490756Sdillon } else { 174590756Sdillon mtx_unlock(mtxp); 174690756Sdillon } 17471541Srgrimes} 17481541Srgrimes 17491541Srgrimes/* 175084827Sjhb * Check to see if this ucred is shared. 17511541Srgrimes */ 175284827Sjhbint 175384827Sjhbcrshared(cr) 17541541Srgrimes struct ucred *cr; 17551541Srgrimes{ 175684827Sjhb int shared; 17571541Srgrimes 175890756Sdillon mtx_lock(cr->cr_mtxp); 175984827Sjhb shared = (cr->cr_ref > 1); 176090756Sdillon mtx_unlock(cr->cr_mtxp); 176184827Sjhb return (shared); 17621541Srgrimes} 17631541Srgrimes 17641541Srgrimes/* 176584827Sjhb * Copy a ucred's contents from a template. Does not block. 176684827Sjhb */ 176784827Sjhbvoid 176884827Sjhbcrcopy(dest, src) 176984827Sjhb struct ucred *dest, *src; 177084827Sjhb{ 177184827Sjhb 177284827Sjhb KASSERT(crshared(dest) == 0, ("crcopy of shared ucred")); 177384827Sjhb bcopy(&src->cr_startcopy, &dest->cr_startcopy, 177487218Srwatson (unsigned)((caddr_t)&src->cr_endcopy - 177584827Sjhb (caddr_t)&src->cr_startcopy)); 177684827Sjhb uihold(dest->cr_uidinfo); 177784827Sjhb uihold(dest->cr_ruidinfo); 177884827Sjhb if (jailed(dest)) 177984827Sjhb prison_hold(dest->cr_prison); 178084827Sjhb} 178184827Sjhb 178284827Sjhb/* 17831541Srgrimes * Dup cred struct to a new held one. 17841541Srgrimes */ 17851541Srgrimesstruct ucred * 17861541Srgrimescrdup(cr) 17871541Srgrimes struct ucred *cr; 17881541Srgrimes{ 17891541Srgrimes struct ucred *newcr; 17901541Srgrimes 179184827Sjhb newcr = crget(); 179284827Sjhb crcopy(newcr, cr); 17931541Srgrimes return (newcr); 17941541Srgrimes} 17951541Srgrimes 179692823Sjhb#ifdef DIAGNOSTIC 179792823Sjhbvoid 179892823Sjhbcred_free_thread(struct thread *td) 179992823Sjhb{ 180092823Sjhb struct ucred *cred; 180192823Sjhb 180292823Sjhb cred = td->td_ucred; 180392823Sjhb td->td_ucred = NULL; 180492823Sjhb if (cred != NULL) 180592823Sjhb crfree(cred); 180692823Sjhb} 180792823Sjhb#endif 180892823Sjhb 18091541Srgrimes/* 181091354Sdd * Fill in a struct xucred based on a struct ucred. 181191354Sdd */ 181291354Sddvoid 181391354Sddcru2x(cr, xcr) 181491354Sdd struct ucred *cr; 181591354Sdd struct xucred *xcr; 181691354Sdd{ 181791354Sdd 181891354Sdd bzero(xcr, sizeof(*xcr)); 181991354Sdd xcr->cr_version = XUCRED_VERSION; 182091354Sdd xcr->cr_uid = cr->cr_uid; 182191354Sdd xcr->cr_ngroups = cr->cr_ngroups; 182291354Sdd bcopy(cr->cr_groups, xcr->cr_groups, sizeof(cr->cr_groups)); 182391354Sdd} 182491354Sdd 182591354Sdd/* 182690748Sjulian * small routine to swap a thread's current ucred for the correct one 182790748Sjulian * taken from the process. 182890748Sjulian */ 182990748Sjulianvoid 183090748Sjuliancred_update_thread(struct thread *td) 183190748Sjulian{ 183290748Sjulian struct proc *p; 183391405Sjhb struct ucred *cred; 183490748Sjulian 183590748Sjulian p = td->td_proc; 183691405Sjhb cred = td->td_ucred; 183791405Sjhb mtx_lock(&Giant); 183890748Sjulian PROC_LOCK(p); 183990748Sjulian td->td_ucred = crhold(p->p_ucred); 184090748Sjulian PROC_UNLOCK(p); 184191405Sjhb if (cred != NULL) 184291405Sjhb crfree(cred); 184391405Sjhb mtx_unlock(&Giant); 184490748Sjulian} 184590748Sjulian 184690748Sjulian/* 18471541Srgrimes * Get login name, if available. 18481541Srgrimes */ 184912221Sbde#ifndef _SYS_SYSPROTO_H_ 18501541Srgrimesstruct getlogin_args { 18511541Srgrimes char *namebuf; 18521541Srgrimes u_int namelen; 18531541Srgrimes}; 185412221Sbde#endif 185582749Sdillon/* 185682749Sdillon * MPSAFE 185782749Sdillon */ 18581541Srgrimes/* ARGSUSED */ 18591549Srgrimesint 186083366Sjuliangetlogin(td, uap) 186183366Sjulian struct thread *td; 18621541Srgrimes struct getlogin_args *uap; 18631541Srgrimes{ 186482749Sdillon int error; 186591140Stanimura char login[MAXLOGNAME]; 186683366Sjulian struct proc *p = td->td_proc; 18671541Srgrimes 186882749Sdillon mtx_lock(&Giant); 186923358Sache if (uap->namelen > MAXLOGNAME) 187023359Sache uap->namelen = MAXLOGNAME; 187191140Stanimura PROC_LOCK(p); 187291140Stanimura SESS_LOCK(p->p_session); 187391140Stanimura bcopy(p->p_session->s_login, login, uap->namelen); 187491140Stanimura SESS_UNLOCK(p->p_session); 187591140Stanimura PROC_UNLOCK(p); 187691140Stanimura error = copyout((caddr_t) login, (caddr_t) uap->namebuf, uap->namelen); 187782749Sdillon mtx_unlock(&Giant); 187882749Sdillon return(error); 18791541Srgrimes} 18801541Srgrimes 18811541Srgrimes/* 18821541Srgrimes * Set login name. 18831541Srgrimes */ 188412221Sbde#ifndef _SYS_SYSPROTO_H_ 18851541Srgrimesstruct setlogin_args { 18861541Srgrimes char *namebuf; 18871541Srgrimes}; 188812221Sbde#endif 188982749Sdillon/* 189082749Sdillon * MPSAFE 189182749Sdillon */ 18921541Srgrimes/* ARGSUSED */ 18931549Srgrimesint 189483366Sjuliansetlogin(td, uap) 189583366Sjulian struct thread *td; 18961541Srgrimes struct setlogin_args *uap; 18971541Srgrimes{ 189883366Sjulian struct proc *p = td->td_proc; 18991541Srgrimes int error; 190023330Sache char logintmp[MAXLOGNAME]; 19011541Srgrimes 190282749Sdillon mtx_lock(&Giant); 190387218Srwatson if ((error = suser_xxx(0, p, PRISON_ROOT)) != 0) 190482749Sdillon goto done2; 190522522Sdavidn error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 190636845Sdfr sizeof(logintmp), (size_t *)0); 190787218Srwatson if (error == ENAMETOOLONG) 19081541Srgrimes error = EINVAL; 190991140Stanimura else if (!error) { 191091140Stanimura PROC_LOCK(p); 191191140Stanimura SESS_LOCK(p->p_session); 191291140Stanimura (void) memcpy(p->p_session->s_login, logintmp, 191323330Sache sizeof(logintmp)); 191491140Stanimura SESS_UNLOCK(p->p_session); 191591140Stanimura PROC_UNLOCK(p); 191691140Stanimura } 191782749Sdillondone2: 191882749Sdillon mtx_unlock(&Giant); 19191541Srgrimes return (error); 19201541Srgrimes} 192131891Ssef 192231891Ssefvoid 192331891Ssefsetsugid(p) 192455338Sphk struct proc *p; 192531891Ssef{ 192631891Ssef p->p_flag |= P_SUGID; 192755707Ssef if (!(p->p_pfsflags & PF_ISUGID)) 192831891Ssef p->p_stops = 0; 192931891Ssef} 193065495Struckman 193182466Srwatson/*- 193282466Srwatson * Change a process's effective uid. 193377183Srwatson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified. 193477183Srwatson * References: newcred must be an exclusive credential reference for the 193577183Srwatson * duration of the call. 193665495Struckman */ 193765495Struckmanvoid 193877183Srwatsonchange_euid(newcred, euid) 193977183Srwatson struct ucred *newcred; 194077183Srwatson uid_t euid; 194165495Struckman{ 194265495Struckman 194377183Srwatson newcred->cr_uid = euid; 194477183Srwatson uifree(newcred->cr_uidinfo); 194577183Srwatson newcred->cr_uidinfo = uifind(euid); 194665495Struckman} 194765495Struckman 194882466Srwatson/*- 194982466Srwatson * Change a process's effective gid. 195077183Srwatson * Side effects: newcred->cr_gid will be modified. 195177183Srwatson * References: newcred must be an exclusive credential reference for the 195277183Srwatson * duration of the call. 195365495Struckman */ 195467629Sgallatinvoid 195577183Srwatsonchange_egid(newcred, egid) 195677183Srwatson struct ucred *newcred; 195777183Srwatson gid_t egid; 195865495Struckman{ 195965495Struckman 196077183Srwatson newcred->cr_groups[0] = egid; 196165495Struckman} 196277183Srwatson 196382466Srwatson/*- 196482466Srwatson * Change a process's real uid. 196577183Srwatson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo 196677183Srwatson * will be updated, and the old and new cr_ruidinfo proc 196777183Srwatson * counts will be updated. 196877183Srwatson * References: newcred must be an exclusive credential reference for the 196977183Srwatson * duration of the call. 197077183Srwatson */ 197177183Srwatsonvoid 197277183Srwatsonchange_ruid(newcred, ruid) 197377183Srwatson struct ucred *newcred; 197477183Srwatson uid_t ruid; 197577183Srwatson{ 197677183Srwatson 197777183Srwatson (void)chgproccnt(newcred->cr_ruidinfo, -1, 0); 197877183Srwatson newcred->cr_ruid = ruid; 197977183Srwatson uifree(newcred->cr_ruidinfo); 198077183Srwatson newcred->cr_ruidinfo = uifind(ruid); 198177183Srwatson (void)chgproccnt(newcred->cr_ruidinfo, 1, 0); 198277183Srwatson} 198377183Srwatson 198482466Srwatson/*- 198582466Srwatson * Change a process's real gid. 198677183Srwatson * Side effects: newcred->cr_rgid will be updated. 198777183Srwatson * References: newcred must be an exclusive credential reference for the 198877183Srwatson * duration of the call. 198977183Srwatson */ 199077183Srwatsonvoid 199177183Srwatsonchange_rgid(newcred, rgid) 199277183Srwatson struct ucred *newcred; 199377183Srwatson gid_t rgid; 199477183Srwatson{ 199577183Srwatson 199677183Srwatson newcred->cr_rgid = rgid; 199777183Srwatson} 199877183Srwatson 199982466Srwatson/*- 200082466Srwatson * Change a process's saved uid. 200177183Srwatson * Side effects: newcred->cr_svuid will be updated. 200277183Srwatson * References: newcred must be an exclusive credential reference for the 200377183Srwatson * duration of the call. 200477183Srwatson */ 200577183Srwatsonvoid 200677183Srwatsonchange_svuid(newcred, svuid) 200777183Srwatson struct ucred *newcred; 200877183Srwatson uid_t svuid; 200977183Srwatson{ 201077183Srwatson 201177183Srwatson newcred->cr_svuid = svuid; 201277183Srwatson} 201377183Srwatson 201482466Srwatson/*- 201582466Srwatson * Change a process's saved gid. 201677183Srwatson * Side effects: newcred->cr_svgid will be updated. 201777183Srwatson * References: newcred must be an exclusive credential reference for the 201877183Srwatson * duration of the call. 201977183Srwatson */ 202077183Srwatsonvoid 202177183Srwatsonchange_svgid(newcred, svgid) 202277183Srwatson struct ucred *newcred; 202377183Srwatson gid_t svgid; 202477183Srwatson{ 202577183Srwatson 202677183Srwatson newcred->cr_svgid = svgid; 202777183Srwatson} 2028