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: stable/11/sys/kern/kern_prot.c 335536 2018-06-22 09:18:38Z avg $"); 46116182Sobrien 4731778Seivind#include "opt_compat.h" 48183982Sbz#include "opt_inet.h" 49183982Sbz#include "opt_inet6.h" 5031778Seivind 511541Srgrimes#include <sys/param.h> 5276166Smarkm#include <sys/systm.h> 531541Srgrimes#include <sys/acct.h> 54132548Srwatson#include <sys/kdb.h> 5541059Speter#include <sys/kernel.h> 5670317Sjake#include <sys/lock.h> 57219304Strasz#include <sys/loginclass.h> 5891140Stanimura#include <sys/malloc.h> 5976166Smarkm#include <sys/mutex.h> 60150634Sjhb#include <sys/refcount.h> 6191140Stanimura#include <sys/sx.h> 62164032Srwatson#include <sys/priv.h> 631541Srgrimes#include <sys/proc.h> 6476166Smarkm#include <sys/sysproto.h> 6587218Srwatson#include <sys/jail.h> 6631891Ssef#include <sys/pioctl.h> 67220212Strasz#include <sys/racct.h> 68335536Savg#include <sys/rctl.h> 6965495Struckman#include <sys/resourcevar.h> 7092976Srwatson#include <sys/socket.h> 7192976Srwatson#include <sys/socketvar.h> 72160139Sjhb#include <sys/syscallsubr.h> 7361287Srwatson#include <sys/sysctl.h> 741541Srgrimes 75219028Snetchild#ifdef REGRESSION 76219028SnetchildFEATURE(regression, 77229818Shrs "Kernel support for interfaces necessary for regression testing (SECURITY RISK!)"); 78219028Snetchild#endif 79219028Snetchild 80183982Sbz#if defined(INET) || defined(INET6) 81183982Sbz#include <netinet/in.h> 82183982Sbz#include <netinet/in_pcb.h> 83183982Sbz#endif 84183982Sbz 85155370Swsalamon#include <security/audit/audit.h> 86163606Srwatson#include <security/mac/mac_framework.h> 87155370Swsalamon 8830354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials"); 8930354Sphk 90162383SrwatsonSYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0, "BSD security policy"); 9187138Srwatson 92194498Sbrooksstatic void crsetgroups_locked(struct ucred *cr, int ngrp, 93194498Sbrooks gid_t *groups); 94194498Sbrooks 9512221Sbde#ifndef _SYS_SYSPROTO_H_ 9611332Sswallacestruct getpid_args { 971541Srgrimes int dummy; 981541Srgrimes}; 9912221Sbde#endif 1001541Srgrimes/* ARGSUSED */ 1011549Srgrimesint 102225617Skmacysys_getpid(struct thread *td, struct getpid_args *uap) 1031541Srgrimes{ 10483366Sjulian struct proc *p = td->td_proc; 1051541Srgrimes 10683366Sjulian td->td_retval[0] = p->p_pid; 107130344Sphk#if defined(COMPAT_43) 108270444Smjg td->td_retval[1] = kern_getppid(td); 1091541Srgrimes#endif 1101541Srgrimes return (0); 1111541Srgrimes} 1121541Srgrimes 11312221Sbde#ifndef _SYS_SYSPROTO_H_ 11411332Sswallacestruct getppid_args { 11511332Sswallace int dummy; 11611332Sswallace}; 11712221Sbde#endif 1181541Srgrimes/* ARGSUSED */ 1191549Srgrimesint 120225617Skmacysys_getppid(struct thread *td, struct getppid_args *uap) 1211541Srgrimes{ 122270444Smjg 123270444Smjg td->td_retval[0] = kern_getppid(td); 124270444Smjg return (0); 125270444Smjg} 126270444Smjg 127270444Smjgint 128270444Smjgkern_getppid(struct thread *td) 129270444Smjg{ 13083366Sjulian struct proc *p = td->td_proc; 131270444Smjg struct proc *pp; 132270444Smjg int ppid; 1331541Srgrimes 13474728Sjhb PROC_LOCK(p); 135270444Smjg if (!(p->p_flag & P_TRACED)) { 136270444Smjg ppid = p->p_pptr->p_pid; 137270444Smjg PROC_UNLOCK(p); 138270444Smjg } else { 139270444Smjg PROC_UNLOCK(p); 140270444Smjg sx_slock(&proctree_lock); 141270444Smjg pp = proc_realparent(p); 142270444Smjg ppid = pp->p_pid; 143270444Smjg sx_sunlock(&proctree_lock); 144270444Smjg } 145270444Smjg 146270444Smjg return (ppid); 1471541Srgrimes} 1481541Srgrimes 14987466Srwatson/* 15087218Srwatson * Get process group ID; note that POSIX getpgrp takes no parameter. 15158717Sdillon */ 15212221Sbde#ifndef _SYS_SYSPROTO_H_ 15311332Sswallacestruct getpgrp_args { 15411332Sswallace int dummy; 15511332Sswallace}; 15612221Sbde#endif 1571549Srgrimesint 158225617Skmacysys_getpgrp(struct thread *td, struct getpgrp_args *uap) 1591541Srgrimes{ 16083366Sjulian struct proc *p = td->td_proc; 1611541Srgrimes 16291140Stanimura PROC_LOCK(p); 16383366Sjulian td->td_retval[0] = p->p_pgrp->pg_id; 16491140Stanimura PROC_UNLOCK(p); 1651541Srgrimes return (0); 1661541Srgrimes} 1671541Srgrimes 168298819Spfg/* Get an arbitrary pid's process group id */ 16912221Sbde#ifndef _SYS_SYSPROTO_H_ 17028401Speterstruct getpgid_args { 17128401Speter pid_t pid; 17228401Speter}; 17328401Speter#endif 17428401Speterint 175225617Skmacysys_getpgid(struct thread *td, struct getpgid_args *uap) 17628401Speter{ 177114031Sjhb struct proc *p; 17892985Sjhb int error; 17941726Struckman 18091140Stanimura if (uap->pid == 0) { 181114031Sjhb p = td->td_proc; 18291140Stanimura PROC_LOCK(p); 183114031Sjhb } else { 184114031Sjhb p = pfind(uap->pid); 185114031Sjhb if (p == NULL) 186114031Sjhb return (ESRCH); 187114031Sjhb error = p_cansee(td, p); 188114031Sjhb if (error) { 189114031Sjhb PROC_UNLOCK(p); 190114031Sjhb return (error); 191114031Sjhb } 19275893Sjhb } 193114031Sjhb td->td_retval[0] = p->p_pgrp->pg_id; 194114031Sjhb PROC_UNLOCK(p); 195114031Sjhb return (0); 19628401Speter} 19728401Speter 19828401Speter/* 199298819Spfg * Get an arbitrary pid's session id. 20028401Speter */ 20128401Speter#ifndef _SYS_SYSPROTO_H_ 20228401Speterstruct getsid_args { 20328401Speter pid_t pid; 20428401Speter}; 20528401Speter#endif 20628401Speterint 207225617Skmacysys_getsid(struct thread *td, struct getsid_args *uap) 20828401Speter{ 209114031Sjhb struct proc *p; 21087218Srwatson int error; 21141726Struckman 21291140Stanimura if (uap->pid == 0) { 213114031Sjhb p = td->td_proc; 21491140Stanimura PROC_LOCK(p); 215114031Sjhb } else { 216114031Sjhb p = pfind(uap->pid); 217114031Sjhb if (p == NULL) 218114031Sjhb return (ESRCH); 219114031Sjhb error = p_cansee(td, p); 220114031Sjhb if (error) { 221114031Sjhb PROC_UNLOCK(p); 222114031Sjhb return (error); 223114031Sjhb } 22475893Sjhb } 225114031Sjhb td->td_retval[0] = p->p_session->s_sid; 226114031Sjhb PROC_UNLOCK(p); 227114031Sjhb return (0); 22828401Speter} 22928401Speter 23028401Speter#ifndef _SYS_SYSPROTO_H_ 23111332Sswallacestruct getuid_args { 23211332Sswallace int dummy; 23311332Sswallace}; 23412221Sbde#endif 2351541Srgrimes/* ARGSUSED */ 2361549Srgrimesint 237225617Skmacysys_getuid(struct thread *td, struct getuid_args *uap) 2381541Srgrimes{ 2391541Srgrimes 24092987Sjhb td->td_retval[0] = td->td_ucred->cr_ruid; 241130344Sphk#if defined(COMPAT_43) 24292987Sjhb td->td_retval[1] = td->td_ucred->cr_uid; 2431541Srgrimes#endif 2441541Srgrimes return (0); 2451541Srgrimes} 2461541Srgrimes 24712221Sbde#ifndef _SYS_SYSPROTO_H_ 24811332Sswallacestruct geteuid_args { 24911332Sswallace int dummy; 25011332Sswallace}; 25112221Sbde#endif 2521541Srgrimes/* ARGSUSED */ 2531549Srgrimesint 254225617Skmacysys_geteuid(struct thread *td, struct geteuid_args *uap) 2551541Srgrimes{ 25692987Sjhb 25792987Sjhb td->td_retval[0] = td->td_ucred->cr_uid; 2581541Srgrimes return (0); 2591541Srgrimes} 2601541Srgrimes 26112221Sbde#ifndef _SYS_SYSPROTO_H_ 26211332Sswallacestruct getgid_args { 26311332Sswallace int dummy; 26411332Sswallace}; 26512221Sbde#endif 2661541Srgrimes/* ARGSUSED */ 2671549Srgrimesint 268225617Skmacysys_getgid(struct thread *td, struct getgid_args *uap) 2691541Srgrimes{ 2701541Srgrimes 27192987Sjhb td->td_retval[0] = td->td_ucred->cr_rgid; 272130344Sphk#if defined(COMPAT_43) 27392987Sjhb td->td_retval[1] = td->td_ucred->cr_groups[0]; 2741541Srgrimes#endif 2751541Srgrimes return (0); 2761541Srgrimes} 2771541Srgrimes 2781541Srgrimes/* 2791541Srgrimes * Get effective group ID. The "egid" is groups[0], and could be obtained 2801541Srgrimes * via getgroups. This syscall exists because it is somewhat painful to do 2811541Srgrimes * correctly in a library function. 2821541Srgrimes */ 28312221Sbde#ifndef _SYS_SYSPROTO_H_ 28411332Sswallacestruct getegid_args { 28511332Sswallace int dummy; 28611332Sswallace}; 28712221Sbde#endif 2881541Srgrimes/* ARGSUSED */ 2891549Srgrimesint 290225617Skmacysys_getegid(struct thread *td, struct getegid_args *uap) 2911541Srgrimes{ 2921541Srgrimes 29392987Sjhb td->td_retval[0] = td->td_ucred->cr_groups[0]; 2941541Srgrimes return (0); 2951541Srgrimes} 2961541Srgrimes 29712221Sbde#ifndef _SYS_SYSPROTO_H_ 2981541Srgrimesstruct getgroups_args { 2991541Srgrimes u_int gidsetsize; 3001541Srgrimes gid_t *gidset; 3011541Srgrimes}; 30212221Sbde#endif 3031549Srgrimesint 304331643Sdimsys_getgroups(struct thread *td, struct getgroups_args *uap) 3051541Srgrimes{ 306273436Smjg struct ucred *cred; 30777183Srwatson u_int ngrp; 30887218Srwatson int error; 3091541Srgrimes 310273436Smjg cred = td->td_ucred; 311273436Smjg ngrp = cred->cr_ngroups; 312273436Smjg 313273436Smjg if (uap->gidsetsize == 0) { 314273436Smjg error = 0; 315194498Sbrooks goto out; 316273436Smjg } 317273436Smjg if (uap->gidsetsize < ngrp) 318273436Smjg return (EINVAL); 319273436Smjg 320273436Smjg error = copyout(cred->cr_groups, uap->gidset, ngrp * sizeof(gid_t)); 321194498Sbrooksout: 322273436Smjg td->td_retval[0] = ngrp; 323160139Sjhb return (error); 324160139Sjhb} 325160139Sjhb 32612221Sbde#ifndef _SYS_SYSPROTO_H_ 32712207Sbdestruct setsid_args { 32811332Sswallace int dummy; 32911332Sswallace}; 33012221Sbde#endif 3311541Srgrimes/* ARGSUSED */ 3321549Srgrimesint 333331643Sdimsys_setsid(struct thread *td, struct setsid_args *uap) 3341541Srgrimes{ 33591140Stanimura struct pgrp *pgrp; 33682749Sdillon int error; 33783366Sjulian struct proc *p = td->td_proc; 33891140Stanimura struct pgrp *newpgrp; 33991140Stanimura struct session *newsess; 3401541Srgrimes 34191140Stanimura error = 0; 34291140Stanimura pgrp = NULL; 34391140Stanimura 344184205Sdes newpgrp = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); 345184205Sdes newsess = malloc(sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO); 34691140Stanimura 34794859Sjhb sx_xlock(&proctree_lock); 34891140Stanimura 34991140Stanimura if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) { 35091140Stanimura if (pgrp != NULL) 35191140Stanimura PGRP_UNLOCK(pgrp); 35282749Sdillon error = EPERM; 35391140Stanimura } else { 35491140Stanimura (void)enterpgrp(p, p->p_pid, newpgrp, newsess); 35583366Sjulian td->td_retval[0] = p->p_pid; 35694859Sjhb newpgrp = NULL; 35794859Sjhb newsess = NULL; 3581541Srgrimes } 35991140Stanimura 36094859Sjhb sx_xunlock(&proctree_lock); 36191140Stanimura 36295973Stanimura if (newpgrp != NULL) 363184205Sdes free(newpgrp, M_PGRP); 36495973Stanimura if (newsess != NULL) 365184205Sdes free(newsess, M_SESSION); 36691140Stanimura 36794859Sjhb return (error); 3681541Srgrimes} 3691541Srgrimes 3701541Srgrimes/* 3711541Srgrimes * set process group (setpgid/old setpgrp) 3721541Srgrimes * 3731541Srgrimes * caller does setpgid(targpid, targpgid) 3741541Srgrimes * 3751541Srgrimes * pid must be caller or child of caller (ESRCH) 3761541Srgrimes * if a child 3771541Srgrimes * pid must be in same session (EPERM) 3781541Srgrimes * pid can't have done an exec (EACCES) 3791541Srgrimes * if pgid != pid 3801541Srgrimes * there must exist some pid in same session having pgid (EPERM) 3811541Srgrimes * pid must not be session leader (EPERM) 3821541Srgrimes */ 38312221Sbde#ifndef _SYS_SYSPROTO_H_ 3841541Srgrimesstruct setpgid_args { 38587218Srwatson int pid; /* target process id */ 38687218Srwatson int pgid; /* target pgrp id */ 3871541Srgrimes}; 38812221Sbde#endif 3891541Srgrimes/* ARGSUSED */ 3901549Srgrimesint 391331643Sdimsys_setpgid(struct thread *td, struct setpgid_args *uap) 3921541Srgrimes{ 39383366Sjulian struct proc *curp = td->td_proc; 394331643Sdim struct proc *targp; /* target process */ 395331643Sdim struct pgrp *pgrp; /* target pgrp */ 39675448Srwatson int error; 39791140Stanimura struct pgrp *newpgrp; 3981541Srgrimes 39920677Sbde if (uap->pgid < 0) 40020677Sbde return (EINVAL); 40191140Stanimura 40291140Stanimura error = 0; 40391140Stanimura 404184205Sdes newpgrp = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); 40591140Stanimura 40694859Sjhb sx_xlock(&proctree_lock); 4071541Srgrimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 40891140Stanimura if ((targp = pfind(uap->pid)) == NULL) { 40982749Sdillon error = ESRCH; 41094859Sjhb goto done; 41175893Sjhb } 41291140Stanimura if (!inferior(targp)) { 41391140Stanimura PROC_UNLOCK(targp); 41491371Stanimura error = ESRCH; 41594859Sjhb goto done; 41691140Stanimura } 417132568Srwatson if ((error = p_cansee(td, targp))) { 41875893Sjhb PROC_UNLOCK(targp); 41994859Sjhb goto done; 42075893Sjhb } 42175893Sjhb if (targp->p_pgrp == NULL || 42275893Sjhb targp->p_session != curp->p_session) { 42375893Sjhb PROC_UNLOCK(targp); 42482749Sdillon error = EPERM; 42594859Sjhb goto done; 42675893Sjhb } 42775893Sjhb if (targp->p_flag & P_EXEC) { 42875893Sjhb PROC_UNLOCK(targp); 42982749Sdillon error = EACCES; 43094859Sjhb goto done; 43175893Sjhb } 43291140Stanimura PROC_UNLOCK(targp); 43391140Stanimura } else 4341541Srgrimes targp = curp; 43575893Sjhb if (SESS_LEADER(targp)) { 43682749Sdillon error = EPERM; 43794859Sjhb goto done; 43875893Sjhb } 43987218Srwatson if (uap->pgid == 0) 4401541Srgrimes uap->pgid = targp->p_pid; 441117214Scognet if ((pgrp = pgfind(uap->pgid)) == NULL) { 442117214Scognet if (uap->pgid == targp->p_pid) { 443117214Scognet error = enterpgrp(targp, uap->pgid, newpgrp, 444117214Scognet NULL); 445117214Scognet if (error == 0) 446117214Scognet newpgrp = NULL; 447117214Scognet } else 448117214Scognet error = EPERM; 44991140Stanimura } else { 450117214Scognet if (pgrp == targp->p_pgrp) { 451117214Scognet PGRP_UNLOCK(pgrp); 45294859Sjhb goto done; 45375893Sjhb } 454117214Scognet if (pgrp->pg_id != targp->p_pid && 455117214Scognet pgrp->pg_session != curp->p_session) { 45691140Stanimura PGRP_UNLOCK(pgrp); 457117214Scognet error = EPERM; 45891140Stanimura goto done; 45991140Stanimura } 46091140Stanimura PGRP_UNLOCK(pgrp); 46191140Stanimura error = enterthispgrp(targp, pgrp); 46282749Sdillon } 46391140Stanimuradone: 46494859Sjhb sx_xunlock(&proctree_lock); 46594859Sjhb KASSERT((error == 0) || (newpgrp != NULL), 46694859Sjhb ("setpgid failed and newpgrp is NULL")); 46795973Stanimura if (newpgrp != NULL) 468184205Sdes free(newpgrp, M_PGRP); 46982749Sdillon return (error); 4701541Srgrimes} 4711541Srgrimes 47224448Speter/* 47324448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 47472093Sasmodai * compatible. It says that setting the uid/gid to euid/egid is a special 47524448Speter * case of "appropriate privilege". Once the rules are expanded out, this 47624448Speter * basically means that setuid(nnn) sets all three id's, in all permitted 47724448Speter * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 47824448Speter * does not set the saved id - this is dangerous for traditional BSD 47924448Speter * programs. For this reason, we *really* do not want to set 48024448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 48124448Speter */ 48224448Speter#define POSIX_APPENDIX_B_4_2_2 48324448Speter 48412221Sbde#ifndef _SYS_SYSPROTO_H_ 4851541Srgrimesstruct setuid_args { 4861541Srgrimes uid_t uid; 4871541Srgrimes}; 48812221Sbde#endif 4891541Srgrimes/* ARGSUSED */ 4901549Srgrimesint 491225617Skmacysys_setuid(struct thread *td, struct setuid_args *uap) 4921541Srgrimes{ 49383366Sjulian struct proc *p = td->td_proc; 49477183Srwatson struct ucred *newcred, *oldcred; 49577183Srwatson uid_t uid; 49698417Salfred struct uidinfo *uip; 49787218Srwatson int error; 4981541Srgrimes 49977183Srwatson uid = uap->uid; 500195104Srwatson AUDIT_ARG_UID(uid); 50194619Sjhb newcred = crget(); 50298417Salfred uip = uifind(uid); 50394619Sjhb PROC_LOCK(p); 504194498Sbrooks /* 505194498Sbrooks * Copy credentials so other references do not see our changes. 506194498Sbrooks */ 507194498Sbrooks oldcred = crcopysafe(p, newcred); 50887466Srwatson 509145147Srwatson#ifdef MAC 510189529Srwatson error = mac_cred_check_setuid(oldcred, uid); 511145147Srwatson if (error) 512145147Srwatson goto fail; 513145147Srwatson#endif 514145147Srwatson 51524448Speter /* 51624448Speter * See if we have "permission" by POSIX 1003.1 rules. 51724448Speter * 51887218Srwatson * Note that setuid(geteuid()) is a special case of 51924448Speter * "appropriate privileges" in appendix B.4.2.2. We need 52072093Sasmodai * to use this clause to be compatible with traditional BSD 52124448Speter * semantics. Basically, it means that "setuid(xx)" sets all 52224448Speter * three id's (assuming you have privs). 52324448Speter * 52424448Speter * Notes on the logic. We do things in three steps. 52524448Speter * 1: We determine if the euid is going to change, and do EPERM 52624448Speter * right away. We unconditionally change the euid later if this 52724448Speter * test is satisfied, simplifying that part of the logic. 52887218Srwatson * 2: We determine if the real and/or saved uids are going to 52924448Speter * change. Determined by compile options. 53024448Speter * 3: Change euid last. (after tests in #2 for "appropriate privs") 53124448Speter */ 53277183Srwatson if (uid != oldcred->cr_ruid && /* allow setuid(getuid()) */ 53317994Sache#ifdef _POSIX_SAVED_IDS 53477183Srwatson uid != oldcred->cr_svuid && /* allow setuid(saved gid) */ 53517994Sache#endif 53624448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 53777183Srwatson uid != oldcred->cr_uid && /* allow setuid(geteuid()) */ 53824448Speter#endif 539170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETUID, 0)) != 0) 540145147Srwatson goto fail; 54124448Speter 54224448Speter#ifdef _POSIX_SAVED_IDS 5431541Srgrimes /* 54424448Speter * Do we have "appropriate privileges" (are we root or uid == euid) 54524448Speter * If so, we are changing the real uid and/or saved uid. 5461541Srgrimes */ 54717994Sache if ( 54824448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 54977183Srwatson uid == oldcred->cr_uid || 55017994Sache#endif 551164032Srwatson /* We are using privs. */ 552170587Srwatson priv_check_cred(oldcred, PRIV_CRED_SETUID, 0) == 0) 55317994Sache#endif 55424448Speter { 55524448Speter /* 55665495Struckman * Set the real uid and transfer proc count to new user. 55724448Speter */ 55877183Srwatson if (uid != oldcred->cr_ruid) { 55998417Salfred change_ruid(newcred, uip); 56065495Struckman setsugid(p); 56124448Speter } 56224448Speter /* 56324448Speter * Set saved uid 56424448Speter * 56524448Speter * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 56624448Speter * the security of seteuid() depends on it. B.4.2.2 says it 56724448Speter * is important that we should do this. 56824448Speter */ 56977183Srwatson if (uid != oldcred->cr_svuid) { 57077183Srwatson change_svuid(newcred, uid); 57131891Ssef setsugid(p); 57224448Speter } 5738141Sache } 57424448Speter 57524448Speter /* 57624448Speter * In all permitted cases, we are changing the euid. 57724448Speter */ 57877183Srwatson if (uid != oldcred->cr_uid) { 57998417Salfred change_euid(newcred, uip); 58031891Ssef setsugid(p); 58124448Speter } 582280130Smjg proc_set_cred(p, newcred); 583220212Strasz#ifdef RACCT 584220212Strasz racct_proc_ucred_changed(p, oldcred, newcred); 585335536Savg crhold(newcred); 586220212Strasz#endif 587335536Savg PROC_UNLOCK(p); 588335536Savg#ifdef RCTL 589335536Savg rctl_proc_ucred_changed(p, newcred); 590335536Savg crfree(newcred); 591335536Savg#endif 59298417Salfred uifree(uip); 59377183Srwatson crfree(oldcred); 59494619Sjhb return (0); 595145147Srwatson 596145147Srwatsonfail: 597145147Srwatson PROC_UNLOCK(p); 598145147Srwatson uifree(uip); 599145147Srwatson crfree(newcred); 600145147Srwatson return (error); 6011541Srgrimes} 6021541Srgrimes 60312221Sbde#ifndef _SYS_SYSPROTO_H_ 6041541Srgrimesstruct seteuid_args { 6051541Srgrimes uid_t euid; 6061541Srgrimes}; 60712221Sbde#endif 6081541Srgrimes/* ARGSUSED */ 6091549Srgrimesint 610225617Skmacysys_seteuid(struct thread *td, struct seteuid_args *uap) 6111541Srgrimes{ 61283366Sjulian struct proc *p = td->td_proc; 61377183Srwatson struct ucred *newcred, *oldcred; 61477183Srwatson uid_t euid; 61598417Salfred struct uidinfo *euip; 61687218Srwatson int error; 6171541Srgrimes 6181541Srgrimes euid = uap->euid; 619195104Srwatson AUDIT_ARG_EUID(euid); 62094619Sjhb newcred = crget(); 62198417Salfred euip = uifind(euid); 62294619Sjhb PROC_LOCK(p); 623194498Sbrooks /* 624194498Sbrooks * Copy credentials so other references do not see our changes. 625194498Sbrooks */ 626194498Sbrooks oldcred = crcopysafe(p, newcred); 627145147Srwatson 628145147Srwatson#ifdef MAC 629189529Srwatson error = mac_cred_check_seteuid(oldcred, euid); 630145147Srwatson if (error) 631145147Srwatson goto fail; 632145147Srwatson#endif 633145147Srwatson 63477183Srwatson if (euid != oldcred->cr_ruid && /* allow seteuid(getuid()) */ 63577183Srwatson euid != oldcred->cr_svuid && /* allow seteuid(saved uid) */ 636170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETEUID, 0)) != 0) 637145147Srwatson goto fail; 638145147Srwatson 6391541Srgrimes /* 640194498Sbrooks * Everything's okay, do it. 6411541Srgrimes */ 64277183Srwatson if (oldcred->cr_uid != euid) { 64398417Salfred change_euid(newcred, euip); 64431891Ssef setsugid(p); 64524449Speter } 646280130Smjg proc_set_cred(p, newcred); 64794619Sjhb PROC_UNLOCK(p); 64898417Salfred uifree(euip); 64977183Srwatson crfree(oldcred); 65094619Sjhb return (0); 651145147Srwatson 652145147Srwatsonfail: 653145147Srwatson PROC_UNLOCK(p); 654145147Srwatson uifree(euip); 655145147Srwatson crfree(newcred); 656145147Srwatson return (error); 6571541Srgrimes} 6581541Srgrimes 65912221Sbde#ifndef _SYS_SYSPROTO_H_ 6601541Srgrimesstruct setgid_args { 6611541Srgrimes gid_t gid; 6621541Srgrimes}; 66312221Sbde#endif 6641541Srgrimes/* ARGSUSED */ 6651549Srgrimesint 666225617Skmacysys_setgid(struct thread *td, struct setgid_args *uap) 6671541Srgrimes{ 66883366Sjulian struct proc *p = td->td_proc; 66977183Srwatson struct ucred *newcred, *oldcred; 67077183Srwatson gid_t gid; 67187218Srwatson int error; 6721541Srgrimes 67377183Srwatson gid = uap->gid; 674195104Srwatson AUDIT_ARG_GID(gid); 67594619Sjhb newcred = crget(); 67694619Sjhb PROC_LOCK(p); 677194498Sbrooks oldcred = crcopysafe(p, newcred); 67887466Srwatson 679145147Srwatson#ifdef MAC 680189529Srwatson error = mac_cred_check_setgid(oldcred, gid); 681145147Srwatson if (error) 682145147Srwatson goto fail; 683145147Srwatson#endif 684145147Srwatson 68524448Speter /* 68624448Speter * See if we have "permission" by POSIX 1003.1 rules. 68724448Speter * 68824448Speter * Note that setgid(getegid()) is a special case of 68924448Speter * "appropriate privileges" in appendix B.4.2.2. We need 69072093Sasmodai * to use this clause to be compatible with traditional BSD 69124448Speter * semantics. Basically, it means that "setgid(xx)" sets all 69224448Speter * three id's (assuming you have privs). 69324448Speter * 69424448Speter * For notes on the logic here, see setuid() above. 69524448Speter */ 69677183Srwatson if (gid != oldcred->cr_rgid && /* allow setgid(getgid()) */ 69717994Sache#ifdef _POSIX_SAVED_IDS 69877183Srwatson gid != oldcred->cr_svgid && /* allow setgid(saved gid) */ 69917994Sache#endif 70024448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 70177183Srwatson gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */ 70224448Speter#endif 703170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETGID, 0)) != 0) 704145147Srwatson goto fail; 70524448Speter 70617994Sache#ifdef _POSIX_SAVED_IDS 70724448Speter /* 70824448Speter * Do we have "appropriate privileges" (are we root or gid == egid) 70924448Speter * If so, we are changing the real uid and saved gid. 71024448Speter */ 71124448Speter if ( 71224448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 71377183Srwatson gid == oldcred->cr_groups[0] || 71417994Sache#endif 715164032Srwatson /* We are using privs. */ 716170587Srwatson priv_check_cred(oldcred, PRIV_CRED_SETGID, 0) == 0) 71724448Speter#endif 71824448Speter { 71924448Speter /* 72024448Speter * Set real gid 72124448Speter */ 72277183Srwatson if (oldcred->cr_rgid != gid) { 72377183Srwatson change_rgid(newcred, gid); 72431891Ssef setsugid(p); 72524448Speter } 72624448Speter /* 72724448Speter * Set saved gid 72824448Speter * 72924448Speter * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 73024448Speter * the security of setegid() depends on it. B.4.2.2 says it 73124448Speter * is important that we should do this. 73224448Speter */ 73377183Srwatson if (oldcred->cr_svgid != gid) { 73477183Srwatson change_svgid(newcred, gid); 73531891Ssef setsugid(p); 73624448Speter } 7378141Sache } 73824448Speter /* 73924448Speter * In all cases permitted cases, we are changing the egid. 74024448Speter * Copy credentials so other references do not see our changes. 74124448Speter */ 74277183Srwatson if (oldcred->cr_groups[0] != gid) { 74377183Srwatson change_egid(newcred, gid); 74431891Ssef setsugid(p); 74524448Speter } 746280130Smjg proc_set_cred(p, newcred); 74794619Sjhb PROC_UNLOCK(p); 74877183Srwatson crfree(oldcred); 74994619Sjhb return (0); 750145147Srwatson 751145147Srwatsonfail: 752145147Srwatson PROC_UNLOCK(p); 753145147Srwatson crfree(newcred); 754145147Srwatson return (error); 7551541Srgrimes} 7561541Srgrimes 75712221Sbde#ifndef _SYS_SYSPROTO_H_ 7581541Srgrimesstruct setegid_args { 7591541Srgrimes gid_t egid; 7601541Srgrimes}; 76112221Sbde#endif 7621541Srgrimes/* ARGSUSED */ 7631549Srgrimesint 764225617Skmacysys_setegid(struct thread *td, struct setegid_args *uap) 7651541Srgrimes{ 76683366Sjulian struct proc *p = td->td_proc; 76777183Srwatson struct ucred *newcred, *oldcred; 76877183Srwatson gid_t egid; 76987218Srwatson int error; 7701541Srgrimes 7711541Srgrimes egid = uap->egid; 772195104Srwatson AUDIT_ARG_EGID(egid); 77394619Sjhb newcred = crget(); 77494619Sjhb PROC_LOCK(p); 775194498Sbrooks oldcred = crcopysafe(p, newcred); 776145147Srwatson 777145147Srwatson#ifdef MAC 778189529Srwatson error = mac_cred_check_setegid(oldcred, egid); 779145147Srwatson if (error) 780145147Srwatson goto fail; 781145147Srwatson#endif 782145147Srwatson 78377183Srwatson if (egid != oldcred->cr_rgid && /* allow setegid(getgid()) */ 78477183Srwatson egid != oldcred->cr_svgid && /* allow setegid(saved gid) */ 785170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETEGID, 0)) != 0) 786145147Srwatson goto fail; 787145147Srwatson 78877183Srwatson if (oldcred->cr_groups[0] != egid) { 78977183Srwatson change_egid(newcred, egid); 79031891Ssef setsugid(p); 79124449Speter } 792280130Smjg proc_set_cred(p, newcred); 79394619Sjhb PROC_UNLOCK(p); 79477183Srwatson crfree(oldcred); 79594619Sjhb return (0); 796145147Srwatson 797145147Srwatsonfail: 798145147Srwatson PROC_UNLOCK(p); 799145147Srwatson crfree(newcred); 800145147Srwatson return (error); 8011541Srgrimes} 8021541Srgrimes 80312221Sbde#ifndef _SYS_SYSPROTO_H_ 8041541Srgrimesstruct setgroups_args { 8051541Srgrimes u_int gidsetsize; 8061541Srgrimes gid_t *gidset; 8071541Srgrimes}; 80812221Sbde#endif 8091541Srgrimes/* ARGSUSED */ 8101549Srgrimesint 811225617Skmacysys_setgroups(struct thread *td, struct setgroups_args *uap) 8121541Srgrimes{ 813273684Smjg gid_t smallgroups[XU_NGROUPS]; 814273685Smjg gid_t *groups; 815273684Smjg u_int gidsetsize; 816160139Sjhb int error; 817160139Sjhb 818273684Smjg gidsetsize = uap->gidsetsize; 819273684Smjg if (gidsetsize > ngroups_max + 1) 820160139Sjhb return (EINVAL); 821273685Smjg 822273684Smjg if (gidsetsize > XU_NGROUPS) 823273684Smjg groups = malloc(gidsetsize * sizeof(gid_t), M_TEMP, M_WAITOK); 824273684Smjg else 825273684Smjg groups = smallgroups; 826273685Smjg 827273684Smjg error = copyin(uap->gidset, groups, gidsetsize * sizeof(gid_t)); 828273685Smjg if (error == 0) 829273685Smjg error = kern_setgroups(td, gidsetsize, groups); 830273685Smjg 831273684Smjg if (gidsetsize > XU_NGROUPS) 832273684Smjg free(groups, M_TEMP); 833194498Sbrooks return (error); 834160139Sjhb} 835160139Sjhb 836160139Sjhbint 837160139Sjhbkern_setgroups(struct thread *td, u_int ngrp, gid_t *groups) 838160139Sjhb{ 83983366Sjulian struct proc *p = td->td_proc; 840160139Sjhb struct ucred *newcred, *oldcred; 8411541Srgrimes int error; 8421541Srgrimes 843273691Smjg MPASS(ngrp <= ngroups_max + 1); 844195104Srwatson AUDIT_ARG_GROUPSET(groups, ngrp); 84594619Sjhb newcred = crget(); 846194498Sbrooks crextend(newcred, ngrp); 84794619Sjhb PROC_LOCK(p); 848194498Sbrooks oldcred = crcopysafe(p, newcred); 849145147Srwatson 850145147Srwatson#ifdef MAC 851189529Srwatson error = mac_cred_check_setgroups(oldcred, ngrp, groups); 852145147Srwatson if (error) 853145147Srwatson goto fail; 854145147Srwatson#endif 855145147Srwatson 856170587Srwatson error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0); 857145147Srwatson if (error) 858145147Srwatson goto fail; 859145147Srwatson 860273685Smjg if (ngrp == 0) { 86124447Speter /* 86224447Speter * setgroups(0, NULL) is a legitimate way of clearing the 86324447Speter * groups vector on non-BSD systems (which generally do not 86424447Speter * have the egid in the groups[0]). We risk security holes 86524447Speter * when running non-BSD software if we do not do the same. 86624447Speter */ 86777183Srwatson newcred->cr_ngroups = 1; 86824447Speter } else { 869194498Sbrooks crsetgroups_locked(newcred, ngrp, groups); 87024447Speter } 87131891Ssef setsugid(p); 872280130Smjg proc_set_cred(p, newcred); 87394619Sjhb PROC_UNLOCK(p); 87477183Srwatson crfree(oldcred); 87594619Sjhb return (0); 876145147Srwatson 877145147Srwatsonfail: 878145147Srwatson PROC_UNLOCK(p); 879145147Srwatson crfree(newcred); 880145147Srwatson return (error); 8811541Srgrimes} 8821541Srgrimes 88312221Sbde#ifndef _SYS_SYSPROTO_H_ 8841541Srgrimesstruct setreuid_args { 8859238Sache uid_t ruid; 8869238Sache uid_t euid; 8871541Srgrimes}; 88812221Sbde#endif 8891541Srgrimes/* ARGSUSED */ 8901549Srgrimesint 891331643Sdimsys_setreuid(struct thread *td, struct setreuid_args *uap) 8921541Srgrimes{ 89383366Sjulian struct proc *p = td->td_proc; 89477183Srwatson struct ucred *newcred, *oldcred; 89587218Srwatson uid_t euid, ruid; 89698417Salfred struct uidinfo *euip, *ruip; 89787218Srwatson int error; 8981541Srgrimes 89987218Srwatson euid = uap->euid; 9009238Sache ruid = uap->ruid; 901195104Srwatson AUDIT_ARG_EUID(euid); 902195104Srwatson AUDIT_ARG_RUID(ruid); 90394619Sjhb newcred = crget(); 90498417Salfred euip = uifind(euid); 90598417Salfred ruip = uifind(ruid); 90694619Sjhb PROC_LOCK(p); 907194498Sbrooks oldcred = crcopysafe(p, newcred); 908145147Srwatson 909145147Srwatson#ifdef MAC 910189529Srwatson error = mac_cred_check_setreuid(oldcred, ruid, euid); 911145147Srwatson if (error) 912145147Srwatson goto fail; 913145147Srwatson#endif 914145147Srwatson 91577183Srwatson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 91677183Srwatson ruid != oldcred->cr_svuid) || 91777183Srwatson (euid != (uid_t)-1 && euid != oldcred->cr_uid && 91877183Srwatson euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) && 919170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETREUID, 0)) != 0) 920145147Srwatson goto fail; 921145147Srwatson 92277183Srwatson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 92398417Salfred change_euid(newcred, euip); 92431891Ssef setsugid(p); 92524450Speter } 92677183Srwatson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 92798417Salfred change_ruid(newcred, ruip); 92831891Ssef setsugid(p); 9298135Sache } 93077183Srwatson if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) && 93177183Srwatson newcred->cr_svuid != newcred->cr_uid) { 93277183Srwatson change_svuid(newcred, newcred->cr_uid); 93331891Ssef setsugid(p); 93424450Speter } 935280130Smjg proc_set_cred(p, newcred); 936220212Strasz#ifdef RACCT 937220212Strasz racct_proc_ucred_changed(p, oldcred, newcred); 938335536Savg crhold(newcred); 939220212Strasz#endif 940335536Savg PROC_UNLOCK(p); 941335536Savg#ifdef RCTL 942335536Savg rctl_proc_ucred_changed(p, newcred); 943335536Savg crfree(newcred); 944335536Savg#endif 94598417Salfred uifree(ruip); 94698417Salfred uifree(euip); 94777183Srwatson crfree(oldcred); 94894619Sjhb return (0); 949145147Srwatson 950145147Srwatsonfail: 951145147Srwatson PROC_UNLOCK(p); 952145147Srwatson uifree(ruip); 953145147Srwatson uifree(euip); 954145147Srwatson crfree(newcred); 955145147Srwatson return (error); 9561541Srgrimes} 9571541Srgrimes 95812221Sbde#ifndef _SYS_SYSPROTO_H_ 9591541Srgrimesstruct setregid_args { 9609238Sache gid_t rgid; 9619238Sache gid_t egid; 9621541Srgrimes}; 96312221Sbde#endif 9641541Srgrimes/* ARGSUSED */ 9651549Srgrimesint 966331643Sdimsys_setregid(struct thread *td, struct setregid_args *uap) 9671541Srgrimes{ 96883366Sjulian struct proc *p = td->td_proc; 96977183Srwatson struct ucred *newcred, *oldcred; 97087218Srwatson gid_t egid, rgid; 97187218Srwatson int error; 9721541Srgrimes 97387218Srwatson egid = uap->egid; 9749238Sache rgid = uap->rgid; 975195104Srwatson AUDIT_ARG_EGID(egid); 976195104Srwatson AUDIT_ARG_RGID(rgid); 97794619Sjhb newcred = crget(); 97894619Sjhb PROC_LOCK(p); 979194498Sbrooks oldcred = crcopysafe(p, newcred); 980145147Srwatson 981145147Srwatson#ifdef MAC 982189529Srwatson error = mac_cred_check_setregid(oldcred, rgid, egid); 983145147Srwatson if (error) 984145147Srwatson goto fail; 985145147Srwatson#endif 986145147Srwatson 98777183Srwatson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 98877183Srwatson rgid != oldcred->cr_svgid) || 98977183Srwatson (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] && 99077183Srwatson egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) && 991170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETREGID, 0)) != 0) 992145147Srwatson goto fail; 99394619Sjhb 99477183Srwatson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 99577183Srwatson change_egid(newcred, egid); 99631891Ssef setsugid(p); 99724450Speter } 99877183Srwatson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 99977183Srwatson change_rgid(newcred, rgid); 100031891Ssef setsugid(p); 100124450Speter } 100277183Srwatson if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) && 100377183Srwatson newcred->cr_svgid != newcred->cr_groups[0]) { 100477183Srwatson change_svgid(newcred, newcred->cr_groups[0]); 100531891Ssef setsugid(p); 100624450Speter } 1007280130Smjg proc_set_cred(p, newcred); 100894619Sjhb PROC_UNLOCK(p); 100977812Sru crfree(oldcred); 101094619Sjhb return (0); 1011145147Srwatson 1012145147Srwatsonfail: 1013145147Srwatson PROC_UNLOCK(p); 1014145147Srwatson crfree(newcred); 1015145147Srwatson return (error); 10161541Srgrimes} 10171541Srgrimes 101856115Speter/* 1019167232Srwatson * setresuid(ruid, euid, suid) is like setreuid except control over the saved 1020167232Srwatson * uid is explicit. 102156115Speter */ 102224453Speter#ifndef _SYS_SYSPROTO_H_ 102356115Speterstruct setresuid_args { 102456115Speter uid_t ruid; 102556115Speter uid_t euid; 102656115Speter uid_t suid; 102756115Speter}; 102856115Speter#endif 102956115Speter/* ARGSUSED */ 103056115Speterint 1031331643Sdimsys_setresuid(struct thread *td, struct setresuid_args *uap) 103256115Speter{ 103383366Sjulian struct proc *p = td->td_proc; 103477183Srwatson struct ucred *newcred, *oldcred; 103587218Srwatson uid_t euid, ruid, suid; 103698417Salfred struct uidinfo *euip, *ruip; 103756115Speter int error; 103856115Speter 103987218Srwatson euid = uap->euid; 104056115Speter ruid = uap->ruid; 104156115Speter suid = uap->suid; 1042195104Srwatson AUDIT_ARG_EUID(euid); 1043195104Srwatson AUDIT_ARG_RUID(ruid); 1044195104Srwatson AUDIT_ARG_SUID(suid); 104594619Sjhb newcred = crget(); 104698417Salfred euip = uifind(euid); 104798417Salfred ruip = uifind(ruid); 104894619Sjhb PROC_LOCK(p); 1049194498Sbrooks oldcred = crcopysafe(p, newcred); 1050145147Srwatson 1051145147Srwatson#ifdef MAC 1052189529Srwatson error = mac_cred_check_setresuid(oldcred, ruid, euid, suid); 1053145147Srwatson if (error) 1054145147Srwatson goto fail; 1055145147Srwatson#endif 1056145147Srwatson 105777183Srwatson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 105877183Srwatson ruid != oldcred->cr_svuid && 105977183Srwatson ruid != oldcred->cr_uid) || 106077183Srwatson (euid != (uid_t)-1 && euid != oldcred->cr_ruid && 106177183Srwatson euid != oldcred->cr_svuid && 106277183Srwatson euid != oldcred->cr_uid) || 106377183Srwatson (suid != (uid_t)-1 && suid != oldcred->cr_ruid && 106477183Srwatson suid != oldcred->cr_svuid && 106577183Srwatson suid != oldcred->cr_uid)) && 1066170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETRESUID, 0)) != 0) 1067145147Srwatson goto fail; 106894619Sjhb 106977183Srwatson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 107098417Salfred change_euid(newcred, euip); 107156115Speter setsugid(p); 107256115Speter } 107377183Srwatson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 107498417Salfred change_ruid(newcred, ruip); 107556115Speter setsugid(p); 107656115Speter } 107777183Srwatson if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) { 107877183Srwatson change_svuid(newcred, suid); 107956115Speter setsugid(p); 108056115Speter } 1081280130Smjg proc_set_cred(p, newcred); 1082220212Strasz#ifdef RACCT 1083220212Strasz racct_proc_ucred_changed(p, oldcred, newcred); 1084335536Savg crhold(newcred); 1085220212Strasz#endif 1086335536Savg PROC_UNLOCK(p); 1087335536Savg#ifdef RCTL 1088335536Savg rctl_proc_ucred_changed(p, newcred); 1089335536Savg crfree(newcred); 1090335536Savg#endif 109198417Salfred uifree(ruip); 109298417Salfred uifree(euip); 109377183Srwatson crfree(oldcred); 109494619Sjhb return (0); 1095145147Srwatson 1096145147Srwatsonfail: 1097145147Srwatson PROC_UNLOCK(p); 1098145147Srwatson uifree(ruip); 1099145147Srwatson uifree(euip); 1100145147Srwatson crfree(newcred); 1101145147Srwatson return (error); 1102145147Srwatson 110356115Speter} 110456115Speter 110556115Speter/* 1106167232Srwatson * setresgid(rgid, egid, sgid) is like setregid except control over the saved 1107167232Srwatson * gid is explicit. 110856115Speter */ 110956115Speter#ifndef _SYS_SYSPROTO_H_ 111056115Speterstruct setresgid_args { 111156115Speter gid_t rgid; 111256115Speter gid_t egid; 111356115Speter gid_t sgid; 111456115Speter}; 111556115Speter#endif 111656115Speter/* ARGSUSED */ 111756115Speterint 1118331643Sdimsys_setresgid(struct thread *td, struct setresgid_args *uap) 111956115Speter{ 112083366Sjulian struct proc *p = td->td_proc; 112177183Srwatson struct ucred *newcred, *oldcred; 112287218Srwatson gid_t egid, rgid, sgid; 112356115Speter int error; 112456115Speter 112587218Srwatson egid = uap->egid; 112656115Speter rgid = uap->rgid; 112756115Speter sgid = uap->sgid; 1128195104Srwatson AUDIT_ARG_EGID(egid); 1129195104Srwatson AUDIT_ARG_RGID(rgid); 1130195104Srwatson AUDIT_ARG_SGID(sgid); 113194619Sjhb newcred = crget(); 113294619Sjhb PROC_LOCK(p); 1133194498Sbrooks oldcred = crcopysafe(p, newcred); 1134145147Srwatson 1135145147Srwatson#ifdef MAC 1136189529Srwatson error = mac_cred_check_setresgid(oldcred, rgid, egid, sgid); 1137145147Srwatson if (error) 1138145147Srwatson goto fail; 1139145147Srwatson#endif 1140145147Srwatson 114177183Srwatson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 114277183Srwatson rgid != oldcred->cr_svgid && 114377183Srwatson rgid != oldcred->cr_groups[0]) || 114477183Srwatson (egid != (gid_t)-1 && egid != oldcred->cr_rgid && 114577183Srwatson egid != oldcred->cr_svgid && 114677183Srwatson egid != oldcred->cr_groups[0]) || 114777183Srwatson (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid && 114877183Srwatson sgid != oldcred->cr_svgid && 114977183Srwatson sgid != oldcred->cr_groups[0])) && 1150170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETRESGID, 0)) != 0) 1151145147Srwatson goto fail; 115294619Sjhb 115377183Srwatson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 115477183Srwatson change_egid(newcred, egid); 115556115Speter setsugid(p); 115656115Speter } 115777183Srwatson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 115877183Srwatson change_rgid(newcred, rgid); 115956115Speter setsugid(p); 116056115Speter } 116177183Srwatson if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) { 116277183Srwatson change_svgid(newcred, sgid); 116356115Speter setsugid(p); 116456115Speter } 1165280130Smjg proc_set_cred(p, newcred); 116694619Sjhb PROC_UNLOCK(p); 116777183Srwatson crfree(oldcred); 116894619Sjhb return (0); 1169145147Srwatson 1170145147Srwatsonfail: 1171145147Srwatson PROC_UNLOCK(p); 1172145147Srwatson crfree(newcred); 1173145147Srwatson return (error); 117456115Speter} 117556115Speter 117656115Speter#ifndef _SYS_SYSPROTO_H_ 117756115Speterstruct getresuid_args { 117856115Speter uid_t *ruid; 117956115Speter uid_t *euid; 118056115Speter uid_t *suid; 118156115Speter}; 118256115Speter#endif 118356115Speter/* ARGSUSED */ 118456115Speterint 1185331643Sdimsys_getresuid(struct thread *td, struct getresuid_args *uap) 118656115Speter{ 118782749Sdillon struct ucred *cred; 118856115Speter int error1 = 0, error2 = 0, error3 = 0; 118956115Speter 119093264Sdillon cred = td->td_ucred; 119156115Speter if (uap->ruid) 119299009Salfred error1 = copyout(&cred->cr_ruid, 119399009Salfred uap->ruid, sizeof(cred->cr_ruid)); 119456115Speter if (uap->euid) 119599009Salfred error2 = copyout(&cred->cr_uid, 119699009Salfred uap->euid, sizeof(cred->cr_uid)); 119756115Speter if (uap->suid) 119899009Salfred error3 = copyout(&cred->cr_svuid, 119999009Salfred uap->suid, sizeof(cred->cr_svuid)); 120087218Srwatson return (error1 ? error1 : error2 ? error2 : error3); 120156115Speter} 120256115Speter 120356115Speter#ifndef _SYS_SYSPROTO_H_ 120456115Speterstruct getresgid_args { 120556115Speter gid_t *rgid; 120656115Speter gid_t *egid; 120756115Speter gid_t *sgid; 120856115Speter}; 120956115Speter#endif 121056115Speter/* ARGSUSED */ 121156115Speterint 1212331643Sdimsys_getresgid(struct thread *td, struct getresgid_args *uap) 121356115Speter{ 121482749Sdillon struct ucred *cred; 121556115Speter int error1 = 0, error2 = 0, error3 = 0; 121656115Speter 121793264Sdillon cred = td->td_ucred; 121856115Speter if (uap->rgid) 121999009Salfred error1 = copyout(&cred->cr_rgid, 122099009Salfred uap->rgid, sizeof(cred->cr_rgid)); 122156115Speter if (uap->egid) 122299009Salfred error2 = copyout(&cred->cr_groups[0], 122399009Salfred uap->egid, sizeof(cred->cr_groups[0])); 122456115Speter if (uap->sgid) 122599009Salfred error3 = copyout(&cred->cr_svgid, 122699009Salfred uap->sgid, sizeof(cred->cr_svgid)); 122787218Srwatson return (error1 ? error1 : error2 ? error2 : error3); 122856115Speter} 122956115Speter 123056115Speter#ifndef _SYS_SYSPROTO_H_ 123124453Speterstruct issetugid_args { 123224453Speter int dummy; 123324453Speter}; 123424453Speter#endif 123524453Speter/* ARGSUSED */ 123624453Speterint 1237331643Sdimsys_issetugid(struct thread *td, struct issetugid_args *uap) 123824453Speter{ 123983366Sjulian struct proc *p = td->td_proc; 124083366Sjulian 124124453Speter /* 124224453Speter * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 124324453Speter * we use P_SUGID because we consider changing the owners as 124424453Speter * "tainting" as well. 124524453Speter * This is significant for procs that start as root and "become" 124624453Speter * a user without an exec - programs cannot know *everything* 124724453Speter * that libc *might* have put in their data segment. 124824453Speter */ 124983366Sjulian td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 125024453Speter return (0); 125124453Speter} 125224453Speter 125375426Srwatsonint 1254225617Skmacysys___setugid(struct thread *td, struct __setugid_args *uap) 125575426Srwatson{ 125682749Sdillon#ifdef REGRESSION 125794619Sjhb struct proc *p; 125875426Srwatson 125994619Sjhb p = td->td_proc; 126075426Srwatson switch (uap->flag) { 126175426Srwatson case 0: 126294619Sjhb PROC_LOCK(p); 126394619Sjhb p->p_flag &= ~P_SUGID; 126494619Sjhb PROC_UNLOCK(p); 126594619Sjhb return (0); 126675426Srwatson case 1: 126794619Sjhb PROC_LOCK(p); 126894619Sjhb p->p_flag |= P_SUGID; 126994619Sjhb PROC_UNLOCK(p); 127094619Sjhb return (0); 127175426Srwatson default: 127294619Sjhb return (EINVAL); 127375426Srwatson } 127475426Srwatson#else /* !REGRESSION */ 127587218Srwatson 127675426Srwatson return (ENOSYS); 127787218Srwatson#endif /* REGRESSION */ 127875426Srwatson} 127975426Srwatson 12801541Srgrimes/* 12811541Srgrimes * Check if gid is a member of the group set. 12821541Srgrimes */ 12831549Srgrimesint 128493580Sjhbgroupmember(gid_t gid, struct ucred *cred) 12851541Srgrimes{ 1286194556Sbrooks int l; 1287194556Sbrooks int h; 1288194556Sbrooks int m; 12891541Srgrimes 1290194556Sbrooks if (cred->cr_groups[0] == gid) 1291194556Sbrooks return(1); 1292194556Sbrooks 1293194556Sbrooks /* 1294194556Sbrooks * If gid was not our primary group, perform a binary search 1295194556Sbrooks * of the supplemental groups. This is possible because we 1296194556Sbrooks * sort the groups in crsetgroups(). 1297194556Sbrooks */ 1298194556Sbrooks l = 1; 1299194556Sbrooks h = cred->cr_ngroups; 1300194556Sbrooks while (l < h) { 1301194556Sbrooks m = l + ((h - l) / 2); 1302194556Sbrooks if (cred->cr_groups[m] < gid) 1303194556Sbrooks l = m + 1; 1304194556Sbrooks else 1305194556Sbrooks h = m; 1306194556Sbrooks } 1307194556Sbrooks if ((l < cred->cr_ngroups) && (cred->cr_groups[l] == gid)) 1308194556Sbrooks return (1); 1309194556Sbrooks 13101541Srgrimes return (0); 13111541Srgrimes} 13121541Srgrimes 131382424Srwatson/* 131487218Srwatson * Test the active securelevel against a given level. securelevel_gt() 131587218Srwatson * implements (securelevel > level). securelevel_ge() implements 131687218Srwatson * (securelevel >= level). Note that the logic is inverted -- these 131787218Srwatson * functions return EPERM on "success" and 0 on "failure". 131883639Srwatson * 1319192895Sjamie * Due to care taken when setting the securelevel, we know that no jail will 1320192895Sjamie * be less secure that its parent (or the physical system), so it is sufficient 1321192895Sjamie * to test the current jail only. 1322192895Sjamie * 1323164032Srwatson * XXXRW: Possibly since this has to do with privilege, it should move to 1324164032Srwatson * kern_priv.c. 132583639Srwatson */ 132683639Srwatsonint 132783639Srwatsonsecurelevel_gt(struct ucred *cr, int level) 132883639Srwatson{ 132983639Srwatson 1330192895Sjamie return (cr->cr_prison->pr_securelevel > level ? EPERM : 0); 133183639Srwatson} 133283639Srwatson 133383639Srwatsonint 133483639Srwatsonsecurelevel_ge(struct ucred *cr, int level) 133583639Srwatson{ 133683639Srwatson 1337192895Sjamie return (cr->cr_prison->pr_securelevel >= level ? EPERM : 0); 133883639Srwatson} 133983639Srwatson 134084736Srwatson/* 134187144Srwatson * 'see_other_uids' determines whether or not visibility of processes 134287218Srwatson * and sockets with credentials holding different real uids is possible 134387138Srwatson * using a variety of system MIBs. 134487218Srwatson * XXX: data declarations should be together near the beginning of the file. 134584736Srwatson */ 134687144Srwatsonstatic int see_other_uids = 1; 134789414SarrSYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW, 134887218Srwatson &see_other_uids, 0, 134984736Srwatson "Unprivileged processes may see subjects/objects with different real uid"); 135084736Srwatson 1351210226Strasz/*- 135292923Srwatson * Determine if u1 "can see" the subject specified by u2, according to the 135392923Srwatson * 'see_other_uids' policy. 135492923Srwatson * Returns: 0 for permitted, ESRCH otherwise 135592923Srwatson * Locks: none 135692923Srwatson * References: *u1 and *u2 must not change during the call 135792923Srwatson * u1 may equal u2, in which case only one reference is required 135892923Srwatson */ 135992923Srwatsonstatic int 136092923Srwatsoncr_seeotheruids(struct ucred *u1, struct ucred *u2) 136192923Srwatson{ 136292923Srwatson 136392923Srwatson if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) { 1364170587Srwatson if (priv_check_cred(u1, PRIV_SEEOTHERUIDS, 0) != 0) 136592923Srwatson return (ESRCH); 136692923Srwatson } 136792923Srwatson return (0); 136892923Srwatson} 136992923Srwatson 1370122869Srwatson/* 1371122869Srwatson * 'see_other_gids' determines whether or not visibility of processes 1372122869Srwatson * and sockets with credentials holding different real gids is possible 1373122869Srwatson * using a variety of system MIBs. 1374122869Srwatson * XXX: data declarations should be together near the beginning of the file. 1375122869Srwatson */ 1376122869Srwatsonstatic int see_other_gids = 1; 1377122869SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, see_other_gids, CTLFLAG_RW, 1378122869Srwatson &see_other_gids, 0, 1379122869Srwatson "Unprivileged processes may see subjects/objects with different real gid"); 1380122869Srwatson 1381122869Srwatson/* 1382122869Srwatson * Determine if u1 can "see" the subject specified by u2, according to the 1383122869Srwatson * 'see_other_gids' policy. 1384122869Srwatson * Returns: 0 for permitted, ESRCH otherwise 1385122869Srwatson * Locks: none 1386122869Srwatson * References: *u1 and *u2 must not change during the call 1387122869Srwatson * u1 may equal u2, in which case only one reference is required 1388122869Srwatson */ 1389122869Srwatsonstatic int 1390122869Srwatsoncr_seeothergids(struct ucred *u1, struct ucred *u2) 1391122869Srwatson{ 1392122869Srwatson int i, match; 1393122869Srwatson 1394122869Srwatson if (!see_other_gids) { 1395122869Srwatson match = 0; 1396122869Srwatson for (i = 0; i < u1->cr_ngroups; i++) { 1397122869Srwatson if (groupmember(u1->cr_groups[i], u2)) 1398122869Srwatson match = 1; 1399122869Srwatson if (match) 1400122869Srwatson break; 1401122869Srwatson } 1402122869Srwatson if (!match) { 1403170587Srwatson if (priv_check_cred(u1, PRIV_SEEOTHERGIDS, 0) != 0) 1404122869Srwatson return (ESRCH); 1405122869Srwatson } 1406122869Srwatson } 1407122869Srwatson return (0); 1408122869Srwatson} 1409122869Srwatson 1410210226Strasz/*- 141182466Srwatson * Determine if u1 "can see" the subject specified by u2. 141274956Srwatson * Returns: 0 for permitted, an errno value otherwise 141374956Srwatson * Locks: none 141487218Srwatson * References: *u1 and *u2 must not change during the call 141574956Srwatson * u1 may equal u2, in which case only one reference is required 141674956Srwatson */ 141774956Srwatsonint 141883742Srwatsoncr_cansee(struct ucred *u1, struct ucred *u2) 141965237Srwatson{ 142072786Srwatson int error; 142153518Sphk 142274956Srwatson if ((error = prison_check(u1, u2))) 142372786Srwatson return (error); 1424101003Srwatson#ifdef MAC 1425172930Srwatson if ((error = mac_cred_check_visible(u1, u2))) 1426101003Srwatson return (error); 1427101003Srwatson#endif 142892923Srwatson if ((error = cr_seeotheruids(u1, u2))) 142992923Srwatson return (error); 1430122869Srwatson if ((error = cr_seeothergids(u1, u2))) 1431122869Srwatson return (error); 143265237Srwatson return (0); 143365237Srwatson} 143465237Srwatson 1435210226Strasz/*- 143696886Sjhb * Determine if td "can see" the subject specified by p. 143782424Srwatson * Returns: 0 for permitted, an errno value otherwise 143896886Sjhb * Locks: Sufficient locks to protect p->p_ucred must be held. td really 143996886Sjhb * should be curthread. 144096886Sjhb * References: td and p must be valid for the lifetime of the call 144182424Srwatson */ 144279335Srwatsonint 144396886Sjhbp_cansee(struct thread *td, struct proc *p) 144474956Srwatson{ 144574956Srwatson 144683742Srwatson /* Wrap cr_cansee() for all functionality. */ 144796886Sjhb KASSERT(td == curthread, ("%s: td not curthread", __func__)); 144896886Sjhb PROC_LOCK_ASSERT(p, MA_OWNED); 144996886Sjhb return (cr_cansee(td->td_ucred, p->p_ucred)); 145074956Srwatson} 145174956Srwatson 1452120052Srwatson/* 1453120052Srwatson * 'conservative_signals' prevents the delivery of a broad class of 1454120052Srwatson * signals by unprivileged processes to processes that have changed their 1455120052Srwatson * credentials since the last invocation of execve(). This can prevent 1456120052Srwatson * the leakage of cached information or retained privileges as a result 1457120052Srwatson * of a common class of signal-related vulnerabilities. However, this 1458120052Srwatson * may interfere with some applications that expect to be able to 1459120052Srwatson * deliver these signals to peer processes after having given up 1460120052Srwatson * privilege. 1461120052Srwatson */ 1462120052Srwatsonstatic int conservative_signals = 1; 1463120052SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, conservative_signals, CTLFLAG_RW, 1464120052Srwatson &conservative_signals, 0, "Unprivileged processes prevented from " 1465120052Srwatson "sending certain signals to processes whose credentials have changed"); 1466210226Strasz/*- 146788943Srwatson * Determine whether cred may deliver the specified signal to proc. 146888943Srwatson * Returns: 0 for permitted, an errno value otherwise. 146988943Srwatson * Locks: A lock must be held for proc. 147088943Srwatson * References: cred and proc must be valid for the lifetime of the call. 147175437Srwatson */ 147275437Srwatsonint 1473141815Ssobomaxcr_cansignal(struct ucred *cred, struct proc *proc, int signum) 147453518Sphk{ 147582466Srwatson int error; 147684826Sjhb 147796886Sjhb PROC_LOCK_ASSERT(proc, MA_OWNED); 147875437Srwatson /* 147988943Srwatson * Jail semantics limit the scope of signalling to proc in the 148088943Srwatson * same jail as cred, if cred is in jail. 148175437Srwatson */ 148288943Srwatson error = prison_check(cred, proc->p_ucred); 148388943Srwatson if (error) 148472786Srwatson return (error); 1485101003Srwatson#ifdef MAC 1486172930Srwatson if ((error = mac_proc_check_signal(cred, proc, signum))) 1487101003Srwatson return (error); 1488101003Srwatson#endif 1489122869Srwatson if ((error = cr_seeotheruids(cred, proc->p_ucred))) 149092923Srwatson return (error); 1491122869Srwatson if ((error = cr_seeothergids(cred, proc->p_ucred))) 1492122869Srwatson return (error); 149365237Srwatson 149465237Srwatson /* 149582424Srwatson * UNIX signal semantics depend on the status of the P_SUGID 149682424Srwatson * bit on the target process. If the bit is set, then additional 149782424Srwatson * restrictions are placed on the set of available signals. 149875437Srwatson */ 1499141815Ssobomax if (conservative_signals && (proc->p_flag & P_SUGID)) { 150075437Srwatson switch (signum) { 150175437Srwatson case 0: 150275437Srwatson case SIGKILL: 150375437Srwatson case SIGINT: 150475437Srwatson case SIGTERM: 1505120052Srwatson case SIGALRM: 150675437Srwatson case SIGSTOP: 150775437Srwatson case SIGTTIN: 150875437Srwatson case SIGTTOU: 150975437Srwatson case SIGTSTP: 151075437Srwatson case SIGHUP: 151175437Srwatson case SIGUSR1: 151275437Srwatson case SIGUSR2: 151382466Srwatson /* 151482466Srwatson * Generally, permit job and terminal control 151582466Srwatson * signals. 151682466Srwatson */ 151775437Srwatson break; 151875437Srwatson default: 151988943Srwatson /* Not permitted without privilege. */ 1520170587Srwatson error = priv_check_cred(cred, PRIV_SIGNAL_SUGID, 0); 152175437Srwatson if (error) 152275437Srwatson return (error); 152375437Srwatson } 152465237Srwatson } 152565237Srwatson 152675480Srwatson /* 152782424Srwatson * Generally, the target credential's ruid or svuid must match the 152875480Srwatson * subject credential's ruid or euid. 152975480Srwatson */ 153088943Srwatson if (cred->cr_ruid != proc->p_ucred->cr_ruid && 153188943Srwatson cred->cr_ruid != proc->p_ucred->cr_svuid && 153288943Srwatson cred->cr_uid != proc->p_ucred->cr_ruid && 153388943Srwatson cred->cr_uid != proc->p_ucred->cr_svuid) { 1534170587Srwatson error = priv_check_cred(cred, PRIV_SIGNAL_DIFFCRED, 0); 153575480Srwatson if (error) 153675480Srwatson return (error); 153775480Srwatson } 153875480Srwatson 153987218Srwatson return (0); 154053518Sphk} 154153518Sphk 1542210226Strasz/*- 154396886Sjhb * Determine whether td may deliver the specified signal to p. 154488943Srwatson * Returns: 0 for permitted, an errno value otherwise 154596886Sjhb * Locks: Sufficient locks to protect various components of td and p 154696886Sjhb * must be held. td must be curthread, and a lock must be 154796886Sjhb * held for p. 154896886Sjhb * References: td and p must be valid for the lifetime of the call 154988943Srwatson */ 155088943Srwatsonint 1551141815Ssobomaxp_cansignal(struct thread *td, struct proc *p, int signum) 155288943Srwatson{ 155388943Srwatson 155496886Sjhb KASSERT(td == curthread, ("%s: td not curthread", __func__)); 155596886Sjhb PROC_LOCK_ASSERT(p, MA_OWNED); 155696886Sjhb if (td->td_proc == p) 155788943Srwatson return (0); 155888943Srwatson 155988943Srwatson /* 156088943Srwatson * UNIX signalling semantics require that processes in the same 156188943Srwatson * session always be able to deliver SIGCONT to one another, 156288943Srwatson * overriding the remaining protections. 156388943Srwatson */ 156496886Sjhb /* XXX: This will require an additional lock of some sort. */ 156596886Sjhb if (signum == SIGCONT && td->td_proc->p_session == p->p_session) 156688943Srwatson return (0); 1567143108Ssobomax /* 1568143800Ssobomax * Some compat layers use SIGTHR and higher signals for 1569143800Ssobomax * communication between different kernel threads of the same 1570143800Ssobomax * process, so that they expect that it's always possible to 1571143800Ssobomax * deliver them, even for suid applications where cr_cansignal() can 1572143108Ssobomax * deny such ability for security consideration. It should be 1573143108Ssobomax * pretty safe to do since the only way to create two processes 1574143108Ssobomax * with the same p_leader is via rfork(2). 1575143108Ssobomax */ 1576143805Ssobomax if (td->td_proc->p_leader != NULL && signum >= SIGTHR && 1577143805Ssobomax signum < SIGTHR + 4 && td->td_proc->p_leader == p->p_leader) 1578143108Ssobomax return (0); 157988943Srwatson 1580141815Ssobomax return (cr_cansignal(td->td_ucred, p, signum)); 158188943Srwatson} 158288943Srwatson 1583210226Strasz/*- 158496886Sjhb * Determine whether td may reschedule p. 158582466Srwatson * Returns: 0 for permitted, an errno value otherwise 158696886Sjhb * Locks: Sufficient locks to protect various components of td and p 158796886Sjhb * must be held. td must be curthread, and a lock must 158896886Sjhb * be held for p. 158996886Sjhb * References: td and p must be valid for the lifetime of the call 159082424Srwatson */ 159179335Srwatsonint 159296886Sjhbp_cansched(struct thread *td, struct proc *p) 159365237Srwatson{ 159472786Srwatson int error; 159565237Srwatson 159696886Sjhb KASSERT(td == curthread, ("%s: td not curthread", __func__)); 159796886Sjhb PROC_LOCK_ASSERT(p, MA_OWNED); 159896886Sjhb if (td->td_proc == p) 159965237Srwatson return (0); 160096886Sjhb if ((error = prison_check(td->td_ucred, p->p_ucred))) 160172786Srwatson return (error); 1602101003Srwatson#ifdef MAC 1603172930Srwatson if ((error = mac_proc_check_sched(td->td_ucred, p))) 1604101003Srwatson return (error); 1605101003Srwatson#endif 160696886Sjhb if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) 160792923Srwatson return (error); 1608122869Srwatson if ((error = cr_seeothergids(td->td_ucred, p->p_ucred))) 1609122869Srwatson return (error); 1610164032Srwatson if (td->td_ucred->cr_ruid != p->p_ucred->cr_ruid && 1611164032Srwatson td->td_ucred->cr_uid != p->p_ucred->cr_ruid) { 1612170587Srwatson error = priv_check(td, PRIV_SCHED_DIFFCRED); 1613164032Srwatson if (error) 1614164032Srwatson return (error); 1615164032Srwatson } 1616164032Srwatson return (0); 161765237Srwatson} 161865237Srwatson 161982424Srwatson/* 162087280Srwatson * The 'unprivileged_proc_debug' flag may be used to disable a variety of 162187280Srwatson * unprivileged inter-process debugging services, including some procfs 162287280Srwatson * functionality, ptrace(), and ktrace(). In the past, inter-process 162387280Srwatson * debugging has been involved in a variety of security problems, and sites 162487280Srwatson * not requiring the service might choose to disable it when hardening 162587280Srwatson * systems. 162682424Srwatson * 162782424Srwatson * XXX: Should modifying and reading this variable require locking? 162887218Srwatson * XXX: data declarations should be together near the beginning of the file. 162982424Srwatson */ 163087144Srwatsonstatic int unprivileged_proc_debug = 1; 163189414SarrSYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW, 163287218Srwatson &unprivileged_proc_debug, 0, 163380735Srwatson "Unprivileged processes may use process debugging facilities"); 163480735Srwatson 1635210226Strasz/*- 163696886Sjhb * Determine whether td may debug p. 163782466Srwatson * Returns: 0 for permitted, an errno value otherwise 163896886Sjhb * Locks: Sufficient locks to protect various components of td and p 163996886Sjhb * must be held. td must be curthread, and a lock must 164096886Sjhb * be held for p. 164196886Sjhb * References: td and p must be valid for the lifetime of the call 164282424Srwatson */ 164379335Srwatsonint 164496886Sjhbp_candebug(struct thread *td, struct proc *p) 164565237Srwatson{ 164687218Srwatson int credentialchanged, error, grpsubset, i, uidsubset; 164765237Srwatson 164896886Sjhb KASSERT(td == curthread, ("%s: td not curthread", __func__)); 164996886Sjhb PROC_LOCK_ASSERT(p, MA_OWNED); 165087144Srwatson if (!unprivileged_proc_debug) { 1651170587Srwatson error = priv_check(td, PRIV_DEBUG_UNPRIV); 165284727Srwatson if (error) 165384727Srwatson return (error); 165484727Srwatson } 165596886Sjhb if (td->td_proc == p) 165684636Sdes return (0); 165796886Sjhb if ((error = prison_check(td->td_ucred, p->p_ucred))) 165872786Srwatson return (error); 1659101003Srwatson#ifdef MAC 1660172930Srwatson if ((error = mac_proc_check_debug(td->td_ucred, p))) 1661101003Srwatson return (error); 1662101003Srwatson#endif 166396886Sjhb if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) 166492923Srwatson return (error); 1665122869Srwatson if ((error = cr_seeothergids(td->td_ucred, p->p_ucred))) 1666122869Srwatson return (error); 166765237Srwatson 166882466Srwatson /* 166996886Sjhb * Is p's group set a subset of td's effective group set? This 167096886Sjhb * includes p's egid, group access list, rgid, and svgid. 167182466Srwatson */ 167285895Srwatson grpsubset = 1; 167396886Sjhb for (i = 0; i < p->p_ucred->cr_ngroups; i++) { 167496886Sjhb if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) { 167585895Srwatson grpsubset = 0; 167685895Srwatson break; 167785895Srwatson } 167885895Srwatson } 167985895Srwatson grpsubset = grpsubset && 168096886Sjhb groupmember(p->p_ucred->cr_rgid, td->td_ucred) && 168196886Sjhb groupmember(p->p_ucred->cr_svgid, td->td_ucred); 168285895Srwatson 168385895Srwatson /* 168496886Sjhb * Are the uids present in p's credential equal to td's 168596886Sjhb * effective uid? This includes p's euid, svuid, and ruid. 168685895Srwatson */ 168796886Sjhb uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid && 168896886Sjhb td->td_ucred->cr_uid == p->p_ucred->cr_svuid && 168996886Sjhb td->td_ucred->cr_uid == p->p_ucred->cr_ruid); 169085895Srwatson 169185895Srwatson /* 169285895Srwatson * Has the credential of the process changed since the last exec()? 169385895Srwatson */ 169496886Sjhb credentialchanged = (p->p_flag & P_SUGID); 169585895Srwatson 169685895Srwatson /* 169796886Sjhb * If p's gids aren't a subset, or the uids aren't a subset, 169885895Srwatson * or the credential has changed, require appropriate privilege 1699164032Srwatson * for td to debug p. 170085895Srwatson */ 1701164032Srwatson if (!grpsubset || !uidsubset) { 1702170587Srwatson error = priv_check(td, PRIV_DEBUG_DIFFCRED); 170384727Srwatson if (error) 170465237Srwatson return (error); 170582466Srwatson } 170665237Srwatson 1707164032Srwatson if (credentialchanged) { 1708170587Srwatson error = priv_check(td, PRIV_DEBUG_SUGID); 1709164032Srwatson if (error) 1710164032Srwatson return (error); 1711164032Srwatson } 1712164032Srwatson 171387218Srwatson /* Can't trace init when securelevel > 0. */ 171496886Sjhb if (p == initproc) { 171596886Sjhb error = securelevel_gt(td->td_ucred, 0); 171683639Srwatson if (error) 171783639Srwatson return (error); 171883639Srwatson } 171965237Srwatson 172085880Srwatson /* 172185880Srwatson * Can't trace a process that's currently exec'ing. 1722164032Srwatson * 172385880Srwatson * XXX: Note, this is not a security policy decision, it's a 172485880Srwatson * basic correctness/functionality decision. Therefore, this check 172585880Srwatson * should be moved to the caller's of p_candebug(). 172685880Srwatson */ 172796886Sjhb if ((p->p_flag & P_INEXEC) != 0) 1728185983Skib return (EBUSY); 172987466Srwatson 1730277322Skib /* Denied explicitely */ 1731277322Skib if ((p->p_flag2 & P2_NOTRACE) != 0) { 1732277322Skib error = priv_check(td, PRIV_DEBUG_DENIED); 1733277322Skib if (error != 0) 1734277322Skib return (error); 1735277322Skib } 1736277322Skib 173765237Srwatson return (0); 173865237Srwatson} 173965237Srwatson 1740210226Strasz/*- 174192976Srwatson * Determine whether the subject represented by cred can "see" a socket. 174292976Srwatson * Returns: 0 for permitted, ENOENT otherwise. 174392976Srwatson */ 174492976Srwatsonint 174592976Srwatsoncr_canseesocket(struct ucred *cred, struct socket *so) 174692976Srwatson{ 174792976Srwatson int error; 174892976Srwatson 174992976Srwatson error = prison_check(cred, so->so_cred); 175092976Srwatson if (error) 175192976Srwatson return (ENOENT); 1752101003Srwatson#ifdef MAC 1753172930Srwatson error = mac_socket_check_visible(cred, so); 1754101003Srwatson if (error) 1755101003Srwatson return (error); 1756101003Srwatson#endif 175792976Srwatson if (cr_seeotheruids(cred, so->so_cred)) 175892976Srwatson return (ENOENT); 1759122869Srwatson if (cr_seeothergids(cred, so->so_cred)) 1760122869Srwatson return (ENOENT); 176192976Srwatson 176292976Srwatson return (0); 176392976Srwatson} 176492976Srwatson 1765183982Sbz#if defined(INET) || defined(INET6) 1766210226Strasz/*- 1767183982Sbz * Determine whether the subject represented by cred can "see" a socket. 1768183982Sbz * Returns: 0 for permitted, ENOENT otherwise. 1769183982Sbz */ 1770183982Sbzint 1771183982Sbzcr_canseeinpcb(struct ucred *cred, struct inpcb *inp) 1772183982Sbz{ 1773183982Sbz int error; 1774183982Sbz 1775183982Sbz error = prison_check(cred, inp->inp_cred); 1776183982Sbz if (error) 1777183982Sbz return (ENOENT); 1778183982Sbz#ifdef MAC 1779183982Sbz INP_LOCK_ASSERT(inp); 1780183982Sbz error = mac_inpcb_check_visible(cred, inp); 1781183982Sbz if (error) 1782183982Sbz return (error); 1783183982Sbz#endif 1784183982Sbz if (cr_seeotheruids(cred, inp->inp_cred)) 1785183982Sbz return (ENOENT); 1786183982Sbz if (cr_seeothergids(cred, inp->inp_cred)) 1787183982Sbz return (ENOENT); 1788183982Sbz 1789183982Sbz return (0); 1790183982Sbz} 1791183982Sbz#endif 1792183982Sbz 1793210226Strasz/*- 1794145234Srwatson * Determine whether td can wait for the exit of p. 1795145234Srwatson * Returns: 0 for permitted, an errno value otherwise 1796145234Srwatson * Locks: Sufficient locks to protect various components of td and p 1797145234Srwatson * must be held. td must be curthread, and a lock must 1798145234Srwatson * be held for p. 1799145234Srwatson * References: td and p must be valid for the lifetime of the call 1800145234Srwatson 1801145234Srwatson */ 1802145234Srwatsonint 1803145234Srwatsonp_canwait(struct thread *td, struct proc *p) 1804145234Srwatson{ 1805145234Srwatson int error; 1806145234Srwatson 1807145234Srwatson KASSERT(td == curthread, ("%s: td not curthread", __func__)); 1808145234Srwatson PROC_LOCK_ASSERT(p, MA_OWNED); 1809195741Sjamie if ((error = prison_check(td->td_ucred, p->p_ucred))) 1810145234Srwatson return (error); 1811145234Srwatson#ifdef MAC 1812172930Srwatson if ((error = mac_proc_check_wait(td->td_ucred, p))) 1813145234Srwatson return (error); 1814145234Srwatson#endif 1815145234Srwatson#if 0 1816145234Srwatson /* XXXMAC: This could have odd effects on some shells. */ 1817145234Srwatson if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) 1818145234Srwatson return (error); 1819145234Srwatson#endif 1820145234Srwatson 1821145234Srwatson return (0); 1822145234Srwatson} 1823145234Srwatson 182453518Sphk/* 18251541Srgrimes * Allocate a zeroed cred structure. 18261541Srgrimes */ 18271541Srgrimesstruct ucred * 182893580Sjhbcrget(void) 18291541Srgrimes{ 1830331643Sdim struct ucred *cr; 18311541Srgrimes 1832184205Sdes cr = malloc(sizeof(*cr), M_CRED, M_WAITOK | M_ZERO); 1833150634Sjhb refcount_init(&cr->cr_ref, 1); 1834170407Srwatson#ifdef AUDIT 1835170407Srwatson audit_cred_init(cr); 1836170407Srwatson#endif 1837101001Srwatson#ifdef MAC 1838172930Srwatson mac_cred_init(cr); 1839101001Srwatson#endif 1840274122Smjg cr->cr_groups = cr->cr_smallgroups; 1841274122Smjg cr->cr_agroups = 1842274122Smjg sizeof(cr->cr_smallgroups) / sizeof(cr->cr_smallgroups[0]); 18431541Srgrimes return (cr); 18441541Srgrimes} 18451541Srgrimes 18461541Srgrimes/* 184782466Srwatson * Claim another reference to a ucred structure. 184869401Salfred */ 184984827Sjhbstruct ucred * 185093580Sjhbcrhold(struct ucred *cr) 185169401Salfred{ 185269401Salfred 1853150634Sjhb refcount_acquire(&cr->cr_ref); 185484827Sjhb return (cr); 185569401Salfred} 185669401Salfred 185769401Salfred/* 1858167211Srwatson * Free a cred structure. Throws away space when ref count gets to 0. 18591541Srgrimes */ 18601549Srgrimesvoid 186193580Sjhbcrfree(struct ucred *cr) 18621541Srgrimes{ 186369239Salfred 186475632Salfred KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref)); 1865150634Sjhb KASSERT(cr->cr_ref != 0xdeadc0de, ("dangling reference to ucred")); 1866150634Sjhb if (refcount_release(&cr->cr_ref)) { 186765495Struckman /* 186865495Struckman * Some callers of crget(), such as nfs_statfs(), 186965495Struckman * allocate a temporary credential, but don't 187065495Struckman * allocate a uidinfo structure. 187165495Struckman */ 187265495Struckman if (cr->cr_uidinfo != NULL) 187365495Struckman uifree(cr->cr_uidinfo); 187477277Srwatson if (cr->cr_ruidinfo != NULL) 187577277Srwatson uifree(cr->cr_ruidinfo); 187672786Srwatson /* 187772786Srwatson * Free a prison, if any. 187872786Srwatson */ 1879192895Sjamie if (cr->cr_prison != NULL) 188072786Srwatson prison_free(cr->cr_prison); 1881219304Strasz if (cr->cr_loginclass != NULL) 1882219304Strasz loginclass_free(cr->cr_loginclass); 1883170407Srwatson#ifdef AUDIT 1884170407Srwatson audit_cred_destroy(cr); 1885170407Srwatson#endif 1886101001Srwatson#ifdef MAC 1887172930Srwatson mac_cred_destroy(cr); 1888101001Srwatson#endif 1889274122Smjg if (cr->cr_groups != cr->cr_smallgroups) 1890274122Smjg free(cr->cr_groups, M_CRED); 1891184205Sdes free(cr, M_CRED); 189290756Sdillon } 18931541Srgrimes} 18941541Srgrimes 18951541Srgrimes/* 189684827Sjhb * Copy a ucred's contents from a template. Does not block. 189784827Sjhb */ 189884827Sjhbvoid 189993580Sjhbcrcopy(struct ucred *dest, struct ucred *src) 190084827Sjhb{ 190184827Sjhb 1902272546Smjg KASSERT(dest->cr_ref == 1, ("crcopy of shared ucred")); 190384827Sjhb bcopy(&src->cr_startcopy, &dest->cr_startcopy, 190487218Srwatson (unsigned)((caddr_t)&src->cr_endcopy - 190584827Sjhb (caddr_t)&src->cr_startcopy)); 1906194498Sbrooks crsetgroups(dest, src->cr_ngroups, src->cr_groups); 190784827Sjhb uihold(dest->cr_uidinfo); 190884827Sjhb uihold(dest->cr_ruidinfo); 1909192895Sjamie prison_hold(dest->cr_prison); 1910219304Strasz loginclass_hold(dest->cr_loginclass); 1911170407Srwatson#ifdef AUDIT 1912170407Srwatson audit_cred_copy(src, dest); 1913170407Srwatson#endif 1914101001Srwatson#ifdef MAC 1915172930Srwatson mac_cred_copy(src, dest); 1916101001Srwatson#endif 191784827Sjhb} 191884827Sjhb 191984827Sjhb/* 19201541Srgrimes * Dup cred struct to a new held one. 19211541Srgrimes */ 19221541Srgrimesstruct ucred * 192393580Sjhbcrdup(struct ucred *cr) 19241541Srgrimes{ 19251541Srgrimes struct ucred *newcr; 19261541Srgrimes 192784827Sjhb newcr = crget(); 192884827Sjhb crcopy(newcr, cr); 19291541Srgrimes return (newcr); 19301541Srgrimes} 19311541Srgrimes 19321541Srgrimes/* 193391354Sdd * Fill in a struct xucred based on a struct ucred. 193491354Sdd */ 193591354Sddvoid 193693580Sjhbcru2x(struct ucred *cr, struct xucred *xcr) 193791354Sdd{ 1938194498Sbrooks int ngroups; 193991354Sdd 194091354Sdd bzero(xcr, sizeof(*xcr)); 194191354Sdd xcr->cr_version = XUCRED_VERSION; 194291354Sdd xcr->cr_uid = cr->cr_uid; 1943194498Sbrooks 1944194498Sbrooks ngroups = MIN(cr->cr_ngroups, XU_NGROUPS); 1945194498Sbrooks xcr->cr_ngroups = ngroups; 1946194498Sbrooks bcopy(cr->cr_groups, xcr->cr_groups, 1947194498Sbrooks ngroups * sizeof(*cr->cr_groups)); 194891354Sdd} 194991354Sdd 195091354Sdd/* 1951280331Smjg * Set initial process credentials. 1952280331Smjg * Callers are responsible for providing the reference for provided credentials. 1953280331Smjg */ 1954280331Smjgvoid 1955280331Smjgproc_set_cred_init(struct proc *p, struct ucred *newcred) 1956280331Smjg{ 1957280331Smjg 1958280331Smjg p->p_ucred = newcred; 1959280331Smjg} 1960280331Smjg 1961280331Smjg/* 1962280130Smjg * Change process credentials. 1963280331Smjg * Callers are responsible for providing the reference for passed credentials 1964280130Smjg * and for freeing old ones. 1965280130Smjg * 1966280130Smjg * Process has to be locked except when it does not have credentials (as it 1967280130Smjg * should not be visible just yet) or when newcred is NULL (as this can be 1968280130Smjg * only used when the process is about to be freed, at which point it should 1969280130Smjg * not be visible anymore). 1970280130Smjg */ 1971194498Sbrooksstruct ucred * 1972280130Smjgproc_set_cred(struct proc *p, struct ucred *newcred) 1973280130Smjg{ 1974280130Smjg struct ucred *oldcred; 1975280130Smjg 1976280331Smjg MPASS(p->p_ucred != NULL); 1977280130Smjg if (newcred == NULL) 1978280130Smjg MPASS(p->p_state == PRS_ZOMBIE); 1979280331Smjg else 1980280130Smjg PROC_LOCK_ASSERT(p, MA_OWNED); 1981280130Smjg 1982280130Smjg oldcred = p->p_ucred; 1983280130Smjg p->p_ucred = newcred; 1984284214Smjg if (newcred != NULL) 1985284214Smjg PROC_UPDATE_COW(p); 1986280130Smjg return (oldcred); 1987280130Smjg} 1988280130Smjg 1989280130Smjgstruct ucred * 1990194498Sbrookscrcopysafe(struct proc *p, struct ucred *cr) 1991194498Sbrooks{ 1992194498Sbrooks struct ucred *oldcred; 1993194498Sbrooks int groups; 1994194498Sbrooks 1995194498Sbrooks PROC_LOCK_ASSERT(p, MA_OWNED); 1996194498Sbrooks 1997194498Sbrooks oldcred = p->p_ucred; 1998194498Sbrooks while (cr->cr_agroups < oldcred->cr_agroups) { 1999194498Sbrooks groups = oldcred->cr_agroups; 2000194498Sbrooks PROC_UNLOCK(p); 2001194498Sbrooks crextend(cr, groups); 2002194498Sbrooks PROC_LOCK(p); 2003194498Sbrooks oldcred = p->p_ucred; 2004194498Sbrooks } 2005194498Sbrooks crcopy(cr, oldcred); 2006194498Sbrooks 2007194498Sbrooks return (oldcred); 2008194498Sbrooks} 2009194498Sbrooks 201090748Sjulian/* 2011194498Sbrooks * Extend the passed in credential to hold n items. 2012194498Sbrooks */ 2013293909Sglebiusvoid 2014194498Sbrookscrextend(struct ucred *cr, int n) 2015194498Sbrooks{ 2016194498Sbrooks int cnt; 2017194498Sbrooks 2018194498Sbrooks /* Truncate? */ 2019194498Sbrooks if (n <= cr->cr_agroups) 2020194498Sbrooks return; 2021194498Sbrooks 2022194498Sbrooks /* 2023194498Sbrooks * We extend by 2 each time since we're using a power of two 2024194498Sbrooks * allocator until we need enough groups to fill a page. 2025194498Sbrooks * Once we're allocating multiple pages, only allocate as many 2026194498Sbrooks * as we actually need. The case of processes needing a 2027194498Sbrooks * non-power of two number of pages seems more likely than 2028194498Sbrooks * a real world process that adds thousands of groups one at a 2029194498Sbrooks * time. 2030194498Sbrooks */ 2031194498Sbrooks if ( n < PAGE_SIZE / sizeof(gid_t) ) { 2032194498Sbrooks if (cr->cr_agroups == 0) 2033194498Sbrooks cnt = MINALLOCSIZE / sizeof(gid_t); 2034194498Sbrooks else 2035194498Sbrooks cnt = cr->cr_agroups * 2; 2036194498Sbrooks 2037194498Sbrooks while (cnt < n) 2038194498Sbrooks cnt *= 2; 2039194498Sbrooks } else 2040194498Sbrooks cnt = roundup2(n, PAGE_SIZE / sizeof(gid_t)); 2041194498Sbrooks 2042194498Sbrooks /* Free the old array. */ 2043274122Smjg if (cr->cr_groups != cr->cr_smallgroups) 2044194498Sbrooks free(cr->cr_groups, M_CRED); 2045194498Sbrooks 2046194498Sbrooks cr->cr_groups = malloc(cnt * sizeof(gid_t), M_CRED, M_WAITOK | M_ZERO); 2047194498Sbrooks cr->cr_agroups = cnt; 2048194498Sbrooks} 2049194498Sbrooks 2050194498Sbrooks/* 2051194556Sbrooks * Copy groups in to a credential, preserving any necessary invariants. 2052194556Sbrooks * Currently this includes the sorting of all supplemental gids. 2053194556Sbrooks * crextend() must have been called before hand to ensure sufficient 2054194556Sbrooks * space is available. 2055194498Sbrooks */ 2056194498Sbrooksstatic void 2057194498Sbrookscrsetgroups_locked(struct ucred *cr, int ngrp, gid_t *groups) 2058194498Sbrooks{ 2059194556Sbrooks int i; 2060194556Sbrooks int j; 2061194556Sbrooks gid_t g; 2062194498Sbrooks 2063194498Sbrooks KASSERT(cr->cr_agroups >= ngrp, ("cr_ngroups is too small")); 2064194498Sbrooks 2065194498Sbrooks bcopy(groups, cr->cr_groups, ngrp * sizeof(gid_t)); 2066194498Sbrooks cr->cr_ngroups = ngrp; 2067194556Sbrooks 2068194556Sbrooks /* 2069194556Sbrooks * Sort all groups except cr_groups[0] to allow groupmember to 2070194556Sbrooks * perform a binary search. 2071194556Sbrooks * 2072194556Sbrooks * XXX: If large numbers of groups become common this should 2073194556Sbrooks * be replaced with shell sort like linux uses or possibly 2074194556Sbrooks * heap sort. 2075194556Sbrooks */ 2076194556Sbrooks for (i = 2; i < ngrp; i++) { 2077194556Sbrooks g = cr->cr_groups[i]; 2078194556Sbrooks for (j = i-1; j >= 1 && g < cr->cr_groups[j]; j--) 2079194556Sbrooks cr->cr_groups[j + 1] = cr->cr_groups[j]; 2080194556Sbrooks cr->cr_groups[j + 1] = g; 2081194556Sbrooks } 2082194498Sbrooks} 2083194498Sbrooks 2084194498Sbrooks/* 2085194498Sbrooks * Copy groups in to a credential after expanding it if required. 2086202143Sbrooks * Truncate the list to (ngroups_max + 1) if it is too large. 2087194498Sbrooks */ 2088194498Sbrooksvoid 2089194498Sbrookscrsetgroups(struct ucred *cr, int ngrp, gid_t *groups) 2090194498Sbrooks{ 2091194498Sbrooks 2092202143Sbrooks if (ngrp > ngroups_max + 1) 2093202143Sbrooks ngrp = ngroups_max + 1; 2094194498Sbrooks 2095194498Sbrooks crextend(cr, ngrp); 2096194498Sbrooks crsetgroups_locked(cr, ngrp, groups); 2097194498Sbrooks} 2098194498Sbrooks 2099194498Sbrooks/* 21001541Srgrimes * Get login name, if available. 21011541Srgrimes */ 210212221Sbde#ifndef _SYS_SYSPROTO_H_ 21031541Srgrimesstruct getlogin_args { 21041541Srgrimes char *namebuf; 21051541Srgrimes u_int namelen; 21061541Srgrimes}; 210712221Sbde#endif 21081541Srgrimes/* ARGSUSED */ 21091549Srgrimesint 2110225617Skmacysys_getlogin(struct thread *td, struct getlogin_args *uap) 21111541Srgrimes{ 211291140Stanimura char login[MAXLOGNAME]; 211383366Sjulian struct proc *p = td->td_proc; 2114274106Sdes size_t len; 21151541Srgrimes 211623358Sache if (uap->namelen > MAXLOGNAME) 211723359Sache uap->namelen = MAXLOGNAME; 211891140Stanimura PROC_LOCK(p); 211991140Stanimura SESS_LOCK(p->p_session); 2120274106Sdes len = strlcpy(login, p->p_session->s_login, uap->namelen) + 1; 212191140Stanimura SESS_UNLOCK(p->p_session); 212291140Stanimura PROC_UNLOCK(p); 2123274106Sdes if (len > uap->namelen) 2124243021Sbapt return (ERANGE); 2125274106Sdes return (copyout(login, uap->namebuf, len)); 21261541Srgrimes} 21271541Srgrimes 21281541Srgrimes/* 21291541Srgrimes * Set login name. 21301541Srgrimes */ 213112221Sbde#ifndef _SYS_SYSPROTO_H_ 21321541Srgrimesstruct setlogin_args { 21331541Srgrimes char *namebuf; 21341541Srgrimes}; 213512221Sbde#endif 21361541Srgrimes/* ARGSUSED */ 21371549Srgrimesint 2138225617Skmacysys_setlogin(struct thread *td, struct setlogin_args *uap) 21391541Srgrimes{ 214083366Sjulian struct proc *p = td->td_proc; 21411541Srgrimes int error; 214223330Sache char logintmp[MAXLOGNAME]; 21431541Srgrimes 2144274106Sdes CTASSERT(sizeof(p->p_session->s_login) >= sizeof(logintmp)); 2145274106Sdes 2146170587Srwatson error = priv_check(td, PRIV_PROC_SETLOGIN); 214794619Sjhb if (error) 214894619Sjhb return (error); 214999009Salfred error = copyinstr(uap->namebuf, logintmp, sizeof(logintmp), NULL); 2150274106Sdes if (error != 0) { 2151274106Sdes if (error == ENAMETOOLONG) 2152274106Sdes error = EINVAL; 2153274106Sdes return (error); 215491140Stanimura } 2155274106Sdes PROC_LOCK(p); 2156274106Sdes SESS_LOCK(p->p_session); 2157274106Sdes strcpy(p->p_session->s_login, logintmp); 2158274106Sdes SESS_UNLOCK(p->p_session); 2159274106Sdes PROC_UNLOCK(p); 2160274106Sdes return (0); 21611541Srgrimes} 216231891Ssef 216331891Ssefvoid 216493580Sjhbsetsugid(struct proc *p) 216531891Ssef{ 216698403Salfred 216798403Salfred PROC_LOCK_ASSERT(p, MA_OWNED); 216831891Ssef p->p_flag |= P_SUGID; 216955707Ssef if (!(p->p_pfsflags & PF_ISUGID)) 217031891Ssef p->p_stops = 0; 217131891Ssef} 217265495Struckman 2173210226Strasz/*- 217482466Srwatson * Change a process's effective uid. 217577183Srwatson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified. 217677183Srwatson * References: newcred must be an exclusive credential reference for the 217777183Srwatson * duration of the call. 217865495Struckman */ 217965495Struckmanvoid 218098417Salfredchange_euid(struct ucred *newcred, struct uidinfo *euip) 218165495Struckman{ 218265495Struckman 218398417Salfred newcred->cr_uid = euip->ui_uid; 218498417Salfred uihold(euip); 218577183Srwatson uifree(newcred->cr_uidinfo); 218698417Salfred newcred->cr_uidinfo = euip; 218765495Struckman} 218865495Struckman 2189210226Strasz/*- 219082466Srwatson * Change a process's effective gid. 219177183Srwatson * Side effects: newcred->cr_gid will be modified. 219277183Srwatson * References: newcred must be an exclusive credential reference for the 219377183Srwatson * duration of the call. 219465495Struckman */ 219567629Sgallatinvoid 219693580Sjhbchange_egid(struct ucred *newcred, gid_t egid) 219765495Struckman{ 219865495Struckman 219977183Srwatson newcred->cr_groups[0] = egid; 220065495Struckman} 220177183Srwatson 2202210226Strasz/*- 220382466Srwatson * Change a process's real uid. 220477183Srwatson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo 220577183Srwatson * will be updated, and the old and new cr_ruidinfo proc 220677183Srwatson * counts will be updated. 220777183Srwatson * References: newcred must be an exclusive credential reference for the 220877183Srwatson * duration of the call. 220977183Srwatson */ 221077183Srwatsonvoid 221198417Salfredchange_ruid(struct ucred *newcred, struct uidinfo *ruip) 221277183Srwatson{ 221377183Srwatson 221477183Srwatson (void)chgproccnt(newcred->cr_ruidinfo, -1, 0); 221598417Salfred newcred->cr_ruid = ruip->ui_uid; 221698417Salfred uihold(ruip); 221777183Srwatson uifree(newcred->cr_ruidinfo); 221898417Salfred newcred->cr_ruidinfo = ruip; 221977183Srwatson (void)chgproccnt(newcred->cr_ruidinfo, 1, 0); 222077183Srwatson} 222177183Srwatson 2222210226Strasz/*- 222382466Srwatson * Change a process's real gid. 222477183Srwatson * Side effects: newcred->cr_rgid will be updated. 222577183Srwatson * References: newcred must be an exclusive credential reference for the 222677183Srwatson * duration of the call. 222777183Srwatson */ 222877183Srwatsonvoid 222993580Sjhbchange_rgid(struct ucred *newcred, gid_t rgid) 223077183Srwatson{ 223177183Srwatson 223277183Srwatson newcred->cr_rgid = rgid; 223377183Srwatson} 223477183Srwatson 2235210226Strasz/*- 223682466Srwatson * Change a process's saved uid. 223777183Srwatson * Side effects: newcred->cr_svuid will be updated. 223877183Srwatson * References: newcred must be an exclusive credential reference for the 223977183Srwatson * duration of the call. 224077183Srwatson */ 224177183Srwatsonvoid 224293580Sjhbchange_svuid(struct ucred *newcred, uid_t svuid) 224377183Srwatson{ 224477183Srwatson 224577183Srwatson newcred->cr_svuid = svuid; 224677183Srwatson} 224777183Srwatson 2248210226Strasz/*- 224982466Srwatson * Change a process's saved gid. 225077183Srwatson * Side effects: newcred->cr_svgid will be updated. 225177183Srwatson * References: newcred must be an exclusive credential reference for the 225277183Srwatson * duration of the call. 225377183Srwatson */ 225477183Srwatsonvoid 225593580Sjhbchange_svgid(struct ucred *newcred, gid_t svgid) 225677183Srwatson{ 225777183Srwatson 225877183Srwatson newcred->cr_svgid = svgid; 225977183Srwatson} 2260