kern_prot.c revision 75448
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. 91541Srgrimes * 101541Srgrimes * Redistribution and use in source and binary forms, with or without 111541Srgrimes * modification, are permitted provided that the following conditions 121541Srgrimes * are met: 131541Srgrimes * 1. Redistributions of source code must retain the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer. 151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161541Srgrimes * notice, this list of conditions and the following disclaimer in the 171541Srgrimes * documentation and/or other materials provided with the distribution. 181541Srgrimes * 3. All advertising materials mentioning features or use of this software 191541Srgrimes * must display the following acknowledgement: 201541Srgrimes * This product includes software developed by the University of 211541Srgrimes * California, Berkeley and its contributors. 221541Srgrimes * 4. Neither the name of the University nor the names of its contributors 231541Srgrimes * may be used to endorse or promote products derived from this software 241541Srgrimes * without specific prior written permission. 251541Srgrimes * 261541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 271541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 281541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 291541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 301541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 311541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 321541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 331541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 341541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 351541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 361541Srgrimes * SUCH DAMAGE. 371541Srgrimes * 381541Srgrimes * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 3950477Speter * $FreeBSD: head/sys/kern/kern_prot.c 75448 2001-04-12 19:39:00Z rwatson $ 401541Srgrimes */ 411541Srgrimes 421541Srgrimes/* 431541Srgrimes * System calls related to processes and protection 441541Srgrimes */ 451541Srgrimes 4631778Seivind#include "opt_compat.h" 4775426Srwatson#include "opt_global.h" 4831778Seivind 491541Srgrimes#include <sys/param.h> 501541Srgrimes#include <sys/acct.h> 511541Srgrimes#include <sys/systm.h> 5212221Sbde#include <sys/sysproto.h> 5341059Speter#include <sys/kernel.h> 5470317Sjake#include <sys/lock.h> 551541Srgrimes#include <sys/proc.h> 561541Srgrimes#include <sys/malloc.h> 5731891Ssef#include <sys/pioctl.h> 5865495Struckman#include <sys/resourcevar.h> 5961287Srwatson#include <sys/sysctl.h> 6072786Srwatson#include <sys/jail.h> 611541Srgrimes 6230354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials"); 6330354Sphk 6412221Sbde#ifndef _SYS_SYSPROTO_H_ 6511332Sswallacestruct getpid_args { 661541Srgrimes int dummy; 671541Srgrimes}; 6812221Sbde#endif 691541Srgrimes 7058717Sdillon/* 7170317Sjake * getpid - MP SAFE 7258717Sdillon */ 7370317Sjake 741541Srgrimes/* ARGSUSED */ 751549Srgrimesint 7630994Sphkgetpid(p, uap) 771541Srgrimes struct proc *p; 7811332Sswallace struct getpid_args *uap; 791541Srgrimes{ 801541Srgrimes 8130994Sphk p->p_retval[0] = p->p_pid; 821541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 8374728Sjhb PROC_LOCK(p); 8430994Sphk p->p_retval[1] = p->p_pptr->p_pid; 8574728Sjhb PROC_UNLOCK(p); 861541Srgrimes#endif 871541Srgrimes return (0); 881541Srgrimes} 891541Srgrimes 9070317Sjake/* 9170317Sjake * getppid - MP SAFE 9270317Sjake */ 9370317Sjake 9412221Sbde#ifndef _SYS_SYSPROTO_H_ 9511332Sswallacestruct getppid_args { 9611332Sswallace int dummy; 9711332Sswallace}; 9812221Sbde#endif 991541Srgrimes/* ARGSUSED */ 1001549Srgrimesint 10130994Sphkgetppid(p, uap) 1021541Srgrimes struct proc *p; 10311332Sswallace struct getppid_args *uap; 1041541Srgrimes{ 1051541Srgrimes 10674728Sjhb PROC_LOCK(p); 10730994Sphk p->p_retval[0] = p->p_pptr->p_pid; 10874728Sjhb PROC_UNLOCK(p); 1091541Srgrimes return (0); 1101541Srgrimes} 1111541Srgrimes 11258717Sdillon/* 11358717Sdillon * Get process group ID; note that POSIX getpgrp takes no parameter 11458717Sdillon * 11558717Sdillon * MP SAFE 11658717Sdillon */ 11712221Sbde#ifndef _SYS_SYSPROTO_H_ 11811332Sswallacestruct getpgrp_args { 11911332Sswallace int dummy; 12011332Sswallace}; 12112221Sbde#endif 12211332Sswallace 1231549Srgrimesint 12430994Sphkgetpgrp(p, uap) 1251541Srgrimes struct proc *p; 12611332Sswallace struct getpgrp_args *uap; 1271541Srgrimes{ 1281541Srgrimes 12930994Sphk p->p_retval[0] = p->p_pgrp->pg_id; 1301541Srgrimes return (0); 1311541Srgrimes} 1321541Srgrimes 13328401Speter/* Get an arbitary pid's process group id */ 13412221Sbde#ifndef _SYS_SYSPROTO_H_ 13528401Speterstruct getpgid_args { 13628401Speter pid_t pid; 13728401Speter}; 13828401Speter#endif 13928401Speter 14028401Speterint 14130994Sphkgetpgid(p, uap) 14228401Speter struct proc *p; 14328401Speter struct getpgid_args *uap; 14428401Speter{ 14541726Struckman struct proc *pt; 14675448Srwatson int error; 14741726Struckman 14841726Struckman pt = p; 14928401Speter if (uap->pid == 0) 15028401Speter goto found; 15128401Speter 15241726Struckman if ((pt = pfind(uap->pid)) == 0) 15328401Speter return ESRCH; 15475448Srwatson if ((error = p_can(p, pt, P_CAN_SEE, NULL))) 15575448Srwatson return (error); 15628401Speterfound: 15741726Struckman p->p_retval[0] = pt->p_pgrp->pg_id; 15828401Speter return 0; 15928401Speter} 16028401Speter 16128401Speter/* 16228401Speter * Get an arbitary pid's session id. 16328401Speter */ 16428401Speter#ifndef _SYS_SYSPROTO_H_ 16528401Speterstruct getsid_args { 16628401Speter pid_t pid; 16728401Speter}; 16828401Speter#endif 16928401Speter 17028401Speterint 17130994Sphkgetsid(p, uap) 17228401Speter struct proc *p; 17328401Speter struct getsid_args *uap; 17428401Speter{ 17541726Struckman struct proc *pt; 17675448Srwatson int error; 17741726Struckman 17841726Struckman pt = p; 17928401Speter if (uap->pid == 0) 18028401Speter goto found; 18128401Speter 18271002Sben if ((pt = pfind(uap->pid)) == 0) 18328401Speter return ESRCH; 18475448Srwatson if ((error = p_can(p, pt, P_CAN_SEE, NULL))) 18575448Srwatson return (error); 18628401Speterfound: 18741726Struckman p->p_retval[0] = pt->p_session->s_sid; 18828401Speter return 0; 18928401Speter} 19028401Speter 19128401Speter 19258941Sdillon/* 19358941Sdillon * getuid() - MP SAFE 19458941Sdillon */ 19528401Speter#ifndef _SYS_SYSPROTO_H_ 19611332Sswallacestruct getuid_args { 19711332Sswallace int dummy; 19811332Sswallace}; 19912221Sbde#endif 20011332Sswallace 2011541Srgrimes/* ARGSUSED */ 2021549Srgrimesint 20330994Sphkgetuid(p, uap) 2041541Srgrimes struct proc *p; 20511332Sswallace struct getuid_args *uap; 2061541Srgrimes{ 2071541Srgrimes 20830994Sphk p->p_retval[0] = p->p_cred->p_ruid; 2091541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 21030994Sphk p->p_retval[1] = p->p_ucred->cr_uid; 2111541Srgrimes#endif 2121541Srgrimes return (0); 2131541Srgrimes} 2141541Srgrimes 21558941Sdillon/* 21658941Sdillon * geteuid() - MP SAFE 21758941Sdillon */ 21812221Sbde#ifndef _SYS_SYSPROTO_H_ 21911332Sswallacestruct geteuid_args { 22011332Sswallace int dummy; 22111332Sswallace}; 22212221Sbde#endif 22311332Sswallace 2241541Srgrimes/* ARGSUSED */ 2251549Srgrimesint 22630994Sphkgeteuid(p, uap) 2271541Srgrimes struct proc *p; 22811332Sswallace struct geteuid_args *uap; 2291541Srgrimes{ 2301541Srgrimes 23130994Sphk p->p_retval[0] = p->p_ucred->cr_uid; 2321541Srgrimes return (0); 2331541Srgrimes} 2341541Srgrimes 23558941Sdillon/* 23658941Sdillon * getgid() - MP SAFE 23758941Sdillon */ 23812221Sbde#ifndef _SYS_SYSPROTO_H_ 23911332Sswallacestruct getgid_args { 24011332Sswallace int dummy; 24111332Sswallace}; 24212221Sbde#endif 24311332Sswallace 2441541Srgrimes/* ARGSUSED */ 2451549Srgrimesint 24630994Sphkgetgid(p, uap) 2471541Srgrimes struct proc *p; 24811332Sswallace struct getgid_args *uap; 2491541Srgrimes{ 2501541Srgrimes 25130994Sphk p->p_retval[0] = p->p_cred->p_rgid; 2521541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 25330994Sphk p->p_retval[1] = p->p_ucred->cr_groups[0]; 2541541Srgrimes#endif 2551541Srgrimes return (0); 2561541Srgrimes} 2571541Srgrimes 2581541Srgrimes/* 2591541Srgrimes * Get effective group ID. The "egid" is groups[0], and could be obtained 2601541Srgrimes * via getgroups. This syscall exists because it is somewhat painful to do 2611541Srgrimes * correctly in a library function. 2621541Srgrimes */ 26312221Sbde#ifndef _SYS_SYSPROTO_H_ 26411332Sswallacestruct getegid_args { 26511332Sswallace int dummy; 26611332Sswallace}; 26712221Sbde#endif 26811332Sswallace 2691541Srgrimes/* ARGSUSED */ 2701549Srgrimesint 27130994Sphkgetegid(p, uap) 2721541Srgrimes struct proc *p; 27311332Sswallace struct getegid_args *uap; 2741541Srgrimes{ 2751541Srgrimes 27630994Sphk p->p_retval[0] = p->p_ucred->cr_groups[0]; 2771541Srgrimes return (0); 2781541Srgrimes} 2791541Srgrimes 28012221Sbde#ifndef _SYS_SYSPROTO_H_ 2811541Srgrimesstruct getgroups_args { 2821541Srgrimes u_int gidsetsize; 2831541Srgrimes gid_t *gidset; 2841541Srgrimes}; 28512221Sbde#endif 2861549Srgrimesint 28730994Sphkgetgroups(p, uap) 2881541Srgrimes struct proc *p; 2891541Srgrimes register struct getgroups_args *uap; 2901541Srgrimes{ 2911541Srgrimes register struct pcred *pc = p->p_cred; 2921541Srgrimes register u_int ngrp; 2931541Srgrimes int error; 2941541Srgrimes 2951541Srgrimes if ((ngrp = uap->gidsetsize) == 0) { 29630994Sphk p->p_retval[0] = pc->pc_ucred->cr_ngroups; 2971541Srgrimes return (0); 2981541Srgrimes } 2991541Srgrimes if (ngrp < pc->pc_ucred->cr_ngroups) 3001541Srgrimes return (EINVAL); 3011541Srgrimes ngrp = pc->pc_ucred->cr_ngroups; 3023098Sphk if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups, 3033098Sphk (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))) 3041541Srgrimes return (error); 30530994Sphk p->p_retval[0] = ngrp; 3061541Srgrimes return (0); 3071541Srgrimes} 3081541Srgrimes 30912221Sbde#ifndef _SYS_SYSPROTO_H_ 31012207Sbdestruct setsid_args { 31111332Sswallace int dummy; 31211332Sswallace}; 31312221Sbde#endif 31411332Sswallace 3151541Srgrimes/* ARGSUSED */ 3161549Srgrimesint 31730994Sphksetsid(p, uap) 3181541Srgrimes register struct proc *p; 31912207Sbde struct setsid_args *uap; 3201541Srgrimes{ 3211541Srgrimes 3221541Srgrimes if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 3231541Srgrimes return (EPERM); 3241541Srgrimes } else { 3251541Srgrimes (void)enterpgrp(p, p->p_pid, 1); 32630994Sphk p->p_retval[0] = p->p_pid; 3271541Srgrimes return (0); 3281541Srgrimes } 3291541Srgrimes} 3301541Srgrimes 3311541Srgrimes/* 3321541Srgrimes * set process group (setpgid/old setpgrp) 3331541Srgrimes * 3341541Srgrimes * caller does setpgid(targpid, targpgid) 3351541Srgrimes * 3361541Srgrimes * pid must be caller or child of caller (ESRCH) 3371541Srgrimes * if a child 3381541Srgrimes * pid must be in same session (EPERM) 3391541Srgrimes * pid can't have done an exec (EACCES) 3401541Srgrimes * if pgid != pid 3411541Srgrimes * there must exist some pid in same session having pgid (EPERM) 3421541Srgrimes * pid must not be session leader (EPERM) 3431541Srgrimes */ 34412221Sbde#ifndef _SYS_SYSPROTO_H_ 3451541Srgrimesstruct setpgid_args { 3461541Srgrimes int pid; /* target process id */ 3471541Srgrimes int pgid; /* target pgrp id */ 3481541Srgrimes}; 34912221Sbde#endif 3501541Srgrimes/* ARGSUSED */ 3511549Srgrimesint 35230994Sphksetpgid(curp, uap) 3531541Srgrimes struct proc *curp; 3541541Srgrimes register struct setpgid_args *uap; 3551541Srgrimes{ 3561541Srgrimes register struct proc *targp; /* target process */ 3571541Srgrimes register struct pgrp *pgrp; /* target pgrp */ 35875448Srwatson int error; 3591541Srgrimes 36020677Sbde if (uap->pgid < 0) 36120677Sbde return (EINVAL); 3621541Srgrimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 3631541Srgrimes if ((targp = pfind(uap->pid)) == 0 || !inferior(targp)) 3641541Srgrimes return (ESRCH); 36575448Srwatson if ((error = p_can(curproc, targp, P_CAN_SEE, NULL))) 36675448Srwatson return (error); 36715985Sdg if (targp->p_pgrp == NULL || targp->p_session != curp->p_session) 3681541Srgrimes return (EPERM); 3691541Srgrimes if (targp->p_flag & P_EXEC) 3701541Srgrimes return (EACCES); 3711541Srgrimes } else 3721541Srgrimes targp = curp; 3731541Srgrimes if (SESS_LEADER(targp)) 3741541Srgrimes return (EPERM); 3751541Srgrimes if (uap->pgid == 0) 3761541Srgrimes uap->pgid = targp->p_pid; 3771541Srgrimes else if (uap->pgid != targp->p_pid) 3781541Srgrimes if ((pgrp = pgfind(uap->pgid)) == 0 || 3791541Srgrimes pgrp->pg_session != curp->p_session) 3801541Srgrimes return (EPERM); 3811541Srgrimes return (enterpgrp(targp, uap->pgid, 0)); 3821541Srgrimes} 3831541Srgrimes 38424448Speter/* 38524448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 38672093Sasmodai * compatible. It says that setting the uid/gid to euid/egid is a special 38724448Speter * case of "appropriate privilege". Once the rules are expanded out, this 38824448Speter * basically means that setuid(nnn) sets all three id's, in all permitted 38924448Speter * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 39024448Speter * does not set the saved id - this is dangerous for traditional BSD 39124448Speter * programs. For this reason, we *really* do not want to set 39224448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 39324448Speter */ 39424448Speter#define POSIX_APPENDIX_B_4_2_2 39524448Speter 39612221Sbde#ifndef _SYS_SYSPROTO_H_ 3971541Srgrimesstruct setuid_args { 3981541Srgrimes uid_t uid; 3991541Srgrimes}; 40012221Sbde#endif 4011541Srgrimes/* ARGSUSED */ 4021549Srgrimesint 40330994Sphksetuid(p, uap) 4041541Srgrimes struct proc *p; 4051541Srgrimes struct setuid_args *uap; 4061541Srgrimes{ 4071541Srgrimes register struct pcred *pc = p->p_cred; 4081541Srgrimes register uid_t uid; 4091541Srgrimes int error; 4101541Srgrimes 41124448Speter /* 41224448Speter * See if we have "permission" by POSIX 1003.1 rules. 41324448Speter * 41424448Speter * Note that setuid(geteuid()) is a special case of 41524448Speter * "appropriate privileges" in appendix B.4.2.2. We need 41672093Sasmodai * to use this clause to be compatible with traditional BSD 41724448Speter * semantics. Basically, it means that "setuid(xx)" sets all 41824448Speter * three id's (assuming you have privs). 41924448Speter * 42024448Speter * Notes on the logic. We do things in three steps. 42124448Speter * 1: We determine if the euid is going to change, and do EPERM 42224448Speter * right away. We unconditionally change the euid later if this 42324448Speter * test is satisfied, simplifying that part of the logic. 42424448Speter * 2: We determine if the real and/or saved uid's are going to 42524448Speter * change. Determined by compile options. 42624448Speter * 3: Change euid last. (after tests in #2 for "appropriate privs") 42724448Speter */ 4281541Srgrimes uid = uap->uid; 42924448Speter if (uid != pc->p_ruid && /* allow setuid(getuid()) */ 43017994Sache#ifdef _POSIX_SAVED_IDS 43124448Speter uid != pc->p_svuid && /* allow setuid(saved gid) */ 43217994Sache#endif 43324448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 43424448Speter uid != pc->pc_ucred->cr_uid && /* allow setuid(geteuid()) */ 43524448Speter#endif 43646155Sphk (error = suser_xxx(0, p, PRISON_ROOT))) 4371541Srgrimes return (error); 43824448Speter 43924448Speter#ifdef _POSIX_SAVED_IDS 4401541Srgrimes /* 44124448Speter * Do we have "appropriate privileges" (are we root or uid == euid) 44224448Speter * If so, we are changing the real uid and/or saved uid. 4431541Srgrimes */ 44417994Sache if ( 44524448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 44624448Speter uid == pc->pc_ucred->cr_uid || 44717994Sache#endif 44846155Sphk suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */ 44917994Sache#endif 45024448Speter { 45124448Speter /* 45265495Struckman * Set the real uid and transfer proc count to new user. 45324448Speter */ 45424448Speter if (uid != pc->p_ruid) { 45565495Struckman change_ruid(p, uid); 45665495Struckman setsugid(p); 45724448Speter } 45824448Speter /* 45924448Speter * Set saved uid 46024448Speter * 46124448Speter * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 46224448Speter * the security of seteuid() depends on it. B.4.2.2 says it 46324448Speter * is important that we should do this. 46424448Speter */ 46524448Speter if (pc->p_svuid != uid) { 46624448Speter pc->p_svuid = uid; 46731891Ssef setsugid(p); 46824448Speter } 4698141Sache } 47024448Speter 47124448Speter /* 47224448Speter * In all permitted cases, we are changing the euid. 47324448Speter * Copy credentials so other references do not see our changes. 47424448Speter */ 47524448Speter if (pc->pc_ucred->cr_uid != uid) { 47665495Struckman change_euid(p, uid); 47731891Ssef setsugid(p); 47824448Speter } 4791541Srgrimes return (0); 4801541Srgrimes} 4811541Srgrimes 48212221Sbde#ifndef _SYS_SYSPROTO_H_ 4831541Srgrimesstruct seteuid_args { 4841541Srgrimes uid_t euid; 4851541Srgrimes}; 48612221Sbde#endif 4871541Srgrimes/* ARGSUSED */ 4881549Srgrimesint 48930994Sphkseteuid(p, uap) 4901541Srgrimes struct proc *p; 4911541Srgrimes struct seteuid_args *uap; 4921541Srgrimes{ 4931541Srgrimes register struct pcred *pc = p->p_cred; 4941541Srgrimes register uid_t euid; 4951541Srgrimes int error; 4961541Srgrimes 4971541Srgrimes euid = uap->euid; 49824449Speter if (euid != pc->p_ruid && /* allow seteuid(getuid()) */ 49924449Speter euid != pc->p_svuid && /* allow seteuid(saved uid) */ 50046155Sphk (error = suser_xxx(0, p, PRISON_ROOT))) 5011541Srgrimes return (error); 5021541Srgrimes /* 5031541Srgrimes * Everything's okay, do it. Copy credentials so other references do 5041541Srgrimes * not see our changes. 5051541Srgrimes */ 50624449Speter if (pc->pc_ucred->cr_uid != euid) { 50765495Struckman change_euid(p, euid); 50831891Ssef setsugid(p); 50924449Speter } 5101541Srgrimes return (0); 5111541Srgrimes} 5121541Srgrimes 51312221Sbde#ifndef _SYS_SYSPROTO_H_ 5141541Srgrimesstruct setgid_args { 5151541Srgrimes gid_t gid; 5161541Srgrimes}; 51712221Sbde#endif 5181541Srgrimes/* ARGSUSED */ 5191549Srgrimesint 52030994Sphksetgid(p, uap) 5211541Srgrimes struct proc *p; 5221541Srgrimes struct setgid_args *uap; 5231541Srgrimes{ 5241541Srgrimes register struct pcred *pc = p->p_cred; 5251541Srgrimes register gid_t gid; 5261541Srgrimes int error; 5271541Srgrimes 52824448Speter /* 52924448Speter * See if we have "permission" by POSIX 1003.1 rules. 53024448Speter * 53124448Speter * Note that setgid(getegid()) is a special case of 53224448Speter * "appropriate privileges" in appendix B.4.2.2. We need 53372093Sasmodai * to use this clause to be compatible with traditional BSD 53424448Speter * semantics. Basically, it means that "setgid(xx)" sets all 53524448Speter * three id's (assuming you have privs). 53624448Speter * 53724448Speter * For notes on the logic here, see setuid() above. 53824448Speter */ 5391541Srgrimes gid = uap->gid; 54024448Speter if (gid != pc->p_rgid && /* allow setgid(getgid()) */ 54117994Sache#ifdef _POSIX_SAVED_IDS 54224448Speter gid != pc->p_svgid && /* allow setgid(saved gid) */ 54317994Sache#endif 54424448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 54524448Speter gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */ 54624448Speter#endif 54746155Sphk (error = suser_xxx(0, p, PRISON_ROOT))) 5481541Srgrimes return (error); 54924448Speter 55017994Sache#ifdef _POSIX_SAVED_IDS 55124448Speter /* 55224448Speter * Do we have "appropriate privileges" (are we root or gid == egid) 55324448Speter * If so, we are changing the real uid and saved gid. 55424448Speter */ 55524448Speter if ( 55624448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 55724448Speter gid == pc->pc_ucred->cr_groups[0] || 55817994Sache#endif 55946155Sphk suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */ 56024448Speter#endif 56124448Speter { 56224448Speter /* 56324448Speter * Set real gid 56424448Speter */ 56524448Speter if (pc->p_rgid != gid) { 56624448Speter pc->p_rgid = gid; 56731891Ssef setsugid(p); 56824448Speter } 56924448Speter /* 57024448Speter * Set saved gid 57124448Speter * 57224448Speter * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 57324448Speter * the security of setegid() depends on it. B.4.2.2 says it 57424448Speter * is important that we should do this. 57524448Speter */ 57624448Speter if (pc->p_svgid != gid) { 57724448Speter pc->p_svgid = gid; 57831891Ssef setsugid(p); 57924448Speter } 5808141Sache } 58124448Speter /* 58224448Speter * In all cases permitted cases, we are changing the egid. 58324448Speter * Copy credentials so other references do not see our changes. 58424448Speter */ 58524448Speter if (pc->pc_ucred->cr_groups[0] != gid) { 58624448Speter pc->pc_ucred = crcopy(pc->pc_ucred); 58724448Speter pc->pc_ucred->cr_groups[0] = gid; 58831891Ssef setsugid(p); 58924448Speter } 5901541Srgrimes return (0); 5911541Srgrimes} 5921541Srgrimes 59312221Sbde#ifndef _SYS_SYSPROTO_H_ 5941541Srgrimesstruct setegid_args { 5951541Srgrimes gid_t egid; 5961541Srgrimes}; 59712221Sbde#endif 5981541Srgrimes/* ARGSUSED */ 5991549Srgrimesint 60030994Sphksetegid(p, uap) 6011541Srgrimes struct proc *p; 6021541Srgrimes struct setegid_args *uap; 6031541Srgrimes{ 6041541Srgrimes register struct pcred *pc = p->p_cred; 6051541Srgrimes register gid_t egid; 6061541Srgrimes int error; 6071541Srgrimes 6081541Srgrimes egid = uap->egid; 60924449Speter if (egid != pc->p_rgid && /* allow setegid(getgid()) */ 61024449Speter egid != pc->p_svgid && /* allow setegid(saved gid) */ 61146155Sphk (error = suser_xxx(0, p, PRISON_ROOT))) 6121541Srgrimes return (error); 61324449Speter if (pc->pc_ucred->cr_groups[0] != egid) { 61424449Speter pc->pc_ucred = crcopy(pc->pc_ucred); 61524449Speter pc->pc_ucred->cr_groups[0] = egid; 61631891Ssef setsugid(p); 61724449Speter } 6181541Srgrimes return (0); 6191541Srgrimes} 6201541Srgrimes 62112221Sbde#ifndef _SYS_SYSPROTO_H_ 6221541Srgrimesstruct setgroups_args { 6231541Srgrimes u_int gidsetsize; 6241541Srgrimes gid_t *gidset; 6251541Srgrimes}; 62612221Sbde#endif 6271541Srgrimes/* ARGSUSED */ 6281549Srgrimesint 62930994Sphksetgroups(p, uap) 6301541Srgrimes struct proc *p; 6311541Srgrimes struct setgroups_args *uap; 6321541Srgrimes{ 6331541Srgrimes register struct pcred *pc = p->p_cred; 6341541Srgrimes register u_int ngrp; 6351541Srgrimes int error; 6361541Srgrimes 63746155Sphk if ((error = suser_xxx(0, p, PRISON_ROOT))) 6381541Srgrimes return (error); 63912063Sdg ngrp = uap->gidsetsize; 64024447Speter if (ngrp > NGROUPS) 6411541Srgrimes return (EINVAL); 64224447Speter /* 64324447Speter * XXX A little bit lazy here. We could test if anything has 64424447Speter * changed before crcopy() and setting P_SUGID. 64524447Speter */ 6461541Srgrimes pc->pc_ucred = crcopy(pc->pc_ucred); 64724447Speter if (ngrp < 1) { 64824447Speter /* 64924447Speter * setgroups(0, NULL) is a legitimate way of clearing the 65024447Speter * groups vector on non-BSD systems (which generally do not 65124447Speter * have the egid in the groups[0]). We risk security holes 65224447Speter * when running non-BSD software if we do not do the same. 65324447Speter */ 65424447Speter pc->pc_ucred->cr_ngroups = 1; 65524447Speter } else { 65624447Speter if ((error = copyin((caddr_t)uap->gidset, 65724447Speter (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))) 65824447Speter return (error); 65924447Speter pc->pc_ucred->cr_ngroups = ngrp; 66024447Speter } 66131891Ssef setsugid(p); 6621541Srgrimes return (0); 6631541Srgrimes} 6641541Srgrimes 66512221Sbde#ifndef _SYS_SYSPROTO_H_ 6661541Srgrimesstruct setreuid_args { 6679238Sache uid_t ruid; 6689238Sache uid_t euid; 6691541Srgrimes}; 67012221Sbde#endif 6711541Srgrimes/* ARGSUSED */ 6721549Srgrimesint 67330994Sphksetreuid(p, uap) 6741541Srgrimes register struct proc *p; 6751541Srgrimes struct setreuid_args *uap; 6761541Srgrimes{ 6771541Srgrimes register struct pcred *pc = p->p_cred; 6789238Sache register uid_t ruid, euid; 6798135Sache int error; 6801541Srgrimes 6819238Sache ruid = uap->ruid; 6829238Sache euid = uap->euid; 68343311Sdillon if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid) || 68443311Sdillon (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid && 68543311Sdillon euid != pc->p_ruid && euid != pc->p_svuid)) && 68646155Sphk (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 6878135Sache return (error); 6889238Sache 68924450Speter if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) { 69065495Struckman change_euid(p, euid); 69131891Ssef setsugid(p); 69224450Speter } 69324450Speter if (ruid != (uid_t)-1 && pc->p_ruid != ruid) { 69465495Struckman change_ruid(p, ruid); 69531891Ssef setsugid(p); 6968135Sache } 69724559Speter if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) && 69824559Speter pc->p_svuid != pc->pc_ucred->cr_uid) { 6998111Sache pc->p_svuid = pc->pc_ucred->cr_uid; 70031891Ssef setsugid(p); 70124450Speter } 7028135Sache return (0); 7031541Srgrimes} 7041541Srgrimes 70512221Sbde#ifndef _SYS_SYSPROTO_H_ 7061541Srgrimesstruct setregid_args { 7079238Sache gid_t rgid; 7089238Sache gid_t egid; 7091541Srgrimes}; 71012221Sbde#endif 7111541Srgrimes/* ARGSUSED */ 7121549Srgrimesint 71330994Sphksetregid(p, uap) 7141541Srgrimes register struct proc *p; 7151541Srgrimes struct setregid_args *uap; 7161541Srgrimes{ 7171541Srgrimes register struct pcred *pc = p->p_cred; 7189238Sache register gid_t rgid, egid; 7198135Sache int error; 7201541Srgrimes 7219238Sache rgid = uap->rgid; 7229238Sache egid = uap->egid; 72343311Sdillon if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid) || 72443311Sdillon (egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] && 72543311Sdillon egid != pc->p_rgid && egid != pc->p_svgid)) && 72646155Sphk (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 7278135Sache return (error); 7289238Sache 72924450Speter if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) { 73024450Speter pc->pc_ucred = crcopy(pc->pc_ucred); 7319238Sache pc->pc_ucred->cr_groups[0] = egid; 73231891Ssef setsugid(p); 73324450Speter } 73424450Speter if (rgid != (gid_t)-1 && pc->p_rgid != rgid) { 7359238Sache pc->p_rgid = rgid; 73631891Ssef setsugid(p); 73724450Speter } 73824559Speter if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) && 73924559Speter pc->p_svgid != pc->pc_ucred->cr_groups[0]) { 7408111Sache pc->p_svgid = pc->pc_ucred->cr_groups[0]; 74131891Ssef setsugid(p); 74224450Speter } 7438135Sache return (0); 7441541Srgrimes} 7451541Srgrimes 74656115Speter/* 74756115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the 74856115Speter * saved uid is explicit. 74956115Speter */ 75056115Speter 75124453Speter#ifndef _SYS_SYSPROTO_H_ 75256115Speterstruct setresuid_args { 75356115Speter uid_t ruid; 75456115Speter uid_t euid; 75556115Speter uid_t suid; 75656115Speter}; 75756115Speter#endif 75856115Speter/* ARGSUSED */ 75956115Speterint 76056115Spetersetresuid(p, uap) 76156115Speter register struct proc *p; 76256115Speter struct setresuid_args *uap; 76356115Speter{ 76456115Speter register struct pcred *pc = p->p_cred; 76556115Speter register uid_t ruid, euid, suid; 76656115Speter int error; 76756115Speter 76856115Speter ruid = uap->ruid; 76956115Speter euid = uap->euid; 77056115Speter suid = uap->suid; 77156115Speter if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid && 77256115Speter ruid != pc->pc_ucred->cr_uid) || 77356115Speter (euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid && 77456115Speter euid != pc->pc_ucred->cr_uid) || 77556115Speter (suid != (uid_t)-1 && suid != pc->p_ruid && suid != pc->p_svuid && 77656115Speter suid != pc->pc_ucred->cr_uid)) && 77756115Speter (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 77856115Speter return (error); 77956115Speter if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) { 78065495Struckman change_euid(p, euid); 78156115Speter setsugid(p); 78256115Speter } 78356115Speter if (ruid != (uid_t)-1 && pc->p_ruid != ruid) { 78465495Struckman change_ruid(p, ruid); 78556115Speter setsugid(p); 78656115Speter } 78756115Speter if (suid != (uid_t)-1 && pc->p_svuid != suid) { 78856115Speter pc->p_svuid = suid; 78956115Speter setsugid(p); 79056115Speter } 79156115Speter return (0); 79256115Speter} 79356115Speter 79456115Speter/* 79556115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the 79656115Speter * saved gid is explicit. 79756115Speter */ 79856115Speter 79956115Speter#ifndef _SYS_SYSPROTO_H_ 80056115Speterstruct setresgid_args { 80156115Speter gid_t rgid; 80256115Speter gid_t egid; 80356115Speter gid_t sgid; 80456115Speter}; 80556115Speter#endif 80656115Speter/* ARGSUSED */ 80756115Speterint 80856115Spetersetresgid(p, uap) 80956115Speter register struct proc *p; 81056115Speter struct setresgid_args *uap; 81156115Speter{ 81256115Speter register struct pcred *pc = p->p_cred; 81356115Speter register gid_t rgid, egid, sgid; 81456115Speter int error; 81556115Speter 81656115Speter rgid = uap->rgid; 81756115Speter egid = uap->egid; 81856115Speter sgid = uap->sgid; 81956115Speter if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid && 82056115Speter rgid != pc->pc_ucred->cr_groups[0]) || 82156115Speter (egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid && 82256115Speter egid != pc->pc_ucred->cr_groups[0]) || 82356115Speter (sgid != (gid_t)-1 && sgid != pc->p_rgid && sgid != pc->p_svgid && 82456115Speter sgid != pc->pc_ucred->cr_groups[0])) && 82556115Speter (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 82656115Speter return (error); 82756115Speter 82856115Speter if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) { 82956115Speter pc->pc_ucred = crcopy(pc->pc_ucred); 83056115Speter pc->pc_ucred->cr_groups[0] = egid; 83156115Speter setsugid(p); 83256115Speter } 83356115Speter if (rgid != (gid_t)-1 && pc->p_rgid != rgid) { 83456115Speter pc->p_rgid = rgid; 83556115Speter setsugid(p); 83656115Speter } 83756115Speter if (sgid != (gid_t)-1 && pc->p_svgid != sgid) { 83856115Speter pc->p_svgid = sgid; 83956115Speter setsugid(p); 84056115Speter } 84156115Speter return (0); 84256115Speter} 84356115Speter 84456115Speter#ifndef _SYS_SYSPROTO_H_ 84556115Speterstruct getresuid_args { 84656115Speter uid_t *ruid; 84756115Speter uid_t *euid; 84856115Speter uid_t *suid; 84956115Speter}; 85056115Speter#endif 85156115Speter/* ARGSUSED */ 85256115Speterint 85356115Spetergetresuid(p, uap) 85456115Speter register struct proc *p; 85556115Speter struct getresuid_args *uap; 85656115Speter{ 85756115Speter struct pcred *pc = p->p_cred; 85856115Speter int error1 = 0, error2 = 0, error3 = 0; 85956115Speter 86056115Speter if (uap->ruid) 86156115Speter error1 = copyout((caddr_t)&pc->p_ruid, 86256115Speter (caddr_t)uap->ruid, sizeof(pc->p_ruid)); 86356115Speter if (uap->euid) 86456115Speter error2 = copyout((caddr_t)&pc->pc_ucred->cr_uid, 86556115Speter (caddr_t)uap->euid, sizeof(pc->pc_ucred->cr_uid)); 86656115Speter if (uap->suid) 86756115Speter error3 = copyout((caddr_t)&pc->p_svuid, 86856115Speter (caddr_t)uap->suid, sizeof(pc->p_svuid)); 86956115Speter return error1 ? error1 : (error2 ? error2 : error3); 87056115Speter} 87156115Speter 87256115Speter#ifndef _SYS_SYSPROTO_H_ 87356115Speterstruct getresgid_args { 87456115Speter gid_t *rgid; 87556115Speter gid_t *egid; 87656115Speter gid_t *sgid; 87756115Speter}; 87856115Speter#endif 87956115Speter/* ARGSUSED */ 88056115Speterint 88156115Spetergetresgid(p, uap) 88256115Speter register struct proc *p; 88356115Speter struct getresgid_args *uap; 88456115Speter{ 88556115Speter struct pcred *pc = p->p_cred; 88656115Speter int error1 = 0, error2 = 0, error3 = 0; 88756115Speter 88856115Speter if (uap->rgid) 88956115Speter error1 = copyout((caddr_t)&pc->p_rgid, 89056115Speter (caddr_t)uap->rgid, sizeof(pc->p_rgid)); 89156115Speter if (uap->egid) 89256115Speter error2 = copyout((caddr_t)&pc->pc_ucred->cr_groups[0], 89356115Speter (caddr_t)uap->egid, sizeof(pc->pc_ucred->cr_groups[0])); 89456115Speter if (uap->sgid) 89556115Speter error3 = copyout((caddr_t)&pc->p_svgid, 89656115Speter (caddr_t)uap->sgid, sizeof(pc->p_svgid)); 89756115Speter return error1 ? error1 : (error2 ? error2 : error3); 89856115Speter} 89956115Speter 90056115Speter 90156115Speter#ifndef _SYS_SYSPROTO_H_ 90224453Speterstruct issetugid_args { 90324453Speter int dummy; 90424453Speter}; 90524453Speter#endif 90624453Speter/* ARGSUSED */ 90724453Speterint 90830994Sphkissetugid(p, uap) 90924453Speter register struct proc *p; 91024453Speter struct issetugid_args *uap; 91124453Speter{ 91224453Speter /* 91324453Speter * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 91424453Speter * we use P_SUGID because we consider changing the owners as 91524453Speter * "tainting" as well. 91624453Speter * This is significant for procs that start as root and "become" 91724453Speter * a user without an exec - programs cannot know *everything* 91824453Speter * that libc *might* have put in their data segment. 91924453Speter */ 92060216Speter p->p_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 92124453Speter return (0); 92224453Speter} 92324453Speter 92475426Srwatsonint 92575426Srwatson__setugid(p, uap) 92675426Srwatson struct proc *p; 92775426Srwatson struct __setugid_args *uap; 92875426Srwatson{ 92975426Srwatson 93075426Srwatson#ifdef REGRESSION 93175426Srwatson switch (uap->flag) { 93275426Srwatson case 0: 93375426Srwatson p->p_flag &= ~P_SUGID; 93475426Srwatson return (0); 93575426Srwatson case 1: 93675426Srwatson p->p_flag |= P_SUGID; 93775426Srwatson return (0); 93875426Srwatson default: 93975426Srwatson return (EINVAL); 94075426Srwatson } 94175426Srwatson#else /* !REGRESSION */ 94275426Srwatson return (ENOSYS); 94375426Srwatson#endif /* !REGRESSION */ 94475426Srwatson} 94575426Srwatson 9461541Srgrimes/* 9471541Srgrimes * Check if gid is a member of the group set. 9481541Srgrimes */ 9491549Srgrimesint 9501541Srgrimesgroupmember(gid, cred) 9511541Srgrimes gid_t gid; 9521541Srgrimes register struct ucred *cred; 9531541Srgrimes{ 9541541Srgrimes register gid_t *gp; 9551541Srgrimes gid_t *egp; 9561541Srgrimes 9571541Srgrimes egp = &(cred->cr_groups[cred->cr_ngroups]); 9581541Srgrimes for (gp = cred->cr_groups; gp < egp; gp++) 9591541Srgrimes if (*gp == gid) 9601541Srgrimes return (1); 9611541Srgrimes return (0); 9621541Srgrimes} 9631541Srgrimes 96461287Srwatsonstatic int suser_permitted = 1; 96561287Srwatson 96661287SrwatsonSYSCTL_INT(_kern, OID_AUTO, suser_permitted, CTLFLAG_RW, &suser_permitted, 0, 96761287Srwatson "processes with uid 0 have privilege"); 96861287Srwatson 9691541Srgrimes/* 9701541Srgrimes * Test whether the specified credentials imply "super-user" 9711541Srgrimes * privilege; if so, and we have accounting info, set the flag 9721541Srgrimes * indicating use of super-powers. 9731541Srgrimes * Returns 0 or error. 9741541Srgrimes */ 9751549Srgrimesint 97646112Sphksuser(p) 97772786Srwatson struct proc *p; 97846112Sphk{ 97946155Sphk return suser_xxx(0, p, 0); 98046112Sphk} 98146112Sphk 98246112Sphkint 98346155Sphksuser_xxx(cred, proc, flag) 98472786Srwatson struct ucred *cred; 98572786Srwatson struct proc *proc; 98646155Sphk int flag; 9871541Srgrimes{ 98861282Srwatson if (!suser_permitted) 98961282Srwatson return (EPERM); 99046155Sphk if (!cred && !proc) { 99146155Sphk printf("suser_xxx(): THINK!\n"); 99246155Sphk return (EPERM); 9931541Srgrimes } 99446155Sphk if (!cred) 99546155Sphk cred = proc->p_ucred; 99646155Sphk if (cred->cr_uid != 0) 99746155Sphk return (EPERM); 99872786Srwatson if (jailed(cred) && !(flag & PRISON_ROOT)) 99946155Sphk return (EPERM); 100046155Sphk return (0); 10011541Srgrimes} 10021541Srgrimes 100374956Srwatson/* 100474956Srwatson * u_cansee(u1, u2): determine if u1 "can see" the subject specified by u2 100574956Srwatson * Arguments: imutable credentials u1, u2 100674956Srwatson * Returns: 0 for permitted, an errno value otherwise 100774956Srwatson * Locks: none 100874956Srwatson * References: u1 and u2 must be valid for the lifetime of the call 100974956Srwatson * u1 may equal u2, in which case only one reference is required 101074956Srwatson */ 101174956Srwatsonint 101274956Srwatsonu_cansee(struct ucred *u1, struct ucred *u2) 101365237Srwatson{ 101472786Srwatson int error; 101553518Sphk 101674956Srwatson if ((error = prison_check(u1, u2))) 101772786Srwatson return (error); 101874956Srwatson if (!ps_showallprocs && u1->cr_uid != u2->cr_uid) { 101975005Srwatson if (suser_xxx(u1, NULL, PRISON_ROOT) != 0) 102074956Srwatson return (ESRCH); 102165293Srwatson } 102265237Srwatson return (0); 102365237Srwatson} 102465237Srwatson 102565237Srwatsonstatic int 102674956Srwatsonp_cansee(struct proc *p1, struct proc *p2, int *privused) 102774956Srwatson{ 102874956Srwatson 102974956Srwatson /* XXX: privused is going away, so don't do that here. */ 103074956Srwatson if (privused != NULL) 103174956Srwatson *privused = 0; 103274956Srwatson /* Wrap u_cansee() for all functionality. */ 103374956Srwatson return (u_cansee(p1->p_ucred, p2->p_ucred)); 103474956Srwatson} 103574956Srwatson 103675437Srwatson/* 103775437Srwatson * Can process p1 send the signal signum to process p2? 103875437Srwatson */ 103975437Srwatsonint 104075437Srwatsonp_cansignal(struct proc *p1, struct proc *p2, int signum) 104153518Sphk{ 104275437Srwatson int error; 104375437Srwatson 104453518Sphk if (p1 == p2) 104553518Sphk return (0); 104665237Srwatson 104775437Srwatson /* 104875437Srwatson * Jail semantics limit the scope of signalling to p2 in the same 104975437Srwatson * jail as p1, if p1 is in jail. 105075437Srwatson */ 105172786Srwatson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 105272786Srwatson return (error); 105365237Srwatson 105465237Srwatson /* 105575437Srwatson * UNIX signalling semantics require that processes in the same 105675437Srwatson * session always be able to deliver SIGCONT to one another, 105775437Srwatson * overriding the remaining protections. 105865237Srwatson */ 105975437Srwatson if (signum == SIGCONT && p1->p_session == p2->p_session) 106053518Sphk return (0); 106165237Srwatson 106275437Srwatson /* 106375437Srwatson * UNIX uid semantics depend on the status of the P_SUGID 106475437Srwatson * bit on the target process. If the bit is set, then more 106575437Srwatson * restricted signal sets are permitted. 106675437Srwatson */ 106775437Srwatson if (p2->p_flag & P_SUGID) { 106875437Srwatson switch (signum) { 106975437Srwatson case 0: 107075437Srwatson case SIGKILL: 107175437Srwatson case SIGINT: 107275437Srwatson case SIGTERM: 107375437Srwatson case SIGSTOP: 107475437Srwatson case SIGTTIN: 107575437Srwatson case SIGTTOU: 107675437Srwatson case SIGTSTP: 107775437Srwatson case SIGHUP: 107875437Srwatson case SIGUSR1: 107975437Srwatson case SIGUSR2: 108075437Srwatson /* 108175437Srwatson * Restricted rules allow a broadish scope of uid 108275437Srwatson * uid overlap. 108375437Srwatson * XXX: Maybe too broad. 108475437Srwatson */ 108575437Srwatson if (p1->p_cred->p_ruid != p2->p_cred->p_ruid && 108675437Srwatson p1->p_ucred->cr_uid != p2->p_cred->p_ruid && 108775437Srwatson p1->p_cred->p_ruid != p2->p_ucred->cr_uid && 108875437Srwatson p1->p_ucred->cr_uid != p2->p_ucred->cr_uid) { 108975437Srwatson /* Not permitted, try privilege. */ 109075437Srwatson error = suser_xxx(NULL, p1, PRISON_ROOT); 109175437Srwatson if (error) 109275437Srwatson return (error); 109375437Srwatson } 109475437Srwatson break; 109575437Srwatson default: 109675437Srwatson /* Not permitted, try privilege. */ 109775437Srwatson error = suser_xxx(NULL, p1, PRISON_ROOT); 109875437Srwatson if (error) 109975437Srwatson return (error); 110075437Srwatson } 110175437Srwatson } else { 110275437Srwatson /* 110375437Srwatson * Normal rules allow a broad scope of uid overlap. 110475437Srwatson * XXX: Maybe too broad. 110575437Srwatson */ 110675437Srwatson if (p1->p_cred->p_ruid != p2->p_cred->p_ruid && 110775437Srwatson p1->p_cred->p_ruid != p2->p_cred->p_svuid && 110875437Srwatson p1->p_ucred->cr_uid != p2->p_cred->p_ruid && 110975437Srwatson p1->p_ucred->cr_uid != p2->p_cred->p_svuid && 111075437Srwatson p1->p_cred->p_ruid != p2->p_ucred->cr_uid && 111175437Srwatson p1->p_ucred->cr_uid != p2->p_ucred->cr_uid) { 111275437Srwatson /* Not permitted, try privilege. */ 111375437Srwatson error = suser_xxx(NULL, p1, PRISON_ROOT); 111475437Srwatson if (error) 111575437Srwatson return (error); 111675437Srwatson } 111765237Srwatson } 111865237Srwatson 111975437Srwatson return (0); 112053518Sphk} 112153518Sphk 112265237Srwatsonstatic int 112372786Srwatsonp_cansched(struct proc *p1, struct proc *p2, int *privused) 112465237Srwatson{ 112572786Srwatson int error; 112665237Srwatson 112765237Srwatson if (privused != NULL) 112865237Srwatson *privused = 0; 112965237Srwatson 113065237Srwatson if (p1 == p2) 113165237Srwatson return (0); 113265237Srwatson 113372786Srwatson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 113472786Srwatson return (error); 113565237Srwatson 113665237Srwatson if (p1->p_cred->p_ruid == p2->p_cred->p_ruid) 113765237Srwatson return (0); 113865237Srwatson if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid) 113965237Srwatson return (0); 114065237Srwatson /* 114165237Srwatson * XXX should a process be able to affect another process 114265237Srwatson * acting as the same uid (i.e., a userland nfsd or the like?) 114365237Srwatson */ 114465237Srwatson if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid) 114565237Srwatson return (0); 114665237Srwatson if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid) 114765237Srwatson return (0); 114865237Srwatson 114965237Srwatson if (!suser_xxx(0, p1, PRISON_ROOT)) { 115065237Srwatson if (privused != NULL) 115165237Srwatson *privused = 1; 115265237Srwatson return (0); 115365237Srwatson } 115465237Srwatson 115565237Srwatson#ifdef CAPABILITIES 115665237Srwatson if (!cap_check_xxx(0, p1, CAP_SYS_NICE, PRISON_ROOT)) { 115765237Srwatson if (privused != NULL) 115865237Srwatson *privused = 1; 115965237Srwatson return (0); 116065237Srwatson } 116165237Srwatson#endif 116265237Srwatson 116365237Srwatson return (EPERM); 116465237Srwatson} 116565237Srwatson 116665237Srwatsonstatic int 116772786Srwatsonp_candebug(struct proc *p1, struct proc *p2, int *privused) 116865237Srwatson{ 116972786Srwatson int error; 117065237Srwatson 117165237Srwatson if (privused != NULL) 117265237Srwatson *privused = 0; 117365237Srwatson 117465237Srwatson /* XXX it is authorized, but semantics don't permit it */ 117565237Srwatson if (p1 == p2) 117665237Srwatson return (0); 117765237Srwatson 117872786Srwatson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 117972786Srwatson return (error); 118065237Srwatson 118165237Srwatson /* not owned by you, has done setuid (unless you're root) */ 118265237Srwatson /* add a CAP_SYS_PTRACE here? */ 118367999Srwatson if (p1->p_cred->pc_ucred->cr_uid != p2->p_cred->p_ruid || 118467999Srwatson p1->p_cred->p_ruid != p2->p_cred->p_ruid || 118568591Srwatson p1->p_cred->p_svuid != p2->p_cred->p_ruid || 118667999Srwatson p2->p_flag & P_SUGID) { 118765237Srwatson if ((error = suser_xxx(0, p1, PRISON_ROOT))) 118865237Srwatson return (error); 118965237Srwatson if (privused != NULL) 119065237Srwatson *privused = 1; 119165237Srwatson } 119265237Srwatson 119365237Srwatson /* can't trace init when securelevel > 0 */ 119465237Srwatson if (securelevel > 0 && p2->p_pid == 1) 119565237Srwatson return (EPERM); 119665237Srwatson 119765237Srwatson return (0); 119865237Srwatson} 119965237Srwatson 120065237Srwatsonint 120172786Srwatsonp_can(struct proc *p1, struct proc *p2, int operation, 120265237Srwatson int *privused) 120365237Srwatson{ 120465237Srwatson 120565237Srwatson switch(operation) { 120665237Srwatson case P_CAN_SEE: 120765237Srwatson return (p_cansee(p1, p2, privused)); 120865237Srwatson 120965237Srwatson case P_CAN_SCHED: 121065237Srwatson return (p_cansched(p1, p2, privused)); 121165237Srwatson 121265237Srwatson case P_CAN_DEBUG: 121365237Srwatson return (p_candebug(p1, p2, privused)); 121465237Srwatson 121565237Srwatson default: 121665237Srwatson panic("p_can: invalid operation"); 121765237Srwatson } 121865237Srwatson} 121965237Srwatson 122065237Srwatson 122153518Sphk/* 12221541Srgrimes * Allocate a zeroed cred structure. 12231541Srgrimes */ 12241541Srgrimesstruct ucred * 12251541Srgrimescrget() 12261541Srgrimes{ 12271541Srgrimes register struct ucred *cr; 12281541Srgrimes 122969239Salfred MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK|M_ZERO); 12301541Srgrimes cr->cr_ref = 1; 123169239Salfred mtx_init(&cr->cr_mtx, "ucred", MTX_DEF); 12321541Srgrimes return (cr); 12331541Srgrimes} 12341541Srgrimes 12351541Srgrimes/* 123672474Srwatson * Claim another reference to a ucred structure 123769401Salfred */ 123869401Salfredvoid 123969401Salfredcrhold(cr) 124069401Salfred struct ucred *cr; 124169401Salfred{ 124269401Salfred 124372200Sbmilekic mtx_lock(&cr->cr_mtx); 124469401Salfred cr->cr_ref++; 124572200Sbmilekic mtx_unlock(&(cr)->cr_mtx); 124669401Salfred} 124769401Salfred 124869401Salfred 124969401Salfred/* 12501541Srgrimes * Free a cred structure. 12511541Srgrimes * Throws away space when ref count gets to 0. 12521541Srgrimes */ 12531549Srgrimesvoid 12541541Srgrimescrfree(cr) 12551541Srgrimes struct ucred *cr; 12561541Srgrimes{ 125769239Salfred 125872200Sbmilekic mtx_lock(&cr->cr_mtx); 125965495Struckman if (--cr->cr_ref == 0) { 126069239Salfred mtx_destroy(&cr->cr_mtx); 126165495Struckman /* 126265495Struckman * Some callers of crget(), such as nfs_statfs(), 126365495Struckman * allocate a temporary credential, but don't 126465495Struckman * allocate a uidinfo structure. 126565495Struckman */ 126665495Struckman if (cr->cr_uidinfo != NULL) 126765495Struckman uifree(cr->cr_uidinfo); 126872786Srwatson /* 126972786Srwatson * Free a prison, if any. 127072786Srwatson */ 127172786Srwatson if (jailed(cr)) 127272786Srwatson prison_free(cr->cr_prison); 12731541Srgrimes FREE((caddr_t)cr, M_CRED); 127469239Salfred } else { 127572200Sbmilekic mtx_unlock(&cr->cr_mtx); 127665495Struckman } 12771541Srgrimes} 12781541Srgrimes 12791541Srgrimes/* 12801541Srgrimes * Copy cred structure to a new one and free the old one. 12811541Srgrimes */ 12821541Srgrimesstruct ucred * 12831541Srgrimescrcopy(cr) 12841541Srgrimes struct ucred *cr; 12851541Srgrimes{ 12861541Srgrimes struct ucred *newcr; 12871541Srgrimes 128872200Sbmilekic mtx_lock(&cr->cr_mtx); 128969239Salfred if (cr->cr_ref == 1) { 129072200Sbmilekic mtx_unlock(&cr->cr_mtx); 12911541Srgrimes return (cr); 129269239Salfred } 129372200Sbmilekic mtx_unlock(&cr->cr_mtx); 129469239Salfred newcr = crdup(cr); 12951541Srgrimes crfree(cr); 12961541Srgrimes return (newcr); 12971541Srgrimes} 12981541Srgrimes 12991541Srgrimes/* 13001541Srgrimes * Dup cred struct to a new held one. 13011541Srgrimes */ 13021541Srgrimesstruct ucred * 13031541Srgrimescrdup(cr) 13041541Srgrimes struct ucred *cr; 13051541Srgrimes{ 13061541Srgrimes struct ucred *newcr; 13071541Srgrimes 130869239Salfred MALLOC(newcr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 13091541Srgrimes *newcr = *cr; 131069239Salfred mtx_init(&newcr->cr_mtx, "ucred", MTX_DEF); 131165495Struckman uihold(newcr->cr_uidinfo); 131272786Srwatson if (jailed(newcr)) 131372786Srwatson prison_hold(newcr->cr_prison); 13141541Srgrimes newcr->cr_ref = 1; 13151541Srgrimes return (newcr); 13161541Srgrimes} 13171541Srgrimes 13181541Srgrimes/* 13191541Srgrimes * Get login name, if available. 13201541Srgrimes */ 132112221Sbde#ifndef _SYS_SYSPROTO_H_ 13221541Srgrimesstruct getlogin_args { 13231541Srgrimes char *namebuf; 13241541Srgrimes u_int namelen; 13251541Srgrimes}; 132612221Sbde#endif 13271541Srgrimes/* ARGSUSED */ 13281549Srgrimesint 132930994Sphkgetlogin(p, uap) 13301541Srgrimes struct proc *p; 13311541Srgrimes struct getlogin_args *uap; 13321541Srgrimes{ 13331541Srgrimes 133423358Sache if (uap->namelen > MAXLOGNAME) 133523359Sache uap->namelen = MAXLOGNAME; 13361541Srgrimes return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 13371541Srgrimes (caddr_t) uap->namebuf, uap->namelen)); 13381541Srgrimes} 13391541Srgrimes 13401541Srgrimes/* 13411541Srgrimes * Set login name. 13421541Srgrimes */ 134312221Sbde#ifndef _SYS_SYSPROTO_H_ 13441541Srgrimesstruct setlogin_args { 13451541Srgrimes char *namebuf; 13461541Srgrimes}; 134712221Sbde#endif 13481541Srgrimes/* ARGSUSED */ 13491549Srgrimesint 135030994Sphksetlogin(p, uap) 13511541Srgrimes struct proc *p; 13521541Srgrimes struct setlogin_args *uap; 13531541Srgrimes{ 13541541Srgrimes int error; 135523330Sache char logintmp[MAXLOGNAME]; 13561541Srgrimes 135746155Sphk if ((error = suser_xxx(0, p, PRISON_ROOT))) 13581541Srgrimes return (error); 135922522Sdavidn error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 136036845Sdfr sizeof(logintmp), (size_t *)0); 13611541Srgrimes if (error == ENAMETOOLONG) 13621541Srgrimes error = EINVAL; 136322522Sdavidn else if (!error) 136422522Sdavidn (void) memcpy(p->p_pgrp->pg_session->s_login, logintmp, 136523330Sache sizeof(logintmp)); 13661541Srgrimes return (error); 13671541Srgrimes} 136831891Ssef 136931891Ssefvoid 137031891Ssefsetsugid(p) 137155338Sphk struct proc *p; 137231891Ssef{ 137331891Ssef p->p_flag |= P_SUGID; 137455707Ssef if (!(p->p_pfsflags & PF_ISUGID)) 137531891Ssef p->p_stops = 0; 137631891Ssef} 137765495Struckman 137865495Struckman/* 137965495Struckman * Helper function to change the effective uid of a process 138065495Struckman */ 138165495Struckmanvoid 138265495Struckmanchange_euid(p, euid) 138365495Struckman struct proc *p; 138465495Struckman uid_t euid; 138565495Struckman{ 138665495Struckman struct pcred *pc; 138765495Struckman struct uidinfo *uip; 138865495Struckman 138965495Struckman pc = p->p_cred; 139065495Struckman /* 139165495Struckman * crcopy is essentially a NOP if ucred has a reference count 139265495Struckman * of 1, which is true if it has already been copied. 139365495Struckman */ 139465495Struckman pc->pc_ucred = crcopy(pc->pc_ucred); 139565495Struckman uip = pc->pc_ucred->cr_uidinfo; 139665495Struckman pc->pc_ucred->cr_uid = euid; 139765495Struckman pc->pc_ucred->cr_uidinfo = uifind(euid); 139865495Struckman uifree(uip); 139965495Struckman} 140065495Struckman 140165495Struckman/* 140265495Struckman * Helper function to change the real uid of a process 140365495Struckman * 140465495Struckman * The per-uid process count for this process is transfered from 140565495Struckman * the old uid to the new uid. 140665495Struckman */ 140767629Sgallatinvoid 140865495Struckmanchange_ruid(p, ruid) 140965495Struckman struct proc *p; 141065495Struckman uid_t ruid; 141165495Struckman{ 141265495Struckman struct pcred *pc; 141365495Struckman struct uidinfo *uip; 141465495Struckman 141565495Struckman pc = p->p_cred; 141665495Struckman (void)chgproccnt(pc->p_uidinfo, -1, 0); 141765495Struckman uip = pc->p_uidinfo; 141865495Struckman /* It is assumed that pcred is not shared between processes */ 141965495Struckman pc->p_ruid = ruid; 142065495Struckman pc->p_uidinfo = uifind(ruid); 142165495Struckman (void)chgproccnt(pc->p_uidinfo, 1, 0); 142265495Struckman uifree(uip); 142365495Struckman} 1424