kern_prot.c revision 80735
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 80735 2001-07-31 15:48:21Z 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> 5076166Smarkm#include <sys/systm.h> 511541Srgrimes#include <sys/acct.h> 5241059Speter#include <sys/kernel.h> 5370317Sjake#include <sys/lock.h> 5476166Smarkm#include <sys/mutex.h> 551541Srgrimes#include <sys/proc.h> 5676166Smarkm#include <sys/sysproto.h> 571541Srgrimes#include <sys/malloc.h> 5831891Ssef#include <sys/pioctl.h> 5965495Struckman#include <sys/resourcevar.h> 6061287Srwatson#include <sys/sysctl.h> 6172786Srwatson#include <sys/jail.h> 621541Srgrimes 6330354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials"); 6430354Sphk 6580735SrwatsonSYSCTL_NODE(_kern, OID_AUTO, security, CTLFLAG_RW, 0, 6680735Srwatson "Kernel security policy"); 6780735Srwatson 6812221Sbde#ifndef _SYS_SYSPROTO_H_ 6911332Sswallacestruct getpid_args { 701541Srgrimes int dummy; 711541Srgrimes}; 7212221Sbde#endif 731541Srgrimes 7458717Sdillon/* 7570317Sjake * getpid - MP SAFE 7658717Sdillon */ 7770317Sjake 781541Srgrimes/* ARGSUSED */ 791549Srgrimesint 8030994Sphkgetpid(p, uap) 811541Srgrimes struct proc *p; 8211332Sswallace struct getpid_args *uap; 831541Srgrimes{ 841541Srgrimes 8530994Sphk p->p_retval[0] = p->p_pid; 861541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 8774728Sjhb PROC_LOCK(p); 8830994Sphk p->p_retval[1] = p->p_pptr->p_pid; 8974728Sjhb PROC_UNLOCK(p); 901541Srgrimes#endif 911541Srgrimes return (0); 921541Srgrimes} 931541Srgrimes 9470317Sjake/* 9570317Sjake * getppid - MP SAFE 9670317Sjake */ 9770317Sjake 9812221Sbde#ifndef _SYS_SYSPROTO_H_ 9911332Sswallacestruct getppid_args { 10011332Sswallace int dummy; 10111332Sswallace}; 10212221Sbde#endif 1031541Srgrimes/* ARGSUSED */ 1041549Srgrimesint 10530994Sphkgetppid(p, uap) 1061541Srgrimes struct proc *p; 10711332Sswallace struct getppid_args *uap; 1081541Srgrimes{ 1091541Srgrimes 11074728Sjhb PROC_LOCK(p); 11130994Sphk p->p_retval[0] = p->p_pptr->p_pid; 11274728Sjhb PROC_UNLOCK(p); 1131541Srgrimes return (0); 1141541Srgrimes} 1151541Srgrimes 11658717Sdillon/* 11758717Sdillon * Get process group ID; note that POSIX getpgrp takes no parameter 11858717Sdillon * 11958717Sdillon * MP SAFE 12058717Sdillon */ 12112221Sbde#ifndef _SYS_SYSPROTO_H_ 12211332Sswallacestruct getpgrp_args { 12311332Sswallace int dummy; 12411332Sswallace}; 12512221Sbde#endif 12611332Sswallace 1271549Srgrimesint 12830994Sphkgetpgrp(p, uap) 1291541Srgrimes struct proc *p; 13011332Sswallace struct getpgrp_args *uap; 1311541Srgrimes{ 1321541Srgrimes 13330994Sphk p->p_retval[0] = p->p_pgrp->pg_id; 1341541Srgrimes return (0); 1351541Srgrimes} 1361541Srgrimes 13728401Speter/* Get an arbitary pid's process group id */ 13812221Sbde#ifndef _SYS_SYSPROTO_H_ 13928401Speterstruct getpgid_args { 14028401Speter pid_t pid; 14128401Speter}; 14228401Speter#endif 14328401Speter 14428401Speterint 14530994Sphkgetpgid(p, uap) 14628401Speter struct proc *p; 14728401Speter struct getpgid_args *uap; 14828401Speter{ 14941726Struckman struct proc *pt; 15075448Srwatson int error; 15141726Struckman 15228401Speter if (uap->pid == 0) 15375893Sjhb p->p_retval[0] = p->p_pgrp->pg_id; 15475893Sjhb else { 15575893Sjhb if ((pt = pfind(uap->pid)) == NULL) 15675893Sjhb return ESRCH; 15779335Srwatson if ((error = p_cansee(p, pt))) { 15875893Sjhb PROC_UNLOCK(pt); 15975893Sjhb return (error); 16075893Sjhb } 16175893Sjhb p->p_retval[0] = pt->p_pgrp->pg_id; 16275893Sjhb PROC_UNLOCK(pt); 16375893Sjhb } 16428401Speter return 0; 16528401Speter} 16628401Speter 16728401Speter/* 16828401Speter * Get an arbitary pid's session id. 16928401Speter */ 17028401Speter#ifndef _SYS_SYSPROTO_H_ 17128401Speterstruct getsid_args { 17228401Speter pid_t pid; 17328401Speter}; 17428401Speter#endif 17528401Speter 17628401Speterint 17730994Sphkgetsid(p, uap) 17828401Speter struct proc *p; 17928401Speter struct getsid_args *uap; 18028401Speter{ 18141726Struckman struct proc *pt; 18275448Srwatson int error; 18341726Struckman 18428401Speter if (uap->pid == 0) 18575893Sjhb p->p_retval[0] = p->p_session->s_sid; 18675893Sjhb else { 18775893Sjhb if ((pt = pfind(uap->pid)) == NULL) 18875893Sjhb return ESRCH; 18979335Srwatson if ((error = p_cansee(p, pt))) { 19075893Sjhb PROC_UNLOCK(pt); 19175893Sjhb return (error); 19275893Sjhb } 19375893Sjhb p->p_retval[0] = pt->p_session->s_sid; 19475893Sjhb PROC_UNLOCK(pt); 19575893Sjhb } 19628401Speter return 0; 19728401Speter} 19828401Speter 19928401Speter 20058941Sdillon/* 20158941Sdillon * getuid() - MP SAFE 20258941Sdillon */ 20328401Speter#ifndef _SYS_SYSPROTO_H_ 20411332Sswallacestruct getuid_args { 20511332Sswallace int dummy; 20611332Sswallace}; 20712221Sbde#endif 20811332Sswallace 2091541Srgrimes/* ARGSUSED */ 2101549Srgrimesint 21130994Sphkgetuid(p, uap) 2121541Srgrimes struct proc *p; 21311332Sswallace struct getuid_args *uap; 2141541Srgrimes{ 2151541Srgrimes 21677183Srwatson p->p_retval[0] = p->p_ucred->cr_ruid; 2171541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 21830994Sphk p->p_retval[1] = p->p_ucred->cr_uid; 2191541Srgrimes#endif 2201541Srgrimes return (0); 2211541Srgrimes} 2221541Srgrimes 22358941Sdillon/* 22458941Sdillon * geteuid() - MP SAFE 22558941Sdillon */ 22612221Sbde#ifndef _SYS_SYSPROTO_H_ 22711332Sswallacestruct geteuid_args { 22811332Sswallace int dummy; 22911332Sswallace}; 23012221Sbde#endif 23111332Sswallace 2321541Srgrimes/* ARGSUSED */ 2331549Srgrimesint 23430994Sphkgeteuid(p, uap) 2351541Srgrimes struct proc *p; 23611332Sswallace struct geteuid_args *uap; 2371541Srgrimes{ 2381541Srgrimes 23930994Sphk p->p_retval[0] = p->p_ucred->cr_uid; 2401541Srgrimes return (0); 2411541Srgrimes} 2421541Srgrimes 24358941Sdillon/* 24458941Sdillon * getgid() - MP SAFE 24558941Sdillon */ 24612221Sbde#ifndef _SYS_SYSPROTO_H_ 24711332Sswallacestruct getgid_args { 24811332Sswallace int dummy; 24911332Sswallace}; 25012221Sbde#endif 25111332Sswallace 2521541Srgrimes/* ARGSUSED */ 2531549Srgrimesint 25430994Sphkgetgid(p, uap) 2551541Srgrimes struct proc *p; 25611332Sswallace struct getgid_args *uap; 2571541Srgrimes{ 2581541Srgrimes 25977183Srwatson p->p_retval[0] = p->p_ucred->cr_rgid; 2601541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 26130994Sphk p->p_retval[1] = p->p_ucred->cr_groups[0]; 2621541Srgrimes#endif 2631541Srgrimes return (0); 2641541Srgrimes} 2651541Srgrimes 2661541Srgrimes/* 2671541Srgrimes * Get effective group ID. The "egid" is groups[0], and could be obtained 2681541Srgrimes * via getgroups. This syscall exists because it is somewhat painful to do 2691541Srgrimes * correctly in a library function. 2701541Srgrimes */ 27112221Sbde#ifndef _SYS_SYSPROTO_H_ 27211332Sswallacestruct getegid_args { 27311332Sswallace int dummy; 27411332Sswallace}; 27512221Sbde#endif 27611332Sswallace 2771541Srgrimes/* ARGSUSED */ 2781549Srgrimesint 27930994Sphkgetegid(p, uap) 2801541Srgrimes struct proc *p; 28111332Sswallace struct getegid_args *uap; 2821541Srgrimes{ 2831541Srgrimes 28430994Sphk p->p_retval[0] = p->p_ucred->cr_groups[0]; 2851541Srgrimes return (0); 2861541Srgrimes} 2871541Srgrimes 28812221Sbde#ifndef _SYS_SYSPROTO_H_ 2891541Srgrimesstruct getgroups_args { 2901541Srgrimes u_int gidsetsize; 2911541Srgrimes gid_t *gidset; 2921541Srgrimes}; 29312221Sbde#endif 2941549Srgrimesint 29530994Sphkgetgroups(p, uap) 2961541Srgrimes struct proc *p; 2971541Srgrimes register struct getgroups_args *uap; 2981541Srgrimes{ 29977183Srwatson struct ucred *cred = p->p_ucred; 30077183Srwatson u_int ngrp; 3011541Srgrimes int error; 3021541Srgrimes 3031541Srgrimes if ((ngrp = uap->gidsetsize) == 0) { 30477183Srwatson p->p_retval[0] = cred->cr_ngroups; 3051541Srgrimes return (0); 3061541Srgrimes } 30777183Srwatson if (ngrp < cred->cr_ngroups) 3081541Srgrimes return (EINVAL); 30977183Srwatson ngrp = cred->cr_ngroups; 31077183Srwatson if ((error = copyout((caddr_t)cred->cr_groups, 3113098Sphk (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))) 3121541Srgrimes return (error); 31330994Sphk p->p_retval[0] = ngrp; 3141541Srgrimes return (0); 3151541Srgrimes} 3161541Srgrimes 31712221Sbde#ifndef _SYS_SYSPROTO_H_ 31812207Sbdestruct setsid_args { 31911332Sswallace int dummy; 32011332Sswallace}; 32112221Sbde#endif 32211332Sswallace 3231541Srgrimes/* ARGSUSED */ 3241549Srgrimesint 32530994Sphksetsid(p, uap) 3261541Srgrimes register struct proc *p; 32712207Sbde struct setsid_args *uap; 3281541Srgrimes{ 3291541Srgrimes 3301541Srgrimes if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 3311541Srgrimes return (EPERM); 3321541Srgrimes } else { 3331541Srgrimes (void)enterpgrp(p, p->p_pid, 1); 33430994Sphk p->p_retval[0] = p->p_pid; 3351541Srgrimes return (0); 3361541Srgrimes } 3371541Srgrimes} 3381541Srgrimes 3391541Srgrimes/* 3401541Srgrimes * set process group (setpgid/old setpgrp) 3411541Srgrimes * 3421541Srgrimes * caller does setpgid(targpid, targpgid) 3431541Srgrimes * 3441541Srgrimes * pid must be caller or child of caller (ESRCH) 3451541Srgrimes * if a child 3461541Srgrimes * pid must be in same session (EPERM) 3471541Srgrimes * pid can't have done an exec (EACCES) 3481541Srgrimes * if pgid != pid 3491541Srgrimes * there must exist some pid in same session having pgid (EPERM) 3501541Srgrimes * pid must not be session leader (EPERM) 3511541Srgrimes */ 35212221Sbde#ifndef _SYS_SYSPROTO_H_ 3531541Srgrimesstruct setpgid_args { 3541541Srgrimes int pid; /* target process id */ 3551541Srgrimes int pgid; /* target pgrp id */ 3561541Srgrimes}; 35712221Sbde#endif 3581541Srgrimes/* ARGSUSED */ 3591549Srgrimesint 36030994Sphksetpgid(curp, uap) 3611541Srgrimes struct proc *curp; 3621541Srgrimes register struct setpgid_args *uap; 3631541Srgrimes{ 3641541Srgrimes register struct proc *targp; /* target process */ 3651541Srgrimes register struct pgrp *pgrp; /* target pgrp */ 36675448Srwatson int error; 3671541Srgrimes 36820677Sbde if (uap->pgid < 0) 36920677Sbde return (EINVAL); 3701541Srgrimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 37175893Sjhb if ((targp = pfind(uap->pid)) == NULL || !inferior(targp)) { 37275893Sjhb if (targp) 37375893Sjhb PROC_UNLOCK(targp); 3741541Srgrimes return (ESRCH); 37575893Sjhb } 37679335Srwatson if ((error = p_cansee(curproc, targp))) { 37775893Sjhb PROC_UNLOCK(targp); 37875448Srwatson return (error); 37975893Sjhb } 38075893Sjhb if (targp->p_pgrp == NULL || 38175893Sjhb targp->p_session != curp->p_session) { 38275893Sjhb PROC_UNLOCK(targp); 3831541Srgrimes return (EPERM); 38475893Sjhb } 38575893Sjhb if (targp->p_flag & P_EXEC) { 38675893Sjhb PROC_UNLOCK(targp); 3871541Srgrimes return (EACCES); 38875893Sjhb } 38975893Sjhb } else { 3901541Srgrimes targp = curp; 39175893Sjhb PROC_LOCK(curp); /* XXX: not needed */ 39275893Sjhb } 39375893Sjhb if (SESS_LEADER(targp)) { 39475893Sjhb PROC_UNLOCK(targp); 3951541Srgrimes return (EPERM); 39675893Sjhb } 3971541Srgrimes if (uap->pgid == 0) 3981541Srgrimes uap->pgid = targp->p_pid; 3991541Srgrimes else if (uap->pgid != targp->p_pid) 4001541Srgrimes if ((pgrp = pgfind(uap->pgid)) == 0 || 40175893Sjhb pgrp->pg_session != curp->p_session) { 40275893Sjhb PROC_UNLOCK(targp); 4031541Srgrimes return (EPERM); 40475893Sjhb } 40575893Sjhb /* XXX: We should probably hold the lock across enterpgrp. */ 40675893Sjhb PROC_UNLOCK(targp); 4071541Srgrimes return (enterpgrp(targp, uap->pgid, 0)); 4081541Srgrimes} 4091541Srgrimes 41024448Speter/* 41124448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 41272093Sasmodai * compatible. It says that setting the uid/gid to euid/egid is a special 41324448Speter * case of "appropriate privilege". Once the rules are expanded out, this 41424448Speter * basically means that setuid(nnn) sets all three id's, in all permitted 41524448Speter * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 41624448Speter * does not set the saved id - this is dangerous for traditional BSD 41724448Speter * programs. For this reason, we *really* do not want to set 41824448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 41924448Speter */ 42024448Speter#define POSIX_APPENDIX_B_4_2_2 42124448Speter 42212221Sbde#ifndef _SYS_SYSPROTO_H_ 4231541Srgrimesstruct setuid_args { 4241541Srgrimes uid_t uid; 4251541Srgrimes}; 42612221Sbde#endif 4271541Srgrimes/* ARGSUSED */ 4281549Srgrimesint 42930994Sphksetuid(p, uap) 4301541Srgrimes struct proc *p; 4311541Srgrimes struct setuid_args *uap; 4321541Srgrimes{ 43377183Srwatson struct ucred *newcred, *oldcred; 43477183Srwatson uid_t uid; 4351541Srgrimes int error; 4361541Srgrimes 43777183Srwatson uid = uap->uid; 43877183Srwatson oldcred = p->p_ucred; 43924448Speter /* 44024448Speter * See if we have "permission" by POSIX 1003.1 rules. 44124448Speter * 44224448Speter * Note that setuid(geteuid()) is a special case of 44324448Speter * "appropriate privileges" in appendix B.4.2.2. We need 44472093Sasmodai * to use this clause to be compatible with traditional BSD 44524448Speter * semantics. Basically, it means that "setuid(xx)" sets all 44624448Speter * three id's (assuming you have privs). 44724448Speter * 44824448Speter * Notes on the logic. We do things in three steps. 44924448Speter * 1: We determine if the euid is going to change, and do EPERM 45024448Speter * right away. We unconditionally change the euid later if this 45124448Speter * test is satisfied, simplifying that part of the logic. 45224448Speter * 2: We determine if the real and/or saved uid's are going to 45324448Speter * change. Determined by compile options. 45424448Speter * 3: Change euid last. (after tests in #2 for "appropriate privs") 45524448Speter */ 45677183Srwatson if (uid != oldcred->cr_ruid && /* allow setuid(getuid()) */ 45717994Sache#ifdef _POSIX_SAVED_IDS 45877183Srwatson uid != oldcred->cr_svuid && /* allow setuid(saved gid) */ 45917994Sache#endif 46024448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 46177183Srwatson uid != oldcred->cr_uid && /* allow setuid(geteuid()) */ 46224448Speter#endif 46377183Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) 4641541Srgrimes return (error); 46524448Speter 46677183Srwatson newcred = crdup(oldcred); 46724448Speter#ifdef _POSIX_SAVED_IDS 4681541Srgrimes /* 46924448Speter * Do we have "appropriate privileges" (are we root or uid == euid) 47024448Speter * If so, we are changing the real uid and/or saved uid. 4711541Srgrimes */ 47217994Sache if ( 47324448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 47477183Srwatson uid == oldcred->cr_uid || 47517994Sache#endif 47677183Srwatson suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */ 47717994Sache#endif 47824448Speter { 47924448Speter /* 48065495Struckman * Set the real uid and transfer proc count to new user. 48124448Speter */ 48277183Srwatson if (uid != oldcred->cr_ruid) { 48377183Srwatson change_ruid(newcred, uid); 48465495Struckman setsugid(p); 48524448Speter } 48624448Speter /* 48724448Speter * Set saved uid 48824448Speter * 48924448Speter * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 49024448Speter * the security of seteuid() depends on it. B.4.2.2 says it 49124448Speter * is important that we should do this. 49224448Speter */ 49377183Srwatson if (uid != oldcred->cr_svuid) { 49477183Srwatson change_svuid(newcred, uid); 49531891Ssef setsugid(p); 49624448Speter } 4978141Sache } 49824448Speter 49924448Speter /* 50024448Speter * In all permitted cases, we are changing the euid. 50124448Speter * Copy credentials so other references do not see our changes. 50224448Speter */ 50377183Srwatson if (uid != oldcred->cr_uid) { 50477183Srwatson change_euid(newcred, uid); 50531891Ssef setsugid(p); 50624448Speter } 50777183Srwatson p->p_ucred = newcred; 50877183Srwatson crfree(oldcred); 5091541Srgrimes return (0); 5101541Srgrimes} 5111541Srgrimes 51212221Sbde#ifndef _SYS_SYSPROTO_H_ 5131541Srgrimesstruct seteuid_args { 5141541Srgrimes uid_t euid; 5151541Srgrimes}; 51612221Sbde#endif 5171541Srgrimes/* ARGSUSED */ 5181549Srgrimesint 51930994Sphkseteuid(p, uap) 5201541Srgrimes struct proc *p; 5211541Srgrimes struct seteuid_args *uap; 5221541Srgrimes{ 52377183Srwatson struct ucred *newcred, *oldcred; 52477183Srwatson uid_t euid; 5251541Srgrimes int error; 5261541Srgrimes 5271541Srgrimes euid = uap->euid; 52877183Srwatson oldcred = p->p_ucred; 52977183Srwatson if (euid != oldcred->cr_ruid && /* allow seteuid(getuid()) */ 53077183Srwatson euid != oldcred->cr_svuid && /* allow seteuid(saved uid) */ 53177183Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) 5321541Srgrimes return (error); 5331541Srgrimes /* 5341541Srgrimes * Everything's okay, do it. Copy credentials so other references do 5351541Srgrimes * not see our changes. 5361541Srgrimes */ 53777183Srwatson newcred = crdup(oldcred); 53877183Srwatson if (oldcred->cr_uid != euid) { 53977183Srwatson change_euid(newcred, euid); 54031891Ssef setsugid(p); 54124449Speter } 54277183Srwatson p->p_ucred = newcred; 54377183Srwatson crfree(oldcred); 5441541Srgrimes return (0); 5451541Srgrimes} 5461541Srgrimes 54712221Sbde#ifndef _SYS_SYSPROTO_H_ 5481541Srgrimesstruct setgid_args { 5491541Srgrimes gid_t gid; 5501541Srgrimes}; 55112221Sbde#endif 5521541Srgrimes/* ARGSUSED */ 5531549Srgrimesint 55430994Sphksetgid(p, uap) 5551541Srgrimes struct proc *p; 5561541Srgrimes struct setgid_args *uap; 5571541Srgrimes{ 55877183Srwatson struct ucred *newcred, *oldcred; 55977183Srwatson gid_t gid; 5601541Srgrimes int error; 5611541Srgrimes 56277183Srwatson gid = uap->gid; 56377183Srwatson oldcred = p->p_ucred; 56424448Speter /* 56524448Speter * See if we have "permission" by POSIX 1003.1 rules. 56624448Speter * 56724448Speter * Note that setgid(getegid()) is a special case of 56824448Speter * "appropriate privileges" in appendix B.4.2.2. We need 56972093Sasmodai * to use this clause to be compatible with traditional BSD 57024448Speter * semantics. Basically, it means that "setgid(xx)" sets all 57124448Speter * three id's (assuming you have privs). 57224448Speter * 57324448Speter * For notes on the logic here, see setuid() above. 57424448Speter */ 57577183Srwatson if (gid != oldcred->cr_rgid && /* allow setgid(getgid()) */ 57617994Sache#ifdef _POSIX_SAVED_IDS 57777183Srwatson gid != oldcred->cr_svgid && /* allow setgid(saved gid) */ 57817994Sache#endif 57924448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 58077183Srwatson gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */ 58124448Speter#endif 58277183Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) 5831541Srgrimes return (error); 58424448Speter 58577183Srwatson newcred = crdup(oldcred); 58617994Sache#ifdef _POSIX_SAVED_IDS 58724448Speter /* 58824448Speter * Do we have "appropriate privileges" (are we root or gid == egid) 58924448Speter * If so, we are changing the real uid and saved gid. 59024448Speter */ 59124448Speter if ( 59224448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 59377183Srwatson gid == oldcred->cr_groups[0] || 59417994Sache#endif 59577183Srwatson suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */ 59624448Speter#endif 59724448Speter { 59824448Speter /* 59924448Speter * Set real gid 60024448Speter */ 60177183Srwatson if (oldcred->cr_rgid != gid) { 60277183Srwatson change_rgid(newcred, gid); 60331891Ssef setsugid(p); 60424448Speter } 60524448Speter /* 60624448Speter * Set saved gid 60724448Speter * 60824448Speter * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 60924448Speter * the security of setegid() depends on it. B.4.2.2 says it 61024448Speter * is important that we should do this. 61124448Speter */ 61277183Srwatson if (oldcred->cr_svgid != gid) { 61377183Srwatson change_svgid(newcred, gid); 61431891Ssef setsugid(p); 61524448Speter } 6168141Sache } 61724448Speter /* 61824448Speter * In all cases permitted cases, we are changing the egid. 61924448Speter * Copy credentials so other references do not see our changes. 62024448Speter */ 62177183Srwatson if (oldcred->cr_groups[0] != gid) { 62277183Srwatson change_egid(newcred, gid); 62331891Ssef setsugid(p); 62424448Speter } 62577183Srwatson p->p_ucred = newcred; 62677183Srwatson crfree(oldcred); 6271541Srgrimes return (0); 6281541Srgrimes} 6291541Srgrimes 63012221Sbde#ifndef _SYS_SYSPROTO_H_ 6311541Srgrimesstruct setegid_args { 6321541Srgrimes gid_t egid; 6331541Srgrimes}; 63412221Sbde#endif 6351541Srgrimes/* ARGSUSED */ 6361549Srgrimesint 63730994Sphksetegid(p, uap) 6381541Srgrimes struct proc *p; 6391541Srgrimes struct setegid_args *uap; 6401541Srgrimes{ 64177183Srwatson struct ucred *newcred, *oldcred; 64277183Srwatson gid_t egid; 6431541Srgrimes int error; 6441541Srgrimes 6451541Srgrimes egid = uap->egid; 64677183Srwatson oldcred = p->p_ucred; 64777183Srwatson if (egid != oldcred->cr_rgid && /* allow setegid(getgid()) */ 64877183Srwatson egid != oldcred->cr_svgid && /* allow setegid(saved gid) */ 64977183Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) 6501541Srgrimes return (error); 65177183Srwatson newcred = crdup(oldcred); 65277183Srwatson if (oldcred->cr_groups[0] != egid) { 65377183Srwatson change_egid(newcred, egid); 65431891Ssef setsugid(p); 65524449Speter } 65677183Srwatson p->p_ucred = newcred; 65777183Srwatson crfree(oldcred); 6581541Srgrimes return (0); 6591541Srgrimes} 6601541Srgrimes 66112221Sbde#ifndef _SYS_SYSPROTO_H_ 6621541Srgrimesstruct setgroups_args { 6631541Srgrimes u_int gidsetsize; 6641541Srgrimes gid_t *gidset; 6651541Srgrimes}; 66612221Sbde#endif 6671541Srgrimes/* ARGSUSED */ 6681549Srgrimesint 66930994Sphksetgroups(p, uap) 6701541Srgrimes struct proc *p; 6711541Srgrimes struct setgroups_args *uap; 6721541Srgrimes{ 67377183Srwatson struct ucred *newcred, *oldcred; 67477183Srwatson u_int ngrp; 6751541Srgrimes int error; 6761541Srgrimes 67777183Srwatson ngrp = uap->gidsetsize; 67877183Srwatson oldcred = p->p_ucred; 67977183Srwatson if ((error = suser_xxx(oldcred, NULL, PRISON_ROOT))) 6801541Srgrimes return (error); 68124447Speter if (ngrp > NGROUPS) 6821541Srgrimes return (EINVAL); 68324447Speter /* 68424447Speter * XXX A little bit lazy here. We could test if anything has 68524447Speter * changed before crcopy() and setting P_SUGID. 68624447Speter */ 68777183Srwatson newcred = crdup(oldcred); 68824447Speter if (ngrp < 1) { 68924447Speter /* 69024447Speter * setgroups(0, NULL) is a legitimate way of clearing the 69124447Speter * groups vector on non-BSD systems (which generally do not 69224447Speter * have the egid in the groups[0]). We risk security holes 69324447Speter * when running non-BSD software if we do not do the same. 69424447Speter */ 69577183Srwatson newcred->cr_ngroups = 1; 69624447Speter } else { 69724447Speter if ((error = copyin((caddr_t)uap->gidset, 69877183Srwatson (caddr_t)newcred->cr_groups, ngrp * sizeof(gid_t)))) { 69977183Srwatson crfree(newcred); 70024447Speter return (error); 70177183Srwatson } 70277183Srwatson newcred->cr_ngroups = ngrp; 70324447Speter } 70431891Ssef setsugid(p); 70577183Srwatson p->p_ucred = newcred; 70677183Srwatson crfree(oldcred); 7071541Srgrimes return (0); 7081541Srgrimes} 7091541Srgrimes 71012221Sbde#ifndef _SYS_SYSPROTO_H_ 7111541Srgrimesstruct setreuid_args { 7129238Sache uid_t ruid; 7139238Sache uid_t euid; 7141541Srgrimes}; 71512221Sbde#endif 7161541Srgrimes/* ARGSUSED */ 7171549Srgrimesint 71830994Sphksetreuid(p, uap) 7191541Srgrimes register struct proc *p; 7201541Srgrimes struct setreuid_args *uap; 7211541Srgrimes{ 72277183Srwatson struct ucred *newcred, *oldcred; 72377183Srwatson uid_t ruid, euid; 7248135Sache int error; 7251541Srgrimes 7269238Sache ruid = uap->ruid; 7279238Sache euid = uap->euid; 72877183Srwatson oldcred = p->p_ucred; 72977183Srwatson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 73077183Srwatson ruid != oldcred->cr_svuid) || 73177183Srwatson (euid != (uid_t)-1 && euid != oldcred->cr_uid && 73277183Srwatson euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) && 73377183Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 7348135Sache return (error); 73577183Srwatson newcred = crdup(oldcred); 73677183Srwatson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 73777183Srwatson change_euid(newcred, euid); 73831891Ssef setsugid(p); 73924450Speter } 74077183Srwatson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 74177183Srwatson change_ruid(newcred, ruid); 74231891Ssef setsugid(p); 7438135Sache } 74477183Srwatson if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) && 74577183Srwatson newcred->cr_svuid != newcred->cr_uid) { 74677183Srwatson change_svuid(newcred, newcred->cr_uid); 74731891Ssef setsugid(p); 74824450Speter } 74977183Srwatson p->p_ucred = newcred; 75077183Srwatson crfree(oldcred); 7518135Sache return (0); 7521541Srgrimes} 7531541Srgrimes 75412221Sbde#ifndef _SYS_SYSPROTO_H_ 7551541Srgrimesstruct setregid_args { 7569238Sache gid_t rgid; 7579238Sache gid_t egid; 7581541Srgrimes}; 75912221Sbde#endif 7601541Srgrimes/* ARGSUSED */ 7611549Srgrimesint 76230994Sphksetregid(p, uap) 7631541Srgrimes register struct proc *p; 7641541Srgrimes struct setregid_args *uap; 7651541Srgrimes{ 76677183Srwatson struct ucred *newcred, *oldcred; 76777183Srwatson gid_t rgid, egid; 7688135Sache int error; 7691541Srgrimes 7709238Sache rgid = uap->rgid; 7719238Sache egid = uap->egid; 77277183Srwatson oldcred = p->p_ucred; 77377183Srwatson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 77477183Srwatson rgid != oldcred->cr_svgid) || 77577183Srwatson (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] && 77677183Srwatson egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) && 77777183Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 7788135Sache return (error); 7799238Sache 78077183Srwatson newcred = crdup(oldcred); 78177183Srwatson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 78277183Srwatson change_egid(newcred, egid); 78331891Ssef setsugid(p); 78424450Speter } 78577183Srwatson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 78677183Srwatson change_rgid(newcred, rgid); 78731891Ssef setsugid(p); 78824450Speter } 78977183Srwatson if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) && 79077183Srwatson newcred->cr_svgid != newcred->cr_groups[0]) { 79177183Srwatson change_svgid(newcred, newcred->cr_groups[0]); 79231891Ssef setsugid(p); 79324450Speter } 79477812Sru p->p_ucred = newcred; 79577812Sru crfree(oldcred); 7968135Sache return (0); 7971541Srgrimes} 7981541Srgrimes 79956115Speter/* 80056115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the 80156115Speter * saved uid is explicit. 80256115Speter */ 80356115Speter 80424453Speter#ifndef _SYS_SYSPROTO_H_ 80556115Speterstruct setresuid_args { 80656115Speter uid_t ruid; 80756115Speter uid_t euid; 80856115Speter uid_t suid; 80956115Speter}; 81056115Speter#endif 81156115Speter/* ARGSUSED */ 81256115Speterint 81356115Spetersetresuid(p, uap) 81456115Speter register struct proc *p; 81556115Speter struct setresuid_args *uap; 81656115Speter{ 81777183Srwatson struct ucred *newcred, *oldcred; 81877183Srwatson uid_t ruid, euid, suid; 81956115Speter int error; 82056115Speter 82156115Speter ruid = uap->ruid; 82256115Speter euid = uap->euid; 82356115Speter suid = uap->suid; 82477183Srwatson oldcred = p->p_ucred; 82577183Srwatson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 82677183Srwatson ruid != oldcred->cr_svuid && 82777183Srwatson ruid != oldcred->cr_uid) || 82877183Srwatson (euid != (uid_t)-1 && euid != oldcred->cr_ruid && 82977183Srwatson euid != oldcred->cr_svuid && 83077183Srwatson euid != oldcred->cr_uid) || 83177183Srwatson (suid != (uid_t)-1 && suid != oldcred->cr_ruid && 83277183Srwatson suid != oldcred->cr_svuid && 83377183Srwatson suid != oldcred->cr_uid)) && 83477183Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 83556115Speter return (error); 83677183Srwatson 83777183Srwatson newcred = crdup(oldcred); 83877183Srwatson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 83977183Srwatson change_euid(newcred, euid); 84056115Speter setsugid(p); 84156115Speter } 84277183Srwatson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 84377183Srwatson change_ruid(newcred, ruid); 84456115Speter setsugid(p); 84556115Speter } 84677183Srwatson if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) { 84777183Srwatson change_svuid(newcred, suid); 84856115Speter setsugid(p); 84956115Speter } 85077183Srwatson p->p_ucred = newcred; 85177183Srwatson crfree(oldcred); 85256115Speter return (0); 85356115Speter} 85456115Speter 85556115Speter/* 85656115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the 85756115Speter * saved gid is explicit. 85856115Speter */ 85956115Speter 86056115Speter#ifndef _SYS_SYSPROTO_H_ 86156115Speterstruct setresgid_args { 86256115Speter gid_t rgid; 86356115Speter gid_t egid; 86456115Speter gid_t sgid; 86556115Speter}; 86656115Speter#endif 86756115Speter/* ARGSUSED */ 86856115Speterint 86956115Spetersetresgid(p, uap) 87056115Speter register struct proc *p; 87156115Speter struct setresgid_args *uap; 87256115Speter{ 87377183Srwatson struct ucred *newcred, *oldcred; 87477183Srwatson gid_t rgid, egid, sgid; 87556115Speter int error; 87656115Speter 87756115Speter rgid = uap->rgid; 87856115Speter egid = uap->egid; 87956115Speter sgid = uap->sgid; 88077183Srwatson oldcred = p->p_ucred; 88177183Srwatson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 88277183Srwatson rgid != oldcred->cr_svgid && 88377183Srwatson rgid != oldcred->cr_groups[0]) || 88477183Srwatson (egid != (gid_t)-1 && egid != oldcred->cr_rgid && 88577183Srwatson egid != oldcred->cr_svgid && 88677183Srwatson egid != oldcred->cr_groups[0]) || 88777183Srwatson (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid && 88877183Srwatson sgid != oldcred->cr_svgid && 88977183Srwatson sgid != oldcred->cr_groups[0])) && 89077183Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 89156115Speter return (error); 89256115Speter 89377183Srwatson newcred = crdup(oldcred); 89477183Srwatson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 89577183Srwatson change_egid(newcred, egid); 89656115Speter setsugid(p); 89756115Speter } 89877183Srwatson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 89977183Srwatson change_rgid(newcred, rgid); 90056115Speter setsugid(p); 90156115Speter } 90277183Srwatson if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) { 90377183Srwatson change_svgid(newcred, sgid); 90456115Speter setsugid(p); 90556115Speter } 90677183Srwatson p->p_ucred = newcred; 90777183Srwatson crfree(oldcred); 90856115Speter return (0); 90956115Speter} 91056115Speter 91156115Speter#ifndef _SYS_SYSPROTO_H_ 91256115Speterstruct getresuid_args { 91356115Speter uid_t *ruid; 91456115Speter uid_t *euid; 91556115Speter uid_t *suid; 91656115Speter}; 91756115Speter#endif 91856115Speter/* ARGSUSED */ 91956115Speterint 92056115Spetergetresuid(p, uap) 92156115Speter register struct proc *p; 92256115Speter struct getresuid_args *uap; 92356115Speter{ 92477183Srwatson struct ucred *cred = p->p_ucred; 92556115Speter int error1 = 0, error2 = 0, error3 = 0; 92656115Speter 92756115Speter if (uap->ruid) 92877183Srwatson error1 = copyout((caddr_t)&cred->cr_ruid, 92977183Srwatson (caddr_t)uap->ruid, sizeof(cred->cr_ruid)); 93056115Speter if (uap->euid) 93177183Srwatson error2 = copyout((caddr_t)&cred->cr_uid, 93277183Srwatson (caddr_t)uap->euid, sizeof(cred->cr_uid)); 93356115Speter if (uap->suid) 93477183Srwatson error3 = copyout((caddr_t)&cred->cr_svuid, 93577183Srwatson (caddr_t)uap->suid, sizeof(cred->cr_svuid)); 93656115Speter return error1 ? error1 : (error2 ? error2 : error3); 93756115Speter} 93856115Speter 93956115Speter#ifndef _SYS_SYSPROTO_H_ 94056115Speterstruct getresgid_args { 94156115Speter gid_t *rgid; 94256115Speter gid_t *egid; 94356115Speter gid_t *sgid; 94456115Speter}; 94556115Speter#endif 94656115Speter/* ARGSUSED */ 94756115Speterint 94856115Spetergetresgid(p, uap) 94956115Speter register struct proc *p; 95056115Speter struct getresgid_args *uap; 95156115Speter{ 95277183Srwatson struct ucred *cred = p->p_ucred; 95356115Speter int error1 = 0, error2 = 0, error3 = 0; 95456115Speter 95556115Speter if (uap->rgid) 95677183Srwatson error1 = copyout((caddr_t)&cred->cr_rgid, 95777183Srwatson (caddr_t)uap->rgid, sizeof(cred->cr_rgid)); 95856115Speter if (uap->egid) 95977183Srwatson error2 = copyout((caddr_t)&cred->cr_groups[0], 96077183Srwatson (caddr_t)uap->egid, sizeof(cred->cr_groups[0])); 96156115Speter if (uap->sgid) 96277183Srwatson error3 = copyout((caddr_t)&cred->cr_svgid, 96377183Srwatson (caddr_t)uap->sgid, sizeof(cred->cr_svgid)); 96456115Speter return error1 ? error1 : (error2 ? error2 : error3); 96556115Speter} 96656115Speter 96756115Speter 96856115Speter#ifndef _SYS_SYSPROTO_H_ 96924453Speterstruct issetugid_args { 97024453Speter int dummy; 97124453Speter}; 97224453Speter#endif 97324453Speter/* ARGSUSED */ 97424453Speterint 97530994Sphkissetugid(p, uap) 97624453Speter register struct proc *p; 97724453Speter struct issetugid_args *uap; 97824453Speter{ 97924453Speter /* 98024453Speter * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 98124453Speter * we use P_SUGID because we consider changing the owners as 98224453Speter * "tainting" as well. 98324453Speter * This is significant for procs that start as root and "become" 98424453Speter * a user without an exec - programs cannot know *everything* 98524453Speter * that libc *might* have put in their data segment. 98624453Speter */ 98760216Speter p->p_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 98824453Speter return (0); 98924453Speter} 99024453Speter 99175426Srwatsonint 99275426Srwatson__setugid(p, uap) 99375426Srwatson struct proc *p; 99475426Srwatson struct __setugid_args *uap; 99575426Srwatson{ 99675426Srwatson 99775426Srwatson#ifdef REGRESSION 99875426Srwatson switch (uap->flag) { 99975426Srwatson case 0: 100075426Srwatson p->p_flag &= ~P_SUGID; 100175426Srwatson return (0); 100275426Srwatson case 1: 100375426Srwatson p->p_flag |= P_SUGID; 100475426Srwatson return (0); 100575426Srwatson default: 100675426Srwatson return (EINVAL); 100775426Srwatson } 100875426Srwatson#else /* !REGRESSION */ 100975426Srwatson return (ENOSYS); 101075426Srwatson#endif /* !REGRESSION */ 101175426Srwatson} 101275426Srwatson 10131541Srgrimes/* 10141541Srgrimes * Check if gid is a member of the group set. 10151541Srgrimes */ 10161549Srgrimesint 10171541Srgrimesgroupmember(gid, cred) 10181541Srgrimes gid_t gid; 101977183Srwatson struct ucred *cred; 10201541Srgrimes{ 10211541Srgrimes register gid_t *gp; 10221541Srgrimes gid_t *egp; 10231541Srgrimes 10241541Srgrimes egp = &(cred->cr_groups[cred->cr_ngroups]); 10251541Srgrimes for (gp = cred->cr_groups; gp < egp; gp++) 10261541Srgrimes if (*gp == gid) 10271541Srgrimes return (1); 10281541Srgrimes return (0); 10291541Srgrimes} 10301541Srgrimes 103161287Srwatsonstatic int suser_permitted = 1; 103261287Srwatson 103380735SrwatsonSYSCTL_INT(_kern_security, OID_AUTO, suser_permitted, CTLFLAG_RW, 103480735Srwatson &suser_permitted, 0, "processes with uid 0 have privilege"); 103561287Srwatson 10361541Srgrimes/* 10371541Srgrimes * Test whether the specified credentials imply "super-user" 10381541Srgrimes * privilege; if so, and we have accounting info, set the flag 10391541Srgrimes * indicating use of super-powers. 10401541Srgrimes * Returns 0 or error. 10411541Srgrimes */ 10421549Srgrimesint 104346112Sphksuser(p) 104472786Srwatson struct proc *p; 104546112Sphk{ 104646155Sphk return suser_xxx(0, p, 0); 104746112Sphk} 104846112Sphk 104946112Sphkint 105046155Sphksuser_xxx(cred, proc, flag) 105172786Srwatson struct ucred *cred; 105272786Srwatson struct proc *proc; 105346155Sphk int flag; 10541541Srgrimes{ 105561282Srwatson if (!suser_permitted) 105661282Srwatson return (EPERM); 105746155Sphk if (!cred && !proc) { 105846155Sphk printf("suser_xxx(): THINK!\n"); 105946155Sphk return (EPERM); 10601541Srgrimes } 106146155Sphk if (!cred) 106246155Sphk cred = proc->p_ucred; 106346155Sphk if (cred->cr_uid != 0) 106446155Sphk return (EPERM); 106572786Srwatson if (jailed(cred) && !(flag & PRISON_ROOT)) 106646155Sphk return (EPERM); 106746155Sphk return (0); 10681541Srgrimes} 10691541Srgrimes 107074956Srwatson/* 107174956Srwatson * u_cansee(u1, u2): determine if u1 "can see" the subject specified by u2 107274956Srwatson * Arguments: imutable credentials u1, u2 107374956Srwatson * Returns: 0 for permitted, an errno value otherwise 107474956Srwatson * Locks: none 107574956Srwatson * References: u1 and u2 must be valid for the lifetime of the call 107674956Srwatson * u1 may equal u2, in which case only one reference is required 107774956Srwatson */ 107874956Srwatsonint 107974956Srwatsonu_cansee(struct ucred *u1, struct ucred *u2) 108065237Srwatson{ 108172786Srwatson int error; 108253518Sphk 108374956Srwatson if ((error = prison_check(u1, u2))) 108472786Srwatson return (error); 108577183Srwatson if (!ps_showallprocs && u1->cr_ruid != u2->cr_ruid) { 108675005Srwatson if (suser_xxx(u1, NULL, PRISON_ROOT) != 0) 108774956Srwatson return (ESRCH); 108865293Srwatson } 108965237Srwatson return (0); 109065237Srwatson} 109165237Srwatson 109279335Srwatsonint 109379335Srwatsonp_cansee(struct proc *p1, struct proc *p2) 109474956Srwatson{ 109574956Srwatson 109674956Srwatson /* Wrap u_cansee() for all functionality. */ 109774956Srwatson return (u_cansee(p1->p_ucred, p2->p_ucred)); 109874956Srwatson} 109974956Srwatson 110075437Srwatson/* 110175437Srwatson * Can process p1 send the signal signum to process p2? 110275437Srwatson */ 110375437Srwatsonint 110475437Srwatsonp_cansignal(struct proc *p1, struct proc *p2, int signum) 110553518Sphk{ 110675437Srwatson int error; 110775437Srwatson 110853518Sphk if (p1 == p2) 110953518Sphk return (0); 111065237Srwatson 111175437Srwatson /* 111275437Srwatson * Jail semantics limit the scope of signalling to p2 in the same 111375437Srwatson * jail as p1, if p1 is in jail. 111475437Srwatson */ 111572786Srwatson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 111672786Srwatson return (error); 111765237Srwatson 111865237Srwatson /* 111975437Srwatson * UNIX signalling semantics require that processes in the same 112075437Srwatson * session always be able to deliver SIGCONT to one another, 112175437Srwatson * overriding the remaining protections. 112265237Srwatson */ 112375437Srwatson if (signum == SIGCONT && p1->p_session == p2->p_session) 112453518Sphk return (0); 112565237Srwatson 112675437Srwatson /* 112775437Srwatson * UNIX uid semantics depend on the status of the P_SUGID 112875437Srwatson * bit on the target process. If the bit is set, then more 112975437Srwatson * restricted signal sets are permitted. 113075437Srwatson */ 113175437Srwatson if (p2->p_flag & P_SUGID) { 113275437Srwatson switch (signum) { 113375437Srwatson case 0: 113475437Srwatson case SIGKILL: 113575437Srwatson case SIGINT: 113675437Srwatson case SIGTERM: 113775437Srwatson case SIGSTOP: 113875437Srwatson case SIGTTIN: 113975437Srwatson case SIGTTOU: 114075437Srwatson case SIGTSTP: 114175437Srwatson case SIGHUP: 114275437Srwatson case SIGUSR1: 114375437Srwatson case SIGUSR2: 114475437Srwatson break; 114575437Srwatson default: 114675437Srwatson /* Not permitted, try privilege. */ 114775437Srwatson error = suser_xxx(NULL, p1, PRISON_ROOT); 114875437Srwatson if (error) 114975437Srwatson return (error); 115075437Srwatson } 115165237Srwatson } 115265237Srwatson 115375480Srwatson /* 115475480Srwatson * Generally, the object credential's ruid or svuid must match the 115575480Srwatson * subject credential's ruid or euid. 115675480Srwatson */ 115777183Srwatson if (p1->p_ucred->cr_ruid != p2->p_ucred->cr_ruid && 115877183Srwatson p1->p_ucred->cr_ruid != p2->p_ucred->cr_svuid && 115977183Srwatson p1->p_ucred->cr_uid != p2->p_ucred->cr_ruid && 116077183Srwatson p1->p_ucred->cr_uid != p2->p_ucred->cr_svuid) { 116175480Srwatson /* Not permitted, try privilege. */ 116275480Srwatson error = suser_xxx(NULL, p1, PRISON_ROOT); 116375480Srwatson if (error) 116475480Srwatson return (error); 116575480Srwatson } 116675480Srwatson 116775437Srwatson return (0); 116853518Sphk} 116953518Sphk 117079335Srwatsonint 117179335Srwatsonp_cansched(struct proc *p1, struct proc *p2) 117265237Srwatson{ 117372786Srwatson int error; 117465237Srwatson 117565237Srwatson if (p1 == p2) 117665237Srwatson return (0); 117765237Srwatson 117872786Srwatson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 117972786Srwatson return (error); 118065237Srwatson 118177183Srwatson if (p1->p_ucred->cr_ruid == p2->p_ucred->cr_ruid) 118265237Srwatson return (0); 118377183Srwatson if (p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid) 118465237Srwatson return (0); 118565237Srwatson 118679335Srwatson if (!suser_xxx(0, p1, PRISON_ROOT)) 118765237Srwatson return (0); 118865237Srwatson 118965237Srwatson#ifdef CAPABILITIES 119079335Srwatson if (!cap_check_xxx(0, p1, CAP_SYS_NICE, PRISON_ROOT)) 119165237Srwatson return (0); 119265237Srwatson#endif 119365237Srwatson 119465237Srwatson return (EPERM); 119565237Srwatson} 119665237Srwatson 119780735Srwatsonstatic int kern_unprivileged_procdebug_permitted = 1; 119880735SrwatsonSYSCTL_INT(_kern_security, OID_AUTO, unprivileged_procdebug_permitted, 119980735Srwatson CTLFLAG_RW, &kern_unprivileged_procdebug_permitted, 0, 120080735Srwatson "Unprivileged processes may use process debugging facilities"); 120180735Srwatson 120279335Srwatsonint 120379335Srwatsonp_candebug(struct proc *p1, struct proc *p2) 120465237Srwatson{ 120572786Srwatson int error; 120665237Srwatson 120765237Srwatson if (p1 == p2) 120865237Srwatson return (0); 120965237Srwatson 121072786Srwatson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 121172786Srwatson return (error); 121265237Srwatson 121365237Srwatson /* not owned by you, has done setuid (unless you're root) */ 121465237Srwatson /* add a CAP_SYS_PTRACE here? */ 121577183Srwatson if (p1->p_ucred->cr_uid != p2->p_ucred->cr_uid || 121677183Srwatson p1->p_ucred->cr_uid != p2->p_ucred->cr_svuid || 121777183Srwatson p1->p_ucred->cr_uid != p2->p_ucred->cr_ruid || 121880735Srwatson p2->p_flag & P_SUGID || !kern_unprivileged_procdebug_permitted) 121965237Srwatson if ((error = suser_xxx(0, p1, PRISON_ROOT))) 122065237Srwatson return (error); 122165237Srwatson 122265237Srwatson /* can't trace init when securelevel > 0 */ 122365237Srwatson if (securelevel > 0 && p2->p_pid == 1) 122465237Srwatson return (EPERM); 122565237Srwatson 122665237Srwatson return (0); 122765237Srwatson} 122865237Srwatson 122953518Sphk/* 12301541Srgrimes * Allocate a zeroed cred structure. 12311541Srgrimes */ 12321541Srgrimesstruct ucred * 12331541Srgrimescrget() 12341541Srgrimes{ 12351541Srgrimes register struct ucred *cr; 12361541Srgrimes 123769239Salfred MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK|M_ZERO); 12381541Srgrimes cr->cr_ref = 1; 123969239Salfred mtx_init(&cr->cr_mtx, "ucred", MTX_DEF); 12401541Srgrimes return (cr); 12411541Srgrimes} 12421541Srgrimes 12431541Srgrimes/* 124472474Srwatson * Claim another reference to a ucred structure 124569401Salfred */ 124669401Salfredvoid 124769401Salfredcrhold(cr) 124869401Salfred struct ucred *cr; 124969401Salfred{ 125069401Salfred 125172200Sbmilekic mtx_lock(&cr->cr_mtx); 125269401Salfred cr->cr_ref++; 125372200Sbmilekic mtx_unlock(&(cr)->cr_mtx); 125469401Salfred} 125569401Salfred 125669401Salfred 125769401Salfred/* 12581541Srgrimes * Free a cred structure. 12591541Srgrimes * Throws away space when ref count gets to 0. 12601541Srgrimes */ 12611549Srgrimesvoid 12621541Srgrimescrfree(cr) 12631541Srgrimes struct ucred *cr; 12641541Srgrimes{ 126569239Salfred 126672200Sbmilekic mtx_lock(&cr->cr_mtx); 126775632Salfred KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref)); 126865495Struckman if (--cr->cr_ref == 0) { 126969239Salfred mtx_destroy(&cr->cr_mtx); 127065495Struckman /* 127165495Struckman * Some callers of crget(), such as nfs_statfs(), 127265495Struckman * allocate a temporary credential, but don't 127365495Struckman * allocate a uidinfo structure. 127465495Struckman */ 127565495Struckman if (cr->cr_uidinfo != NULL) 127665495Struckman uifree(cr->cr_uidinfo); 127777277Srwatson if (cr->cr_ruidinfo != NULL) 127877277Srwatson uifree(cr->cr_ruidinfo); 127972786Srwatson /* 128072786Srwatson * Free a prison, if any. 128172786Srwatson */ 128272786Srwatson if (jailed(cr)) 128372786Srwatson prison_free(cr->cr_prison); 12841541Srgrimes FREE((caddr_t)cr, M_CRED); 128569239Salfred } else { 128672200Sbmilekic mtx_unlock(&cr->cr_mtx); 128765495Struckman } 12881541Srgrimes} 12891541Srgrimes 12901541Srgrimes/* 12911541Srgrimes * Copy cred structure to a new one and free the old one. 12921541Srgrimes */ 12931541Srgrimesstruct ucred * 12941541Srgrimescrcopy(cr) 12951541Srgrimes struct ucred *cr; 12961541Srgrimes{ 12971541Srgrimes struct ucred *newcr; 12981541Srgrimes 129972200Sbmilekic mtx_lock(&cr->cr_mtx); 130069239Salfred if (cr->cr_ref == 1) { 130172200Sbmilekic mtx_unlock(&cr->cr_mtx); 13021541Srgrimes return (cr); 130369239Salfred } 130472200Sbmilekic mtx_unlock(&cr->cr_mtx); 130569239Salfred newcr = crdup(cr); 13061541Srgrimes crfree(cr); 13071541Srgrimes return (newcr); 13081541Srgrimes} 13091541Srgrimes 13101541Srgrimes/* 13111541Srgrimes * Dup cred struct to a new held one. 13121541Srgrimes */ 13131541Srgrimesstruct ucred * 13141541Srgrimescrdup(cr) 13151541Srgrimes struct ucred *cr; 13161541Srgrimes{ 13171541Srgrimes struct ucred *newcr; 13181541Srgrimes 131969239Salfred MALLOC(newcr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 13201541Srgrimes *newcr = *cr; 132169239Salfred mtx_init(&newcr->cr_mtx, "ucred", MTX_DEF); 132265495Struckman uihold(newcr->cr_uidinfo); 132377183Srwatson uihold(newcr->cr_ruidinfo); 132472786Srwatson if (jailed(newcr)) 132572786Srwatson prison_hold(newcr->cr_prison); 13261541Srgrimes newcr->cr_ref = 1; 13271541Srgrimes return (newcr); 13281541Srgrimes} 13291541Srgrimes 13301541Srgrimes/* 13311541Srgrimes * Get login name, if available. 13321541Srgrimes */ 133312221Sbde#ifndef _SYS_SYSPROTO_H_ 13341541Srgrimesstruct getlogin_args { 13351541Srgrimes char *namebuf; 13361541Srgrimes u_int namelen; 13371541Srgrimes}; 133812221Sbde#endif 13391541Srgrimes/* ARGSUSED */ 13401549Srgrimesint 134130994Sphkgetlogin(p, uap) 13421541Srgrimes struct proc *p; 13431541Srgrimes struct getlogin_args *uap; 13441541Srgrimes{ 13451541Srgrimes 134623358Sache if (uap->namelen > MAXLOGNAME) 134723359Sache uap->namelen = MAXLOGNAME; 13481541Srgrimes return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 13491541Srgrimes (caddr_t) uap->namebuf, uap->namelen)); 13501541Srgrimes} 13511541Srgrimes 13521541Srgrimes/* 13531541Srgrimes * Set login name. 13541541Srgrimes */ 135512221Sbde#ifndef _SYS_SYSPROTO_H_ 13561541Srgrimesstruct setlogin_args { 13571541Srgrimes char *namebuf; 13581541Srgrimes}; 135912221Sbde#endif 13601541Srgrimes/* ARGSUSED */ 13611549Srgrimesint 136230994Sphksetlogin(p, uap) 13631541Srgrimes struct proc *p; 13641541Srgrimes struct setlogin_args *uap; 13651541Srgrimes{ 13661541Srgrimes int error; 136723330Sache char logintmp[MAXLOGNAME]; 13681541Srgrimes 136946155Sphk if ((error = suser_xxx(0, p, PRISON_ROOT))) 13701541Srgrimes return (error); 137122522Sdavidn error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 137236845Sdfr sizeof(logintmp), (size_t *)0); 13731541Srgrimes if (error == ENAMETOOLONG) 13741541Srgrimes error = EINVAL; 137522522Sdavidn else if (!error) 137622522Sdavidn (void) memcpy(p->p_pgrp->pg_session->s_login, logintmp, 137723330Sache sizeof(logintmp)); 13781541Srgrimes return (error); 13791541Srgrimes} 138031891Ssef 138131891Ssefvoid 138231891Ssefsetsugid(p) 138355338Sphk struct proc *p; 138431891Ssef{ 138531891Ssef p->p_flag |= P_SUGID; 138655707Ssef if (!(p->p_pfsflags & PF_ISUGID)) 138731891Ssef p->p_stops = 0; 138831891Ssef} 138965495Struckman 139065495Struckman/* 139177183Srwatson * change_euid(): Change a process's effective uid. 139277183Srwatson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified. 139377183Srwatson * References: newcred must be an exclusive credential reference for the 139477183Srwatson * duration of the call. 139565495Struckman */ 139665495Struckmanvoid 139777183Srwatsonchange_euid(newcred, euid) 139877183Srwatson struct ucred *newcred; 139977183Srwatson uid_t euid; 140065495Struckman{ 140165495Struckman 140277183Srwatson newcred->cr_uid = euid; 140377183Srwatson uifree(newcred->cr_uidinfo); 140477183Srwatson newcred->cr_uidinfo = uifind(euid); 140565495Struckman} 140665495Struckman 140765495Struckman/* 140877183Srwatson * change_egid(): Change a process's effective gid. 140977183Srwatson * Side effects: newcred->cr_gid will be modified. 141077183Srwatson * References: newcred must be an exclusive credential reference for the 141177183Srwatson * duration of the call. 141265495Struckman */ 141367629Sgallatinvoid 141477183Srwatsonchange_egid(newcred, egid) 141577183Srwatson struct ucred *newcred; 141677183Srwatson gid_t egid; 141765495Struckman{ 141865495Struckman 141977183Srwatson newcred->cr_groups[0] = egid; 142065495Struckman} 142177183Srwatson 142277183Srwatson/* 142377183Srwatson * change_ruid(): Change a process's real uid. 142477183Srwatson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo 142577183Srwatson * will be updated, and the old and new cr_ruidinfo proc 142677183Srwatson * counts will be updated. 142777183Srwatson * References: newcred must be an exclusive credential reference for the 142877183Srwatson * duration of the call. 142977183Srwatson */ 143077183Srwatsonvoid 143177183Srwatsonchange_ruid(newcred, ruid) 143277183Srwatson struct ucred *newcred; 143377183Srwatson uid_t ruid; 143477183Srwatson{ 143577183Srwatson 143677183Srwatson (void)chgproccnt(newcred->cr_ruidinfo, -1, 0); 143777183Srwatson newcred->cr_ruid = ruid; 143877183Srwatson uifree(newcred->cr_ruidinfo); 143977183Srwatson newcred->cr_ruidinfo = uifind(ruid); 144077183Srwatson (void)chgproccnt(newcred->cr_ruidinfo, 1, 0); 144177183Srwatson} 144277183Srwatson 144377183Srwatson/* 144477183Srwatson * change_rgid(): Change a process's real gid. 144577183Srwatson * Side effects: newcred->cr_rgid will be updated. 144677183Srwatson * References: newcred must be an exclusive credential reference for the 144777183Srwatson * duration of the call. 144877183Srwatson */ 144977183Srwatsonvoid 145077183Srwatsonchange_rgid(newcred, rgid) 145177183Srwatson struct ucred *newcred; 145277183Srwatson gid_t rgid; 145377183Srwatson{ 145477183Srwatson 145577183Srwatson newcred->cr_rgid = rgid; 145677183Srwatson} 145777183Srwatson 145877183Srwatson/* 145977183Srwatson * change_svuid(): Change a process's saved uid. 146077183Srwatson * Side effects: newcred->cr_svuid will be updated. 146177183Srwatson * References: newcred must be an exclusive credential reference for the 146277183Srwatson * duration of the call. 146377183Srwatson */ 146477183Srwatsonvoid 146577183Srwatsonchange_svuid(newcred, svuid) 146677183Srwatson struct ucred *newcred; 146777183Srwatson uid_t svuid; 146877183Srwatson{ 146977183Srwatson 147077183Srwatson newcred->cr_svuid = svuid; 147177183Srwatson} 147277183Srwatson 147377183Srwatson/* 147477183Srwatson * change_svgid(): Change a process's saved gid. 147577183Srwatson * Side effects: newcred->cr_svgid will be updated. 147677183Srwatson * References: newcred must be an exclusive credential reference for the 147777183Srwatson * duration of the call. 147877183Srwatson */ 147977183Srwatsonvoid 148077183Srwatsonchange_svgid(newcred, svgid) 148177183Srwatson struct ucred *newcred; 148277183Srwatson gid_t svgid; 148377183Srwatson{ 148477183Srwatson 148577183Srwatson newcred->cr_svgid = svgid; 148677183Srwatson} 1487