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$"); 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> 6865495Struckman#include <sys/resourcevar.h> 6992976Srwatson#include <sys/socket.h> 7092976Srwatson#include <sys/socketvar.h> 71160139Sjhb#include <sys/syscallsubr.h> 7261287Srwatson#include <sys/sysctl.h> 731541Srgrimes 74219028Snetchild#ifdef REGRESSION 75219028SnetchildFEATURE(regression, 76229818Shrs "Kernel support for interfaces necessary for regression testing (SECURITY RISK!)"); 77219028Snetchild#endif 78219028Snetchild 79183982Sbz#if defined(INET) || defined(INET6) 80183982Sbz#include <netinet/in.h> 81183982Sbz#include <netinet/in_pcb.h> 82183982Sbz#endif 83183982Sbz 84155370Swsalamon#include <security/audit/audit.h> 85163606Srwatson#include <security/mac/mac_framework.h> 86155370Swsalamon 8730354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials"); 8830354Sphk 89162383SrwatsonSYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0, "BSD security policy"); 9087138Srwatson 91194498Sbrooksstatic void crsetgroups_locked(struct ucred *cr, int ngrp, 92194498Sbrooks gid_t *groups); 93194498Sbrooks 9412221Sbde#ifndef _SYS_SYSPROTO_H_ 9511332Sswallacestruct getpid_args { 961541Srgrimes int dummy; 971541Srgrimes}; 9812221Sbde#endif 991541Srgrimes/* ARGSUSED */ 1001549Srgrimesint 101225617Skmacysys_getpid(struct thread *td, struct getpid_args *uap) 1021541Srgrimes{ 10383366Sjulian struct proc *p = td->td_proc; 1041541Srgrimes 10583366Sjulian td->td_retval[0] = p->p_pid; 106130344Sphk#if defined(COMPAT_43) 10774728Sjhb PROC_LOCK(p); 10883366Sjulian td->td_retval[1] = p->p_pptr->p_pid; 10974728Sjhb PROC_UNLOCK(p); 1101541Srgrimes#endif 1111541Srgrimes return (0); 1121541Srgrimes} 1131541Srgrimes 11412221Sbde#ifndef _SYS_SYSPROTO_H_ 11511332Sswallacestruct getppid_args { 11611332Sswallace int dummy; 11711332Sswallace}; 11812221Sbde#endif 1191541Srgrimes/* ARGSUSED */ 1201549Srgrimesint 121225617Skmacysys_getppid(struct thread *td, struct getppid_args *uap) 1221541Srgrimes{ 12383366Sjulian struct proc *p = td->td_proc; 1241541Srgrimes 12574728Sjhb PROC_LOCK(p); 12683366Sjulian td->td_retval[0] = p->p_pptr->p_pid; 12774728Sjhb PROC_UNLOCK(p); 1281541Srgrimes return (0); 1291541Srgrimes} 1301541Srgrimes 13187466Srwatson/* 13287218Srwatson * Get process group ID; note that POSIX getpgrp takes no parameter. 13358717Sdillon */ 13412221Sbde#ifndef _SYS_SYSPROTO_H_ 13511332Sswallacestruct getpgrp_args { 13611332Sswallace int dummy; 13711332Sswallace}; 13812221Sbde#endif 1391549Srgrimesint 140225617Skmacysys_getpgrp(struct thread *td, struct getpgrp_args *uap) 1411541Srgrimes{ 14283366Sjulian struct proc *p = td->td_proc; 1431541Srgrimes 14491140Stanimura PROC_LOCK(p); 14583366Sjulian td->td_retval[0] = p->p_pgrp->pg_id; 14691140Stanimura PROC_UNLOCK(p); 1471541Srgrimes return (0); 1481541Srgrimes} 1491541Srgrimes 150302234Sbdrewery/* Get an arbitrary pid's process group id */ 15112221Sbde#ifndef _SYS_SYSPROTO_H_ 15228401Speterstruct getpgid_args { 15328401Speter pid_t pid; 15428401Speter}; 15528401Speter#endif 15628401Speterint 157225617Skmacysys_getpgid(struct thread *td, struct getpgid_args *uap) 15828401Speter{ 159114031Sjhb struct proc *p; 16092985Sjhb int error; 16141726Struckman 16291140Stanimura if (uap->pid == 0) { 163114031Sjhb p = td->td_proc; 16491140Stanimura PROC_LOCK(p); 165114031Sjhb } else { 166114031Sjhb p = pfind(uap->pid); 167114031Sjhb if (p == NULL) 168114031Sjhb return (ESRCH); 169114031Sjhb error = p_cansee(td, p); 170114031Sjhb if (error) { 171114031Sjhb PROC_UNLOCK(p); 172114031Sjhb return (error); 173114031Sjhb } 17475893Sjhb } 175114031Sjhb td->td_retval[0] = p->p_pgrp->pg_id; 176114031Sjhb PROC_UNLOCK(p); 177114031Sjhb return (0); 17828401Speter} 17928401Speter 18028401Speter/* 181302234Sbdrewery * Get an arbitrary pid's session id. 18228401Speter */ 18328401Speter#ifndef _SYS_SYSPROTO_H_ 18428401Speterstruct getsid_args { 18528401Speter pid_t pid; 18628401Speter}; 18728401Speter#endif 18828401Speterint 189225617Skmacysys_getsid(struct thread *td, struct getsid_args *uap) 19028401Speter{ 191114031Sjhb struct proc *p; 19287218Srwatson int error; 19341726Struckman 19491140Stanimura if (uap->pid == 0) { 195114031Sjhb p = td->td_proc; 19691140Stanimura PROC_LOCK(p); 197114031Sjhb } else { 198114031Sjhb p = pfind(uap->pid); 199114031Sjhb if (p == NULL) 200114031Sjhb return (ESRCH); 201114031Sjhb error = p_cansee(td, p); 202114031Sjhb if (error) { 203114031Sjhb PROC_UNLOCK(p); 204114031Sjhb return (error); 205114031Sjhb } 20675893Sjhb } 207114031Sjhb td->td_retval[0] = p->p_session->s_sid; 208114031Sjhb PROC_UNLOCK(p); 209114031Sjhb return (0); 21028401Speter} 21128401Speter 21228401Speter#ifndef _SYS_SYSPROTO_H_ 21311332Sswallacestruct getuid_args { 21411332Sswallace int dummy; 21511332Sswallace}; 21612221Sbde#endif 2171541Srgrimes/* ARGSUSED */ 2181549Srgrimesint 219225617Skmacysys_getuid(struct thread *td, struct getuid_args *uap) 2201541Srgrimes{ 2211541Srgrimes 22292987Sjhb td->td_retval[0] = td->td_ucred->cr_ruid; 223130344Sphk#if defined(COMPAT_43) 22492987Sjhb td->td_retval[1] = td->td_ucred->cr_uid; 2251541Srgrimes#endif 2261541Srgrimes return (0); 2271541Srgrimes} 2281541Srgrimes 22912221Sbde#ifndef _SYS_SYSPROTO_H_ 23011332Sswallacestruct geteuid_args { 23111332Sswallace int dummy; 23211332Sswallace}; 23312221Sbde#endif 2341541Srgrimes/* ARGSUSED */ 2351549Srgrimesint 236225617Skmacysys_geteuid(struct thread *td, struct geteuid_args *uap) 2371541Srgrimes{ 23892987Sjhb 23992987Sjhb td->td_retval[0] = td->td_ucred->cr_uid; 2401541Srgrimes return (0); 2411541Srgrimes} 2421541Srgrimes 24312221Sbde#ifndef _SYS_SYSPROTO_H_ 24411332Sswallacestruct getgid_args { 24511332Sswallace int dummy; 24611332Sswallace}; 24712221Sbde#endif 2481541Srgrimes/* ARGSUSED */ 2491549Srgrimesint 250225617Skmacysys_getgid(struct thread *td, struct getgid_args *uap) 2511541Srgrimes{ 2521541Srgrimes 25392987Sjhb td->td_retval[0] = td->td_ucred->cr_rgid; 254130344Sphk#if defined(COMPAT_43) 25592987Sjhb td->td_retval[1] = td->td_ucred->cr_groups[0]; 2561541Srgrimes#endif 2571541Srgrimes return (0); 2581541Srgrimes} 2591541Srgrimes 2601541Srgrimes/* 2611541Srgrimes * Get effective group ID. The "egid" is groups[0], and could be obtained 2621541Srgrimes * via getgroups. This syscall exists because it is somewhat painful to do 2631541Srgrimes * correctly in a library function. 2641541Srgrimes */ 26512221Sbde#ifndef _SYS_SYSPROTO_H_ 26611332Sswallacestruct getegid_args { 26711332Sswallace int dummy; 26811332Sswallace}; 26912221Sbde#endif 2701541Srgrimes/* ARGSUSED */ 2711549Srgrimesint 272225617Skmacysys_getegid(struct thread *td, struct getegid_args *uap) 2731541Srgrimes{ 2741541Srgrimes 27592987Sjhb td->td_retval[0] = td->td_ucred->cr_groups[0]; 2761541Srgrimes return (0); 2771541Srgrimes} 2781541Srgrimes 27912221Sbde#ifndef _SYS_SYSPROTO_H_ 2801541Srgrimesstruct getgroups_args { 2811541Srgrimes u_int gidsetsize; 2821541Srgrimes gid_t *gidset; 2831541Srgrimes}; 28412221Sbde#endif 2851549Srgrimesint 286225617Skmacysys_getgroups(struct thread *td, register struct getgroups_args *uap) 2871541Srgrimes{ 288194498Sbrooks gid_t *groups; 28977183Srwatson u_int ngrp; 29087218Srwatson int error; 2911541Srgrimes 292202342Sbrooks if (uap->gidsetsize < td->td_ucred->cr_ngroups) { 293202342Sbrooks if (uap->gidsetsize == 0) 294202342Sbrooks ngrp = 0; 295202342Sbrooks else 296202342Sbrooks return (EINVAL); 297202342Sbrooks } else 298202342Sbrooks ngrp = td->td_ucred->cr_ngroups; 299194498Sbrooks groups = malloc(ngrp * sizeof(*groups), M_TEMP, M_WAITOK); 300160139Sjhb error = kern_getgroups(td, &ngrp, groups); 301160139Sjhb if (error) 302194498Sbrooks goto out; 303160139Sjhb if (uap->gidsetsize > 0) 304160139Sjhb error = copyout(groups, uap->gidset, ngrp * sizeof(gid_t)); 305160139Sjhb if (error == 0) 306160139Sjhb td->td_retval[0] = ngrp; 307194498Sbrooksout: 308194498Sbrooks free(groups, M_TEMP); 309160139Sjhb return (error); 310160139Sjhb} 311160139Sjhb 312160139Sjhbint 313160139Sjhbkern_getgroups(struct thread *td, u_int *ngrp, gid_t *groups) 314160139Sjhb{ 315160139Sjhb struct ucred *cred; 316160139Sjhb 31792987Sjhb cred = td->td_ucred; 318160139Sjhb if (*ngrp == 0) { 319160139Sjhb *ngrp = cred->cr_ngroups; 32092987Sjhb return (0); 3211541Srgrimes } 322160139Sjhb if (*ngrp < cred->cr_ngroups) 32392987Sjhb return (EINVAL); 324160139Sjhb *ngrp = cred->cr_ngroups; 325160139Sjhb bcopy(cred->cr_groups, groups, *ngrp * sizeof(gid_t)); 326160139Sjhb return (0); 3271541Srgrimes} 3281541Srgrimes 32912221Sbde#ifndef _SYS_SYSPROTO_H_ 33012207Sbdestruct setsid_args { 33111332Sswallace int dummy; 33211332Sswallace}; 33312221Sbde#endif 3341541Srgrimes/* ARGSUSED */ 3351549Srgrimesint 336225617Skmacysys_setsid(register struct thread *td, struct setsid_args *uap) 3371541Srgrimes{ 33891140Stanimura struct pgrp *pgrp; 33982749Sdillon int error; 34083366Sjulian struct proc *p = td->td_proc; 34191140Stanimura struct pgrp *newpgrp; 34291140Stanimura struct session *newsess; 3431541Srgrimes 34491140Stanimura error = 0; 34591140Stanimura pgrp = NULL; 34691140Stanimura 347184205Sdes newpgrp = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); 348184205Sdes newsess = malloc(sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO); 34991140Stanimura 35094859Sjhb sx_xlock(&proctree_lock); 35191140Stanimura 35291140Stanimura if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) { 35391140Stanimura if (pgrp != NULL) 35491140Stanimura PGRP_UNLOCK(pgrp); 35582749Sdillon error = EPERM; 35691140Stanimura } else { 35791140Stanimura (void)enterpgrp(p, p->p_pid, newpgrp, newsess); 35883366Sjulian td->td_retval[0] = p->p_pid; 35994859Sjhb newpgrp = NULL; 36094859Sjhb newsess = NULL; 3611541Srgrimes } 36291140Stanimura 36394859Sjhb sx_xunlock(&proctree_lock); 36491140Stanimura 36595973Stanimura if (newpgrp != NULL) 366184205Sdes free(newpgrp, M_PGRP); 36795973Stanimura if (newsess != NULL) 368184205Sdes free(newsess, M_SESSION); 36991140Stanimura 37094859Sjhb return (error); 3711541Srgrimes} 3721541Srgrimes 3731541Srgrimes/* 3741541Srgrimes * set process group (setpgid/old setpgrp) 3751541Srgrimes * 3761541Srgrimes * caller does setpgid(targpid, targpgid) 3771541Srgrimes * 3781541Srgrimes * pid must be caller or child of caller (ESRCH) 3791541Srgrimes * if a child 3801541Srgrimes * pid must be in same session (EPERM) 3811541Srgrimes * pid can't have done an exec (EACCES) 3821541Srgrimes * if pgid != pid 3831541Srgrimes * there must exist some pid in same session having pgid (EPERM) 3841541Srgrimes * pid must not be session leader (EPERM) 3851541Srgrimes */ 38612221Sbde#ifndef _SYS_SYSPROTO_H_ 3871541Srgrimesstruct setpgid_args { 38887218Srwatson int pid; /* target process id */ 38987218Srwatson int pgid; /* target pgrp id */ 3901541Srgrimes}; 39112221Sbde#endif 3921541Srgrimes/* ARGSUSED */ 3931549Srgrimesint 394225617Skmacysys_setpgid(struct thread *td, register struct setpgid_args *uap) 3951541Srgrimes{ 39683366Sjulian struct proc *curp = td->td_proc; 39787218Srwatson register struct proc *targp; /* target process */ 39887218Srwatson register struct pgrp *pgrp; /* target pgrp */ 39975448Srwatson int error; 40091140Stanimura struct pgrp *newpgrp; 4011541Srgrimes 40220677Sbde if (uap->pgid < 0) 40320677Sbde return (EINVAL); 40491140Stanimura 40591140Stanimura error = 0; 40691140Stanimura 407184205Sdes newpgrp = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); 40891140Stanimura 40994859Sjhb sx_xlock(&proctree_lock); 4101541Srgrimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 41191140Stanimura if ((targp = pfind(uap->pid)) == NULL) { 41282749Sdillon error = ESRCH; 41394859Sjhb goto done; 41475893Sjhb } 41591140Stanimura if (!inferior(targp)) { 41691140Stanimura PROC_UNLOCK(targp); 41791371Stanimura error = ESRCH; 41894859Sjhb goto done; 41991140Stanimura } 420132568Srwatson if ((error = p_cansee(td, targp))) { 42175893Sjhb PROC_UNLOCK(targp); 42294859Sjhb goto done; 42375893Sjhb } 42475893Sjhb if (targp->p_pgrp == NULL || 42575893Sjhb targp->p_session != curp->p_session) { 42675893Sjhb PROC_UNLOCK(targp); 42782749Sdillon error = EPERM; 42894859Sjhb goto done; 42975893Sjhb } 43075893Sjhb if (targp->p_flag & P_EXEC) { 43175893Sjhb PROC_UNLOCK(targp); 43282749Sdillon error = EACCES; 43394859Sjhb goto done; 43475893Sjhb } 43591140Stanimura PROC_UNLOCK(targp); 43691140Stanimura } else 4371541Srgrimes targp = curp; 43875893Sjhb if (SESS_LEADER(targp)) { 43982749Sdillon error = EPERM; 44094859Sjhb goto done; 44175893Sjhb } 44287218Srwatson if (uap->pgid == 0) 4431541Srgrimes uap->pgid = targp->p_pid; 444117214Scognet if ((pgrp = pgfind(uap->pgid)) == NULL) { 445117214Scognet if (uap->pgid == targp->p_pid) { 446117214Scognet error = enterpgrp(targp, uap->pgid, newpgrp, 447117214Scognet NULL); 448117214Scognet if (error == 0) 449117214Scognet newpgrp = NULL; 450117214Scognet } else 451117214Scognet error = EPERM; 45291140Stanimura } else { 453117214Scognet if (pgrp == targp->p_pgrp) { 454117214Scognet PGRP_UNLOCK(pgrp); 45594859Sjhb goto done; 45675893Sjhb } 457117214Scognet if (pgrp->pg_id != targp->p_pid && 458117214Scognet pgrp->pg_session != curp->p_session) { 45991140Stanimura PGRP_UNLOCK(pgrp); 460117214Scognet error = EPERM; 46191140Stanimura goto done; 46291140Stanimura } 46391140Stanimura PGRP_UNLOCK(pgrp); 46491140Stanimura error = enterthispgrp(targp, pgrp); 46582749Sdillon } 46691140Stanimuradone: 46794859Sjhb sx_xunlock(&proctree_lock); 46894859Sjhb KASSERT((error == 0) || (newpgrp != NULL), 46994859Sjhb ("setpgid failed and newpgrp is NULL")); 47095973Stanimura if (newpgrp != NULL) 471184205Sdes free(newpgrp, M_PGRP); 47282749Sdillon return (error); 4731541Srgrimes} 4741541Srgrimes 47524448Speter/* 47624448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 47772093Sasmodai * compatible. It says that setting the uid/gid to euid/egid is a special 47824448Speter * case of "appropriate privilege". Once the rules are expanded out, this 47924448Speter * basically means that setuid(nnn) sets all three id's, in all permitted 48024448Speter * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 48124448Speter * does not set the saved id - this is dangerous for traditional BSD 48224448Speter * programs. For this reason, we *really* do not want to set 48324448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 48424448Speter */ 48524448Speter#define POSIX_APPENDIX_B_4_2_2 48624448Speter 48712221Sbde#ifndef _SYS_SYSPROTO_H_ 4881541Srgrimesstruct setuid_args { 4891541Srgrimes uid_t uid; 4901541Srgrimes}; 49112221Sbde#endif 4921541Srgrimes/* ARGSUSED */ 4931549Srgrimesint 494225617Skmacysys_setuid(struct thread *td, struct setuid_args *uap) 4951541Srgrimes{ 49683366Sjulian struct proc *p = td->td_proc; 49777183Srwatson struct ucred *newcred, *oldcred; 49877183Srwatson uid_t uid; 49998417Salfred struct uidinfo *uip; 50087218Srwatson int error; 5011541Srgrimes 50277183Srwatson uid = uap->uid; 503195104Srwatson AUDIT_ARG_UID(uid); 50494619Sjhb newcred = crget(); 50598417Salfred uip = uifind(uid); 50694619Sjhb PROC_LOCK(p); 507194498Sbrooks /* 508194498Sbrooks * Copy credentials so other references do not see our changes. 509194498Sbrooks */ 510194498Sbrooks oldcred = crcopysafe(p, newcred); 51187466Srwatson 512145147Srwatson#ifdef MAC 513189529Srwatson error = mac_cred_check_setuid(oldcred, uid); 514145147Srwatson if (error) 515145147Srwatson goto fail; 516145147Srwatson#endif 517145147Srwatson 51824448Speter /* 51924448Speter * See if we have "permission" by POSIX 1003.1 rules. 52024448Speter * 52187218Srwatson * Note that setuid(geteuid()) is a special case of 52224448Speter * "appropriate privileges" in appendix B.4.2.2. We need 52372093Sasmodai * to use this clause to be compatible with traditional BSD 52424448Speter * semantics. Basically, it means that "setuid(xx)" sets all 52524448Speter * three id's (assuming you have privs). 52624448Speter * 52724448Speter * Notes on the logic. We do things in three steps. 52824448Speter * 1: We determine if the euid is going to change, and do EPERM 52924448Speter * right away. We unconditionally change the euid later if this 53024448Speter * test is satisfied, simplifying that part of the logic. 53187218Srwatson * 2: We determine if the real and/or saved uids are going to 53224448Speter * change. Determined by compile options. 53324448Speter * 3: Change euid last. (after tests in #2 for "appropriate privs") 53424448Speter */ 53577183Srwatson if (uid != oldcred->cr_ruid && /* allow setuid(getuid()) */ 53617994Sache#ifdef _POSIX_SAVED_IDS 53777183Srwatson uid != oldcred->cr_svuid && /* allow setuid(saved gid) */ 53817994Sache#endif 53924448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 54077183Srwatson uid != oldcred->cr_uid && /* allow setuid(geteuid()) */ 54124448Speter#endif 542170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETUID, 0)) != 0) 543145147Srwatson goto fail; 54424448Speter 54524448Speter#ifdef _POSIX_SAVED_IDS 5461541Srgrimes /* 54724448Speter * Do we have "appropriate privileges" (are we root or uid == euid) 54824448Speter * If so, we are changing the real uid and/or saved uid. 5491541Srgrimes */ 55017994Sache if ( 55124448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 55277183Srwatson uid == oldcred->cr_uid || 55317994Sache#endif 554164032Srwatson /* We are using privs. */ 555170587Srwatson priv_check_cred(oldcred, PRIV_CRED_SETUID, 0) == 0) 55617994Sache#endif 55724448Speter { 55824448Speter /* 55965495Struckman * Set the real uid and transfer proc count to new user. 56024448Speter */ 56177183Srwatson if (uid != oldcred->cr_ruid) { 56298417Salfred change_ruid(newcred, uip); 56365495Struckman setsugid(p); 56424448Speter } 56524448Speter /* 56624448Speter * Set saved uid 56724448Speter * 56824448Speter * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 56924448Speter * the security of seteuid() depends on it. B.4.2.2 says it 57024448Speter * is important that we should do this. 57124448Speter */ 57277183Srwatson if (uid != oldcred->cr_svuid) { 57377183Srwatson change_svuid(newcred, uid); 57431891Ssef setsugid(p); 57524448Speter } 5768141Sache } 57724448Speter 57824448Speter /* 57924448Speter * In all permitted cases, we are changing the euid. 58024448Speter */ 58177183Srwatson if (uid != oldcred->cr_uid) { 58298417Salfred change_euid(newcred, uip); 58331891Ssef setsugid(p); 58424448Speter } 585302229Sbdrewery proc_set_cred(p, newcred); 58694619Sjhb PROC_UNLOCK(p); 587220212Strasz#ifdef RACCT 588220212Strasz racct_proc_ucred_changed(p, oldcred, newcred); 589220212Strasz#endif 59098417Salfred uifree(uip); 59177183Srwatson crfree(oldcred); 59294619Sjhb return (0); 593145147Srwatson 594145147Srwatsonfail: 595145147Srwatson PROC_UNLOCK(p); 596145147Srwatson uifree(uip); 597145147Srwatson crfree(newcred); 598145147Srwatson return (error); 5991541Srgrimes} 6001541Srgrimes 60112221Sbde#ifndef _SYS_SYSPROTO_H_ 6021541Srgrimesstruct seteuid_args { 6031541Srgrimes uid_t euid; 6041541Srgrimes}; 60512221Sbde#endif 6061541Srgrimes/* ARGSUSED */ 6071549Srgrimesint 608225617Skmacysys_seteuid(struct thread *td, struct seteuid_args *uap) 6091541Srgrimes{ 61083366Sjulian struct proc *p = td->td_proc; 61177183Srwatson struct ucred *newcred, *oldcred; 61277183Srwatson uid_t euid; 61398417Salfred struct uidinfo *euip; 61487218Srwatson int error; 6151541Srgrimes 6161541Srgrimes euid = uap->euid; 617195104Srwatson AUDIT_ARG_EUID(euid); 61894619Sjhb newcred = crget(); 61998417Salfred euip = uifind(euid); 62094619Sjhb PROC_LOCK(p); 621194498Sbrooks /* 622194498Sbrooks * Copy credentials so other references do not see our changes. 623194498Sbrooks */ 624194498Sbrooks oldcred = crcopysafe(p, newcred); 625145147Srwatson 626145147Srwatson#ifdef MAC 627189529Srwatson error = mac_cred_check_seteuid(oldcred, euid); 628145147Srwatson if (error) 629145147Srwatson goto fail; 630145147Srwatson#endif 631145147Srwatson 63277183Srwatson if (euid != oldcred->cr_ruid && /* allow seteuid(getuid()) */ 63377183Srwatson euid != oldcred->cr_svuid && /* allow seteuid(saved uid) */ 634170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETEUID, 0)) != 0) 635145147Srwatson goto fail; 636145147Srwatson 6371541Srgrimes /* 638194498Sbrooks * Everything's okay, do it. 6391541Srgrimes */ 64077183Srwatson if (oldcred->cr_uid != euid) { 64198417Salfred change_euid(newcred, euip); 64231891Ssef setsugid(p); 64324449Speter } 644302229Sbdrewery proc_set_cred(p, newcred); 64594619Sjhb PROC_UNLOCK(p); 64698417Salfred uifree(euip); 64777183Srwatson crfree(oldcred); 64894619Sjhb return (0); 649145147Srwatson 650145147Srwatsonfail: 651145147Srwatson PROC_UNLOCK(p); 652145147Srwatson uifree(euip); 653145147Srwatson crfree(newcred); 654145147Srwatson return (error); 6551541Srgrimes} 6561541Srgrimes 65712221Sbde#ifndef _SYS_SYSPROTO_H_ 6581541Srgrimesstruct setgid_args { 6591541Srgrimes gid_t gid; 6601541Srgrimes}; 66112221Sbde#endif 6621541Srgrimes/* ARGSUSED */ 6631549Srgrimesint 664225617Skmacysys_setgid(struct thread *td, struct setgid_args *uap) 6651541Srgrimes{ 66683366Sjulian struct proc *p = td->td_proc; 66777183Srwatson struct ucred *newcred, *oldcred; 66877183Srwatson gid_t gid; 66987218Srwatson int error; 6701541Srgrimes 67177183Srwatson gid = uap->gid; 672195104Srwatson AUDIT_ARG_GID(gid); 67394619Sjhb newcred = crget(); 67494619Sjhb PROC_LOCK(p); 675194498Sbrooks oldcred = crcopysafe(p, newcred); 67687466Srwatson 677145147Srwatson#ifdef MAC 678189529Srwatson error = mac_cred_check_setgid(oldcred, gid); 679145147Srwatson if (error) 680145147Srwatson goto fail; 681145147Srwatson#endif 682145147Srwatson 68324448Speter /* 68424448Speter * See if we have "permission" by POSIX 1003.1 rules. 68524448Speter * 68624448Speter * Note that setgid(getegid()) is a special case of 68724448Speter * "appropriate privileges" in appendix B.4.2.2. We need 68872093Sasmodai * to use this clause to be compatible with traditional BSD 68924448Speter * semantics. Basically, it means that "setgid(xx)" sets all 69024448Speter * three id's (assuming you have privs). 69124448Speter * 69224448Speter * For notes on the logic here, see setuid() above. 69324448Speter */ 69477183Srwatson if (gid != oldcred->cr_rgid && /* allow setgid(getgid()) */ 69517994Sache#ifdef _POSIX_SAVED_IDS 69677183Srwatson gid != oldcred->cr_svgid && /* allow setgid(saved gid) */ 69717994Sache#endif 69824448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 69977183Srwatson gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */ 70024448Speter#endif 701170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETGID, 0)) != 0) 702145147Srwatson goto fail; 70324448Speter 70417994Sache#ifdef _POSIX_SAVED_IDS 70524448Speter /* 70624448Speter * Do we have "appropriate privileges" (are we root or gid == egid) 70724448Speter * If so, we are changing the real uid and saved gid. 70824448Speter */ 70924448Speter if ( 71024448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 71177183Srwatson gid == oldcred->cr_groups[0] || 71217994Sache#endif 713164032Srwatson /* We are using privs. */ 714170587Srwatson priv_check_cred(oldcred, PRIV_CRED_SETGID, 0) == 0) 71524448Speter#endif 71624448Speter { 71724448Speter /* 71824448Speter * Set real gid 71924448Speter */ 72077183Srwatson if (oldcred->cr_rgid != gid) { 72177183Srwatson change_rgid(newcred, gid); 72231891Ssef setsugid(p); 72324448Speter } 72424448Speter /* 72524448Speter * Set saved gid 72624448Speter * 72724448Speter * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 72824448Speter * the security of setegid() depends on it. B.4.2.2 says it 72924448Speter * is important that we should do this. 73024448Speter */ 73177183Srwatson if (oldcred->cr_svgid != gid) { 73277183Srwatson change_svgid(newcred, gid); 73331891Ssef setsugid(p); 73424448Speter } 7358141Sache } 73624448Speter /* 73724448Speter * In all cases permitted cases, we are changing the egid. 73824448Speter * Copy credentials so other references do not see our changes. 73924448Speter */ 74077183Srwatson if (oldcred->cr_groups[0] != gid) { 74177183Srwatson change_egid(newcred, gid); 74231891Ssef setsugid(p); 74324448Speter } 744302229Sbdrewery proc_set_cred(p, newcred); 74594619Sjhb PROC_UNLOCK(p); 74677183Srwatson crfree(oldcred); 74794619Sjhb return (0); 748145147Srwatson 749145147Srwatsonfail: 750145147Srwatson PROC_UNLOCK(p); 751145147Srwatson crfree(newcred); 752145147Srwatson return (error); 7531541Srgrimes} 7541541Srgrimes 75512221Sbde#ifndef _SYS_SYSPROTO_H_ 7561541Srgrimesstruct setegid_args { 7571541Srgrimes gid_t egid; 7581541Srgrimes}; 75912221Sbde#endif 7601541Srgrimes/* ARGSUSED */ 7611549Srgrimesint 762225617Skmacysys_setegid(struct thread *td, struct setegid_args *uap) 7631541Srgrimes{ 76483366Sjulian struct proc *p = td->td_proc; 76577183Srwatson struct ucred *newcred, *oldcred; 76677183Srwatson gid_t egid; 76787218Srwatson int error; 7681541Srgrimes 7691541Srgrimes egid = uap->egid; 770195104Srwatson AUDIT_ARG_EGID(egid); 77194619Sjhb newcred = crget(); 77294619Sjhb PROC_LOCK(p); 773194498Sbrooks oldcred = crcopysafe(p, newcred); 774145147Srwatson 775145147Srwatson#ifdef MAC 776189529Srwatson error = mac_cred_check_setegid(oldcred, egid); 777145147Srwatson if (error) 778145147Srwatson goto fail; 779145147Srwatson#endif 780145147Srwatson 78177183Srwatson if (egid != oldcred->cr_rgid && /* allow setegid(getgid()) */ 78277183Srwatson egid != oldcred->cr_svgid && /* allow setegid(saved gid) */ 783170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETEGID, 0)) != 0) 784145147Srwatson goto fail; 785145147Srwatson 78677183Srwatson if (oldcred->cr_groups[0] != egid) { 78777183Srwatson change_egid(newcred, egid); 78831891Ssef setsugid(p); 78924449Speter } 790302229Sbdrewery proc_set_cred(p, newcred); 79194619Sjhb PROC_UNLOCK(p); 79277183Srwatson crfree(oldcred); 79394619Sjhb return (0); 794145147Srwatson 795145147Srwatsonfail: 796145147Srwatson PROC_UNLOCK(p); 797145147Srwatson crfree(newcred); 798145147Srwatson return (error); 7991541Srgrimes} 8001541Srgrimes 80112221Sbde#ifndef _SYS_SYSPROTO_H_ 8021541Srgrimesstruct setgroups_args { 8031541Srgrimes u_int gidsetsize; 8041541Srgrimes gid_t *gidset; 8051541Srgrimes}; 80612221Sbde#endif 8071541Srgrimes/* ARGSUSED */ 8081549Srgrimesint 809225617Skmacysys_setgroups(struct thread *td, struct setgroups_args *uap) 8101541Srgrimes{ 811194498Sbrooks gid_t *groups = NULL; 812160139Sjhb int error; 813160139Sjhb 814202143Sbrooks if (uap->gidsetsize > ngroups_max + 1) 815160139Sjhb return (EINVAL); 816194498Sbrooks groups = malloc(uap->gidsetsize * sizeof(gid_t), M_TEMP, M_WAITOK); 817160139Sjhb error = copyin(uap->gidset, groups, uap->gidsetsize * sizeof(gid_t)); 818160139Sjhb if (error) 819194498Sbrooks goto out; 820194498Sbrooks error = kern_setgroups(td, uap->gidsetsize, groups); 821194498Sbrooksout: 822194498Sbrooks free(groups, M_TEMP); 823194498Sbrooks return (error); 824160139Sjhb} 825160139Sjhb 826160139Sjhbint 827160139Sjhbkern_setgroups(struct thread *td, u_int ngrp, gid_t *groups) 828160139Sjhb{ 82983366Sjulian struct proc *p = td->td_proc; 830160139Sjhb struct ucred *newcred, *oldcred; 8311541Srgrimes int error; 8321541Srgrimes 833202143Sbrooks if (ngrp > ngroups_max + 1) 83494619Sjhb return (EINVAL); 835195104Srwatson AUDIT_ARG_GROUPSET(groups, ngrp); 83694619Sjhb newcred = crget(); 837194498Sbrooks crextend(newcred, ngrp); 83894619Sjhb PROC_LOCK(p); 839194498Sbrooks oldcred = crcopysafe(p, newcred); 840145147Srwatson 841145147Srwatson#ifdef MAC 842189529Srwatson error = mac_cred_check_setgroups(oldcred, ngrp, groups); 843145147Srwatson if (error) 844145147Srwatson goto fail; 845145147Srwatson#endif 846145147Srwatson 847170587Srwatson error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0); 848145147Srwatson if (error) 849145147Srwatson goto fail; 850145147Srwatson 85124447Speter if (ngrp < 1) { 85224447Speter /* 85324447Speter * setgroups(0, NULL) is a legitimate way of clearing the 85424447Speter * groups vector on non-BSD systems (which generally do not 85524447Speter * have the egid in the groups[0]). We risk security holes 85624447Speter * when running non-BSD software if we do not do the same. 85724447Speter */ 85877183Srwatson newcred->cr_ngroups = 1; 85924447Speter } else { 860194498Sbrooks crsetgroups_locked(newcred, ngrp, groups); 86124447Speter } 86231891Ssef setsugid(p); 863302229Sbdrewery proc_set_cred(p, newcred); 86494619Sjhb PROC_UNLOCK(p); 86577183Srwatson crfree(oldcred); 86694619Sjhb return (0); 867145147Srwatson 868145147Srwatsonfail: 869145147Srwatson PROC_UNLOCK(p); 870145147Srwatson crfree(newcred); 871145147Srwatson return (error); 8721541Srgrimes} 8731541Srgrimes 87412221Sbde#ifndef _SYS_SYSPROTO_H_ 8751541Srgrimesstruct setreuid_args { 8769238Sache uid_t ruid; 8779238Sache uid_t euid; 8781541Srgrimes}; 87912221Sbde#endif 8801541Srgrimes/* ARGSUSED */ 8811549Srgrimesint 882225617Skmacysys_setreuid(register struct thread *td, struct setreuid_args *uap) 8831541Srgrimes{ 88483366Sjulian struct proc *p = td->td_proc; 88577183Srwatson struct ucred *newcred, *oldcred; 88687218Srwatson uid_t euid, ruid; 88798417Salfred struct uidinfo *euip, *ruip; 88887218Srwatson int error; 8891541Srgrimes 89087218Srwatson euid = uap->euid; 8919238Sache ruid = uap->ruid; 892195104Srwatson AUDIT_ARG_EUID(euid); 893195104Srwatson AUDIT_ARG_RUID(ruid); 89494619Sjhb newcred = crget(); 89598417Salfred euip = uifind(euid); 89698417Salfred ruip = uifind(ruid); 89794619Sjhb PROC_LOCK(p); 898194498Sbrooks oldcred = crcopysafe(p, newcred); 899145147Srwatson 900145147Srwatson#ifdef MAC 901189529Srwatson error = mac_cred_check_setreuid(oldcred, ruid, euid); 902145147Srwatson if (error) 903145147Srwatson goto fail; 904145147Srwatson#endif 905145147Srwatson 90677183Srwatson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 90777183Srwatson ruid != oldcred->cr_svuid) || 90877183Srwatson (euid != (uid_t)-1 && euid != oldcred->cr_uid && 90977183Srwatson euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) && 910170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETREUID, 0)) != 0) 911145147Srwatson goto fail; 912145147Srwatson 91377183Srwatson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 91498417Salfred change_euid(newcred, euip); 91531891Ssef setsugid(p); 91624450Speter } 91777183Srwatson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 91898417Salfred change_ruid(newcred, ruip); 91931891Ssef setsugid(p); 9208135Sache } 92177183Srwatson if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) && 92277183Srwatson newcred->cr_svuid != newcred->cr_uid) { 92377183Srwatson change_svuid(newcred, newcred->cr_uid); 92431891Ssef setsugid(p); 92524450Speter } 926302229Sbdrewery proc_set_cred(p, newcred); 92794619Sjhb PROC_UNLOCK(p); 928220212Strasz#ifdef RACCT 929220212Strasz racct_proc_ucred_changed(p, oldcred, newcred); 930220212Strasz#endif 93198417Salfred uifree(ruip); 93298417Salfred uifree(euip); 93377183Srwatson crfree(oldcred); 93494619Sjhb return (0); 935145147Srwatson 936145147Srwatsonfail: 937145147Srwatson PROC_UNLOCK(p); 938145147Srwatson uifree(ruip); 939145147Srwatson uifree(euip); 940145147Srwatson crfree(newcred); 941145147Srwatson return (error); 9421541Srgrimes} 9431541Srgrimes 94412221Sbde#ifndef _SYS_SYSPROTO_H_ 9451541Srgrimesstruct setregid_args { 9469238Sache gid_t rgid; 9479238Sache gid_t egid; 9481541Srgrimes}; 94912221Sbde#endif 9501541Srgrimes/* ARGSUSED */ 9511549Srgrimesint 952225617Skmacysys_setregid(register struct thread *td, struct setregid_args *uap) 9531541Srgrimes{ 95483366Sjulian struct proc *p = td->td_proc; 95577183Srwatson struct ucred *newcred, *oldcred; 95687218Srwatson gid_t egid, rgid; 95787218Srwatson int error; 9581541Srgrimes 95987218Srwatson egid = uap->egid; 9609238Sache rgid = uap->rgid; 961195104Srwatson AUDIT_ARG_EGID(egid); 962195104Srwatson AUDIT_ARG_RGID(rgid); 96394619Sjhb newcred = crget(); 96494619Sjhb PROC_LOCK(p); 965194498Sbrooks oldcred = crcopysafe(p, newcred); 966145147Srwatson 967145147Srwatson#ifdef MAC 968189529Srwatson error = mac_cred_check_setregid(oldcred, rgid, egid); 969145147Srwatson if (error) 970145147Srwatson goto fail; 971145147Srwatson#endif 972145147Srwatson 97377183Srwatson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 97477183Srwatson rgid != oldcred->cr_svgid) || 97577183Srwatson (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] && 97677183Srwatson egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) && 977170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETREGID, 0)) != 0) 978145147Srwatson goto fail; 97994619Sjhb 98077183Srwatson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 98177183Srwatson change_egid(newcred, egid); 98231891Ssef setsugid(p); 98324450Speter } 98477183Srwatson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 98577183Srwatson change_rgid(newcred, rgid); 98631891Ssef setsugid(p); 98724450Speter } 98877183Srwatson if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) && 98977183Srwatson newcred->cr_svgid != newcred->cr_groups[0]) { 99077183Srwatson change_svgid(newcred, newcred->cr_groups[0]); 99131891Ssef setsugid(p); 99224450Speter } 993302229Sbdrewery proc_set_cred(p, newcred); 99494619Sjhb PROC_UNLOCK(p); 99577812Sru crfree(oldcred); 99694619Sjhb return (0); 997145147Srwatson 998145147Srwatsonfail: 999145147Srwatson PROC_UNLOCK(p); 1000145147Srwatson crfree(newcred); 1001145147Srwatson return (error); 10021541Srgrimes} 10031541Srgrimes 100456115Speter/* 1005167232Srwatson * setresuid(ruid, euid, suid) is like setreuid except control over the saved 1006167232Srwatson * uid is explicit. 100756115Speter */ 100824453Speter#ifndef _SYS_SYSPROTO_H_ 100956115Speterstruct setresuid_args { 101056115Speter uid_t ruid; 101156115Speter uid_t euid; 101256115Speter uid_t suid; 101356115Speter}; 101456115Speter#endif 101556115Speter/* ARGSUSED */ 101656115Speterint 1017225617Skmacysys_setresuid(register struct thread *td, struct setresuid_args *uap) 101856115Speter{ 101983366Sjulian struct proc *p = td->td_proc; 102077183Srwatson struct ucred *newcred, *oldcred; 102187218Srwatson uid_t euid, ruid, suid; 102298417Salfred struct uidinfo *euip, *ruip; 102356115Speter int error; 102456115Speter 102587218Srwatson euid = uap->euid; 102656115Speter ruid = uap->ruid; 102756115Speter suid = uap->suid; 1028195104Srwatson AUDIT_ARG_EUID(euid); 1029195104Srwatson AUDIT_ARG_RUID(ruid); 1030195104Srwatson AUDIT_ARG_SUID(suid); 103194619Sjhb newcred = crget(); 103298417Salfred euip = uifind(euid); 103398417Salfred ruip = uifind(ruid); 103494619Sjhb PROC_LOCK(p); 1035194498Sbrooks oldcred = crcopysafe(p, newcred); 1036145147Srwatson 1037145147Srwatson#ifdef MAC 1038189529Srwatson error = mac_cred_check_setresuid(oldcred, ruid, euid, suid); 1039145147Srwatson if (error) 1040145147Srwatson goto fail; 1041145147Srwatson#endif 1042145147Srwatson 104377183Srwatson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 104477183Srwatson ruid != oldcred->cr_svuid && 104577183Srwatson ruid != oldcred->cr_uid) || 104677183Srwatson (euid != (uid_t)-1 && euid != oldcred->cr_ruid && 104777183Srwatson euid != oldcred->cr_svuid && 104877183Srwatson euid != oldcred->cr_uid) || 104977183Srwatson (suid != (uid_t)-1 && suid != oldcred->cr_ruid && 105077183Srwatson suid != oldcred->cr_svuid && 105177183Srwatson suid != oldcred->cr_uid)) && 1052170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETRESUID, 0)) != 0) 1053145147Srwatson goto fail; 105494619Sjhb 105577183Srwatson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 105698417Salfred change_euid(newcred, euip); 105756115Speter setsugid(p); 105856115Speter } 105977183Srwatson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 106098417Salfred change_ruid(newcred, ruip); 106156115Speter setsugid(p); 106256115Speter } 106377183Srwatson if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) { 106477183Srwatson change_svuid(newcred, suid); 106556115Speter setsugid(p); 106656115Speter } 1067302229Sbdrewery proc_set_cred(p, newcred); 106894619Sjhb PROC_UNLOCK(p); 1069220212Strasz#ifdef RACCT 1070220212Strasz racct_proc_ucred_changed(p, oldcred, newcred); 1071220212Strasz#endif 107298417Salfred uifree(ruip); 107398417Salfred uifree(euip); 107477183Srwatson crfree(oldcred); 107594619Sjhb return (0); 1076145147Srwatson 1077145147Srwatsonfail: 1078145147Srwatson PROC_UNLOCK(p); 1079145147Srwatson uifree(ruip); 1080145147Srwatson uifree(euip); 1081145147Srwatson crfree(newcred); 1082145147Srwatson return (error); 1083145147Srwatson 108456115Speter} 108556115Speter 108656115Speter/* 1087167232Srwatson * setresgid(rgid, egid, sgid) is like setregid except control over the saved 1088167232Srwatson * gid is explicit. 108956115Speter */ 109056115Speter#ifndef _SYS_SYSPROTO_H_ 109156115Speterstruct setresgid_args { 109256115Speter gid_t rgid; 109356115Speter gid_t egid; 109456115Speter gid_t sgid; 109556115Speter}; 109656115Speter#endif 109756115Speter/* ARGSUSED */ 109856115Speterint 1099225617Skmacysys_setresgid(register struct thread *td, struct setresgid_args *uap) 110056115Speter{ 110183366Sjulian struct proc *p = td->td_proc; 110277183Srwatson struct ucred *newcred, *oldcred; 110387218Srwatson gid_t egid, rgid, sgid; 110456115Speter int error; 110556115Speter 110687218Srwatson egid = uap->egid; 110756115Speter rgid = uap->rgid; 110856115Speter sgid = uap->sgid; 1109195104Srwatson AUDIT_ARG_EGID(egid); 1110195104Srwatson AUDIT_ARG_RGID(rgid); 1111195104Srwatson AUDIT_ARG_SGID(sgid); 111294619Sjhb newcred = crget(); 111394619Sjhb PROC_LOCK(p); 1114194498Sbrooks oldcred = crcopysafe(p, newcred); 1115145147Srwatson 1116145147Srwatson#ifdef MAC 1117189529Srwatson error = mac_cred_check_setresgid(oldcred, rgid, egid, sgid); 1118145147Srwatson if (error) 1119145147Srwatson goto fail; 1120145147Srwatson#endif 1121145147Srwatson 112277183Srwatson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 112377183Srwatson rgid != oldcred->cr_svgid && 112477183Srwatson rgid != oldcred->cr_groups[0]) || 112577183Srwatson (egid != (gid_t)-1 && egid != oldcred->cr_rgid && 112677183Srwatson egid != oldcred->cr_svgid && 112777183Srwatson egid != oldcred->cr_groups[0]) || 112877183Srwatson (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid && 112977183Srwatson sgid != oldcred->cr_svgid && 113077183Srwatson sgid != oldcred->cr_groups[0])) && 1131170587Srwatson (error = priv_check_cred(oldcred, PRIV_CRED_SETRESGID, 0)) != 0) 1132145147Srwatson goto fail; 113394619Sjhb 113477183Srwatson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 113577183Srwatson change_egid(newcred, egid); 113656115Speter setsugid(p); 113756115Speter } 113877183Srwatson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 113977183Srwatson change_rgid(newcred, rgid); 114056115Speter setsugid(p); 114156115Speter } 114277183Srwatson if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) { 114377183Srwatson change_svgid(newcred, sgid); 114456115Speter setsugid(p); 114556115Speter } 1146302229Sbdrewery proc_set_cred(p, newcred); 114794619Sjhb PROC_UNLOCK(p); 114877183Srwatson crfree(oldcred); 114994619Sjhb return (0); 1150145147Srwatson 1151145147Srwatsonfail: 1152145147Srwatson PROC_UNLOCK(p); 1153145147Srwatson crfree(newcred); 1154145147Srwatson return (error); 115556115Speter} 115656115Speter 115756115Speter#ifndef _SYS_SYSPROTO_H_ 115856115Speterstruct getresuid_args { 115956115Speter uid_t *ruid; 116056115Speter uid_t *euid; 116156115Speter uid_t *suid; 116256115Speter}; 116356115Speter#endif 116456115Speter/* ARGSUSED */ 116556115Speterint 1166225617Skmacysys_getresuid(register struct thread *td, struct getresuid_args *uap) 116756115Speter{ 116882749Sdillon struct ucred *cred; 116956115Speter int error1 = 0, error2 = 0, error3 = 0; 117056115Speter 117193264Sdillon cred = td->td_ucred; 117256115Speter if (uap->ruid) 117399009Salfred error1 = copyout(&cred->cr_ruid, 117499009Salfred uap->ruid, sizeof(cred->cr_ruid)); 117556115Speter if (uap->euid) 117699009Salfred error2 = copyout(&cred->cr_uid, 117799009Salfred uap->euid, sizeof(cred->cr_uid)); 117856115Speter if (uap->suid) 117999009Salfred error3 = copyout(&cred->cr_svuid, 118099009Salfred uap->suid, sizeof(cred->cr_svuid)); 118187218Srwatson return (error1 ? error1 : error2 ? error2 : error3); 118256115Speter} 118356115Speter 118456115Speter#ifndef _SYS_SYSPROTO_H_ 118556115Speterstruct getresgid_args { 118656115Speter gid_t *rgid; 118756115Speter gid_t *egid; 118856115Speter gid_t *sgid; 118956115Speter}; 119056115Speter#endif 119156115Speter/* ARGSUSED */ 119256115Speterint 1193225617Skmacysys_getresgid(register struct thread *td, struct getresgid_args *uap) 119456115Speter{ 119582749Sdillon struct ucred *cred; 119656115Speter int error1 = 0, error2 = 0, error3 = 0; 119756115Speter 119893264Sdillon cred = td->td_ucred; 119956115Speter if (uap->rgid) 120099009Salfred error1 = copyout(&cred->cr_rgid, 120199009Salfred uap->rgid, sizeof(cred->cr_rgid)); 120256115Speter if (uap->egid) 120399009Salfred error2 = copyout(&cred->cr_groups[0], 120499009Salfred uap->egid, sizeof(cred->cr_groups[0])); 120556115Speter if (uap->sgid) 120699009Salfred error3 = copyout(&cred->cr_svgid, 120799009Salfred uap->sgid, sizeof(cred->cr_svgid)); 120887218Srwatson return (error1 ? error1 : error2 ? error2 : error3); 120956115Speter} 121056115Speter 121156115Speter#ifndef _SYS_SYSPROTO_H_ 121224453Speterstruct issetugid_args { 121324453Speter int dummy; 121424453Speter}; 121524453Speter#endif 121624453Speter/* ARGSUSED */ 121724453Speterint 1218225617Skmacysys_issetugid(register struct thread *td, struct issetugid_args *uap) 121924453Speter{ 122083366Sjulian struct proc *p = td->td_proc; 122183366Sjulian 122224453Speter /* 122324453Speter * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 122424453Speter * we use P_SUGID because we consider changing the owners as 122524453Speter * "tainting" as well. 122624453Speter * This is significant for procs that start as root and "become" 122724453Speter * a user without an exec - programs cannot know *everything* 122824453Speter * that libc *might* have put in their data segment. 122924453Speter */ 123091140Stanimura PROC_LOCK(p); 123183366Sjulian td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 123291140Stanimura PROC_UNLOCK(p); 123324453Speter return (0); 123424453Speter} 123524453Speter 123675426Srwatsonint 1237225617Skmacysys___setugid(struct thread *td, struct __setugid_args *uap) 123875426Srwatson{ 123982749Sdillon#ifdef REGRESSION 124094619Sjhb struct proc *p; 124175426Srwatson 124294619Sjhb p = td->td_proc; 124375426Srwatson switch (uap->flag) { 124475426Srwatson case 0: 124594619Sjhb PROC_LOCK(p); 124694619Sjhb p->p_flag &= ~P_SUGID; 124794619Sjhb PROC_UNLOCK(p); 124894619Sjhb return (0); 124975426Srwatson case 1: 125094619Sjhb PROC_LOCK(p); 125194619Sjhb p->p_flag |= P_SUGID; 125294619Sjhb PROC_UNLOCK(p); 125394619Sjhb return (0); 125475426Srwatson default: 125594619Sjhb return (EINVAL); 125675426Srwatson } 125775426Srwatson#else /* !REGRESSION */ 125887218Srwatson 125975426Srwatson return (ENOSYS); 126087218Srwatson#endif /* REGRESSION */ 126175426Srwatson} 126275426Srwatson 12631541Srgrimes/* 12641541Srgrimes * Check if gid is a member of the group set. 12651541Srgrimes */ 12661549Srgrimesint 126793580Sjhbgroupmember(gid_t gid, struct ucred *cred) 12681541Srgrimes{ 1269194556Sbrooks int l; 1270194556Sbrooks int h; 1271194556Sbrooks int m; 12721541Srgrimes 1273194556Sbrooks if (cred->cr_groups[0] == gid) 1274194556Sbrooks return(1); 1275194556Sbrooks 1276194556Sbrooks /* 1277194556Sbrooks * If gid was not our primary group, perform a binary search 1278194556Sbrooks * of the supplemental groups. This is possible because we 1279194556Sbrooks * sort the groups in crsetgroups(). 1280194556Sbrooks */ 1281194556Sbrooks l = 1; 1282194556Sbrooks h = cred->cr_ngroups; 1283194556Sbrooks while (l < h) { 1284194556Sbrooks m = l + ((h - l) / 2); 1285194556Sbrooks if (cred->cr_groups[m] < gid) 1286194556Sbrooks l = m + 1; 1287194556Sbrooks else 1288194556Sbrooks h = m; 1289194556Sbrooks } 1290194556Sbrooks if ((l < cred->cr_ngroups) && (cred->cr_groups[l] == gid)) 1291194556Sbrooks return (1); 1292194556Sbrooks 12931541Srgrimes return (0); 12941541Srgrimes} 12951541Srgrimes 129682424Srwatson/* 129787218Srwatson * Test the active securelevel against a given level. securelevel_gt() 129887218Srwatson * implements (securelevel > level). securelevel_ge() implements 129987218Srwatson * (securelevel >= level). Note that the logic is inverted -- these 130087218Srwatson * functions return EPERM on "success" and 0 on "failure". 130183639Srwatson * 1302192895Sjamie * Due to care taken when setting the securelevel, we know that no jail will 1303192895Sjamie * be less secure that its parent (or the physical system), so it is sufficient 1304192895Sjamie * to test the current jail only. 1305192895Sjamie * 1306164032Srwatson * XXXRW: Possibly since this has to do with privilege, it should move to 1307164032Srwatson * kern_priv.c. 130883639Srwatson */ 130983639Srwatsonint 131083639Srwatsonsecurelevel_gt(struct ucred *cr, int level) 131183639Srwatson{ 131283639Srwatson 1313192895Sjamie return (cr->cr_prison->pr_securelevel > level ? EPERM : 0); 131483639Srwatson} 131583639Srwatson 131683639Srwatsonint 131783639Srwatsonsecurelevel_ge(struct ucred *cr, int level) 131883639Srwatson{ 131983639Srwatson 1320192895Sjamie return (cr->cr_prison->pr_securelevel >= level ? EPERM : 0); 132183639Srwatson} 132283639Srwatson 132384736Srwatson/* 132487144Srwatson * 'see_other_uids' determines whether or not visibility of processes 132587218Srwatson * and sockets with credentials holding different real uids is possible 132687138Srwatson * using a variety of system MIBs. 132787218Srwatson * XXX: data declarations should be together near the beginning of the file. 132884736Srwatson */ 132987144Srwatsonstatic int see_other_uids = 1; 133089414SarrSYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW, 133187218Srwatson &see_other_uids, 0, 133284736Srwatson "Unprivileged processes may see subjects/objects with different real uid"); 133384736Srwatson 1334210226Strasz/*- 133592923Srwatson * Determine if u1 "can see" the subject specified by u2, according to the 133692923Srwatson * 'see_other_uids' policy. 133792923Srwatson * Returns: 0 for permitted, ESRCH otherwise 133892923Srwatson * Locks: none 133992923Srwatson * References: *u1 and *u2 must not change during the call 134092923Srwatson * u1 may equal u2, in which case only one reference is required 134192923Srwatson */ 134292923Srwatsonstatic int 134392923Srwatsoncr_seeotheruids(struct ucred *u1, struct ucred *u2) 134492923Srwatson{ 134592923Srwatson 134692923Srwatson if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) { 1347170587Srwatson if (priv_check_cred(u1, PRIV_SEEOTHERUIDS, 0) != 0) 134892923Srwatson return (ESRCH); 134992923Srwatson } 135092923Srwatson return (0); 135192923Srwatson} 135292923Srwatson 1353122869Srwatson/* 1354122869Srwatson * 'see_other_gids' determines whether or not visibility of processes 1355122869Srwatson * and sockets with credentials holding different real gids is possible 1356122869Srwatson * using a variety of system MIBs. 1357122869Srwatson * XXX: data declarations should be together near the beginning of the file. 1358122869Srwatson */ 1359122869Srwatsonstatic int see_other_gids = 1; 1360122869SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, see_other_gids, CTLFLAG_RW, 1361122869Srwatson &see_other_gids, 0, 1362122869Srwatson "Unprivileged processes may see subjects/objects with different real gid"); 1363122869Srwatson 1364122869Srwatson/* 1365122869Srwatson * Determine if u1 can "see" the subject specified by u2, according to the 1366122869Srwatson * 'see_other_gids' policy. 1367122869Srwatson * Returns: 0 for permitted, ESRCH otherwise 1368122869Srwatson * Locks: none 1369122869Srwatson * References: *u1 and *u2 must not change during the call 1370122869Srwatson * u1 may equal u2, in which case only one reference is required 1371122869Srwatson */ 1372122869Srwatsonstatic int 1373122869Srwatsoncr_seeothergids(struct ucred *u1, struct ucred *u2) 1374122869Srwatson{ 1375122869Srwatson int i, match; 1376122869Srwatson 1377122869Srwatson if (!see_other_gids) { 1378122869Srwatson match = 0; 1379122869Srwatson for (i = 0; i < u1->cr_ngroups; i++) { 1380122869Srwatson if (groupmember(u1->cr_groups[i], u2)) 1381122869Srwatson match = 1; 1382122869Srwatson if (match) 1383122869Srwatson break; 1384122869Srwatson } 1385122869Srwatson if (!match) { 1386170587Srwatson if (priv_check_cred(u1, PRIV_SEEOTHERGIDS, 0) != 0) 1387122869Srwatson return (ESRCH); 1388122869Srwatson } 1389122869Srwatson } 1390122869Srwatson return (0); 1391122869Srwatson} 1392122869Srwatson 1393210226Strasz/*- 139482466Srwatson * Determine if u1 "can see" the subject specified by u2. 139574956Srwatson * Returns: 0 for permitted, an errno value otherwise 139674956Srwatson * Locks: none 139787218Srwatson * References: *u1 and *u2 must not change during the call 139874956Srwatson * u1 may equal u2, in which case only one reference is required 139974956Srwatson */ 140074956Srwatsonint 140183742Srwatsoncr_cansee(struct ucred *u1, struct ucred *u2) 140265237Srwatson{ 140372786Srwatson int error; 140453518Sphk 140574956Srwatson if ((error = prison_check(u1, u2))) 140672786Srwatson return (error); 1407101003Srwatson#ifdef MAC 1408172930Srwatson if ((error = mac_cred_check_visible(u1, u2))) 1409101003Srwatson return (error); 1410101003Srwatson#endif 141192923Srwatson if ((error = cr_seeotheruids(u1, u2))) 141292923Srwatson return (error); 1413122869Srwatson if ((error = cr_seeothergids(u1, u2))) 1414122869Srwatson return (error); 141565237Srwatson return (0); 141665237Srwatson} 141765237Srwatson 1418210226Strasz/*- 141996886Sjhb * Determine if td "can see" the subject specified by p. 142082424Srwatson * Returns: 0 for permitted, an errno value otherwise 142196886Sjhb * Locks: Sufficient locks to protect p->p_ucred must be held. td really 142296886Sjhb * should be curthread. 142396886Sjhb * References: td and p must be valid for the lifetime of the call 142482424Srwatson */ 142579335Srwatsonint 142696886Sjhbp_cansee(struct thread *td, struct proc *p) 142774956Srwatson{ 142874956Srwatson 142983742Srwatson /* Wrap cr_cansee() for all functionality. */ 143096886Sjhb KASSERT(td == curthread, ("%s: td not curthread", __func__)); 143196886Sjhb PROC_LOCK_ASSERT(p, MA_OWNED); 143296886Sjhb return (cr_cansee(td->td_ucred, p->p_ucred)); 143374956Srwatson} 143474956Srwatson 1435120052Srwatson/* 1436120052Srwatson * 'conservative_signals' prevents the delivery of a broad class of 1437120052Srwatson * signals by unprivileged processes to processes that have changed their 1438120052Srwatson * credentials since the last invocation of execve(). This can prevent 1439120052Srwatson * the leakage of cached information or retained privileges as a result 1440120052Srwatson * of a common class of signal-related vulnerabilities. However, this 1441120052Srwatson * may interfere with some applications that expect to be able to 1442120052Srwatson * deliver these signals to peer processes after having given up 1443120052Srwatson * privilege. 1444120052Srwatson */ 1445120052Srwatsonstatic int conservative_signals = 1; 1446120052SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, conservative_signals, CTLFLAG_RW, 1447120052Srwatson &conservative_signals, 0, "Unprivileged processes prevented from " 1448120052Srwatson "sending certain signals to processes whose credentials have changed"); 1449210226Strasz/*- 145088943Srwatson * Determine whether cred may deliver the specified signal to proc. 145188943Srwatson * Returns: 0 for permitted, an errno value otherwise. 145288943Srwatson * Locks: A lock must be held for proc. 145388943Srwatson * References: cred and proc must be valid for the lifetime of the call. 145475437Srwatson */ 145575437Srwatsonint 1456141815Ssobomaxcr_cansignal(struct ucred *cred, struct proc *proc, int signum) 145753518Sphk{ 145882466Srwatson int error; 145984826Sjhb 146096886Sjhb PROC_LOCK_ASSERT(proc, MA_OWNED); 146175437Srwatson /* 146288943Srwatson * Jail semantics limit the scope of signalling to proc in the 146388943Srwatson * same jail as cred, if cred is in jail. 146475437Srwatson */ 146588943Srwatson error = prison_check(cred, proc->p_ucred); 146688943Srwatson if (error) 146772786Srwatson return (error); 1468101003Srwatson#ifdef MAC 1469172930Srwatson if ((error = mac_proc_check_signal(cred, proc, signum))) 1470101003Srwatson return (error); 1471101003Srwatson#endif 1472122869Srwatson if ((error = cr_seeotheruids(cred, proc->p_ucred))) 147392923Srwatson return (error); 1474122869Srwatson if ((error = cr_seeothergids(cred, proc->p_ucred))) 1475122869Srwatson return (error); 147665237Srwatson 147765237Srwatson /* 147882424Srwatson * UNIX signal semantics depend on the status of the P_SUGID 147982424Srwatson * bit on the target process. If the bit is set, then additional 148082424Srwatson * restrictions are placed on the set of available signals. 148175437Srwatson */ 1482141815Ssobomax if (conservative_signals && (proc->p_flag & P_SUGID)) { 148375437Srwatson switch (signum) { 148475437Srwatson case 0: 148575437Srwatson case SIGKILL: 148675437Srwatson case SIGINT: 148775437Srwatson case SIGTERM: 1488120052Srwatson case SIGALRM: 148975437Srwatson case SIGSTOP: 149075437Srwatson case SIGTTIN: 149175437Srwatson case SIGTTOU: 149275437Srwatson case SIGTSTP: 149375437Srwatson case SIGHUP: 149475437Srwatson case SIGUSR1: 149575437Srwatson case SIGUSR2: 149682466Srwatson /* 149782466Srwatson * Generally, permit job and terminal control 149882466Srwatson * signals. 149982466Srwatson */ 150075437Srwatson break; 150175437Srwatson default: 150288943Srwatson /* Not permitted without privilege. */ 1503170587Srwatson error = priv_check_cred(cred, PRIV_SIGNAL_SUGID, 0); 150475437Srwatson if (error) 150575437Srwatson return (error); 150675437Srwatson } 150765237Srwatson } 150865237Srwatson 150975480Srwatson /* 151082424Srwatson * Generally, the target credential's ruid or svuid must match the 151175480Srwatson * subject credential's ruid or euid. 151275480Srwatson */ 151388943Srwatson if (cred->cr_ruid != proc->p_ucred->cr_ruid && 151488943Srwatson cred->cr_ruid != proc->p_ucred->cr_svuid && 151588943Srwatson cred->cr_uid != proc->p_ucred->cr_ruid && 151688943Srwatson cred->cr_uid != proc->p_ucred->cr_svuid) { 1517170587Srwatson error = priv_check_cred(cred, PRIV_SIGNAL_DIFFCRED, 0); 151875480Srwatson if (error) 151975480Srwatson return (error); 152075480Srwatson } 152175480Srwatson 152287218Srwatson return (0); 152353518Sphk} 152453518Sphk 1525210226Strasz/*- 152696886Sjhb * Determine whether td may deliver the specified signal to p. 152788943Srwatson * Returns: 0 for permitted, an errno value otherwise 152896886Sjhb * Locks: Sufficient locks to protect various components of td and p 152996886Sjhb * must be held. td must be curthread, and a lock must be 153096886Sjhb * held for p. 153196886Sjhb * References: td and p must be valid for the lifetime of the call 153288943Srwatson */ 153388943Srwatsonint 1534141815Ssobomaxp_cansignal(struct thread *td, struct proc *p, int signum) 153588943Srwatson{ 153688943Srwatson 153796886Sjhb KASSERT(td == curthread, ("%s: td not curthread", __func__)); 153896886Sjhb PROC_LOCK_ASSERT(p, MA_OWNED); 153996886Sjhb if (td->td_proc == p) 154088943Srwatson return (0); 154188943Srwatson 154288943Srwatson /* 154388943Srwatson * UNIX signalling semantics require that processes in the same 154488943Srwatson * session always be able to deliver SIGCONT to one another, 154588943Srwatson * overriding the remaining protections. 154688943Srwatson */ 154796886Sjhb /* XXX: This will require an additional lock of some sort. */ 154896886Sjhb if (signum == SIGCONT && td->td_proc->p_session == p->p_session) 154988943Srwatson return (0); 1550143108Ssobomax /* 1551143800Ssobomax * Some compat layers use SIGTHR and higher signals for 1552143800Ssobomax * communication between different kernel threads of the same 1553143800Ssobomax * process, so that they expect that it's always possible to 1554143800Ssobomax * deliver them, even for suid applications where cr_cansignal() can 1555143108Ssobomax * deny such ability for security consideration. It should be 1556143108Ssobomax * pretty safe to do since the only way to create two processes 1557143108Ssobomax * with the same p_leader is via rfork(2). 1558143108Ssobomax */ 1559143805Ssobomax if (td->td_proc->p_leader != NULL && signum >= SIGTHR && 1560143805Ssobomax signum < SIGTHR + 4 && td->td_proc->p_leader == p->p_leader) 1561143108Ssobomax return (0); 156288943Srwatson 1563141815Ssobomax return (cr_cansignal(td->td_ucred, p, signum)); 156488943Srwatson} 156588943Srwatson 1566210226Strasz/*- 156796886Sjhb * Determine whether td may reschedule p. 156882466Srwatson * Returns: 0 for permitted, an errno value otherwise 156996886Sjhb * Locks: Sufficient locks to protect various components of td and p 157096886Sjhb * must be held. td must be curthread, and a lock must 157196886Sjhb * be held for p. 157296886Sjhb * References: td and p must be valid for the lifetime of the call 157382424Srwatson */ 157479335Srwatsonint 157596886Sjhbp_cansched(struct thread *td, struct proc *p) 157665237Srwatson{ 157772786Srwatson int error; 157865237Srwatson 157996886Sjhb KASSERT(td == curthread, ("%s: td not curthread", __func__)); 158096886Sjhb PROC_LOCK_ASSERT(p, MA_OWNED); 158196886Sjhb if (td->td_proc == p) 158265237Srwatson return (0); 158396886Sjhb if ((error = prison_check(td->td_ucred, p->p_ucred))) 158472786Srwatson return (error); 1585101003Srwatson#ifdef MAC 1586172930Srwatson if ((error = mac_proc_check_sched(td->td_ucred, p))) 1587101003Srwatson return (error); 1588101003Srwatson#endif 158996886Sjhb if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) 159092923Srwatson return (error); 1591122869Srwatson if ((error = cr_seeothergids(td->td_ucred, p->p_ucred))) 1592122869Srwatson return (error); 1593164032Srwatson if (td->td_ucred->cr_ruid != p->p_ucred->cr_ruid && 1594164032Srwatson td->td_ucred->cr_uid != p->p_ucred->cr_ruid) { 1595170587Srwatson error = priv_check(td, PRIV_SCHED_DIFFCRED); 1596164032Srwatson if (error) 1597164032Srwatson return (error); 1598164032Srwatson } 1599164032Srwatson return (0); 160065237Srwatson} 160165237Srwatson 160282424Srwatson/* 160387280Srwatson * The 'unprivileged_proc_debug' flag may be used to disable a variety of 160487280Srwatson * unprivileged inter-process debugging services, including some procfs 160587280Srwatson * functionality, ptrace(), and ktrace(). In the past, inter-process 160687280Srwatson * debugging has been involved in a variety of security problems, and sites 160787280Srwatson * not requiring the service might choose to disable it when hardening 160887280Srwatson * systems. 160982424Srwatson * 161082424Srwatson * XXX: Should modifying and reading this variable require locking? 161187218Srwatson * XXX: data declarations should be together near the beginning of the file. 161282424Srwatson */ 161387144Srwatsonstatic int unprivileged_proc_debug = 1; 161489414SarrSYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW, 161587218Srwatson &unprivileged_proc_debug, 0, 161680735Srwatson "Unprivileged processes may use process debugging facilities"); 161780735Srwatson 1618210226Strasz/*- 161996886Sjhb * Determine whether td may debug p. 162082466Srwatson * Returns: 0 for permitted, an errno value otherwise 162196886Sjhb * Locks: Sufficient locks to protect various components of td and p 162296886Sjhb * must be held. td must be curthread, and a lock must 162396886Sjhb * be held for p. 162496886Sjhb * References: td and p must be valid for the lifetime of the call 162582424Srwatson */ 162679335Srwatsonint 162796886Sjhbp_candebug(struct thread *td, struct proc *p) 162865237Srwatson{ 162987218Srwatson int credentialchanged, error, grpsubset, i, uidsubset; 163065237Srwatson 163196886Sjhb KASSERT(td == curthread, ("%s: td not curthread", __func__)); 163296886Sjhb PROC_LOCK_ASSERT(p, MA_OWNED); 163387144Srwatson if (!unprivileged_proc_debug) { 1634170587Srwatson error = priv_check(td, PRIV_DEBUG_UNPRIV); 163584727Srwatson if (error) 163684727Srwatson return (error); 163784727Srwatson } 163896886Sjhb if (td->td_proc == p) 163984636Sdes return (0); 164096886Sjhb if ((error = prison_check(td->td_ucred, p->p_ucred))) 164172786Srwatson return (error); 1642101003Srwatson#ifdef MAC 1643172930Srwatson if ((error = mac_proc_check_debug(td->td_ucred, p))) 1644101003Srwatson return (error); 1645101003Srwatson#endif 164696886Sjhb if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) 164792923Srwatson return (error); 1648122869Srwatson if ((error = cr_seeothergids(td->td_ucred, p->p_ucred))) 1649122869Srwatson return (error); 165065237Srwatson 165182466Srwatson /* 165296886Sjhb * Is p's group set a subset of td's effective group set? This 165396886Sjhb * includes p's egid, group access list, rgid, and svgid. 165482466Srwatson */ 165585895Srwatson grpsubset = 1; 165696886Sjhb for (i = 0; i < p->p_ucred->cr_ngroups; i++) { 165796886Sjhb if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) { 165885895Srwatson grpsubset = 0; 165985895Srwatson break; 166085895Srwatson } 166185895Srwatson } 166285895Srwatson grpsubset = grpsubset && 166396886Sjhb groupmember(p->p_ucred->cr_rgid, td->td_ucred) && 166496886Sjhb groupmember(p->p_ucred->cr_svgid, td->td_ucred); 166585895Srwatson 166685895Srwatson /* 166796886Sjhb * Are the uids present in p's credential equal to td's 166896886Sjhb * effective uid? This includes p's euid, svuid, and ruid. 166985895Srwatson */ 167096886Sjhb uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid && 167196886Sjhb td->td_ucred->cr_uid == p->p_ucred->cr_svuid && 167296886Sjhb td->td_ucred->cr_uid == p->p_ucred->cr_ruid); 167385895Srwatson 167485895Srwatson /* 167585895Srwatson * Has the credential of the process changed since the last exec()? 167685895Srwatson */ 167796886Sjhb credentialchanged = (p->p_flag & P_SUGID); 167885895Srwatson 167985895Srwatson /* 168096886Sjhb * If p's gids aren't a subset, or the uids aren't a subset, 168185895Srwatson * or the credential has changed, require appropriate privilege 1682164032Srwatson * for td to debug p. 168385895Srwatson */ 1684164032Srwatson if (!grpsubset || !uidsubset) { 1685170587Srwatson error = priv_check(td, PRIV_DEBUG_DIFFCRED); 168684727Srwatson if (error) 168765237Srwatson return (error); 168882466Srwatson } 168965237Srwatson 1690164032Srwatson if (credentialchanged) { 1691170587Srwatson error = priv_check(td, PRIV_DEBUG_SUGID); 1692164032Srwatson if (error) 1693164032Srwatson return (error); 1694164032Srwatson } 1695164032Srwatson 169687218Srwatson /* Can't trace init when securelevel > 0. */ 169796886Sjhb if (p == initproc) { 169896886Sjhb error = securelevel_gt(td->td_ucred, 0); 169983639Srwatson if (error) 170083639Srwatson return (error); 170183639Srwatson } 170265237Srwatson 170385880Srwatson /* 170485880Srwatson * Can't trace a process that's currently exec'ing. 1705164032Srwatson * 170685880Srwatson * XXX: Note, this is not a security policy decision, it's a 170785880Srwatson * basic correctness/functionality decision. Therefore, this check 170885880Srwatson * should be moved to the caller's of p_candebug(). 170985880Srwatson */ 171096886Sjhb if ((p->p_flag & P_INEXEC) != 0) 1711185983Skib return (EBUSY); 171287466Srwatson 1713277698Skib /* Denied explicitely */ 1714277698Skib if ((p->p_flag2 & P2_NOTRACE) != 0) { 1715277698Skib error = priv_check(td, PRIV_DEBUG_DENIED); 1716277698Skib if (error != 0) 1717277698Skib return (error); 1718277698Skib } 1719277698Skib 172065237Srwatson return (0); 172165237Srwatson} 172265237Srwatson 1723210226Strasz/*- 172492976Srwatson * Determine whether the subject represented by cred can "see" a socket. 172592976Srwatson * Returns: 0 for permitted, ENOENT otherwise. 172692976Srwatson */ 172792976Srwatsonint 172892976Srwatsoncr_canseesocket(struct ucred *cred, struct socket *so) 172992976Srwatson{ 173092976Srwatson int error; 173192976Srwatson 173292976Srwatson error = prison_check(cred, so->so_cred); 173392976Srwatson if (error) 173492976Srwatson return (ENOENT); 1735101003Srwatson#ifdef MAC 1736172930Srwatson error = mac_socket_check_visible(cred, so); 1737101003Srwatson if (error) 1738101003Srwatson return (error); 1739101003Srwatson#endif 174092976Srwatson if (cr_seeotheruids(cred, so->so_cred)) 174192976Srwatson return (ENOENT); 1742122869Srwatson if (cr_seeothergids(cred, so->so_cred)) 1743122869Srwatson return (ENOENT); 174492976Srwatson 174592976Srwatson return (0); 174692976Srwatson} 174792976Srwatson 1748183982Sbz#if defined(INET) || defined(INET6) 1749210226Strasz/*- 1750183982Sbz * Determine whether the subject represented by cred can "see" a socket. 1751183982Sbz * Returns: 0 for permitted, ENOENT otherwise. 1752183982Sbz */ 1753183982Sbzint 1754183982Sbzcr_canseeinpcb(struct ucred *cred, struct inpcb *inp) 1755183982Sbz{ 1756183982Sbz int error; 1757183982Sbz 1758183982Sbz error = prison_check(cred, inp->inp_cred); 1759183982Sbz if (error) 1760183982Sbz return (ENOENT); 1761183982Sbz#ifdef MAC 1762183982Sbz INP_LOCK_ASSERT(inp); 1763183982Sbz error = mac_inpcb_check_visible(cred, inp); 1764183982Sbz if (error) 1765183982Sbz return (error); 1766183982Sbz#endif 1767183982Sbz if (cr_seeotheruids(cred, inp->inp_cred)) 1768183982Sbz return (ENOENT); 1769183982Sbz if (cr_seeothergids(cred, inp->inp_cred)) 1770183982Sbz return (ENOENT); 1771183982Sbz 1772183982Sbz return (0); 1773183982Sbz} 1774183982Sbz#endif 1775183982Sbz 1776210226Strasz/*- 1777145234Srwatson * Determine whether td can wait for the exit of p. 1778145234Srwatson * Returns: 0 for permitted, an errno value otherwise 1779145234Srwatson * Locks: Sufficient locks to protect various components of td and p 1780145234Srwatson * must be held. td must be curthread, and a lock must 1781145234Srwatson * be held for p. 1782145234Srwatson * References: td and p must be valid for the lifetime of the call 1783145234Srwatson 1784145234Srwatson */ 1785145234Srwatsonint 1786145234Srwatsonp_canwait(struct thread *td, struct proc *p) 1787145234Srwatson{ 1788145234Srwatson int error; 1789145234Srwatson 1790145234Srwatson KASSERT(td == curthread, ("%s: td not curthread", __func__)); 1791145234Srwatson PROC_LOCK_ASSERT(p, MA_OWNED); 1792195741Sjamie if ((error = prison_check(td->td_ucred, p->p_ucred))) 1793145234Srwatson return (error); 1794145234Srwatson#ifdef MAC 1795172930Srwatson if ((error = mac_proc_check_wait(td->td_ucred, p))) 1796145234Srwatson return (error); 1797145234Srwatson#endif 1798145234Srwatson#if 0 1799145234Srwatson /* XXXMAC: This could have odd effects on some shells. */ 1800145234Srwatson if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) 1801145234Srwatson return (error); 1802145234Srwatson#endif 1803145234Srwatson 1804145234Srwatson return (0); 1805145234Srwatson} 1806145234Srwatson 180753518Sphk/* 18081541Srgrimes * Allocate a zeroed cred structure. 18091541Srgrimes */ 18101541Srgrimesstruct ucred * 181193580Sjhbcrget(void) 18121541Srgrimes{ 18131541Srgrimes register struct ucred *cr; 18141541Srgrimes 1815184205Sdes cr = malloc(sizeof(*cr), M_CRED, M_WAITOK | M_ZERO); 1816150634Sjhb refcount_init(&cr->cr_ref, 1); 1817170407Srwatson#ifdef AUDIT 1818170407Srwatson audit_cred_init(cr); 1819170407Srwatson#endif 1820101001Srwatson#ifdef MAC 1821172930Srwatson mac_cred_init(cr); 1822101001Srwatson#endif 1823194498Sbrooks crextend(cr, XU_NGROUPS); 18241541Srgrimes return (cr); 18251541Srgrimes} 18261541Srgrimes 18271541Srgrimes/* 182882466Srwatson * Claim another reference to a ucred structure. 182969401Salfred */ 183084827Sjhbstruct ucred * 183193580Sjhbcrhold(struct ucred *cr) 183269401Salfred{ 183369401Salfred 1834150634Sjhb refcount_acquire(&cr->cr_ref); 183584827Sjhb return (cr); 183669401Salfred} 183769401Salfred 183869401Salfred/* 1839167211Srwatson * Free a cred structure. Throws away space when ref count gets to 0. 18401541Srgrimes */ 18411549Srgrimesvoid 184293580Sjhbcrfree(struct ucred *cr) 18431541Srgrimes{ 184469239Salfred 184575632Salfred KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref)); 1846150634Sjhb KASSERT(cr->cr_ref != 0xdeadc0de, ("dangling reference to ucred")); 1847150634Sjhb if (refcount_release(&cr->cr_ref)) { 184865495Struckman /* 184965495Struckman * Some callers of crget(), such as nfs_statfs(), 185065495Struckman * allocate a temporary credential, but don't 185165495Struckman * allocate a uidinfo structure. 185265495Struckman */ 185365495Struckman if (cr->cr_uidinfo != NULL) 185465495Struckman uifree(cr->cr_uidinfo); 185577277Srwatson if (cr->cr_ruidinfo != NULL) 185677277Srwatson uifree(cr->cr_ruidinfo); 185772786Srwatson /* 185872786Srwatson * Free a prison, if any. 185972786Srwatson */ 1860192895Sjamie if (cr->cr_prison != NULL) 186172786Srwatson prison_free(cr->cr_prison); 1862219304Strasz if (cr->cr_loginclass != NULL) 1863219304Strasz loginclass_free(cr->cr_loginclass); 1864170407Srwatson#ifdef AUDIT 1865170407Srwatson audit_cred_destroy(cr); 1866170407Srwatson#endif 1867101001Srwatson#ifdef MAC 1868172930Srwatson mac_cred_destroy(cr); 1869101001Srwatson#endif 1870194498Sbrooks free(cr->cr_groups, M_CRED); 1871184205Sdes free(cr, M_CRED); 187290756Sdillon } 18731541Srgrimes} 18741541Srgrimes 18751541Srgrimes/* 187684827Sjhb * Check to see if this ucred is shared. 18771541Srgrimes */ 187884827Sjhbint 187993580Sjhbcrshared(struct ucred *cr) 18801541Srgrimes{ 18811541Srgrimes 1882150634Sjhb return (cr->cr_ref > 1); 18831541Srgrimes} 18841541Srgrimes 18851541Srgrimes/* 188684827Sjhb * Copy a ucred's contents from a template. Does not block. 188784827Sjhb */ 188884827Sjhbvoid 188993580Sjhbcrcopy(struct ucred *dest, struct ucred *src) 189084827Sjhb{ 189184827Sjhb 189284827Sjhb KASSERT(crshared(dest) == 0, ("crcopy of shared ucred")); 189384827Sjhb bcopy(&src->cr_startcopy, &dest->cr_startcopy, 189487218Srwatson (unsigned)((caddr_t)&src->cr_endcopy - 189584827Sjhb (caddr_t)&src->cr_startcopy)); 1896194498Sbrooks crsetgroups(dest, src->cr_ngroups, src->cr_groups); 189784827Sjhb uihold(dest->cr_uidinfo); 189884827Sjhb uihold(dest->cr_ruidinfo); 1899192895Sjamie prison_hold(dest->cr_prison); 1900219304Strasz loginclass_hold(dest->cr_loginclass); 1901170407Srwatson#ifdef AUDIT 1902170407Srwatson audit_cred_copy(src, dest); 1903170407Srwatson#endif 1904101001Srwatson#ifdef MAC 1905172930Srwatson mac_cred_copy(src, dest); 1906101001Srwatson#endif 190784827Sjhb} 190884827Sjhb 190984827Sjhb/* 19101541Srgrimes * Dup cred struct to a new held one. 19111541Srgrimes */ 19121541Srgrimesstruct ucred * 191393580Sjhbcrdup(struct ucred *cr) 19141541Srgrimes{ 19151541Srgrimes struct ucred *newcr; 19161541Srgrimes 191784827Sjhb newcr = crget(); 191884827Sjhb crcopy(newcr, cr); 19191541Srgrimes return (newcr); 19201541Srgrimes} 19211541Srgrimes 19221541Srgrimes/* 192391354Sdd * Fill in a struct xucred based on a struct ucred. 192491354Sdd */ 192591354Sddvoid 192693580Sjhbcru2x(struct ucred *cr, struct xucred *xcr) 192791354Sdd{ 1928194498Sbrooks int ngroups; 192991354Sdd 193091354Sdd bzero(xcr, sizeof(*xcr)); 193191354Sdd xcr->cr_version = XUCRED_VERSION; 193291354Sdd xcr->cr_uid = cr->cr_uid; 1933194498Sbrooks 1934194498Sbrooks ngroups = MIN(cr->cr_ngroups, XU_NGROUPS); 1935194498Sbrooks xcr->cr_ngroups = ngroups; 1936194498Sbrooks bcopy(cr->cr_groups, xcr->cr_groups, 1937194498Sbrooks ngroups * sizeof(*cr->cr_groups)); 193891354Sdd} 193991354Sdd 194091354Sdd/* 1941167211Srwatson * small routine to swap a thread's current ucred for the correct one taken 1942167211Srwatson * from the process. 194390748Sjulian */ 194490748Sjulianvoid 194590748Sjuliancred_update_thread(struct thread *td) 194690748Sjulian{ 194790748Sjulian struct proc *p; 194891405Sjhb struct ucred *cred; 194990748Sjulian 195090748Sjulian p = td->td_proc; 195191405Sjhb cred = td->td_ucred; 195290748Sjulian PROC_LOCK(p); 195390748Sjulian td->td_ucred = crhold(p->p_ucred); 195490748Sjulian PROC_UNLOCK(p); 195591405Sjhb if (cred != NULL) 195691405Sjhb crfree(cred); 195790748Sjulian} 195890748Sjulian 1959302229Sbdrewery/* 1960303846Sbdrewery * Set initial process credentials. 1961303846Sbdrewery * Callers are responsible for providing the reference for provided credentials. 1962303846Sbdrewery */ 1963303846Sbdreweryvoid 1964303846Sbdreweryproc_set_cred_init(struct proc *p, struct ucred *newcred) 1965303846Sbdrewery{ 1966303846Sbdrewery 1967303846Sbdrewery p->p_ucred = newcred; 1968303846Sbdrewery} 1969303846Sbdrewery 1970303846Sbdrewery/* 1971302229Sbdrewery * Change process credentials. 1972303846Sbdrewery * Callers are responsible for providing the reference for passed credentials 1973302229Sbdrewery * and for freeing old ones. 1974302229Sbdrewery * 1975302229Sbdrewery * Process has to be locked except when it does not have credentials (as it 1976302229Sbdrewery * should not be visible just yet) or when newcred is NULL (as this can be 1977302229Sbdrewery * only used when the process is about to be freed, at which point it should 1978302229Sbdrewery * not be visible anymore). 1979302229Sbdrewery */ 1980194498Sbrooksstruct ucred * 1981302229Sbdreweryproc_set_cred(struct proc *p, struct ucred *newcred) 1982302229Sbdrewery{ 1983302229Sbdrewery struct ucred *oldcred; 1984302229Sbdrewery 1985303846Sbdrewery MPASS(p->p_ucred != NULL); 1986302229Sbdrewery if (newcred == NULL) 1987302229Sbdrewery MPASS(p->p_state == PRS_ZOMBIE); 1988303846Sbdrewery else 1989302229Sbdrewery PROC_LOCK_ASSERT(p, MA_OWNED); 1990302229Sbdrewery 1991302229Sbdrewery oldcred = p->p_ucred; 1992302229Sbdrewery p->p_ucred = newcred; 1993302229Sbdrewery return (oldcred); 1994302229Sbdrewery} 1995302229Sbdrewery 1996302229Sbdrewerystruct ucred * 1997194498Sbrookscrcopysafe(struct proc *p, struct ucred *cr) 1998194498Sbrooks{ 1999194498Sbrooks struct ucred *oldcred; 2000194498Sbrooks int groups; 2001194498Sbrooks 2002194498Sbrooks PROC_LOCK_ASSERT(p, MA_OWNED); 2003194498Sbrooks 2004194498Sbrooks oldcred = p->p_ucred; 2005194498Sbrooks while (cr->cr_agroups < oldcred->cr_agroups) { 2006194498Sbrooks groups = oldcred->cr_agroups; 2007194498Sbrooks PROC_UNLOCK(p); 2008194498Sbrooks crextend(cr, groups); 2009194498Sbrooks PROC_LOCK(p); 2010194498Sbrooks oldcred = p->p_ucred; 2011194498Sbrooks } 2012194498Sbrooks crcopy(cr, oldcred); 2013194498Sbrooks 2014194498Sbrooks return (oldcred); 2015194498Sbrooks} 2016194498Sbrooks 201790748Sjulian/* 2018194498Sbrooks * Extend the passed in credential to hold n items. 2019194498Sbrooks */ 2020293897Sglebiusvoid 2021194498Sbrookscrextend(struct ucred *cr, int n) 2022194498Sbrooks{ 2023194498Sbrooks int cnt; 2024194498Sbrooks 2025194498Sbrooks /* Truncate? */ 2026194498Sbrooks if (n <= cr->cr_agroups) 2027194498Sbrooks return; 2028194498Sbrooks 2029194498Sbrooks /* 2030194498Sbrooks * We extend by 2 each time since we're using a power of two 2031194498Sbrooks * allocator until we need enough groups to fill a page. 2032194498Sbrooks * Once we're allocating multiple pages, only allocate as many 2033194498Sbrooks * as we actually need. The case of processes needing a 2034194498Sbrooks * non-power of two number of pages seems more likely than 2035194498Sbrooks * a real world process that adds thousands of groups one at a 2036194498Sbrooks * time. 2037194498Sbrooks */ 2038194498Sbrooks if ( n < PAGE_SIZE / sizeof(gid_t) ) { 2039194498Sbrooks if (cr->cr_agroups == 0) 2040194498Sbrooks cnt = MINALLOCSIZE / sizeof(gid_t); 2041194498Sbrooks else 2042194498Sbrooks cnt = cr->cr_agroups * 2; 2043194498Sbrooks 2044194498Sbrooks while (cnt < n) 2045194498Sbrooks cnt *= 2; 2046194498Sbrooks } else 2047194498Sbrooks cnt = roundup2(n, PAGE_SIZE / sizeof(gid_t)); 2048194498Sbrooks 2049194498Sbrooks /* Free the old array. */ 2050194498Sbrooks if (cr->cr_groups) 2051194498Sbrooks free(cr->cr_groups, M_CRED); 2052194498Sbrooks 2053194498Sbrooks cr->cr_groups = malloc(cnt * sizeof(gid_t), M_CRED, M_WAITOK | M_ZERO); 2054194498Sbrooks cr->cr_agroups = cnt; 2055194498Sbrooks} 2056194498Sbrooks 2057194498Sbrooks/* 2058194556Sbrooks * Copy groups in to a credential, preserving any necessary invariants. 2059194556Sbrooks * Currently this includes the sorting of all supplemental gids. 2060194556Sbrooks * crextend() must have been called before hand to ensure sufficient 2061194556Sbrooks * space is available. 2062194498Sbrooks */ 2063194498Sbrooksstatic void 2064194498Sbrookscrsetgroups_locked(struct ucred *cr, int ngrp, gid_t *groups) 2065194498Sbrooks{ 2066194556Sbrooks int i; 2067194556Sbrooks int j; 2068194556Sbrooks gid_t g; 2069194498Sbrooks 2070194498Sbrooks KASSERT(cr->cr_agroups >= ngrp, ("cr_ngroups is too small")); 2071194498Sbrooks 2072194498Sbrooks bcopy(groups, cr->cr_groups, ngrp * sizeof(gid_t)); 2073194498Sbrooks cr->cr_ngroups = ngrp; 2074194556Sbrooks 2075194556Sbrooks /* 2076194556Sbrooks * Sort all groups except cr_groups[0] to allow groupmember to 2077194556Sbrooks * perform a binary search. 2078194556Sbrooks * 2079194556Sbrooks * XXX: If large numbers of groups become common this should 2080194556Sbrooks * be replaced with shell sort like linux uses or possibly 2081194556Sbrooks * heap sort. 2082194556Sbrooks */ 2083194556Sbrooks for (i = 2; i < ngrp; i++) { 2084194556Sbrooks g = cr->cr_groups[i]; 2085194556Sbrooks for (j = i-1; j >= 1 && g < cr->cr_groups[j]; j--) 2086194556Sbrooks cr->cr_groups[j + 1] = cr->cr_groups[j]; 2087194556Sbrooks cr->cr_groups[j + 1] = g; 2088194556Sbrooks } 2089194498Sbrooks} 2090194498Sbrooks 2091194498Sbrooks/* 2092194498Sbrooks * Copy groups in to a credential after expanding it if required. 2093202143Sbrooks * Truncate the list to (ngroups_max + 1) if it is too large. 2094194498Sbrooks */ 2095194498Sbrooksvoid 2096194498Sbrookscrsetgroups(struct ucred *cr, int ngrp, gid_t *groups) 2097194498Sbrooks{ 2098194498Sbrooks 2099202143Sbrooks if (ngrp > ngroups_max + 1) 2100202143Sbrooks ngrp = ngroups_max + 1; 2101194498Sbrooks 2102194498Sbrooks crextend(cr, ngrp); 2103194498Sbrooks crsetgroups_locked(cr, ngrp, groups); 2104194498Sbrooks} 2105194498Sbrooks 2106194498Sbrooks/* 21071541Srgrimes * Get login name, if available. 21081541Srgrimes */ 210912221Sbde#ifndef _SYS_SYSPROTO_H_ 21101541Srgrimesstruct getlogin_args { 21111541Srgrimes char *namebuf; 21121541Srgrimes u_int namelen; 21131541Srgrimes}; 211412221Sbde#endif 21151541Srgrimes/* ARGSUSED */ 21161549Srgrimesint 2117225617Skmacysys_getlogin(struct thread *td, struct getlogin_args *uap) 21181541Srgrimes{ 211991140Stanimura char login[MAXLOGNAME]; 212083366Sjulian struct proc *p = td->td_proc; 2121274107Sdes size_t len; 21221541Srgrimes 212323358Sache if (uap->namelen > MAXLOGNAME) 212423359Sache uap->namelen = MAXLOGNAME; 212591140Stanimura PROC_LOCK(p); 212691140Stanimura SESS_LOCK(p->p_session); 2127274107Sdes len = strlcpy(login, p->p_session->s_login, uap->namelen) + 1; 212891140Stanimura SESS_UNLOCK(p->p_session); 212991140Stanimura PROC_UNLOCK(p); 2130274107Sdes if (len > uap->namelen) 2131243021Sbapt return (ERANGE); 2132274107Sdes return (copyout(login, uap->namebuf, len)); 21331541Srgrimes} 21341541Srgrimes 21351541Srgrimes/* 21361541Srgrimes * Set login name. 21371541Srgrimes */ 213812221Sbde#ifndef _SYS_SYSPROTO_H_ 21391541Srgrimesstruct setlogin_args { 21401541Srgrimes char *namebuf; 21411541Srgrimes}; 214212221Sbde#endif 21431541Srgrimes/* ARGSUSED */ 21441549Srgrimesint 2145225617Skmacysys_setlogin(struct thread *td, struct setlogin_args *uap) 21461541Srgrimes{ 214783366Sjulian struct proc *p = td->td_proc; 21481541Srgrimes int error; 214923330Sache char logintmp[MAXLOGNAME]; 21501541Srgrimes 2151274107Sdes CTASSERT(sizeof(p->p_session->s_login) >= sizeof(logintmp)); 2152274107Sdes 2153170587Srwatson error = priv_check(td, PRIV_PROC_SETLOGIN); 215494619Sjhb if (error) 215594619Sjhb return (error); 215699009Salfred error = copyinstr(uap->namebuf, logintmp, sizeof(logintmp), NULL); 2157274107Sdes if (error != 0) { 2158274107Sdes if (error == ENAMETOOLONG) 2159274107Sdes error = EINVAL; 2160274107Sdes return (error); 216191140Stanimura } 2162274107Sdes PROC_LOCK(p); 2163274107Sdes SESS_LOCK(p->p_session); 2164274107Sdes strcpy(p->p_session->s_login, logintmp); 2165274107Sdes SESS_UNLOCK(p->p_session); 2166274107Sdes PROC_UNLOCK(p); 2167274107Sdes return (0); 21681541Srgrimes} 216931891Ssef 217031891Ssefvoid 217193580Sjhbsetsugid(struct proc *p) 217231891Ssef{ 217398403Salfred 217498403Salfred PROC_LOCK_ASSERT(p, MA_OWNED); 217531891Ssef p->p_flag |= P_SUGID; 217655707Ssef if (!(p->p_pfsflags & PF_ISUGID)) 217731891Ssef p->p_stops = 0; 217831891Ssef} 217965495Struckman 2180210226Strasz/*- 218182466Srwatson * Change a process's effective uid. 218277183Srwatson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified. 218377183Srwatson * References: newcred must be an exclusive credential reference for the 218477183Srwatson * duration of the call. 218565495Struckman */ 218665495Struckmanvoid 218798417Salfredchange_euid(struct ucred *newcred, struct uidinfo *euip) 218865495Struckman{ 218965495Struckman 219098417Salfred newcred->cr_uid = euip->ui_uid; 219198417Salfred uihold(euip); 219277183Srwatson uifree(newcred->cr_uidinfo); 219398417Salfred newcred->cr_uidinfo = euip; 219465495Struckman} 219565495Struckman 2196210226Strasz/*- 219782466Srwatson * Change a process's effective gid. 219877183Srwatson * Side effects: newcred->cr_gid will be modified. 219977183Srwatson * References: newcred must be an exclusive credential reference for the 220077183Srwatson * duration of the call. 220165495Struckman */ 220267629Sgallatinvoid 220393580Sjhbchange_egid(struct ucred *newcred, gid_t egid) 220465495Struckman{ 220565495Struckman 220677183Srwatson newcred->cr_groups[0] = egid; 220765495Struckman} 220877183Srwatson 2209210226Strasz/*- 221082466Srwatson * Change a process's real uid. 221177183Srwatson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo 221277183Srwatson * will be updated, and the old and new cr_ruidinfo proc 221377183Srwatson * counts will be updated. 221477183Srwatson * References: newcred must be an exclusive credential reference for the 221577183Srwatson * duration of the call. 221677183Srwatson */ 221777183Srwatsonvoid 221898417Salfredchange_ruid(struct ucred *newcred, struct uidinfo *ruip) 221977183Srwatson{ 222077183Srwatson 222177183Srwatson (void)chgproccnt(newcred->cr_ruidinfo, -1, 0); 222298417Salfred newcred->cr_ruid = ruip->ui_uid; 222398417Salfred uihold(ruip); 222477183Srwatson uifree(newcred->cr_ruidinfo); 222598417Salfred newcred->cr_ruidinfo = ruip; 222677183Srwatson (void)chgproccnt(newcred->cr_ruidinfo, 1, 0); 222777183Srwatson} 222877183Srwatson 2229210226Strasz/*- 223082466Srwatson * Change a process's real gid. 223177183Srwatson * Side effects: newcred->cr_rgid will be updated. 223277183Srwatson * References: newcred must be an exclusive credential reference for the 223377183Srwatson * duration of the call. 223477183Srwatson */ 223577183Srwatsonvoid 223693580Sjhbchange_rgid(struct ucred *newcred, gid_t rgid) 223777183Srwatson{ 223877183Srwatson 223977183Srwatson newcred->cr_rgid = rgid; 224077183Srwatson} 224177183Srwatson 2242210226Strasz/*- 224382466Srwatson * Change a process's saved uid. 224477183Srwatson * Side effects: newcred->cr_svuid will be updated. 224577183Srwatson * References: newcred must be an exclusive credential reference for the 224677183Srwatson * duration of the call. 224777183Srwatson */ 224877183Srwatsonvoid 224993580Sjhbchange_svuid(struct ucred *newcred, uid_t svuid) 225077183Srwatson{ 225177183Srwatson 225277183Srwatson newcred->cr_svuid = svuid; 225377183Srwatson} 225477183Srwatson 2255210226Strasz/*- 225682466Srwatson * Change a process's saved gid. 225777183Srwatson * Side effects: newcred->cr_svgid will be updated. 225877183Srwatson * References: newcred must be an exclusive credential reference for the 225977183Srwatson * duration of the call. 226077183Srwatson */ 226177183Srwatsonvoid 226293580Sjhbchange_svgid(struct ucred *newcred, gid_t svgid) 226377183Srwatson{ 226477183Srwatson 226577183Srwatson newcred->cr_svgid = svgid; 226677183Srwatson} 2267