kern_prot.c revision 170587
1139804Simp/*- 21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 3165897Srwatson * The Regents of the University of California. 41541Srgrimes * (c) UNIX System Laboratories, Inc. 5165897Srwatson * Copyright (c) 2000-2001 Robert N. M. Watson. 6165897Srwatson * All rights reserved. 7165897Srwatson * 81541Srgrimes * All or some portions of this file are derived from material licensed 91541Srgrimes * to the University of California by American Telephone and Telegraph 101541Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 111541Srgrimes * the permission of UNIX System Laboratories, Inc. 121541Srgrimes * 131541Srgrimes * Redistribution and use in source and binary forms, with or without 141541Srgrimes * modification, are permitted provided that the following conditions 151541Srgrimes * are met: 161541Srgrimes * 1. Redistributions of source code must retain the above copyright 171541Srgrimes * notice, this list of conditions and the following disclaimer. 181541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 191541Srgrimes * notice, this list of conditions and the following disclaimer in the 201541Srgrimes * documentation and/or other materials provided with the distribution. 211541Srgrimes * 4. Neither the name of the University nor the names of its contributors 221541Srgrimes * may be used to endorse or promote products derived from this software 231541Srgrimes * without specific prior written permission. 241541Srgrimes * 251541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 261541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 271541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 281541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 291541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 301541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 311541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 321541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 331541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 341541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 351541Srgrimes * SUCH DAMAGE. 361541Srgrimes * 371541Srgrimes * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 381541Srgrimes */ 391541Srgrimes 401541Srgrimes/* 411541Srgrimes * System calls related to processes and protection 421541Srgrimes */ 431541Srgrimes 44116182Sobrien#include <sys/cdefs.h> 45116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_prot.c 170587 2007-06-12 00:12:01Z rwatson $"); 46116182Sobrien 4731778Seivind#include "opt_compat.h" 48101001Srwatson#include "opt_mac.h" 4931778Seivind 501541Srgrimes#include <sys/param.h> 5176166Smarkm#include <sys/systm.h> 521541Srgrimes#include <sys/acct.h> 53132548Srwatson#include <sys/kdb.h> 5441059Speter#include <sys/kernel.h> 5570317Sjake#include <sys/lock.h> 5691140Stanimura#include <sys/malloc.h> 5776166Smarkm#include <sys/mutex.h> 58150634Sjhb#include <sys/refcount.h> 5991140Stanimura#include <sys/sx.h> 60164032Srwatson#include <sys/priv.h> 611541Srgrimes#include <sys/proc.h> 6276166Smarkm#include <sys/sysproto.h> 6387218Srwatson#include <sys/jail.h> 6431891Ssef#include <sys/pioctl.h> 6565495Struckman#include <sys/resourcevar.h> 6692976Srwatson#include <sys/socket.h> 6792976Srwatson#include <sys/socketvar.h> 68160139Sjhb#include <sys/syscallsubr.h> 6961287Srwatson#include <sys/sysctl.h> 701541Srgrimes 71155370Swsalamon#include <security/audit/audit.h> 72163606Srwatson#include <security/mac/mac_framework.h> 73155370Swsalamon 7430354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials"); 7530354Sphk 76162383SrwatsonSYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0, "BSD security policy"); 7787138Srwatson 7812221Sbde#ifndef _SYS_SYSPROTO_H_ 7911332Sswallacestruct getpid_args { 801541Srgrimes int dummy; 811541Srgrimes}; 8212221Sbde#endif 831541Srgrimes/* ARGSUSED */ 841549Srgrimesint 8593580Sjhbgetpid(struct thread *td, struct getpid_args *uap) 861541Srgrimes{ 8783366Sjulian struct proc *p = td->td_proc; 881541Srgrimes 8983366Sjulian td->td_retval[0] = p->p_pid; 90130344Sphk#if defined(COMPAT_43) 9174728Sjhb PROC_LOCK(p); 9283366Sjulian td->td_retval[1] = p->p_pptr->p_pid; 9374728Sjhb PROC_UNLOCK(p); 941541Srgrimes#endif 951541Srgrimes return (0); 961541Srgrimes} 971541Srgrimes 9812221Sbde#ifndef _SYS_SYSPROTO_H_ 9911332Sswallacestruct getppid_args { 10011332Sswallace int dummy; 10111332Sswallace}; 10212221Sbde#endif 1031541Srgrimes/* ARGSUSED */ 1041549Srgrimesint 10593580Sjhbgetppid(struct thread *td, struct getppid_args *uap) 1061541Srgrimes{ 10783366Sjulian struct proc *p = td->td_proc; 1081541Srgrimes 10974728Sjhb PROC_LOCK(p); 11083366Sjulian td->td_retval[0] = p->p_pptr->p_pid; 11174728Sjhb PROC_UNLOCK(p); 1121541Srgrimes return (0); 1131541Srgrimes} 1141541Srgrimes 11587466Srwatson/* 11687218Srwatson * Get process group ID; note that POSIX getpgrp takes no parameter. 11758717Sdillon */ 11812221Sbde#ifndef _SYS_SYSPROTO_H_ 11911332Sswallacestruct getpgrp_args { 12011332Sswallace int dummy; 12111332Sswallace}; 12212221Sbde#endif 1231549Srgrimesint 12493580Sjhbgetpgrp(struct thread *td, struct getpgrp_args *uap) 1251541Srgrimes{ 12683366Sjulian struct proc *p = td->td_proc; 1271541Srgrimes 12891140Stanimura PROC_LOCK(p); 12983366Sjulian td->td_retval[0] = p->p_pgrp->pg_id; 13091140Stanimura PROC_UNLOCK(p); 1311541Srgrimes return (0); 1321541Srgrimes} 1331541Srgrimes 13428401Speter/* Get an arbitary pid's process group id */ 13512221Sbde#ifndef _SYS_SYSPROTO_H_ 13628401Speterstruct getpgid_args { 13728401Speter pid_t pid; 13828401Speter}; 13928401Speter#endif 14028401Speterint 14193580Sjhbgetpgid(struct thread *td, struct getpgid_args *uap) 14228401Speter{ 143114031Sjhb struct proc *p; 14492985Sjhb int error; 14541726Struckman 14691140Stanimura if (uap->pid == 0) { 147114031Sjhb p = td->td_proc; 14891140Stanimura PROC_LOCK(p); 149114031Sjhb } else { 150114031Sjhb p = pfind(uap->pid); 151114031Sjhb if (p == NULL) 152114031Sjhb return (ESRCH); 153114031Sjhb error = p_cansee(td, p); 154114031Sjhb if (error) { 155114031Sjhb PROC_UNLOCK(p); 156114031Sjhb return (error); 157114031Sjhb } 15875893Sjhb } 159114031Sjhb td->td_retval[0] = p->p_pgrp->pg_id; 160114031Sjhb PROC_UNLOCK(p); 161114031Sjhb return (0); 16228401Speter} 16328401Speter 16428401Speter/* 16528401Speter * Get an arbitary pid's session id. 16628401Speter */ 16728401Speter#ifndef _SYS_SYSPROTO_H_ 16828401Speterstruct getsid_args { 16928401Speter pid_t pid; 17028401Speter}; 17128401Speter#endif 17228401Speterint 17393580Sjhbgetsid(struct thread *td, struct getsid_args *uap) 17428401Speter{ 175114031Sjhb struct proc *p; 17687218Srwatson int error; 17741726Struckman 17891140Stanimura if (uap->pid == 0) { 179114031Sjhb p = td->td_proc; 18091140Stanimura PROC_LOCK(p); 181114031Sjhb } else { 182114031Sjhb p = pfind(uap->pid); 183114031Sjhb if (p == NULL) 184114031Sjhb return (ESRCH); 185114031Sjhb error = p_cansee(td, p); 186114031Sjhb if (error) { 187114031Sjhb PROC_UNLOCK(p); 188114031Sjhb return (error); 189114031Sjhb } 19075893Sjhb } 191114031Sjhb td->td_retval[0] = p->p_session->s_sid; 192114031Sjhb PROC_UNLOCK(p); 193114031Sjhb return (0); 19428401Speter} 19528401Speter 19628401Speter#ifndef _SYS_SYSPROTO_H_ 19711332Sswallacestruct getuid_args { 19811332Sswallace int dummy; 19911332Sswallace}; 20012221Sbde#endif 2011541Srgrimes/* ARGSUSED */ 2021549Srgrimesint 20393580Sjhbgetuid(struct thread *td, struct getuid_args *uap) 2041541Srgrimes{ 2051541Srgrimes 20692987Sjhb td->td_retval[0] = td->td_ucred->cr_ruid; 207130344Sphk#if defined(COMPAT_43) 20892987Sjhb td->td_retval[1] = td->td_ucred->cr_uid; 2091541Srgrimes#endif 2101541Srgrimes return (0); 2111541Srgrimes} 2121541Srgrimes 21312221Sbde#ifndef _SYS_SYSPROTO_H_ 21411332Sswallacestruct geteuid_args { 21511332Sswallace int dummy; 21611332Sswallace}; 21712221Sbde#endif 2181541Srgrimes/* ARGSUSED */ 2191549Srgrimesint 22093580Sjhbgeteuid(struct thread *td, struct geteuid_args *uap) 2211541Srgrimes{ 22292987Sjhb 22392987Sjhb td->td_retval[0] = td->td_ucred->cr_uid; 2241541Srgrimes return (0); 2251541Srgrimes} 2261541Srgrimes 22712221Sbde#ifndef _SYS_SYSPROTO_H_ 22811332Sswallacestruct getgid_args { 22911332Sswallace int dummy; 23011332Sswallace}; 23112221Sbde#endif 2321541Srgrimes/* ARGSUSED */ 2331549Srgrimesint 23493580Sjhbgetgid(struct thread *td, struct getgid_args *uap) 2351541Srgrimes{ 2361541Srgrimes 23792987Sjhb td->td_retval[0] = td->td_ucred->cr_rgid; 238130344Sphk#if defined(COMPAT_43) 23992987Sjhb td->td_retval[1] = td->td_ucred->cr_groups[0]; 2401541Srgrimes#endif 2411541Srgrimes return (0); 2421541Srgrimes} 2431541Srgrimes 2441541Srgrimes/* 2451541Srgrimes * Get effective group ID. The "egid" is groups[0], and could be obtained 2461541Srgrimes * via getgroups. This syscall exists because it is somewhat painful to do 2471541Srgrimes * correctly in a library function. 2481541Srgrimes */ 24912221Sbde#ifndef _SYS_SYSPROTO_H_ 25011332Sswallacestruct getegid_args { 25111332Sswallace int dummy; 25211332Sswallace}; 25312221Sbde#endif 2541541Srgrimes/* ARGSUSED */ 2551549Srgrimesint 25693580Sjhbgetegid(struct thread *td, struct getegid_args *uap) 2571541Srgrimes{ 2581541Srgrimes 25992987Sjhb td->td_retval[0] = td->td_ucred->cr_groups[0]; 2601541Srgrimes return (0); 2611541Srgrimes} 2621541Srgrimes 26312221Sbde#ifndef _SYS_SYSPROTO_H_ 2641541Srgrimesstruct getgroups_args { 2651541Srgrimes u_int gidsetsize; 2661541Srgrimes gid_t *gidset; 2671541Srgrimes}; 26812221Sbde#endif 2691549Srgrimesint 27093580Sjhbgetgroups(struct thread *td, register struct getgroups_args *uap) 2711541Srgrimes{ 272160139Sjhb gid_t groups[NGROUPS]; 27377183Srwatson u_int ngrp; 27487218Srwatson int error; 2751541Srgrimes 276160139Sjhb ngrp = MIN(uap->gidsetsize, NGROUPS); 277160139Sjhb error = kern_getgroups(td, &ngrp, groups); 278160139Sjhb if (error) 279160139Sjhb return (error); 280160139Sjhb if (uap->gidsetsize > 0) 281160139Sjhb error = copyout(groups, uap->gidset, ngrp * sizeof(gid_t)); 282160139Sjhb if (error == 0) 283160139Sjhb td->td_retval[0] = ngrp; 284160139Sjhb return (error); 285160139Sjhb} 286160139Sjhb 287160139Sjhbint 288160139Sjhbkern_getgroups(struct thread *td, u_int *ngrp, gid_t *groups) 289160139Sjhb{ 290160139Sjhb struct ucred *cred; 291160139Sjhb 29292987Sjhb cred = td->td_ucred; 293160139Sjhb if (*ngrp == 0) { 294160139Sjhb *ngrp = cred->cr_ngroups; 29592987Sjhb return (0); 2961541Srgrimes } 297160139Sjhb if (*ngrp < cred->cr_ngroups) 29892987Sjhb return (EINVAL); 299160139Sjhb *ngrp = cred->cr_ngroups; 300160139Sjhb bcopy(cred->cr_groups, groups, *ngrp * sizeof(gid_t)); 301160139Sjhb return (0); 3021541Srgrimes} 3031541Srgrimes 30412221Sbde#ifndef _SYS_SYSPROTO_H_ 30512207Sbdestruct setsid_args { 30611332Sswallace int dummy; 30711332Sswallace}; 30812221Sbde#endif 3091541Srgrimes/* ARGSUSED */ 3101549Srgrimesint 31193580Sjhbsetsid(register struct thread *td, struct setsid_args *uap) 3121541Srgrimes{ 31391140Stanimura struct pgrp *pgrp; 31482749Sdillon int error; 31583366Sjulian struct proc *p = td->td_proc; 31691140Stanimura struct pgrp *newpgrp; 31791140Stanimura struct session *newsess; 3181541Srgrimes 31991140Stanimura error = 0; 32091140Stanimura pgrp = NULL; 32191140Stanimura 322111119Simp MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); 323111119Simp MALLOC(newsess, struct session *, sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO); 32491140Stanimura 32594859Sjhb sx_xlock(&proctree_lock); 32691140Stanimura 32791140Stanimura if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) { 32891140Stanimura if (pgrp != NULL) 32991140Stanimura PGRP_UNLOCK(pgrp); 33082749Sdillon error = EPERM; 33191140Stanimura } else { 33291140Stanimura (void)enterpgrp(p, p->p_pid, newpgrp, newsess); 33383366Sjulian td->td_retval[0] = p->p_pid; 33494859Sjhb newpgrp = NULL; 33594859Sjhb newsess = NULL; 3361541Srgrimes } 33791140Stanimura 33894859Sjhb sx_xunlock(&proctree_lock); 33991140Stanimura 34095973Stanimura if (newpgrp != NULL) 34195973Stanimura FREE(newpgrp, M_PGRP); 34295973Stanimura if (newsess != NULL) 34395973Stanimura FREE(newsess, M_SESSION); 34491140Stanimura 34594859Sjhb return (error); 3461541Srgrimes} 3471541Srgrimes 3481541Srgrimes/* 3491541Srgrimes * set process group (setpgid/old setpgrp) 3501541Srgrimes * 3511541Srgrimes * caller does setpgid(targpid, targpgid) 3521541Srgrimes * 3531541Srgrimes * pid must be caller or child of caller (ESRCH) 3541541Srgrimes * if a child 3551541Srgrimes * pid must be in same session (EPERM) 3561541Srgrimes * pid can't have done an exec (EACCES) 3571541Srgrimes * if pgid != pid 3581541Srgrimes * there must exist some pid in same session having pgid (EPERM) 3591541Srgrimes * pid must not be session leader (EPERM) 3601541Srgrimes */ 36112221Sbde#ifndef _SYS_SYSPROTO_H_ 3621541Srgrimesstruct setpgid_args { 36387218Srwatson int pid; /* target process id */ 36487218Srwatson int pgid; /* target pgrp id */ 3651541Srgrimes}; 36612221Sbde#endif 3671541Srgrimes/* ARGSUSED */ 3681549Srgrimesint 36993580Sjhbsetpgid(struct thread *td, register struct setpgid_args *uap) 3701541Srgrimes{ 37183366Sjulian struct proc *curp = td->td_proc; 37287218Srwatson register struct proc *targp; /* target process */ 37387218Srwatson register struct pgrp *pgrp; /* target pgrp */ 37475448Srwatson int error; 37591140Stanimura struct pgrp *newpgrp; 3761541Srgrimes 37720677Sbde if (uap->pgid < 0) 37820677Sbde return (EINVAL); 37991140Stanimura 38091140Stanimura error = 0; 38191140Stanimura 382111119Simp MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); 38391140Stanimura 38494859Sjhb sx_xlock(&proctree_lock); 3851541Srgrimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 38691140Stanimura if ((targp = pfind(uap->pid)) == NULL) { 38782749Sdillon error = ESRCH; 38894859Sjhb goto done; 38975893Sjhb } 39091140Stanimura if (!inferior(targp)) { 39191140Stanimura PROC_UNLOCK(targp); 39291371Stanimura error = ESRCH; 39394859Sjhb goto done; 39491140Stanimura } 395132568Srwatson if ((error = p_cansee(td, targp))) { 39675893Sjhb PROC_UNLOCK(targp); 39794859Sjhb goto done; 39875893Sjhb } 39975893Sjhb if (targp->p_pgrp == NULL || 40075893Sjhb targp->p_session != curp->p_session) { 40175893Sjhb PROC_UNLOCK(targp); 40282749Sdillon error = EPERM; 40394859Sjhb goto done; 40475893Sjhb } 40575893Sjhb if (targp->p_flag & P_EXEC) { 40675893Sjhb PROC_UNLOCK(targp); 40782749Sdillon error = EACCES; 40894859Sjhb goto done; 40975893Sjhb } 41091140Stanimura PROC_UNLOCK(targp); 41191140Stanimura } else 4121541Srgrimes targp = curp; 41375893Sjhb if (SESS_LEADER(targp)) { 41482749Sdillon error = EPERM; 41594859Sjhb goto done; 41675893Sjhb } 41787218Srwatson if (uap->pgid == 0) 4181541Srgrimes uap->pgid = targp->p_pid; 419117214Scognet if ((pgrp = pgfind(uap->pgid)) == NULL) { 420117214Scognet if (uap->pgid == targp->p_pid) { 421117214Scognet error = enterpgrp(targp, uap->pgid, newpgrp, 422117214Scognet NULL); 423117214Scognet if (error == 0) 424117214Scognet newpgrp = NULL; 425117214Scognet } else 426117214Scognet error = EPERM; 42791140Stanimura } else { 428117214Scognet if (pgrp == targp->p_pgrp) { 429117214Scognet PGRP_UNLOCK(pgrp); 43094859Sjhb goto done; 43175893Sjhb } 432117214Scognet if (pgrp->pg_id != targp->p_pid && 433117214Scognet pgrp->pg_session != curp->p_session) { 43491140Stanimura PGRP_UNLOCK(pgrp); 435117214Scognet error = EPERM; 43691140Stanimura goto done; 43791140Stanimura } 43891140Stanimura PGRP_UNLOCK(pgrp); 43991140Stanimura error = enterthispgrp(targp, pgrp); 44082749Sdillon } 44191140Stanimuradone: 44294859Sjhb sx_xunlock(&proctree_lock); 44394859Sjhb KASSERT((error == 0) || (newpgrp != NULL), 44494859Sjhb ("setpgid failed and newpgrp is NULL")); 44595973Stanimura if (newpgrp != NULL) 44691140Stanimura FREE(newpgrp, M_PGRP); 44782749Sdillon return (error); 4481541Srgrimes} 4491541Srgrimes 45024448Speter/* 45124448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 45272093Sasmodai * compatible. It says that setting the uid/gid to euid/egid is a special 45324448Speter * case of "appropriate privilege". Once the rules are expanded out, this 45424448Speter * basically means that setuid(nnn) sets all three id's, in all permitted 45524448Speter * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 45624448Speter * does not set the saved id - this is dangerous for traditional BSD 45724448Speter * programs. For this reason, we *really* do not want to set 45824448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 45924448Speter */ 46024448Speter#define POSIX_APPENDIX_B_4_2_2 46124448Speter 46212221Sbde#ifndef _SYS_SYSPROTO_H_ 4631541Srgrimesstruct setuid_args { 4641541Srgrimes uid_t uid; 4651541Srgrimes}; 46612221Sbde#endif 4671541Srgrimes/* ARGSUSED */ 4681549Srgrimesint 46993580Sjhbsetuid(struct thread *td, struct setuid_args *uap) 4701541Srgrimes{ 47183366Sjulian struct proc *p = td->td_proc; 47277183Srwatson struct ucred *newcred, *oldcred; 47377183Srwatson uid_t uid; 47498417Salfred struct uidinfo *uip; 47587218Srwatson int error; 4761541Srgrimes 47777183Srwatson uid = uap->uid; 478155370Swsalamon AUDIT_ARG(uid, uid); 47994619Sjhb newcred = crget(); 48098417Salfred uip = uifind(uid); 48194619Sjhb PROC_LOCK(p); 48287219Srwatson oldcred = p->p_ucred; 48387466Srwatson 484145147Srwatson#ifdef MAC 485145147Srwatson error = mac_check_proc_setuid(p, oldcred, uid); 486145147Srwatson if (error) 487145147Srwatson goto fail; 488145147Srwatson#endif 489145147Srwatson 49024448Speter /* 49124448Speter * See if we have "permission" by POSIX 1003.1 rules. 49224448Speter * 49387218Srwatson * Note that setuid(geteuid()) is a special case of 49424448Speter * "appropriate privileges" in appendix B.4.2.2. We need 49572093Sasmodai * to use this clause to be compatible with traditional BSD 49624448Speter * semantics. Basically, it means that "setuid(xx)" sets all 49724448Speter * three id's (assuming you have privs). 49824448Speter * 49924448Speter * Notes on the logic. We do things in three steps. 50024448Speter * 1: We determine if the euid is going to change, and do EPERM 50124448Speter * right away. We unconditionally change the euid later if this 50224448Speter * test is satisfied, simplifying that part of the logic. 50387218Srwatson * 2: We determine if the real and/or saved uids are going to 50424448Speter * change. Determined by compile options. 50524448Speter * 3: Change euid last. (after tests in #2 for "appropriate privs") 50624448Speter */ 50777183Srwatson if (uid != oldcred->cr_ruid && /* allow setuid(getuid()) */ 50817994Sache#ifdef _POSIX_SAVED_IDS 50977183Srwatson uid != oldcred->cr_svuid && /* allow setuid(saved gid) */ 51017994Sache#endif 51124448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 51277183Srwatson uid != oldcred->cr_uid && /* allow setuid(geteuid()) */ 51324448Speter#endif 514170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETUID, 0)) != 0) 515145147Srwatson goto fail; 51624448Speter 51798417Salfred /* 51898417Salfred * Copy credentials so other references do not see our changes. 51998417Salfred */ 52094619Sjhb crcopy(newcred, oldcred); 52124448Speter#ifdef _POSIX_SAVED_IDS 5221541Srgrimes /* 52324448Speter * Do we have "appropriate privileges" (are we root or uid == euid) 52424448Speter * If so, we are changing the real uid and/or saved uid. 5251541Srgrimes */ 52617994Sache if ( 52724448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 52877183Srwatson uid == oldcred->cr_uid || 52917994Sache#endif 530164032Srwatson /* We are using privs. */ 531170587Srwatson priv_check_cred(oldcred, PRIV_CRED_SETUID, 0) == 0) 53217994Sache#endif 53324448Speter { 53424448Speter /* 53565495Struckman * Set the real uid and transfer proc count to new user. 53624448Speter */ 53777183Srwatson if (uid != oldcred->cr_ruid) { 53898417Salfred change_ruid(newcred, uip); 53965495Struckman setsugid(p); 54024448Speter } 54124448Speter /* 54224448Speter * Set saved uid 54324448Speter * 54424448Speter * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 54524448Speter * the security of seteuid() depends on it. B.4.2.2 says it 54624448Speter * is important that we should do this. 54724448Speter */ 54877183Srwatson if (uid != oldcred->cr_svuid) { 54977183Srwatson change_svuid(newcred, uid); 55031891Ssef setsugid(p); 55124448Speter } 5528141Sache } 55324448Speter 55424448Speter /* 55524448Speter * In all permitted cases, we are changing the euid. 55624448Speter */ 55777183Srwatson if (uid != oldcred->cr_uid) { 55898417Salfred change_euid(newcred, uip); 55931891Ssef setsugid(p); 56024448Speter } 56177183Srwatson p->p_ucred = newcred; 56294619Sjhb PROC_UNLOCK(p); 56398417Salfred uifree(uip); 56477183Srwatson crfree(oldcred); 56594619Sjhb return (0); 566145147Srwatson 567145147Srwatsonfail: 568145147Srwatson PROC_UNLOCK(p); 569145147Srwatson uifree(uip); 570145147Srwatson crfree(newcred); 571145147Srwatson return (error); 5721541Srgrimes} 5731541Srgrimes 57412221Sbde#ifndef _SYS_SYSPROTO_H_ 5751541Srgrimesstruct seteuid_args { 5761541Srgrimes uid_t euid; 5771541Srgrimes}; 57812221Sbde#endif 5791541Srgrimes/* ARGSUSED */ 5801549Srgrimesint 58193580Sjhbseteuid(struct thread *td, struct seteuid_args *uap) 5821541Srgrimes{ 58383366Sjulian struct proc *p = td->td_proc; 58477183Srwatson struct ucred *newcred, *oldcred; 58577183Srwatson uid_t euid; 58698417Salfred struct uidinfo *euip; 58787218Srwatson int error; 5881541Srgrimes 5891541Srgrimes euid = uap->euid; 590155370Swsalamon AUDIT_ARG(euid, euid); 59194619Sjhb newcred = crget(); 59298417Salfred euip = uifind(euid); 59394619Sjhb PROC_LOCK(p); 59477183Srwatson oldcred = p->p_ucred; 595145147Srwatson 596145147Srwatson#ifdef MAC 597145147Srwatson error = mac_check_proc_seteuid(p, oldcred, euid); 598145147Srwatson if (error) 599145147Srwatson goto fail; 600145147Srwatson#endif 601145147Srwatson 60277183Srwatson if (euid != oldcred->cr_ruid && /* allow seteuid(getuid()) */ 60377183Srwatson euid != oldcred->cr_svuid && /* allow seteuid(saved uid) */ 604170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETEUID, 0)) != 0) 605145147Srwatson goto fail; 606145147Srwatson 6071541Srgrimes /* 6081541Srgrimes * Everything's okay, do it. Copy credentials so other references do 6091541Srgrimes * not see our changes. 6101541Srgrimes */ 61194619Sjhb crcopy(newcred, oldcred); 61277183Srwatson if (oldcred->cr_uid != euid) { 61398417Salfred change_euid(newcred, euip); 61431891Ssef setsugid(p); 61524449Speter } 61677183Srwatson p->p_ucred = newcred; 61794619Sjhb PROC_UNLOCK(p); 61898417Salfred uifree(euip); 61977183Srwatson crfree(oldcred); 62094619Sjhb return (0); 621145147Srwatson 622145147Srwatsonfail: 623145147Srwatson PROC_UNLOCK(p); 624145147Srwatson uifree(euip); 625145147Srwatson crfree(newcred); 626145147Srwatson return (error); 6271541Srgrimes} 6281541Srgrimes 62912221Sbde#ifndef _SYS_SYSPROTO_H_ 6301541Srgrimesstruct setgid_args { 6311541Srgrimes gid_t gid; 6321541Srgrimes}; 63312221Sbde#endif 6341541Srgrimes/* ARGSUSED */ 6351549Srgrimesint 63693580Sjhbsetgid(struct thread *td, struct setgid_args *uap) 6371541Srgrimes{ 63883366Sjulian struct proc *p = td->td_proc; 63977183Srwatson struct ucred *newcred, *oldcred; 64077183Srwatson gid_t gid; 64187218Srwatson int error; 6421541Srgrimes 64377183Srwatson gid = uap->gid; 644155370Swsalamon AUDIT_ARG(gid, gid); 64594619Sjhb newcred = crget(); 64694619Sjhb PROC_LOCK(p); 64777183Srwatson oldcred = p->p_ucred; 64887466Srwatson 649145147Srwatson#ifdef MAC 650145147Srwatson error = mac_check_proc_setgid(p, oldcred, gid); 651145147Srwatson if (error) 652145147Srwatson goto fail; 653145147Srwatson#endif 654145147Srwatson 65524448Speter /* 65624448Speter * See if we have "permission" by POSIX 1003.1 rules. 65724448Speter * 65824448Speter * Note that setgid(getegid()) is a special case of 65924448Speter * "appropriate privileges" in appendix B.4.2.2. We need 66072093Sasmodai * to use this clause to be compatible with traditional BSD 66124448Speter * semantics. Basically, it means that "setgid(xx)" sets all 66224448Speter * three id's (assuming you have privs). 66324448Speter * 66424448Speter * For notes on the logic here, see setuid() above. 66524448Speter */ 66677183Srwatson if (gid != oldcred->cr_rgid && /* allow setgid(getgid()) */ 66717994Sache#ifdef _POSIX_SAVED_IDS 66877183Srwatson gid != oldcred->cr_svgid && /* allow setgid(saved gid) */ 66917994Sache#endif 67024448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 67177183Srwatson gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */ 67224448Speter#endif 673170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETGID, 0)) != 0) 674145147Srwatson goto fail; 67524448Speter 67694619Sjhb crcopy(newcred, oldcred); 67717994Sache#ifdef _POSIX_SAVED_IDS 67824448Speter /* 67924448Speter * Do we have "appropriate privileges" (are we root or gid == egid) 68024448Speter * If so, we are changing the real uid and saved gid. 68124448Speter */ 68224448Speter if ( 68324448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 68477183Srwatson gid == oldcred->cr_groups[0] || 68517994Sache#endif 686164032Srwatson /* We are using privs. */ 687170587Srwatson priv_check_cred(oldcred, PRIV_CRED_SETGID, 0) == 0) 68824448Speter#endif 68924448Speter { 69024448Speter /* 69124448Speter * Set real gid 69224448Speter */ 69377183Srwatson if (oldcred->cr_rgid != gid) { 69477183Srwatson change_rgid(newcred, gid); 69531891Ssef setsugid(p); 69624448Speter } 69724448Speter /* 69824448Speter * Set saved gid 69924448Speter * 70024448Speter * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 70124448Speter * the security of setegid() depends on it. B.4.2.2 says it 70224448Speter * is important that we should do this. 70324448Speter */ 70477183Srwatson if (oldcred->cr_svgid != gid) { 70577183Srwatson change_svgid(newcred, gid); 70631891Ssef setsugid(p); 70724448Speter } 7088141Sache } 70924448Speter /* 71024448Speter * In all cases permitted cases, we are changing the egid. 71124448Speter * Copy credentials so other references do not see our changes. 71224448Speter */ 71377183Srwatson if (oldcred->cr_groups[0] != gid) { 71477183Srwatson change_egid(newcred, gid); 71531891Ssef setsugid(p); 71624448Speter } 71777183Srwatson p->p_ucred = newcred; 71894619Sjhb PROC_UNLOCK(p); 71977183Srwatson crfree(oldcred); 72094619Sjhb return (0); 721145147Srwatson 722145147Srwatsonfail: 723145147Srwatson PROC_UNLOCK(p); 724145147Srwatson crfree(newcred); 725145147Srwatson return (error); 7261541Srgrimes} 7271541Srgrimes 72812221Sbde#ifndef _SYS_SYSPROTO_H_ 7291541Srgrimesstruct setegid_args { 7301541Srgrimes gid_t egid; 7311541Srgrimes}; 73212221Sbde#endif 7331541Srgrimes/* ARGSUSED */ 7341549Srgrimesint 73593580Sjhbsetegid(struct thread *td, struct setegid_args *uap) 7361541Srgrimes{ 73783366Sjulian struct proc *p = td->td_proc; 73877183Srwatson struct ucred *newcred, *oldcred; 73977183Srwatson gid_t egid; 74087218Srwatson int error; 7411541Srgrimes 7421541Srgrimes egid = uap->egid; 743155370Swsalamon AUDIT_ARG(egid, egid); 74494619Sjhb newcred = crget(); 74594619Sjhb PROC_LOCK(p); 74677183Srwatson oldcred = p->p_ucred; 747145147Srwatson 748145147Srwatson#ifdef MAC 749145147Srwatson error = mac_check_proc_setegid(p, oldcred, egid); 750145147Srwatson if (error) 751145147Srwatson goto fail; 752145147Srwatson#endif 753145147Srwatson 75477183Srwatson if (egid != oldcred->cr_rgid && /* allow setegid(getgid()) */ 75577183Srwatson egid != oldcred->cr_svgid && /* allow setegid(saved gid) */ 756170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETEGID, 0)) != 0) 757145147Srwatson goto fail; 758145147Srwatson 75994619Sjhb crcopy(newcred, oldcred); 76077183Srwatson if (oldcred->cr_groups[0] != egid) { 76177183Srwatson change_egid(newcred, egid); 76231891Ssef setsugid(p); 76324449Speter } 76477183Srwatson p->p_ucred = newcred; 76594619Sjhb PROC_UNLOCK(p); 76677183Srwatson crfree(oldcred); 76794619Sjhb return (0); 768145147Srwatson 769145147Srwatsonfail: 770145147Srwatson PROC_UNLOCK(p); 771145147Srwatson crfree(newcred); 772145147Srwatson return (error); 7731541Srgrimes} 7741541Srgrimes 77512221Sbde#ifndef _SYS_SYSPROTO_H_ 7761541Srgrimesstruct setgroups_args { 7771541Srgrimes u_int gidsetsize; 7781541Srgrimes gid_t *gidset; 7791541Srgrimes}; 78012221Sbde#endif 7811541Srgrimes/* ARGSUSED */ 7821549Srgrimesint 78393580Sjhbsetgroups(struct thread *td, struct setgroups_args *uap) 7841541Srgrimes{ 785160139Sjhb gid_t groups[NGROUPS]; 786160139Sjhb int error; 787160139Sjhb 788160139Sjhb if (uap->gidsetsize > NGROUPS) 789160139Sjhb return (EINVAL); 790160139Sjhb error = copyin(uap->gidset, groups, uap->gidsetsize * sizeof(gid_t)); 791160139Sjhb if (error) 792160139Sjhb return (error); 793160139Sjhb return (kern_setgroups(td, uap->gidsetsize, groups)); 794160139Sjhb} 795160139Sjhb 796160139Sjhbint 797160139Sjhbkern_setgroups(struct thread *td, u_int ngrp, gid_t *groups) 798160139Sjhb{ 79983366Sjulian struct proc *p = td->td_proc; 800160139Sjhb struct ucred *newcred, *oldcred; 8011541Srgrimes int error; 8021541Srgrimes 80394619Sjhb if (ngrp > NGROUPS) 80494619Sjhb return (EINVAL); 805160139Sjhb AUDIT_ARG(groupset, groups, ngrp); 80694619Sjhb newcred = crget(); 80794619Sjhb PROC_LOCK(p); 80877183Srwatson oldcred = p->p_ucred; 809145147Srwatson 810145147Srwatson#ifdef MAC 811160139Sjhb error = mac_check_proc_setgroups(p, oldcred, ngrp, groups); 812145147Srwatson if (error) 813145147Srwatson goto fail; 814145147Srwatson#endif 815145147Srwatson 816170587Srwatson error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0); 817145147Srwatson if (error) 818145147Srwatson goto fail; 819145147Srwatson 82024447Speter /* 82124447Speter * XXX A little bit lazy here. We could test if anything has 82224447Speter * changed before crcopy() and setting P_SUGID. 82324447Speter */ 82494619Sjhb crcopy(newcred, oldcred); 82524447Speter if (ngrp < 1) { 82624447Speter /* 82724447Speter * setgroups(0, NULL) is a legitimate way of clearing the 82824447Speter * groups vector on non-BSD systems (which generally do not 82924447Speter * have the egid in the groups[0]). We risk security holes 83024447Speter * when running non-BSD software if we do not do the same. 83124447Speter */ 83277183Srwatson newcred->cr_ngroups = 1; 83324447Speter } else { 834160139Sjhb bcopy(groups, newcred->cr_groups, ngrp * sizeof(gid_t)); 83577183Srwatson newcred->cr_ngroups = ngrp; 83624447Speter } 83731891Ssef setsugid(p); 83877183Srwatson p->p_ucred = newcred; 83994619Sjhb PROC_UNLOCK(p); 84077183Srwatson crfree(oldcred); 84194619Sjhb return (0); 842145147Srwatson 843145147Srwatsonfail: 844145147Srwatson PROC_UNLOCK(p); 845145147Srwatson crfree(newcred); 846145147Srwatson return (error); 8471541Srgrimes} 8481541Srgrimes 84912221Sbde#ifndef _SYS_SYSPROTO_H_ 8501541Srgrimesstruct setreuid_args { 8519238Sache uid_t ruid; 8529238Sache uid_t euid; 8531541Srgrimes}; 85412221Sbde#endif 8551541Srgrimes/* ARGSUSED */ 8561549Srgrimesint 85793580Sjhbsetreuid(register struct thread *td, struct setreuid_args *uap) 8581541Srgrimes{ 85983366Sjulian struct proc *p = td->td_proc; 86077183Srwatson struct ucred *newcred, *oldcred; 86187218Srwatson uid_t euid, ruid; 86298417Salfred struct uidinfo *euip, *ruip; 86387218Srwatson int error; 8641541Srgrimes 86587218Srwatson euid = uap->euid; 8669238Sache ruid = uap->ruid; 867155370Swsalamon AUDIT_ARG(euid, euid); 868155370Swsalamon AUDIT_ARG(ruid, ruid); 86994619Sjhb newcred = crget(); 87098417Salfred euip = uifind(euid); 87198417Salfred ruip = uifind(ruid); 87294619Sjhb PROC_LOCK(p); 87377183Srwatson oldcred = p->p_ucred; 874145147Srwatson 875145147Srwatson#ifdef MAC 876145147Srwatson error = mac_check_proc_setreuid(p, oldcred, ruid, euid); 877145147Srwatson if (error) 878145147Srwatson goto fail; 879145147Srwatson#endif 880145147Srwatson 88177183Srwatson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 88277183Srwatson ruid != oldcred->cr_svuid) || 88377183Srwatson (euid != (uid_t)-1 && euid != oldcred->cr_uid && 88477183Srwatson euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) && 885170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETREUID, 0)) != 0) 886145147Srwatson goto fail; 887145147Srwatson 88894619Sjhb crcopy(newcred, oldcred); 88977183Srwatson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 89098417Salfred change_euid(newcred, euip); 89131891Ssef setsugid(p); 89224450Speter } 89377183Srwatson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 89498417Salfred change_ruid(newcred, ruip); 89531891Ssef setsugid(p); 8968135Sache } 89777183Srwatson if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) && 89877183Srwatson newcred->cr_svuid != newcred->cr_uid) { 89977183Srwatson change_svuid(newcred, newcred->cr_uid); 90031891Ssef setsugid(p); 90124450Speter } 90277183Srwatson p->p_ucred = newcred; 90394619Sjhb PROC_UNLOCK(p); 90498417Salfred uifree(ruip); 90598417Salfred uifree(euip); 90677183Srwatson crfree(oldcred); 90794619Sjhb return (0); 908145147Srwatson 909145147Srwatsonfail: 910145147Srwatson PROC_UNLOCK(p); 911145147Srwatson uifree(ruip); 912145147Srwatson uifree(euip); 913145147Srwatson crfree(newcred); 914145147Srwatson return (error); 9151541Srgrimes} 9161541Srgrimes 91712221Sbde#ifndef _SYS_SYSPROTO_H_ 9181541Srgrimesstruct setregid_args { 9199238Sache gid_t rgid; 9209238Sache gid_t egid; 9211541Srgrimes}; 92212221Sbde#endif 9231541Srgrimes/* ARGSUSED */ 9241549Srgrimesint 92593580Sjhbsetregid(register struct thread *td, struct setregid_args *uap) 9261541Srgrimes{ 92783366Sjulian struct proc *p = td->td_proc; 92877183Srwatson struct ucred *newcred, *oldcred; 92987218Srwatson gid_t egid, rgid; 93087218Srwatson int error; 9311541Srgrimes 93287218Srwatson egid = uap->egid; 9339238Sache rgid = uap->rgid; 934155370Swsalamon AUDIT_ARG(egid, egid); 935155370Swsalamon AUDIT_ARG(rgid, rgid); 93694619Sjhb newcred = crget(); 93794619Sjhb PROC_LOCK(p); 93877183Srwatson oldcred = p->p_ucred; 939145147Srwatson 940145147Srwatson#ifdef MAC 941145147Srwatson error = mac_check_proc_setregid(p, oldcred, rgid, egid); 942145147Srwatson if (error) 943145147Srwatson goto fail; 944145147Srwatson#endif 945145147Srwatson 94677183Srwatson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 94777183Srwatson rgid != oldcred->cr_svgid) || 94877183Srwatson (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] && 94977183Srwatson egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) && 950170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETREGID, 0)) != 0) 951145147Srwatson goto fail; 95294619Sjhb 95394619Sjhb crcopy(newcred, oldcred); 95477183Srwatson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 95577183Srwatson change_egid(newcred, egid); 95631891Ssef setsugid(p); 95724450Speter } 95877183Srwatson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 95977183Srwatson change_rgid(newcred, rgid); 96031891Ssef setsugid(p); 96124450Speter } 96277183Srwatson if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) && 96377183Srwatson newcred->cr_svgid != newcred->cr_groups[0]) { 96477183Srwatson change_svgid(newcred, newcred->cr_groups[0]); 96531891Ssef setsugid(p); 96624450Speter } 96777812Sru p->p_ucred = newcred; 96894619Sjhb PROC_UNLOCK(p); 96977812Sru crfree(oldcred); 97094619Sjhb return (0); 971145147Srwatson 972145147Srwatsonfail: 973145147Srwatson PROC_UNLOCK(p); 974145147Srwatson crfree(newcred); 975145147Srwatson return (error); 9761541Srgrimes} 9771541Srgrimes 97856115Speter/* 979167232Srwatson * setresuid(ruid, euid, suid) is like setreuid except control over the saved 980167232Srwatson * uid is explicit. 98156115Speter */ 98224453Speter#ifndef _SYS_SYSPROTO_H_ 98356115Speterstruct setresuid_args { 98456115Speter uid_t ruid; 98556115Speter uid_t euid; 98656115Speter uid_t suid; 98756115Speter}; 98856115Speter#endif 98956115Speter/* ARGSUSED */ 99056115Speterint 99193580Sjhbsetresuid(register struct thread *td, struct setresuid_args *uap) 99256115Speter{ 99383366Sjulian struct proc *p = td->td_proc; 99477183Srwatson struct ucred *newcred, *oldcred; 99587218Srwatson uid_t euid, ruid, suid; 99698417Salfred struct uidinfo *euip, *ruip; 99756115Speter int error; 99856115Speter 99987218Srwatson euid = uap->euid; 100056115Speter ruid = uap->ruid; 100156115Speter suid = uap->suid; 1002155370Swsalamon AUDIT_ARG(euid, euid); 1003155370Swsalamon AUDIT_ARG(ruid, ruid); 1004155370Swsalamon AUDIT_ARG(suid, suid); 100594619Sjhb newcred = crget(); 100698417Salfred euip = uifind(euid); 100798417Salfred ruip = uifind(ruid); 100894619Sjhb PROC_LOCK(p); 100977183Srwatson oldcred = p->p_ucred; 1010145147Srwatson 1011145147Srwatson#ifdef MAC 1012145147Srwatson error = mac_check_proc_setresuid(p, oldcred, ruid, euid, suid); 1013145147Srwatson if (error) 1014145147Srwatson goto fail; 1015145147Srwatson#endif 1016145147Srwatson 101777183Srwatson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 101877183Srwatson ruid != oldcred->cr_svuid && 101977183Srwatson ruid != oldcred->cr_uid) || 102077183Srwatson (euid != (uid_t)-1 && euid != oldcred->cr_ruid && 102177183Srwatson euid != oldcred->cr_svuid && 102277183Srwatson euid != oldcred->cr_uid) || 102377183Srwatson (suid != (uid_t)-1 && suid != oldcred->cr_ruid && 102477183Srwatson suid != oldcred->cr_svuid && 102577183Srwatson suid != oldcred->cr_uid)) && 1026170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETRESUID, 0)) != 0) 1027145147Srwatson goto fail; 102894619Sjhb 102994619Sjhb crcopy(newcred, oldcred); 103077183Srwatson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 103198417Salfred change_euid(newcred, euip); 103256115Speter setsugid(p); 103356115Speter } 103477183Srwatson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 103598417Salfred change_ruid(newcred, ruip); 103656115Speter setsugid(p); 103756115Speter } 103877183Srwatson if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) { 103977183Srwatson change_svuid(newcred, suid); 104056115Speter setsugid(p); 104156115Speter } 104277183Srwatson p->p_ucred = newcred; 104394619Sjhb PROC_UNLOCK(p); 104498417Salfred uifree(ruip); 104598417Salfred uifree(euip); 104677183Srwatson crfree(oldcred); 104794619Sjhb return (0); 1048145147Srwatson 1049145147Srwatsonfail: 1050145147Srwatson PROC_UNLOCK(p); 1051145147Srwatson uifree(ruip); 1052145147Srwatson uifree(euip); 1053145147Srwatson crfree(newcred); 1054145147Srwatson return (error); 1055145147Srwatson 105656115Speter} 105756115Speter 105856115Speter/* 1059167232Srwatson * setresgid(rgid, egid, sgid) is like setregid except control over the saved 1060167232Srwatson * gid is explicit. 106156115Speter */ 106256115Speter#ifndef _SYS_SYSPROTO_H_ 106356115Speterstruct setresgid_args { 106456115Speter gid_t rgid; 106556115Speter gid_t egid; 106656115Speter gid_t sgid; 106756115Speter}; 106856115Speter#endif 106956115Speter/* ARGSUSED */ 107056115Speterint 107193580Sjhbsetresgid(register struct thread *td, struct setresgid_args *uap) 107256115Speter{ 107383366Sjulian struct proc *p = td->td_proc; 107477183Srwatson struct ucred *newcred, *oldcred; 107587218Srwatson gid_t egid, rgid, sgid; 107656115Speter int error; 107756115Speter 107887218Srwatson egid = uap->egid; 107956115Speter rgid = uap->rgid; 108056115Speter sgid = uap->sgid; 1081155370Swsalamon AUDIT_ARG(egid, egid); 1082155370Swsalamon AUDIT_ARG(rgid, rgid); 1083155370Swsalamon AUDIT_ARG(sgid, sgid); 108494619Sjhb newcred = crget(); 108594619Sjhb PROC_LOCK(p); 108677183Srwatson oldcred = p->p_ucred; 1087145147Srwatson 1088145147Srwatson#ifdef MAC 1089145147Srwatson error = mac_check_proc_setresgid(p, oldcred, rgid, egid, sgid); 1090145147Srwatson if (error) 1091145147Srwatson goto fail; 1092145147Srwatson#endif 1093145147Srwatson 109477183Srwatson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 109577183Srwatson rgid != oldcred->cr_svgid && 109677183Srwatson rgid != oldcred->cr_groups[0]) || 109777183Srwatson (egid != (gid_t)-1 && egid != oldcred->cr_rgid && 109877183Srwatson egid != oldcred->cr_svgid && 109977183Srwatson egid != oldcred->cr_groups[0]) || 110077183Srwatson (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid && 110177183Srwatson sgid != oldcred->cr_svgid && 110277183Srwatson sgid != oldcred->cr_groups[0])) && 1103170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETRESGID, 0)) != 0) 1104145147Srwatson goto fail; 110594619Sjhb 110694619Sjhb crcopy(newcred, oldcred); 110777183Srwatson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 110877183Srwatson change_egid(newcred, egid); 110956115Speter setsugid(p); 111056115Speter } 111177183Srwatson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 111277183Srwatson change_rgid(newcred, rgid); 111356115Speter setsugid(p); 111456115Speter } 111577183Srwatson if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) { 111677183Srwatson change_svgid(newcred, sgid); 111756115Speter setsugid(p); 111856115Speter } 111977183Srwatson p->p_ucred = newcred; 112094619Sjhb PROC_UNLOCK(p); 112177183Srwatson crfree(oldcred); 112294619Sjhb return (0); 1123145147Srwatson 1124145147Srwatsonfail: 1125145147Srwatson PROC_UNLOCK(p); 1126145147Srwatson crfree(newcred); 1127145147Srwatson return (error); 112856115Speter} 112956115Speter 113056115Speter#ifndef _SYS_SYSPROTO_H_ 113156115Speterstruct getresuid_args { 113256115Speter uid_t *ruid; 113356115Speter uid_t *euid; 113456115Speter uid_t *suid; 113556115Speter}; 113656115Speter#endif 113756115Speter/* ARGSUSED */ 113856115Speterint 113993580Sjhbgetresuid(register struct thread *td, struct getresuid_args *uap) 114056115Speter{ 114182749Sdillon struct ucred *cred; 114256115Speter int error1 = 0, error2 = 0, error3 = 0; 114356115Speter 114493264Sdillon cred = td->td_ucred; 114556115Speter if (uap->ruid) 114699009Salfred error1 = copyout(&cred->cr_ruid, 114799009Salfred uap->ruid, sizeof(cred->cr_ruid)); 114856115Speter if (uap->euid) 114999009Salfred error2 = copyout(&cred->cr_uid, 115099009Salfred uap->euid, sizeof(cred->cr_uid)); 115156115Speter if (uap->suid) 115299009Salfred error3 = copyout(&cred->cr_svuid, 115399009Salfred uap->suid, sizeof(cred->cr_svuid)); 115487218Srwatson return (error1 ? error1 : error2 ? error2 : error3); 115556115Speter} 115656115Speter 115756115Speter#ifndef _SYS_SYSPROTO_H_ 115856115Speterstruct getresgid_args { 115956115Speter gid_t *rgid; 116056115Speter gid_t *egid; 116156115Speter gid_t *sgid; 116256115Speter}; 116356115Speter#endif 116456115Speter/* ARGSUSED */ 116556115Speterint 116693580Sjhbgetresgid(register struct thread *td, struct getresgid_args *uap) 116756115Speter{ 116882749Sdillon struct ucred *cred; 116956115Speter int error1 = 0, error2 = 0, error3 = 0; 117056115Speter 117193264Sdillon cred = td->td_ucred; 117256115Speter if (uap->rgid) 117399009Salfred error1 = copyout(&cred->cr_rgid, 117499009Salfred uap->rgid, sizeof(cred->cr_rgid)); 117556115Speter if (uap->egid) 117699009Salfred error2 = copyout(&cred->cr_groups[0], 117799009Salfred uap->egid, sizeof(cred->cr_groups[0])); 117856115Speter if (uap->sgid) 117999009Salfred error3 = copyout(&cred->cr_svgid, 118099009Salfred uap->sgid, sizeof(cred->cr_svgid)); 118187218Srwatson return (error1 ? error1 : error2 ? error2 : error3); 118256115Speter} 118356115Speter 118456115Speter#ifndef _SYS_SYSPROTO_H_ 118524453Speterstruct issetugid_args { 118624453Speter int dummy; 118724453Speter}; 118824453Speter#endif 118924453Speter/* ARGSUSED */ 119024453Speterint 119193580Sjhbissetugid(register struct thread *td, struct issetugid_args *uap) 119224453Speter{ 119383366Sjulian struct proc *p = td->td_proc; 119483366Sjulian 119524453Speter /* 119624453Speter * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 119724453Speter * we use P_SUGID because we consider changing the owners as 119824453Speter * "tainting" as well. 119924453Speter * This is significant for procs that start as root and "become" 120024453Speter * a user without an exec - programs cannot know *everything* 120124453Speter * that libc *might* have put in their data segment. 120224453Speter */ 120391140Stanimura PROC_LOCK(p); 120483366Sjulian td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 120591140Stanimura PROC_UNLOCK(p); 120624453Speter return (0); 120724453Speter} 120824453Speter 120975426Srwatsonint 121093580Sjhb__setugid(struct thread *td, struct __setugid_args *uap) 121175426Srwatson{ 121282749Sdillon#ifdef REGRESSION 121394619Sjhb struct proc *p; 121475426Srwatson 121594619Sjhb p = td->td_proc; 121675426Srwatson switch (uap->flag) { 121775426Srwatson case 0: 121894619Sjhb PROC_LOCK(p); 121994619Sjhb p->p_flag &= ~P_SUGID; 122094619Sjhb PROC_UNLOCK(p); 122194619Sjhb return (0); 122275426Srwatson case 1: 122394619Sjhb PROC_LOCK(p); 122494619Sjhb p->p_flag |= P_SUGID; 122594619Sjhb PROC_UNLOCK(p); 122694619Sjhb return (0); 122775426Srwatson default: 122894619Sjhb return (EINVAL); 122975426Srwatson } 123075426Srwatson#else /* !REGRESSION */ 123187218Srwatson 123275426Srwatson return (ENOSYS); 123387218Srwatson#endif /* REGRESSION */ 123475426Srwatson} 123575426Srwatson 12361541Srgrimes/* 12371541Srgrimes * Check if gid is a member of the group set. 12381541Srgrimes */ 12391549Srgrimesint 124093580Sjhbgroupmember(gid_t gid, struct ucred *cred) 12411541Srgrimes{ 12421541Srgrimes register gid_t *gp; 12431541Srgrimes gid_t *egp; 12441541Srgrimes 12451541Srgrimes egp = &(cred->cr_groups[cred->cr_ngroups]); 12461541Srgrimes for (gp = cred->cr_groups; gp < egp; gp++) 12471541Srgrimes if (*gp == gid) 12481541Srgrimes return (1); 12491541Srgrimes return (0); 12501541Srgrimes} 12511541Srgrimes 125282424Srwatson/* 125387218Srwatson * Test the active securelevel against a given level. securelevel_gt() 125487218Srwatson * implements (securelevel > level). securelevel_ge() implements 125587218Srwatson * (securelevel >= level). Note that the logic is inverted -- these 125687218Srwatson * functions return EPERM on "success" and 0 on "failure". 125783639Srwatson * 1258164032Srwatson * XXXRW: Possibly since this has to do with privilege, it should move to 1259164032Srwatson * kern_priv.c. 126083639Srwatson */ 126183639Srwatsonint 126283639Srwatsonsecurelevel_gt(struct ucred *cr, int level) 126383639Srwatson{ 126487218Srwatson int active_securelevel; 126583639Srwatson 126687218Srwatson active_securelevel = securelevel; 126793732Sjhb KASSERT(cr != NULL, ("securelevel_gt: null cr")); 1268140678Srwatson if (cr->cr_prison != NULL) 126987218Srwatson active_securelevel = imax(cr->cr_prison->pr_securelevel, 127087218Srwatson active_securelevel); 127187218Srwatson return (active_securelevel > level ? EPERM : 0); 127283639Srwatson} 127383639Srwatson 127483639Srwatsonint 127583639Srwatsonsecurelevel_ge(struct ucred *cr, int level) 127683639Srwatson{ 127787218Srwatson int active_securelevel; 127883639Srwatson 127987218Srwatson active_securelevel = securelevel; 128093732Sjhb KASSERT(cr != NULL, ("securelevel_ge: null cr")); 1281140678Srwatson if (cr->cr_prison != NULL) 128287218Srwatson active_securelevel = imax(cr->cr_prison->pr_securelevel, 128387218Srwatson active_securelevel); 128487218Srwatson return (active_securelevel >= level ? EPERM : 0); 128583639Srwatson} 128683639Srwatson 128784736Srwatson/* 128887144Srwatson * 'see_other_uids' determines whether or not visibility of processes 128987218Srwatson * and sockets with credentials holding different real uids is possible 129087138Srwatson * using a variety of system MIBs. 129187218Srwatson * XXX: data declarations should be together near the beginning of the file. 129284736Srwatson */ 129387144Srwatsonstatic int see_other_uids = 1; 129489414SarrSYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW, 129587218Srwatson &see_other_uids, 0, 129684736Srwatson "Unprivileged processes may see subjects/objects with different real uid"); 129784736Srwatson 129882466Srwatson/*- 129992923Srwatson * Determine if u1 "can see" the subject specified by u2, according to the 130092923Srwatson * 'see_other_uids' policy. 130192923Srwatson * Returns: 0 for permitted, ESRCH otherwise 130292923Srwatson * Locks: none 130392923Srwatson * References: *u1 and *u2 must not change during the call 130492923Srwatson * u1 may equal u2, in which case only one reference is required 130592923Srwatson */ 130692923Srwatsonstatic int 130792923Srwatsoncr_seeotheruids(struct ucred *u1, struct ucred *u2) 130892923Srwatson{ 130992923Srwatson 131092923Srwatson if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) { 1311170587Srwatson if (priv_check_cred(u1, PRIV_SEEOTHERUIDS, 0) != 0) 131292923Srwatson return (ESRCH); 131392923Srwatson } 131492923Srwatson return (0); 131592923Srwatson} 131692923Srwatson 1317122869Srwatson/* 1318122869Srwatson * 'see_other_gids' determines whether or not visibility of processes 1319122869Srwatson * and sockets with credentials holding different real gids is possible 1320122869Srwatson * using a variety of system MIBs. 1321122869Srwatson * XXX: data declarations should be together near the beginning of the file. 1322122869Srwatson */ 1323122869Srwatsonstatic int see_other_gids = 1; 1324122869SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, see_other_gids, CTLFLAG_RW, 1325122869Srwatson &see_other_gids, 0, 1326122869Srwatson "Unprivileged processes may see subjects/objects with different real gid"); 1327122869Srwatson 1328122869Srwatson/* 1329122869Srwatson * Determine if u1 can "see" the subject specified by u2, according to the 1330122869Srwatson * 'see_other_gids' policy. 1331122869Srwatson * Returns: 0 for permitted, ESRCH otherwise 1332122869Srwatson * Locks: none 1333122869Srwatson * References: *u1 and *u2 must not change during the call 1334122869Srwatson * u1 may equal u2, in which case only one reference is required 1335122869Srwatson */ 1336122869Srwatsonstatic int 1337122869Srwatsoncr_seeothergids(struct ucred *u1, struct ucred *u2) 1338122869Srwatson{ 1339122869Srwatson int i, match; 1340122869Srwatson 1341122869Srwatson if (!see_other_gids) { 1342122869Srwatson match = 0; 1343122869Srwatson for (i = 0; i < u1->cr_ngroups; i++) { 1344122869Srwatson if (groupmember(u1->cr_groups[i], u2)) 1345122869Srwatson match = 1; 1346122869Srwatson if (match) 1347122869Srwatson break; 1348122869Srwatson } 1349122869Srwatson if (!match) { 1350170587Srwatson if (priv_check_cred(u1, PRIV_SEEOTHERGIDS, 0) != 0) 1351122869Srwatson return (ESRCH); 1352122869Srwatson } 1353122869Srwatson } 1354122869Srwatson return (0); 1355122869Srwatson} 1356122869Srwatson 135792923Srwatson/*- 135882466Srwatson * Determine if u1 "can see" the subject specified by u2. 135974956Srwatson * Returns: 0 for permitted, an errno value otherwise 136074956Srwatson * Locks: none 136187218Srwatson * References: *u1 and *u2 must not change during the call 136274956Srwatson * u1 may equal u2, in which case only one reference is required 136374956Srwatson */ 136474956Srwatsonint 136583742Srwatsoncr_cansee(struct ucred *u1, struct ucred *u2) 136665237Srwatson{ 136772786Srwatson int error; 136853518Sphk 136974956Srwatson if ((error = prison_check(u1, u2))) 137072786Srwatson return (error); 1371101003Srwatson#ifdef MAC 1372101003Srwatson if ((error = mac_check_cred_visible(u1, u2))) 1373101003Srwatson return (error); 1374101003Srwatson#endif 137592923Srwatson if ((error = cr_seeotheruids(u1, u2))) 137692923Srwatson return (error); 1377122869Srwatson if ((error = cr_seeothergids(u1, u2))) 1378122869Srwatson return (error); 137965237Srwatson return (0); 138065237Srwatson} 138165237Srwatson 138282466Srwatson/*- 138396886Sjhb * Determine if td "can see" the subject specified by p. 138482424Srwatson * Returns: 0 for permitted, an errno value otherwise 138596886Sjhb * Locks: Sufficient locks to protect p->p_ucred must be held. td really 138696886Sjhb * should be curthread. 138796886Sjhb * References: td and p must be valid for the lifetime of the call 138882424Srwatson */ 138979335Srwatsonint 139096886Sjhbp_cansee(struct thread *td, struct proc *p) 139174956Srwatson{ 139274956Srwatson 139383742Srwatson /* Wrap cr_cansee() for all functionality. */ 139496886Sjhb KASSERT(td == curthread, ("%s: td not curthread", __func__)); 139596886Sjhb PROC_LOCK_ASSERT(p, MA_OWNED); 139696886Sjhb return (cr_cansee(td->td_ucred, p->p_ucred)); 139774956Srwatson} 139874956Srwatson 1399120052Srwatson/* 1400120052Srwatson * 'conservative_signals' prevents the delivery of a broad class of 1401120052Srwatson * signals by unprivileged processes to processes that have changed their 1402120052Srwatson * credentials since the last invocation of execve(). This can prevent 1403120052Srwatson * the leakage of cached information or retained privileges as a result 1404120052Srwatson * of a common class of signal-related vulnerabilities. However, this 1405120052Srwatson * may interfere with some applications that expect to be able to 1406120052Srwatson * deliver these signals to peer processes after having given up 1407120052Srwatson * privilege. 1408120052Srwatson */ 1409120052Srwatsonstatic int conservative_signals = 1; 1410120052SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, conservative_signals, CTLFLAG_RW, 1411120052Srwatson &conservative_signals, 0, "Unprivileged processes prevented from " 1412120052Srwatson "sending certain signals to processes whose credentials have changed"); 141382466Srwatson/*- 141488943Srwatson * Determine whether cred may deliver the specified signal to proc. 141588943Srwatson * Returns: 0 for permitted, an errno value otherwise. 141688943Srwatson * Locks: A lock must be held for proc. 141788943Srwatson * References: cred and proc must be valid for the lifetime of the call. 141875437Srwatson */ 141975437Srwatsonint 1420141815Ssobomaxcr_cansignal(struct ucred *cred, struct proc *proc, int signum) 142153518Sphk{ 142282466Srwatson int error; 142384826Sjhb 142496886Sjhb PROC_LOCK_ASSERT(proc, MA_OWNED); 142575437Srwatson /* 142688943Srwatson * Jail semantics limit the scope of signalling to proc in the 142788943Srwatson * same jail as cred, if cred is in jail. 142875437Srwatson */ 142988943Srwatson error = prison_check(cred, proc->p_ucred); 143088943Srwatson if (error) 143172786Srwatson return (error); 1432101003Srwatson#ifdef MAC 1433101003Srwatson if ((error = mac_check_proc_signal(cred, proc, signum))) 1434101003Srwatson return (error); 1435101003Srwatson#endif 1436122869Srwatson if ((error = cr_seeotheruids(cred, proc->p_ucred))) 143792923Srwatson return (error); 1438122869Srwatson if ((error = cr_seeothergids(cred, proc->p_ucred))) 1439122869Srwatson return (error); 144065237Srwatson 144165237Srwatson /* 144282424Srwatson * UNIX signal semantics depend on the status of the P_SUGID 144382424Srwatson * bit on the target process. If the bit is set, then additional 144482424Srwatson * restrictions are placed on the set of available signals. 144575437Srwatson */ 1446141815Ssobomax if (conservative_signals && (proc->p_flag & P_SUGID)) { 144775437Srwatson switch (signum) { 144875437Srwatson case 0: 144975437Srwatson case SIGKILL: 145075437Srwatson case SIGINT: 145175437Srwatson case SIGTERM: 1452120052Srwatson case SIGALRM: 145375437Srwatson case SIGSTOP: 145475437Srwatson case SIGTTIN: 145575437Srwatson case SIGTTOU: 145675437Srwatson case SIGTSTP: 145775437Srwatson case SIGHUP: 145875437Srwatson case SIGUSR1: 145975437Srwatson case SIGUSR2: 146082466Srwatson /* 146182466Srwatson * Generally, permit job and terminal control 146282466Srwatson * signals. 146382466Srwatson */ 146475437Srwatson break; 146575437Srwatson default: 146688943Srwatson /* Not permitted without privilege. */ 1467170587Srwatson error = priv_check_cred(cred, PRIV_SIGNAL_SUGID, 0); 146875437Srwatson if (error) 146975437Srwatson return (error); 147075437Srwatson } 147165237Srwatson } 147265237Srwatson 147375480Srwatson /* 147482424Srwatson * Generally, the target credential's ruid or svuid must match the 147575480Srwatson * subject credential's ruid or euid. 147675480Srwatson */ 147788943Srwatson if (cred->cr_ruid != proc->p_ucred->cr_ruid && 147888943Srwatson cred->cr_ruid != proc->p_ucred->cr_svuid && 147988943Srwatson cred->cr_uid != proc->p_ucred->cr_ruid && 148088943Srwatson cred->cr_uid != proc->p_ucred->cr_svuid) { 1481170587Srwatson error = priv_check_cred(cred, PRIV_SIGNAL_DIFFCRED, 0); 148275480Srwatson if (error) 148375480Srwatson return (error); 148475480Srwatson } 148575480Srwatson 148687218Srwatson return (0); 148753518Sphk} 148853518Sphk 148982466Srwatson/*- 149096886Sjhb * Determine whether td may deliver the specified signal to p. 149188943Srwatson * Returns: 0 for permitted, an errno value otherwise 149296886Sjhb * Locks: Sufficient locks to protect various components of td and p 149396886Sjhb * must be held. td must be curthread, and a lock must be 149496886Sjhb * held for p. 149596886Sjhb * References: td and p must be valid for the lifetime of the call 149688943Srwatson */ 149788943Srwatsonint 1498141815Ssobomaxp_cansignal(struct thread *td, struct proc *p, int signum) 149988943Srwatson{ 150088943Srwatson 150196886Sjhb KASSERT(td == curthread, ("%s: td not curthread", __func__)); 150296886Sjhb PROC_LOCK_ASSERT(p, MA_OWNED); 150396886Sjhb if (td->td_proc == p) 150488943Srwatson return (0); 150588943Srwatson 150688943Srwatson /* 150788943Srwatson * UNIX signalling semantics require that processes in the same 150888943Srwatson * session always be able to deliver SIGCONT to one another, 150988943Srwatson * overriding the remaining protections. 151088943Srwatson */ 151196886Sjhb /* XXX: This will require an additional lock of some sort. */ 151296886Sjhb if (signum == SIGCONT && td->td_proc->p_session == p->p_session) 151388943Srwatson return (0); 1514143108Ssobomax /* 1515143800Ssobomax * Some compat layers use SIGTHR and higher signals for 1516143800Ssobomax * communication between different kernel threads of the same 1517143800Ssobomax * process, so that they expect that it's always possible to 1518143800Ssobomax * deliver them, even for suid applications where cr_cansignal() can 1519143108Ssobomax * deny such ability for security consideration. It should be 1520143108Ssobomax * pretty safe to do since the only way to create two processes 1521143108Ssobomax * with the same p_leader is via rfork(2). 1522143108Ssobomax */ 1523143805Ssobomax if (td->td_proc->p_leader != NULL && signum >= SIGTHR && 1524143805Ssobomax signum < SIGTHR + 4 && td->td_proc->p_leader == p->p_leader) 1525143108Ssobomax return (0); 152688943Srwatson 1527141815Ssobomax return (cr_cansignal(td->td_ucred, p, signum)); 152888943Srwatson} 152988943Srwatson 153088943Srwatson/*- 153196886Sjhb * Determine whether td may reschedule p. 153282466Srwatson * Returns: 0 for permitted, an errno value otherwise 153396886Sjhb * Locks: Sufficient locks to protect various components of td and p 153496886Sjhb * must be held. td must be curthread, and a lock must 153596886Sjhb * be held for p. 153696886Sjhb * References: td and p must be valid for the lifetime of the call 153782424Srwatson */ 153879335Srwatsonint 153996886Sjhbp_cansched(struct thread *td, struct proc *p) 154065237Srwatson{ 154172786Srwatson int error; 154265237Srwatson 154396886Sjhb KASSERT(td == curthread, ("%s: td not curthread", __func__)); 154496886Sjhb PROC_LOCK_ASSERT(p, MA_OWNED); 154596886Sjhb if (td->td_proc == p) 154665237Srwatson return (0); 154796886Sjhb if ((error = prison_check(td->td_ucred, p->p_ucred))) 154872786Srwatson return (error); 1549101003Srwatson#ifdef MAC 1550101003Srwatson if ((error = mac_check_proc_sched(td->td_ucred, p))) 1551101003Srwatson return (error); 1552101003Srwatson#endif 155396886Sjhb if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) 155492923Srwatson return (error); 1555122869Srwatson if ((error = cr_seeothergids(td->td_ucred, p->p_ucred))) 1556122869Srwatson return (error); 1557164032Srwatson if (td->td_ucred->cr_ruid != p->p_ucred->cr_ruid && 1558164032Srwatson td->td_ucred->cr_uid != p->p_ucred->cr_ruid) { 1559170587Srwatson error = priv_check(td, PRIV_SCHED_DIFFCRED); 1560164032Srwatson if (error) 1561164032Srwatson return (error); 1562164032Srwatson } 1563164032Srwatson return (0); 156465237Srwatson} 156565237Srwatson 156682424Srwatson/* 156787280Srwatson * The 'unprivileged_proc_debug' flag may be used to disable a variety of 156887280Srwatson * unprivileged inter-process debugging services, including some procfs 156987280Srwatson * functionality, ptrace(), and ktrace(). In the past, inter-process 157087280Srwatson * debugging has been involved in a variety of security problems, and sites 157187280Srwatson * not requiring the service might choose to disable it when hardening 157287280Srwatson * systems. 157382424Srwatson * 157482424Srwatson * XXX: Should modifying and reading this variable require locking? 157587218Srwatson * XXX: data declarations should be together near the beginning of the file. 157682424Srwatson */ 157787144Srwatsonstatic int unprivileged_proc_debug = 1; 157889414SarrSYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW, 157987218Srwatson &unprivileged_proc_debug, 0, 158080735Srwatson "Unprivileged processes may use process debugging facilities"); 158180735Srwatson 158282466Srwatson/*- 158396886Sjhb * Determine whether td may debug p. 158482466Srwatson * Returns: 0 for permitted, an errno value otherwise 158596886Sjhb * Locks: Sufficient locks to protect various components of td and p 158696886Sjhb * must be held. td must be curthread, and a lock must 158796886Sjhb * be held for p. 158896886Sjhb * References: td and p must be valid for the lifetime of the call 158982424Srwatson */ 159079335Srwatsonint 159196886Sjhbp_candebug(struct thread *td, struct proc *p) 159265237Srwatson{ 159387218Srwatson int credentialchanged, error, grpsubset, i, uidsubset; 159465237Srwatson 159596886Sjhb KASSERT(td == curthread, ("%s: td not curthread", __func__)); 159696886Sjhb PROC_LOCK_ASSERT(p, MA_OWNED); 159787144Srwatson if (!unprivileged_proc_debug) { 1598170587Srwatson error = priv_check(td, PRIV_DEBUG_UNPRIV); 159984727Srwatson if (error) 160084727Srwatson return (error); 160184727Srwatson } 160296886Sjhb if (td->td_proc == p) 160384636Sdes return (0); 160496886Sjhb if ((error = prison_check(td->td_ucred, p->p_ucred))) 160572786Srwatson return (error); 1606101003Srwatson#ifdef MAC 1607101003Srwatson if ((error = mac_check_proc_debug(td->td_ucred, p))) 1608101003Srwatson return (error); 1609101003Srwatson#endif 161096886Sjhb if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) 161192923Srwatson return (error); 1612122869Srwatson if ((error = cr_seeothergids(td->td_ucred, p->p_ucred))) 1613122869Srwatson return (error); 161465237Srwatson 161582466Srwatson /* 161696886Sjhb * Is p's group set a subset of td's effective group set? This 161796886Sjhb * includes p's egid, group access list, rgid, and svgid. 161882466Srwatson */ 161985895Srwatson grpsubset = 1; 162096886Sjhb for (i = 0; i < p->p_ucred->cr_ngroups; i++) { 162196886Sjhb if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) { 162285895Srwatson grpsubset = 0; 162385895Srwatson break; 162485895Srwatson } 162585895Srwatson } 162685895Srwatson grpsubset = grpsubset && 162796886Sjhb groupmember(p->p_ucred->cr_rgid, td->td_ucred) && 162896886Sjhb groupmember(p->p_ucred->cr_svgid, td->td_ucred); 162985895Srwatson 163085895Srwatson /* 163196886Sjhb * Are the uids present in p's credential equal to td's 163296886Sjhb * effective uid? This includes p's euid, svuid, and ruid. 163385895Srwatson */ 163496886Sjhb uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid && 163596886Sjhb td->td_ucred->cr_uid == p->p_ucred->cr_svuid && 163696886Sjhb td->td_ucred->cr_uid == p->p_ucred->cr_ruid); 163785895Srwatson 163885895Srwatson /* 163985895Srwatson * Has the credential of the process changed since the last exec()? 164085895Srwatson */ 164196886Sjhb credentialchanged = (p->p_flag & P_SUGID); 164285895Srwatson 164385895Srwatson /* 164496886Sjhb * If p's gids aren't a subset, or the uids aren't a subset, 164585895Srwatson * or the credential has changed, require appropriate privilege 1646164032Srwatson * for td to debug p. 164785895Srwatson */ 1648164032Srwatson if (!grpsubset || !uidsubset) { 1649170587Srwatson error = priv_check(td, PRIV_DEBUG_DIFFCRED); 165084727Srwatson if (error) 165165237Srwatson return (error); 165282466Srwatson } 165365237Srwatson 1654164032Srwatson if (credentialchanged) { 1655170587Srwatson error = priv_check(td, PRIV_DEBUG_SUGID); 1656164032Srwatson if (error) 1657164032Srwatson return (error); 1658164032Srwatson } 1659164032Srwatson 166087218Srwatson /* Can't trace init when securelevel > 0. */ 166196886Sjhb if (p == initproc) { 166296886Sjhb error = securelevel_gt(td->td_ucred, 0); 166383639Srwatson if (error) 166483639Srwatson return (error); 166583639Srwatson } 166665237Srwatson 166785880Srwatson /* 166885880Srwatson * Can't trace a process that's currently exec'ing. 1669164032Srwatson * 167085880Srwatson * XXX: Note, this is not a security policy decision, it's a 167185880Srwatson * basic correctness/functionality decision. Therefore, this check 167285880Srwatson * should be moved to the caller's of p_candebug(). 167385880Srwatson */ 167496886Sjhb if ((p->p_flag & P_INEXEC) != 0) 167585598Sdes return (EAGAIN); 167687466Srwatson 167765237Srwatson return (0); 167865237Srwatson} 167965237Srwatson 168092976Srwatson/*- 168192976Srwatson * Determine whether the subject represented by cred can "see" a socket. 168292976Srwatson * Returns: 0 for permitted, ENOENT otherwise. 168392976Srwatson */ 168492976Srwatsonint 168592976Srwatsoncr_canseesocket(struct ucred *cred, struct socket *so) 168692976Srwatson{ 168792976Srwatson int error; 168892976Srwatson 168992976Srwatson error = prison_check(cred, so->so_cred); 169092976Srwatson if (error) 169192976Srwatson return (ENOENT); 1692101003Srwatson#ifdef MAC 1693130398Srwatson SOCK_LOCK(so); 1694101003Srwatson error = mac_check_socket_visible(cred, so); 1695130398Srwatson SOCK_UNLOCK(so); 1696101003Srwatson if (error) 1697101003Srwatson return (error); 1698101003Srwatson#endif 169992976Srwatson if (cr_seeotheruids(cred, so->so_cred)) 170092976Srwatson return (ENOENT); 1701122869Srwatson if (cr_seeothergids(cred, so->so_cred)) 1702122869Srwatson return (ENOENT); 170392976Srwatson 170492976Srwatson return (0); 170592976Srwatson} 170692976Srwatson 1707145234Srwatson/*- 1708145234Srwatson * Determine whether td can wait for the exit of p. 1709145234Srwatson * Returns: 0 for permitted, an errno value otherwise 1710145234Srwatson * Locks: Sufficient locks to protect various components of td and p 1711145234Srwatson * must be held. td must be curthread, and a lock must 1712145234Srwatson * be held for p. 1713145234Srwatson * References: td and p must be valid for the lifetime of the call 1714145234Srwatson 1715145234Srwatson */ 1716145234Srwatsonint 1717145234Srwatsonp_canwait(struct thread *td, struct proc *p) 1718145234Srwatson{ 1719145234Srwatson int error; 1720145234Srwatson 1721145234Srwatson KASSERT(td == curthread, ("%s: td not curthread", __func__)); 1722145234Srwatson PROC_LOCK_ASSERT(p, MA_OWNED); 1723145234Srwatson if ((error = prison_check(td->td_ucred, p->p_ucred))) 1724145234Srwatson return (error); 1725145234Srwatson#ifdef MAC 1726145234Srwatson if ((error = mac_check_proc_wait(td->td_ucred, p))) 1727145234Srwatson return (error); 1728145234Srwatson#endif 1729145234Srwatson#if 0 1730145234Srwatson /* XXXMAC: This could have odd effects on some shells. */ 1731145234Srwatson if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) 1732145234Srwatson return (error); 1733145234Srwatson#endif 1734145234Srwatson 1735145234Srwatson return (0); 1736145234Srwatson} 1737145234Srwatson 173853518Sphk/* 17391541Srgrimes * Allocate a zeroed cred structure. 17401541Srgrimes */ 17411541Srgrimesstruct ucred * 174293580Sjhbcrget(void) 17431541Srgrimes{ 17441541Srgrimes register struct ucred *cr; 17451541Srgrimes 1746111119Simp MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK | M_ZERO); 1747150634Sjhb refcount_init(&cr->cr_ref, 1); 1748170407Srwatson#ifdef AUDIT 1749170407Srwatson audit_cred_init(cr); 1750170407Srwatson#endif 1751101001Srwatson#ifdef MAC 1752101001Srwatson mac_init_cred(cr); 1753101001Srwatson#endif 17541541Srgrimes return (cr); 17551541Srgrimes} 17561541Srgrimes 17571541Srgrimes/* 175882466Srwatson * Claim another reference to a ucred structure. 175969401Salfred */ 176084827Sjhbstruct ucred * 176193580Sjhbcrhold(struct ucred *cr) 176269401Salfred{ 176369401Salfred 1764150634Sjhb refcount_acquire(&cr->cr_ref); 176584827Sjhb return (cr); 176669401Salfred} 176769401Salfred 176869401Salfred/* 1769167211Srwatson * Free a cred structure. Throws away space when ref count gets to 0. 17701541Srgrimes */ 17711549Srgrimesvoid 177293580Sjhbcrfree(struct ucred *cr) 17731541Srgrimes{ 177469239Salfred 177575632Salfred KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref)); 1776150634Sjhb KASSERT(cr->cr_ref != 0xdeadc0de, ("dangling reference to ucred")); 1777150634Sjhb if (refcount_release(&cr->cr_ref)) { 177865495Struckman /* 177965495Struckman * Some callers of crget(), such as nfs_statfs(), 178065495Struckman * allocate a temporary credential, but don't 178165495Struckman * allocate a uidinfo structure. 178265495Struckman */ 178365495Struckman if (cr->cr_uidinfo != NULL) 178465495Struckman uifree(cr->cr_uidinfo); 178577277Srwatson if (cr->cr_ruidinfo != NULL) 178677277Srwatson uifree(cr->cr_ruidinfo); 178772786Srwatson /* 178872786Srwatson * Free a prison, if any. 178972786Srwatson */ 179072786Srwatson if (jailed(cr)) 179172786Srwatson prison_free(cr->cr_prison); 1792170407Srwatson#ifdef AUDIT 1793170407Srwatson audit_cred_destroy(cr); 1794170407Srwatson#endif 1795101001Srwatson#ifdef MAC 1796101001Srwatson mac_destroy_cred(cr); 1797101001Srwatson#endif 179899009Salfred FREE(cr, M_CRED); 179990756Sdillon } 18001541Srgrimes} 18011541Srgrimes 18021541Srgrimes/* 180384827Sjhb * Check to see if this ucred is shared. 18041541Srgrimes */ 180584827Sjhbint 180693580Sjhbcrshared(struct ucred *cr) 18071541Srgrimes{ 18081541Srgrimes 1809150634Sjhb return (cr->cr_ref > 1); 18101541Srgrimes} 18111541Srgrimes 18121541Srgrimes/* 181384827Sjhb * Copy a ucred's contents from a template. Does not block. 181484827Sjhb */ 181584827Sjhbvoid 181693580Sjhbcrcopy(struct ucred *dest, struct ucred *src) 181784827Sjhb{ 181884827Sjhb 181984827Sjhb KASSERT(crshared(dest) == 0, ("crcopy of shared ucred")); 182084827Sjhb bcopy(&src->cr_startcopy, &dest->cr_startcopy, 182187218Srwatson (unsigned)((caddr_t)&src->cr_endcopy - 182284827Sjhb (caddr_t)&src->cr_startcopy)); 182384827Sjhb uihold(dest->cr_uidinfo); 182484827Sjhb uihold(dest->cr_ruidinfo); 182584827Sjhb if (jailed(dest)) 182684827Sjhb prison_hold(dest->cr_prison); 1827170407Srwatson#ifdef AUDIT 1828170407Srwatson audit_cred_copy(src, dest); 1829170407Srwatson#endif 1830101001Srwatson#ifdef MAC 1831123173Srwatson mac_copy_cred(src, dest); 1832101001Srwatson#endif 183384827Sjhb} 183484827Sjhb 183584827Sjhb/* 18361541Srgrimes * Dup cred struct to a new held one. 18371541Srgrimes */ 18381541Srgrimesstruct ucred * 183993580Sjhbcrdup(struct ucred *cr) 18401541Srgrimes{ 18411541Srgrimes struct ucred *newcr; 18421541Srgrimes 184384827Sjhb newcr = crget(); 184484827Sjhb crcopy(newcr, cr); 18451541Srgrimes return (newcr); 18461541Srgrimes} 18471541Srgrimes 18481541Srgrimes/* 184991354Sdd * Fill in a struct xucred based on a struct ucred. 185091354Sdd */ 185191354Sddvoid 185293580Sjhbcru2x(struct ucred *cr, struct xucred *xcr) 185391354Sdd{ 185491354Sdd 185591354Sdd bzero(xcr, sizeof(*xcr)); 185691354Sdd xcr->cr_version = XUCRED_VERSION; 185791354Sdd xcr->cr_uid = cr->cr_uid; 185891354Sdd xcr->cr_ngroups = cr->cr_ngroups; 185991354Sdd bcopy(cr->cr_groups, xcr->cr_groups, sizeof(cr->cr_groups)); 186091354Sdd} 186191354Sdd 186291354Sdd/* 1863167211Srwatson * small routine to swap a thread's current ucred for the correct one taken 1864167211Srwatson * from the process. 186590748Sjulian */ 186690748Sjulianvoid 186790748Sjuliancred_update_thread(struct thread *td) 186890748Sjulian{ 186990748Sjulian struct proc *p; 187091405Sjhb struct ucred *cred; 187190748Sjulian 187290748Sjulian p = td->td_proc; 187391405Sjhb cred = td->td_ucred; 187490748Sjulian PROC_LOCK(p); 187590748Sjulian td->td_ucred = crhold(p->p_ucred); 187690748Sjulian PROC_UNLOCK(p); 187791405Sjhb if (cred != NULL) 187891405Sjhb crfree(cred); 187990748Sjulian} 188090748Sjulian 188190748Sjulian/* 18821541Srgrimes * Get login name, if available. 18831541Srgrimes */ 188412221Sbde#ifndef _SYS_SYSPROTO_H_ 18851541Srgrimesstruct getlogin_args { 18861541Srgrimes char *namebuf; 18871541Srgrimes u_int namelen; 18881541Srgrimes}; 188912221Sbde#endif 18901541Srgrimes/* ARGSUSED */ 18911549Srgrimesint 189293580Sjhbgetlogin(struct thread *td, struct getlogin_args *uap) 18931541Srgrimes{ 189482749Sdillon int error; 189591140Stanimura char login[MAXLOGNAME]; 189683366Sjulian struct proc *p = td->td_proc; 18971541Srgrimes 189823358Sache if (uap->namelen > MAXLOGNAME) 189923359Sache uap->namelen = MAXLOGNAME; 190091140Stanimura PROC_LOCK(p); 190191140Stanimura SESS_LOCK(p->p_session); 190291140Stanimura bcopy(p->p_session->s_login, login, uap->namelen); 190391140Stanimura SESS_UNLOCK(p->p_session); 190491140Stanimura PROC_UNLOCK(p); 190599009Salfred error = copyout(login, uap->namebuf, uap->namelen); 190682749Sdillon return(error); 19071541Srgrimes} 19081541Srgrimes 19091541Srgrimes/* 19101541Srgrimes * Set login name. 19111541Srgrimes */ 191212221Sbde#ifndef _SYS_SYSPROTO_H_ 19131541Srgrimesstruct setlogin_args { 19141541Srgrimes char *namebuf; 19151541Srgrimes}; 191612221Sbde#endif 19171541Srgrimes/* ARGSUSED */ 19181549Srgrimesint 191993580Sjhbsetlogin(struct thread *td, struct setlogin_args *uap) 19201541Srgrimes{ 192183366Sjulian struct proc *p = td->td_proc; 19221541Srgrimes int error; 192323330Sache char logintmp[MAXLOGNAME]; 19241541Srgrimes 1925170587Srwatson error = priv_check(td, PRIV_PROC_SETLOGIN); 192694619Sjhb if (error) 192794619Sjhb return (error); 192899009Salfred error = copyinstr(uap->namebuf, logintmp, sizeof(logintmp), NULL); 192987218Srwatson if (error == ENAMETOOLONG) 19301541Srgrimes error = EINVAL; 193191140Stanimura else if (!error) { 193291140Stanimura PROC_LOCK(p); 193391140Stanimura SESS_LOCK(p->p_session); 193491140Stanimura (void) memcpy(p->p_session->s_login, logintmp, 193523330Sache sizeof(logintmp)); 193691140Stanimura SESS_UNLOCK(p->p_session); 193791140Stanimura PROC_UNLOCK(p); 193891140Stanimura } 19391541Srgrimes return (error); 19401541Srgrimes} 194131891Ssef 194231891Ssefvoid 194393580Sjhbsetsugid(struct proc *p) 194431891Ssef{ 194598403Salfred 194698403Salfred PROC_LOCK_ASSERT(p, MA_OWNED); 194731891Ssef p->p_flag |= P_SUGID; 194855707Ssef if (!(p->p_pfsflags & PF_ISUGID)) 194931891Ssef p->p_stops = 0; 195031891Ssef} 195165495Struckman 195282466Srwatson/*- 195382466Srwatson * Change a process's effective uid. 195477183Srwatson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified. 195577183Srwatson * References: newcred must be an exclusive credential reference for the 195677183Srwatson * duration of the call. 195765495Struckman */ 195865495Struckmanvoid 195998417Salfredchange_euid(struct ucred *newcred, struct uidinfo *euip) 196065495Struckman{ 196165495Struckman 196298417Salfred newcred->cr_uid = euip->ui_uid; 196398417Salfred uihold(euip); 196477183Srwatson uifree(newcred->cr_uidinfo); 196598417Salfred newcred->cr_uidinfo = euip; 196665495Struckman} 196765495Struckman 196882466Srwatson/*- 196982466Srwatson * Change a process's effective gid. 197077183Srwatson * Side effects: newcred->cr_gid will be modified. 197177183Srwatson * References: newcred must be an exclusive credential reference for the 197277183Srwatson * duration of the call. 197365495Struckman */ 197467629Sgallatinvoid 197593580Sjhbchange_egid(struct ucred *newcred, gid_t egid) 197665495Struckman{ 197765495Struckman 197877183Srwatson newcred->cr_groups[0] = egid; 197965495Struckman} 198077183Srwatson 198182466Srwatson/*- 198282466Srwatson * Change a process's real uid. 198377183Srwatson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo 198477183Srwatson * will be updated, and the old and new cr_ruidinfo proc 198577183Srwatson * counts will be updated. 198677183Srwatson * References: newcred must be an exclusive credential reference for the 198777183Srwatson * duration of the call. 198877183Srwatson */ 198977183Srwatsonvoid 199098417Salfredchange_ruid(struct ucred *newcred, struct uidinfo *ruip) 199177183Srwatson{ 199277183Srwatson 199377183Srwatson (void)chgproccnt(newcred->cr_ruidinfo, -1, 0); 199498417Salfred newcred->cr_ruid = ruip->ui_uid; 199598417Salfred uihold(ruip); 199677183Srwatson uifree(newcred->cr_ruidinfo); 199798417Salfred newcred->cr_ruidinfo = ruip; 199877183Srwatson (void)chgproccnt(newcred->cr_ruidinfo, 1, 0); 199977183Srwatson} 200077183Srwatson 200182466Srwatson/*- 200282466Srwatson * Change a process's real gid. 200377183Srwatson * Side effects: newcred->cr_rgid will be updated. 200477183Srwatson * References: newcred must be an exclusive credential reference for the 200577183Srwatson * duration of the call. 200677183Srwatson */ 200777183Srwatsonvoid 200893580Sjhbchange_rgid(struct ucred *newcred, gid_t rgid) 200977183Srwatson{ 201077183Srwatson 201177183Srwatson newcred->cr_rgid = rgid; 201277183Srwatson} 201377183Srwatson 201482466Srwatson/*- 201582466Srwatson * Change a process's saved uid. 201677183Srwatson * Side effects: newcred->cr_svuid will be updated. 201777183Srwatson * References: newcred must be an exclusive credential reference for the 201877183Srwatson * duration of the call. 201977183Srwatson */ 202077183Srwatsonvoid 202193580Sjhbchange_svuid(struct ucred *newcred, uid_t svuid) 202277183Srwatson{ 202377183Srwatson 202477183Srwatson newcred->cr_svuid = svuid; 202577183Srwatson} 202677183Srwatson 202782466Srwatson/*- 202882466Srwatson * Change a process's saved gid. 202977183Srwatson * Side effects: newcred->cr_svgid will be updated. 203077183Srwatson * References: newcred must be an exclusive credential reference for the 203177183Srwatson * duration of the call. 203277183Srwatson */ 203377183Srwatsonvoid 203493580Sjhbchange_svgid(struct ucred *newcred, gid_t svgid) 203577183Srwatson{ 203677183Srwatson 203777183Srwatson newcred->cr_svgid = svgid; 203877183Srwatson} 2039