1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * (c) UNIX System Laboratories, Inc. 5df8bae1dSRodney W. Grimes * All or some portions of this file are derived from material licensed 6df8bae1dSRodney W. Grimes * to the University of California by American Telephone and Telegraph 7df8bae1dSRodney W. Grimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8df8bae1dSRodney W. Grimes * the permission of UNIX System Laboratories, Inc. 9eb725b4eSRobert Watson * Copyright (c) 2000-2001 Robert N. M. Watson. All rights reserved. 10df8bae1dSRodney W. Grimes * 11df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 12df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 13df8bae1dSRodney W. Grimes * are met: 14df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 15df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 16df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 17df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 18df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 19df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 20df8bae1dSRodney W. Grimes * must display the following acknowledgement: 21df8bae1dSRodney W. Grimes * This product includes software developed by the University of 22df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 23df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 24df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 25df8bae1dSRodney W. Grimes * without specific prior written permission. 26df8bae1dSRodney W. Grimes * 27df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37df8bae1dSRodney W. Grimes * SUCH DAMAGE. 38df8bae1dSRodney W. Grimes * 39df8bae1dSRodney W. Grimes * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 40c3aac50fSPeter Wemm * $FreeBSD$ 41df8bae1dSRodney W. Grimes */ 42df8bae1dSRodney W. Grimes 43df8bae1dSRodney W. Grimes /* 44df8bae1dSRodney W. Grimes * System calls related to processes and protection 45df8bae1dSRodney W. Grimes */ 46df8bae1dSRodney W. Grimes 475591b823SEivind Eklund #include "opt_compat.h" 48130d0157SRobert Watson #include "opt_global.h" 495591b823SEivind Eklund 50df8bae1dSRodney W. Grimes #include <sys/param.h> 51df8bae1dSRodney W. Grimes #include <sys/systm.h> 52fb919e4dSMark Murray #include <sys/acct.h> 531c5bb3eaSPeter Wemm #include <sys/kernel.h> 5498f03f90SJake Burkholder #include <sys/lock.h> 55fb919e4dSMark Murray #include <sys/mutex.h> 56df8bae1dSRodney W. Grimes #include <sys/proc.h> 575b29d6e9SJohn Baldwin #include <sys/sx.h> 58fb919e4dSMark Murray #include <sys/sysproto.h> 59eb725b4eSRobert Watson #include <sys/jail.h> 60df8bae1dSRodney W. Grimes #include <sys/malloc.h> 61d5f81602SSean Eric Fagan #include <sys/pioctl.h> 62f535380cSDon Lewis #include <sys/resourcevar.h> 63579f4eb4SRobert Watson #include <sys/sysctl.h> 64df8bae1dSRodney W. Grimes 65a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_CRED, "cred", "credentials"); 66a1c995b6SPoul-Henning Kamp 670ef5652eSRobert Watson SYSCTL_NODE(_kern, OID_AUTO, security, CTLFLAG_RW, 0, 680ef5652eSRobert Watson "Kernel security policy"); 6948713bdcSRobert Watson SYSCTL_NODE(_kern_security, OID_AUTO, bsd, CTLFLAG_RW, 0, 7048713bdcSRobert Watson "BSD security policy"); 7148713bdcSRobert Watson 72d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 73ad7507e2SSteven Wallace struct getpid_args { 74df8bae1dSRodney W. Grimes int dummy; 75df8bae1dSRodney W. Grimes }; 76d2d3e875SBruce Evans #endif 77835a82eeSMatthew Dillon /* 78835a82eeSMatthew Dillon * MPSAFE 79835a82eeSMatthew Dillon */ 80df8bae1dSRodney W. Grimes /* ARGSUSED */ 8126f9a767SRodney W. Grimes int 82b40ce416SJulian Elischer getpid(td, uap) 83b40ce416SJulian Elischer struct thread *td; 84ad7507e2SSteven Wallace struct getpid_args *uap; 85df8bae1dSRodney W. Grimes { 86b40ce416SJulian Elischer struct proc *p = td->td_proc; 87d23f5958SMatthew Dillon int s; 88df8bae1dSRodney W. Grimes 89d23f5958SMatthew Dillon s = mtx_lock_giant(kern_giant_proc); 90b40ce416SJulian Elischer td->td_retval[0] = p->p_pid; 91df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 92bae3a80bSJohn Baldwin PROC_LOCK(p); 93b40ce416SJulian Elischer td->td_retval[1] = p->p_pptr->p_pid; 94bae3a80bSJohn Baldwin PROC_UNLOCK(p); 95df8bae1dSRodney W. Grimes #endif 96d23f5958SMatthew Dillon mtx_unlock_giant(s); 97df8bae1dSRodney W. Grimes return (0); 98df8bae1dSRodney W. Grimes } 99df8bae1dSRodney W. Grimes 100d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 101ad7507e2SSteven Wallace struct getppid_args { 102ad7507e2SSteven Wallace int dummy; 103ad7507e2SSteven Wallace }; 104d2d3e875SBruce Evans #endif 105835a82eeSMatthew Dillon /* 106835a82eeSMatthew Dillon * MPSAFE 107835a82eeSMatthew Dillon */ 108df8bae1dSRodney W. Grimes /* ARGSUSED */ 10926f9a767SRodney W. Grimes int 110b40ce416SJulian Elischer getppid(td, uap) 111b40ce416SJulian Elischer struct thread *td; 112ad7507e2SSteven Wallace struct getppid_args *uap; 113df8bae1dSRodney W. Grimes { 114b40ce416SJulian Elischer struct proc *p = td->td_proc; 115d23f5958SMatthew Dillon int s; 116df8bae1dSRodney W. Grimes 117d23f5958SMatthew Dillon s = mtx_lock_giant(kern_giant_proc); 118bae3a80bSJohn Baldwin PROC_LOCK(p); 119b40ce416SJulian Elischer td->td_retval[0] = p->p_pptr->p_pid; 120bae3a80bSJohn Baldwin PROC_UNLOCK(p); 121d23f5958SMatthew Dillon mtx_unlock_giant(s); 122df8bae1dSRodney W. Grimes return (0); 123df8bae1dSRodney W. Grimes } 124df8bae1dSRodney W. Grimes 12536e9f877SMatthew Dillon /* 126eb725b4eSRobert Watson * Get process group ID; note that POSIX getpgrp takes no parameter. 12736e9f877SMatthew Dillon */ 128d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 129ad7507e2SSteven Wallace struct getpgrp_args { 130ad7507e2SSteven Wallace int dummy; 131ad7507e2SSteven Wallace }; 132d2d3e875SBruce Evans #endif 133835a82eeSMatthew Dillon /* 134835a82eeSMatthew Dillon * MPSAFE 135835a82eeSMatthew Dillon */ 13626f9a767SRodney W. Grimes int 137b40ce416SJulian Elischer getpgrp(td, uap) 138b40ce416SJulian Elischer struct thread *td; 139ad7507e2SSteven Wallace struct getpgrp_args *uap; 140df8bae1dSRodney W. Grimes { 141b40ce416SJulian Elischer struct proc *p = td->td_proc; 142df8bae1dSRodney W. Grimes 143835a82eeSMatthew Dillon mtx_lock(&Giant); 144b40ce416SJulian Elischer td->td_retval[0] = p->p_pgrp->pg_id; 145835a82eeSMatthew Dillon mtx_unlock(&Giant); 146df8bae1dSRodney W. Grimes return (0); 147df8bae1dSRodney W. Grimes } 148df8bae1dSRodney W. Grimes 1491a5018a0SPeter Wemm /* Get an arbitary pid's process group id */ 1501a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1511a5018a0SPeter Wemm struct getpgid_args { 1521a5018a0SPeter Wemm pid_t pid; 1531a5018a0SPeter Wemm }; 1541a5018a0SPeter Wemm #endif 155835a82eeSMatthew Dillon /* 156835a82eeSMatthew Dillon * MPSAFE 157835a82eeSMatthew Dillon */ 1581a5018a0SPeter Wemm int 159b40ce416SJulian Elischer getpgid(td, uap) 160b40ce416SJulian Elischer struct thread *td; 1611a5018a0SPeter Wemm struct getpgid_args *uap; 1621a5018a0SPeter Wemm { 163b40ce416SJulian Elischer struct proc *p = td->td_proc; 16465de0c7aSDon Lewis struct proc *pt; 165eb725b4eSRobert Watson int error, s; 16665de0c7aSDon Lewis 167d23f5958SMatthew Dillon s = mtx_lock_giant(kern_giant_proc); 168eb725b4eSRobert Watson error = 0; 1691a5018a0SPeter Wemm if (uap->pid == 0) 170b40ce416SJulian Elischer td->td_retval[0] = p->p_pgrp->pg_id; 1716a90c862SJohn Baldwin else if ((pt = pfind(uap->pid)) == NULL) 172835a82eeSMatthew Dillon error = ESRCH; 1736a90c862SJohn Baldwin else { 1746a90c862SJohn Baldwin error = p_cansee(p, pt); 1756a90c862SJohn Baldwin if (error == 0) 176b40ce416SJulian Elischer td->td_retval[0] = pt->p_pgrp->pg_id; 17733a9ed9dSJohn Baldwin PROC_UNLOCK(pt); 17833a9ed9dSJohn Baldwin } 179d23f5958SMatthew Dillon mtx_unlock_giant(s); 180835a82eeSMatthew Dillon return (error); 1811a5018a0SPeter Wemm } 1821a5018a0SPeter Wemm 1831a5018a0SPeter Wemm /* 1841a5018a0SPeter Wemm * Get an arbitary pid's session id. 1851a5018a0SPeter Wemm */ 1861a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1871a5018a0SPeter Wemm struct getsid_args { 1881a5018a0SPeter Wemm pid_t pid; 1891a5018a0SPeter Wemm }; 1901a5018a0SPeter Wemm #endif 191835a82eeSMatthew Dillon /* 192835a82eeSMatthew Dillon * MPSAFE 193835a82eeSMatthew Dillon */ 1941a5018a0SPeter Wemm int 195b40ce416SJulian Elischer getsid(td, uap) 196b40ce416SJulian Elischer struct thread *td; 1971a5018a0SPeter Wemm struct getsid_args *uap; 1981a5018a0SPeter Wemm { 199b40ce416SJulian Elischer struct proc *p = td->td_proc; 20065de0c7aSDon Lewis struct proc *pt; 201eb725b4eSRobert Watson int error; 20265de0c7aSDon Lewis 203835a82eeSMatthew Dillon mtx_lock(&Giant); 204eb725b4eSRobert Watson error = 0; 2056a90c862SJohn Baldwin if (uap->pid == 0) 206b40ce416SJulian Elischer td->td_retval[0] = p->p_session->s_sid; 2076a90c862SJohn Baldwin else if ((pt = pfind(uap->pid)) == NULL) 208835a82eeSMatthew Dillon error = ESRCH; 2096a90c862SJohn Baldwin else { 2106a90c862SJohn Baldwin error = p_cansee(p, pt); 2116a90c862SJohn Baldwin if (error == 0) 212b40ce416SJulian Elischer td->td_retval[0] = pt->p_session->s_sid; 21333a9ed9dSJohn Baldwin PROC_UNLOCK(pt); 21433a9ed9dSJohn Baldwin } 215835a82eeSMatthew Dillon mtx_unlock(&Giant); 216835a82eeSMatthew Dillon return (error); 2171a5018a0SPeter Wemm } 2181a5018a0SPeter Wemm 219d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 220ad7507e2SSteven Wallace struct getuid_args { 221ad7507e2SSteven Wallace int dummy; 222ad7507e2SSteven Wallace }; 223d2d3e875SBruce Evans #endif 224835a82eeSMatthew Dillon /* 225835a82eeSMatthew Dillon * MPSAFE 226835a82eeSMatthew Dillon */ 227df8bae1dSRodney W. Grimes /* ARGSUSED */ 22826f9a767SRodney W. Grimes int 229b40ce416SJulian Elischer getuid(td, uap) 230b40ce416SJulian Elischer struct thread *td; 231ad7507e2SSteven Wallace struct getuid_args *uap; 232df8bae1dSRodney W. Grimes { 233b40ce416SJulian Elischer struct proc *p = td->td_proc; 234df8bae1dSRodney W. Grimes 235835a82eeSMatthew Dillon mtx_lock(&Giant); 236b40ce416SJulian Elischer td->td_retval[0] = p->p_ucred->cr_ruid; 237df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 238b40ce416SJulian Elischer td->td_retval[1] = p->p_ucred->cr_uid; 239df8bae1dSRodney W. Grimes #endif 240835a82eeSMatthew Dillon mtx_unlock(&Giant); 241df8bae1dSRodney W. Grimes return (0); 242df8bae1dSRodney W. Grimes } 243df8bae1dSRodney W. Grimes 244d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 245ad7507e2SSteven Wallace struct geteuid_args { 246ad7507e2SSteven Wallace int dummy; 247ad7507e2SSteven Wallace }; 248d2d3e875SBruce Evans #endif 249eb725b4eSRobert Watson /* 250eb725b4eSRobert Watson * MPSAFE 251eb725b4eSRobert Watson */ 252df8bae1dSRodney W. Grimes /* ARGSUSED */ 25326f9a767SRodney W. Grimes int 254b40ce416SJulian Elischer geteuid(td, uap) 255b40ce416SJulian Elischer struct thread *td; 256ad7507e2SSteven Wallace struct geteuid_args *uap; 257df8bae1dSRodney W. Grimes { 258835a82eeSMatthew Dillon mtx_lock(&Giant); 259b40ce416SJulian Elischer td->td_retval[0] = td->td_proc->p_ucred->cr_uid; 260835a82eeSMatthew Dillon mtx_unlock(&Giant); 261df8bae1dSRodney W. Grimes return (0); 262df8bae1dSRodney W. Grimes } 263df8bae1dSRodney W. Grimes 264d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 265ad7507e2SSteven Wallace struct getgid_args { 266ad7507e2SSteven Wallace int dummy; 267ad7507e2SSteven Wallace }; 268d2d3e875SBruce Evans #endif 269835a82eeSMatthew Dillon /* 270835a82eeSMatthew Dillon * MPSAFE 271835a82eeSMatthew Dillon */ 272df8bae1dSRodney W. Grimes /* ARGSUSED */ 27326f9a767SRodney W. Grimes int 274b40ce416SJulian Elischer getgid(td, uap) 275b40ce416SJulian Elischer struct thread *td; 276ad7507e2SSteven Wallace struct getgid_args *uap; 277df8bae1dSRodney W. Grimes { 278b40ce416SJulian Elischer struct proc *p = td->td_proc; 279df8bae1dSRodney W. Grimes 280835a82eeSMatthew Dillon mtx_lock(&Giant); 281b40ce416SJulian Elischer td->td_retval[0] = p->p_ucred->cr_rgid; 282df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 283b40ce416SJulian Elischer td->td_retval[1] = p->p_ucred->cr_groups[0]; 284df8bae1dSRodney W. Grimes #endif 285835a82eeSMatthew Dillon mtx_unlock(&Giant); 286df8bae1dSRodney W. Grimes return (0); 287df8bae1dSRodney W. Grimes } 288df8bae1dSRodney W. Grimes 289df8bae1dSRodney W. Grimes /* 290df8bae1dSRodney W. Grimes * Get effective group ID. The "egid" is groups[0], and could be obtained 291df8bae1dSRodney W. Grimes * via getgroups. This syscall exists because it is somewhat painful to do 292df8bae1dSRodney W. Grimes * correctly in a library function. 293df8bae1dSRodney W. Grimes */ 294d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 295ad7507e2SSteven Wallace struct getegid_args { 296ad7507e2SSteven Wallace int dummy; 297ad7507e2SSteven Wallace }; 298d2d3e875SBruce Evans #endif 299835a82eeSMatthew Dillon /* 300835a82eeSMatthew Dillon * MPSAFE 301835a82eeSMatthew Dillon */ 302df8bae1dSRodney W. Grimes /* ARGSUSED */ 30326f9a767SRodney W. Grimes int 304b40ce416SJulian Elischer getegid(td, uap) 305b40ce416SJulian Elischer struct thread *td; 306ad7507e2SSteven Wallace struct getegid_args *uap; 307df8bae1dSRodney W. Grimes { 308b40ce416SJulian Elischer struct proc *p = td->td_proc; 309df8bae1dSRodney W. Grimes 310835a82eeSMatthew Dillon mtx_lock(&Giant); 311b40ce416SJulian Elischer td->td_retval[0] = p->p_ucred->cr_groups[0]; 312835a82eeSMatthew Dillon mtx_unlock(&Giant); 313df8bae1dSRodney W. Grimes return (0); 314df8bae1dSRodney W. Grimes } 315df8bae1dSRodney W. Grimes 316d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 317df8bae1dSRodney W. Grimes struct getgroups_args { 318df8bae1dSRodney W. Grimes u_int gidsetsize; 319df8bae1dSRodney W. Grimes gid_t *gidset; 320df8bae1dSRodney W. Grimes }; 321d2d3e875SBruce Evans #endif 322835a82eeSMatthew Dillon /* 323835a82eeSMatthew Dillon * MPSAFE 324835a82eeSMatthew Dillon */ 32526f9a767SRodney W. Grimes int 326b40ce416SJulian Elischer getgroups(td, uap) 327b40ce416SJulian Elischer struct thread *td; 328df8bae1dSRodney W. Grimes register struct getgroups_args *uap; 329df8bae1dSRodney W. Grimes { 330835a82eeSMatthew Dillon struct ucred *cred; 331b40ce416SJulian Elischer struct proc *p = td->td_proc; 332b1fc0ec1SRobert Watson u_int ngrp; 333eb725b4eSRobert Watson int error; 334df8bae1dSRodney W. Grimes 335835a82eeSMatthew Dillon mtx_lock(&Giant); 336eb725b4eSRobert Watson error = 0; 337835a82eeSMatthew Dillon cred = p->p_ucred; 338df8bae1dSRodney W. Grimes if ((ngrp = uap->gidsetsize) == 0) { 339b40ce416SJulian Elischer td->td_retval[0] = cred->cr_ngroups; 340835a82eeSMatthew Dillon goto done2; 341df8bae1dSRodney W. Grimes } 342835a82eeSMatthew Dillon if (ngrp < cred->cr_ngroups) { 343835a82eeSMatthew Dillon error = EINVAL; 344835a82eeSMatthew Dillon goto done2; 345835a82eeSMatthew Dillon } 346b1fc0ec1SRobert Watson ngrp = cred->cr_ngroups; 347b1fc0ec1SRobert Watson if ((error = copyout((caddr_t)cred->cr_groups, 348eb725b4eSRobert Watson (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))) 349835a82eeSMatthew Dillon goto done2; 350b40ce416SJulian Elischer td->td_retval[0] = ngrp; 351835a82eeSMatthew Dillon done2: 352835a82eeSMatthew Dillon mtx_unlock(&Giant); 353835a82eeSMatthew Dillon return (error); 354df8bae1dSRodney W. Grimes } 355df8bae1dSRodney W. Grimes 356d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 35782970b81SBruce Evans struct setsid_args { 358ad7507e2SSteven Wallace int dummy; 359ad7507e2SSteven Wallace }; 360d2d3e875SBruce Evans #endif 361835a82eeSMatthew Dillon /* 362835a82eeSMatthew Dillon * MPSAFE 363835a82eeSMatthew Dillon */ 364df8bae1dSRodney W. Grimes /* ARGSUSED */ 36526f9a767SRodney W. Grimes int 366b40ce416SJulian Elischer setsid(td, uap) 367b40ce416SJulian Elischer register struct thread *td; 36882970b81SBruce Evans struct setsid_args *uap; 369df8bae1dSRodney W. Grimes { 370835a82eeSMatthew Dillon int error; 371b40ce416SJulian Elischer struct proc *p = td->td_proc; 372df8bae1dSRodney W. Grimes 373835a82eeSMatthew Dillon mtx_lock(&Giant); 374eb725b4eSRobert Watson if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) 375835a82eeSMatthew Dillon error = EPERM; 376eb725b4eSRobert Watson else { 377df8bae1dSRodney W. Grimes (void)enterpgrp(p, p->p_pid, 1); 378b40ce416SJulian Elischer td->td_retval[0] = p->p_pid; 379835a82eeSMatthew Dillon error = 0; 380df8bae1dSRodney W. Grimes } 381835a82eeSMatthew Dillon mtx_unlock(&Giant); 382835a82eeSMatthew Dillon return (error); 383df8bae1dSRodney W. Grimes } 384df8bae1dSRodney W. Grimes 385df8bae1dSRodney W. Grimes /* 386df8bae1dSRodney W. Grimes * set process group (setpgid/old setpgrp) 387df8bae1dSRodney W. Grimes * 388df8bae1dSRodney W. Grimes * caller does setpgid(targpid, targpgid) 389df8bae1dSRodney W. Grimes * 390df8bae1dSRodney W. Grimes * pid must be caller or child of caller (ESRCH) 391df8bae1dSRodney W. Grimes * if a child 392df8bae1dSRodney W. Grimes * pid must be in same session (EPERM) 393df8bae1dSRodney W. Grimes * pid can't have done an exec (EACCES) 394df8bae1dSRodney W. Grimes * if pgid != pid 395df8bae1dSRodney W. Grimes * there must exist some pid in same session having pgid (EPERM) 396df8bae1dSRodney W. Grimes * pid must not be session leader (EPERM) 397df8bae1dSRodney W. Grimes */ 398d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 399df8bae1dSRodney W. Grimes struct setpgid_args { 400df8bae1dSRodney W. Grimes int pid; /* target process id */ 401df8bae1dSRodney W. Grimes int pgid; /* target pgrp id */ 402df8bae1dSRodney W. Grimes }; 403d2d3e875SBruce Evans #endif 404835a82eeSMatthew Dillon /* 405835a82eeSMatthew Dillon * MPSAFE 406835a82eeSMatthew Dillon */ 407df8bae1dSRodney W. Grimes /* ARGSUSED */ 40826f9a767SRodney W. Grimes int 409b40ce416SJulian Elischer setpgid(td, uap) 410b40ce416SJulian Elischer struct thread *td; 411df8bae1dSRodney W. Grimes register struct setpgid_args *uap; 412df8bae1dSRodney W. Grimes { 413b40ce416SJulian Elischer struct proc *curp = td->td_proc; 414df8bae1dSRodney W. Grimes register struct proc *targp; /* target process */ 415df8bae1dSRodney W. Grimes register struct pgrp *pgrp; /* target pgrp */ 416eb9e5c1dSRobert Watson int error; 417df8bae1dSRodney W. Grimes 41878f64bccSBruce Evans if (uap->pgid < 0) 41978f64bccSBruce Evans return (EINVAL); 420835a82eeSMatthew Dillon mtx_lock(&Giant); 4215b29d6e9SJohn Baldwin sx_slock(&proctree_lock); 422df8bae1dSRodney W. Grimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 42333a9ed9dSJohn Baldwin if ((targp = pfind(uap->pid)) == NULL || !inferior(targp)) { 42433a9ed9dSJohn Baldwin if (targp) 42533a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 426835a82eeSMatthew Dillon error = ESRCH; 427835a82eeSMatthew Dillon goto done2; 42833a9ed9dSJohn Baldwin } 429a0f75161SRobert Watson if ((error = p_cansee(curproc, targp))) { 43033a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 431835a82eeSMatthew Dillon goto done2; 43233a9ed9dSJohn Baldwin } 43333a9ed9dSJohn Baldwin if (targp->p_pgrp == NULL || 43433a9ed9dSJohn Baldwin targp->p_session != curp->p_session) { 43533a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 436835a82eeSMatthew Dillon error = EPERM; 437835a82eeSMatthew Dillon goto done2; 43833a9ed9dSJohn Baldwin } 43933a9ed9dSJohn Baldwin if (targp->p_flag & P_EXEC) { 44033a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 441835a82eeSMatthew Dillon error = EACCES; 442835a82eeSMatthew Dillon goto done2; 44333a9ed9dSJohn Baldwin } 44433a9ed9dSJohn Baldwin } else { 445df8bae1dSRodney W. Grimes targp = curp; 44633a9ed9dSJohn Baldwin PROC_LOCK(curp); /* XXX: not needed */ 44733a9ed9dSJohn Baldwin } 44833a9ed9dSJohn Baldwin if (SESS_LEADER(targp)) { 44933a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 450835a82eeSMatthew Dillon error = EPERM; 451835a82eeSMatthew Dillon goto done2; 45233a9ed9dSJohn Baldwin } 453eb725b4eSRobert Watson if (uap->pgid == 0) 454df8bae1dSRodney W. Grimes uap->pgid = targp->p_pid; 455eb725b4eSRobert Watson else if (uap->pgid != targp->p_pid) { 456df8bae1dSRodney W. Grimes if ((pgrp = pgfind(uap->pgid)) == 0 || 45733a9ed9dSJohn Baldwin pgrp->pg_session != curp->p_session) { 45833a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 459835a82eeSMatthew Dillon error = EPERM; 460835a82eeSMatthew Dillon goto done2; 461835a82eeSMatthew Dillon } 46233a9ed9dSJohn Baldwin } 46333a9ed9dSJohn Baldwin /* XXX: We should probably hold the lock across enterpgrp. */ 46433a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 465835a82eeSMatthew Dillon error = enterpgrp(targp, uap->pgid, 0); 466835a82eeSMatthew Dillon done2: 4675b29d6e9SJohn Baldwin sx_sunlock(&proctree_lock); 468835a82eeSMatthew Dillon mtx_unlock(&Giant); 469835a82eeSMatthew Dillon return (error); 470df8bae1dSRodney W. Grimes } 471df8bae1dSRodney W. Grimes 472a08f4bf6SPeter Wemm /* 473a08f4bf6SPeter Wemm * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 4742fa72ea7SJeroen Ruigrok van der Werven * compatible. It says that setting the uid/gid to euid/egid is a special 475a08f4bf6SPeter Wemm * case of "appropriate privilege". Once the rules are expanded out, this 476a08f4bf6SPeter Wemm * basically means that setuid(nnn) sets all three id's, in all permitted 477a08f4bf6SPeter Wemm * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 478a08f4bf6SPeter Wemm * does not set the saved id - this is dangerous for traditional BSD 479a08f4bf6SPeter Wemm * programs. For this reason, we *really* do not want to set 480a08f4bf6SPeter Wemm * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 481a08f4bf6SPeter Wemm */ 482a08f4bf6SPeter Wemm #define POSIX_APPENDIX_B_4_2_2 483a08f4bf6SPeter Wemm 484d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 485df8bae1dSRodney W. Grimes struct setuid_args { 486df8bae1dSRodney W. Grimes uid_t uid; 487df8bae1dSRodney W. Grimes }; 488d2d3e875SBruce Evans #endif 489835a82eeSMatthew Dillon /* 490835a82eeSMatthew Dillon * MPSAFE 491835a82eeSMatthew Dillon */ 492df8bae1dSRodney W. Grimes /* ARGSUSED */ 49326f9a767SRodney W. Grimes int 494b40ce416SJulian Elischer setuid(td, uap) 495b40ce416SJulian Elischer struct thread *td; 496df8bae1dSRodney W. Grimes struct setuid_args *uap; 497df8bae1dSRodney W. Grimes { 498b40ce416SJulian Elischer struct proc *p = td->td_proc; 499b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 500b1fc0ec1SRobert Watson uid_t uid; 501eb725b4eSRobert Watson int error; 502df8bae1dSRodney W. Grimes 503eb725b4eSRobert Watson uid = uap->uid; 504835a82eeSMatthew Dillon mtx_lock(&Giant); 505eb725b4eSRobert Watson error = 0; 506f605567cSRobert Watson oldcred = p->p_ucred; 507a08f4bf6SPeter Wemm /* 508a08f4bf6SPeter Wemm * See if we have "permission" by POSIX 1003.1 rules. 509a08f4bf6SPeter Wemm * 510a08f4bf6SPeter Wemm * Note that setuid(geteuid()) is a special case of 511a08f4bf6SPeter Wemm * "appropriate privileges" in appendix B.4.2.2. We need 5122fa72ea7SJeroen Ruigrok van der Werven * to use this clause to be compatible with traditional BSD 513a08f4bf6SPeter Wemm * semantics. Basically, it means that "setuid(xx)" sets all 514a08f4bf6SPeter Wemm * three id's (assuming you have privs). 515a08f4bf6SPeter Wemm * 516a08f4bf6SPeter Wemm * Notes on the logic. We do things in three steps. 517a08f4bf6SPeter Wemm * 1: We determine if the euid is going to change, and do EPERM 518a08f4bf6SPeter Wemm * right away. We unconditionally change the euid later if this 519a08f4bf6SPeter Wemm * test is satisfied, simplifying that part of the logic. 520eb725b4eSRobert Watson * 2: We determine if the real and/or saved uids are going to 521a08f4bf6SPeter Wemm * change. Determined by compile options. 522a08f4bf6SPeter Wemm * 3: Change euid last. (after tests in #2 for "appropriate privs") 523a08f4bf6SPeter Wemm */ 524b1fc0ec1SRobert Watson if (uid != oldcred->cr_ruid && /* allow setuid(getuid()) */ 5253f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS 526b1fc0ec1SRobert Watson uid != oldcred->cr_svuid && /* allow setuid(saved gid) */ 527a08f4bf6SPeter Wemm #endif 528a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 529b1fc0ec1SRobert Watson uid != oldcred->cr_uid && /* allow setuid(geteuid()) */ 5303f246666SAndrey A. Chernov #endif 531eb725b4eSRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 532835a82eeSMatthew Dillon goto done2; 533a08f4bf6SPeter Wemm 534b1fc0ec1SRobert Watson newcred = crdup(oldcred); 535a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS 536df8bae1dSRodney W. Grimes /* 537a08f4bf6SPeter Wemm * Do we have "appropriate privileges" (are we root or uid == euid) 538a08f4bf6SPeter Wemm * If so, we are changing the real uid and/or saved uid. 539df8bae1dSRodney W. Grimes */ 5403f246666SAndrey A. Chernov if ( 541a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 542b1fc0ec1SRobert Watson uid == oldcred->cr_uid || 5433f246666SAndrey A. Chernov #endif 544b1fc0ec1SRobert Watson suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */ 545a08f4bf6SPeter Wemm #endif 546a08f4bf6SPeter Wemm { 547a08f4bf6SPeter Wemm /* 548f535380cSDon Lewis * Set the real uid and transfer proc count to new user. 549a08f4bf6SPeter Wemm */ 550b1fc0ec1SRobert Watson if (uid != oldcred->cr_ruid) { 551b1fc0ec1SRobert Watson change_ruid(newcred, uid); 552f535380cSDon Lewis setsugid(p); 553d3cdb93dSAndrey A. Chernov } 554a08f4bf6SPeter Wemm /* 555a08f4bf6SPeter Wemm * Set saved uid 556a08f4bf6SPeter Wemm * 557a08f4bf6SPeter Wemm * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 558a08f4bf6SPeter Wemm * the security of seteuid() depends on it. B.4.2.2 says it 559a08f4bf6SPeter Wemm * is important that we should do this. 560a08f4bf6SPeter Wemm */ 561b1fc0ec1SRobert Watson if (uid != oldcred->cr_svuid) { 562b1fc0ec1SRobert Watson change_svuid(newcred, uid); 563d5f81602SSean Eric Fagan setsugid(p); 564a08f4bf6SPeter Wemm } 565a08f4bf6SPeter Wemm } 566a08f4bf6SPeter Wemm 567a08f4bf6SPeter Wemm /* 568a08f4bf6SPeter Wemm * In all permitted cases, we are changing the euid. 569a08f4bf6SPeter Wemm * Copy credentials so other references do not see our changes. 570a08f4bf6SPeter Wemm */ 571b1fc0ec1SRobert Watson if (uid != oldcred->cr_uid) { 572b1fc0ec1SRobert Watson change_euid(newcred, uid); 573d5f81602SSean Eric Fagan setsugid(p); 574a08f4bf6SPeter Wemm } 575b1fc0ec1SRobert Watson p->p_ucred = newcred; 576b1fc0ec1SRobert Watson crfree(oldcred); 577835a82eeSMatthew Dillon done2: 578835a82eeSMatthew Dillon mtx_unlock(&Giant); 579835a82eeSMatthew Dillon return (error); 580df8bae1dSRodney W. Grimes } 581df8bae1dSRodney W. Grimes 582d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 583df8bae1dSRodney W. Grimes struct seteuid_args { 584df8bae1dSRodney W. Grimes uid_t euid; 585df8bae1dSRodney W. Grimes }; 586d2d3e875SBruce Evans #endif 587835a82eeSMatthew Dillon /* 588835a82eeSMatthew Dillon * MPSAFE 589835a82eeSMatthew Dillon */ 590df8bae1dSRodney W. Grimes /* ARGSUSED */ 59126f9a767SRodney W. Grimes int 592b40ce416SJulian Elischer seteuid(td, uap) 593b40ce416SJulian Elischer struct thread *td; 594df8bae1dSRodney W. Grimes struct seteuid_args *uap; 595df8bae1dSRodney W. Grimes { 596b40ce416SJulian Elischer struct proc *p = td->td_proc; 597b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 598b1fc0ec1SRobert Watson uid_t euid; 599eb725b4eSRobert Watson int error; 600df8bae1dSRodney W. Grimes 601df8bae1dSRodney W. Grimes euid = uap->euid; 602835a82eeSMatthew Dillon mtx_lock(&Giant); 603eb725b4eSRobert Watson error = 0; 604b1fc0ec1SRobert Watson oldcred = p->p_ucred; 605b1fc0ec1SRobert Watson if (euid != oldcred->cr_ruid && /* allow seteuid(getuid()) */ 606b1fc0ec1SRobert Watson euid != oldcred->cr_svuid && /* allow seteuid(saved uid) */ 607eb725b4eSRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 608835a82eeSMatthew Dillon goto done2; 609df8bae1dSRodney W. Grimes /* 610df8bae1dSRodney W. Grimes * Everything's okay, do it. Copy credentials so other references do 611df8bae1dSRodney W. Grimes * not see our changes. 612df8bae1dSRodney W. Grimes */ 613b1fc0ec1SRobert Watson newcred = crdup(oldcred); 614b1fc0ec1SRobert Watson if (oldcred->cr_uid != euid) { 615b1fc0ec1SRobert Watson change_euid(newcred, euid); 616d5f81602SSean Eric Fagan setsugid(p); 617229a15f0SPeter Wemm } 618b1fc0ec1SRobert Watson p->p_ucred = newcred; 619b1fc0ec1SRobert Watson crfree(oldcred); 620835a82eeSMatthew Dillon done2: 621835a82eeSMatthew Dillon mtx_unlock(&Giant); 622835a82eeSMatthew Dillon return (error); 623df8bae1dSRodney W. Grimes } 624df8bae1dSRodney W. Grimes 625d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 626df8bae1dSRodney W. Grimes struct setgid_args { 627df8bae1dSRodney W. Grimes gid_t gid; 628df8bae1dSRodney W. Grimes }; 629d2d3e875SBruce Evans #endif 630835a82eeSMatthew Dillon /* 631835a82eeSMatthew Dillon * MPSAFE 632835a82eeSMatthew Dillon */ 633df8bae1dSRodney W. Grimes /* ARGSUSED */ 63426f9a767SRodney W. Grimes int 635b40ce416SJulian Elischer setgid(td, uap) 636b40ce416SJulian Elischer struct thread *td; 637df8bae1dSRodney W. Grimes struct setgid_args *uap; 638df8bae1dSRodney W. Grimes { 639b40ce416SJulian Elischer struct proc *p = td->td_proc; 640b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 641b1fc0ec1SRobert Watson gid_t gid; 642eb725b4eSRobert Watson int error; 643df8bae1dSRodney W. Grimes 644b1fc0ec1SRobert Watson gid = uap->gid; 645835a82eeSMatthew Dillon mtx_lock(&Giant); 646eb725b4eSRobert Watson error = 0; 647b1fc0ec1SRobert Watson oldcred = p->p_ucred; 648a08f4bf6SPeter Wemm /* 649a08f4bf6SPeter Wemm * See if we have "permission" by POSIX 1003.1 rules. 650a08f4bf6SPeter Wemm * 651a08f4bf6SPeter Wemm * Note that setgid(getegid()) is a special case of 652a08f4bf6SPeter Wemm * "appropriate privileges" in appendix B.4.2.2. We need 6532fa72ea7SJeroen Ruigrok van der Werven * to use this clause to be compatible with traditional BSD 654a08f4bf6SPeter Wemm * semantics. Basically, it means that "setgid(xx)" sets all 655a08f4bf6SPeter Wemm * three id's (assuming you have privs). 656a08f4bf6SPeter Wemm * 657a08f4bf6SPeter Wemm * For notes on the logic here, see setuid() above. 658a08f4bf6SPeter Wemm */ 659b1fc0ec1SRobert Watson if (gid != oldcred->cr_rgid && /* allow setgid(getgid()) */ 6603f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS 661b1fc0ec1SRobert Watson gid != oldcred->cr_svgid && /* allow setgid(saved gid) */ 662a08f4bf6SPeter Wemm #endif 663a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 664b1fc0ec1SRobert Watson gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */ 6653f246666SAndrey A. Chernov #endif 666eb725b4eSRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 667835a82eeSMatthew Dillon goto done2; 668a08f4bf6SPeter Wemm 669b1fc0ec1SRobert Watson newcred = crdup(oldcred); 670a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS 671a08f4bf6SPeter Wemm /* 672a08f4bf6SPeter Wemm * Do we have "appropriate privileges" (are we root or gid == egid) 673a08f4bf6SPeter Wemm * If so, we are changing the real uid and saved gid. 674a08f4bf6SPeter Wemm */ 675a08f4bf6SPeter Wemm if ( 676a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 677b1fc0ec1SRobert Watson gid == oldcred->cr_groups[0] || 678a08f4bf6SPeter Wemm #endif 679b1fc0ec1SRobert Watson suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */ 680a08f4bf6SPeter Wemm #endif 681a08f4bf6SPeter Wemm { 682a08f4bf6SPeter Wemm /* 683a08f4bf6SPeter Wemm * Set real gid 684a08f4bf6SPeter Wemm */ 685b1fc0ec1SRobert Watson if (oldcred->cr_rgid != gid) { 686b1fc0ec1SRobert Watson change_rgid(newcred, gid); 687d5f81602SSean Eric Fagan setsugid(p); 688a08f4bf6SPeter Wemm } 689a08f4bf6SPeter Wemm /* 690a08f4bf6SPeter Wemm * Set saved gid 691a08f4bf6SPeter Wemm * 692a08f4bf6SPeter Wemm * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 693a08f4bf6SPeter Wemm * the security of setegid() depends on it. B.4.2.2 says it 694a08f4bf6SPeter Wemm * is important that we should do this. 695a08f4bf6SPeter Wemm */ 696b1fc0ec1SRobert Watson if (oldcred->cr_svgid != gid) { 697b1fc0ec1SRobert Watson change_svgid(newcred, gid); 698d5f81602SSean Eric Fagan setsugid(p); 699a08f4bf6SPeter Wemm } 700a08f4bf6SPeter Wemm } 701a08f4bf6SPeter Wemm /* 702a08f4bf6SPeter Wemm * In all cases permitted cases, we are changing the egid. 703a08f4bf6SPeter Wemm * Copy credentials so other references do not see our changes. 704a08f4bf6SPeter Wemm */ 705b1fc0ec1SRobert Watson if (oldcred->cr_groups[0] != gid) { 706b1fc0ec1SRobert Watson change_egid(newcred, gid); 707d5f81602SSean Eric Fagan setsugid(p); 708a08f4bf6SPeter Wemm } 709b1fc0ec1SRobert Watson p->p_ucred = newcred; 710b1fc0ec1SRobert Watson crfree(oldcred); 711835a82eeSMatthew Dillon done2: 712835a82eeSMatthew Dillon mtx_unlock(&Giant); 713835a82eeSMatthew Dillon return (error); 714df8bae1dSRodney W. Grimes } 715df8bae1dSRodney W. Grimes 716d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 717df8bae1dSRodney W. Grimes struct setegid_args { 718df8bae1dSRodney W. Grimes gid_t egid; 719df8bae1dSRodney W. Grimes }; 720d2d3e875SBruce Evans #endif 721835a82eeSMatthew Dillon /* 722835a82eeSMatthew Dillon * MPSAFE 723835a82eeSMatthew Dillon */ 724df8bae1dSRodney W. Grimes /* ARGSUSED */ 72526f9a767SRodney W. Grimes int 726b40ce416SJulian Elischer setegid(td, uap) 727b40ce416SJulian Elischer struct thread *td; 728df8bae1dSRodney W. Grimes struct setegid_args *uap; 729df8bae1dSRodney W. Grimes { 730b40ce416SJulian Elischer struct proc *p = td->td_proc; 731b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 732b1fc0ec1SRobert Watson gid_t egid; 733eb725b4eSRobert Watson int error; 734df8bae1dSRodney W. Grimes 735df8bae1dSRodney W. Grimes egid = uap->egid; 736835a82eeSMatthew Dillon mtx_lock(&Giant); 737eb725b4eSRobert Watson error = 0; 738b1fc0ec1SRobert Watson oldcred = p->p_ucred; 739b1fc0ec1SRobert Watson if (egid != oldcred->cr_rgid && /* allow setegid(getgid()) */ 740b1fc0ec1SRobert Watson egid != oldcred->cr_svgid && /* allow setegid(saved gid) */ 741eb725b4eSRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 742835a82eeSMatthew Dillon goto done2; 743b1fc0ec1SRobert Watson newcred = crdup(oldcred); 744b1fc0ec1SRobert Watson if (oldcred->cr_groups[0] != egid) { 745b1fc0ec1SRobert Watson change_egid(newcred, egid); 746d5f81602SSean Eric Fagan setsugid(p); 747229a15f0SPeter Wemm } 748b1fc0ec1SRobert Watson p->p_ucred = newcred; 749b1fc0ec1SRobert Watson crfree(oldcred); 750835a82eeSMatthew Dillon done2: 751835a82eeSMatthew Dillon mtx_unlock(&Giant); 752835a82eeSMatthew Dillon return (error); 753df8bae1dSRodney W. Grimes } 754df8bae1dSRodney W. Grimes 755d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 756df8bae1dSRodney W. Grimes struct setgroups_args { 757df8bae1dSRodney W. Grimes u_int gidsetsize; 758df8bae1dSRodney W. Grimes gid_t *gidset; 759df8bae1dSRodney W. Grimes }; 760d2d3e875SBruce Evans #endif 761835a82eeSMatthew Dillon /* 762835a82eeSMatthew Dillon * MPSAFE 763835a82eeSMatthew Dillon */ 764df8bae1dSRodney W. Grimes /* ARGSUSED */ 76526f9a767SRodney W. Grimes int 766b40ce416SJulian Elischer setgroups(td, uap) 767b40ce416SJulian Elischer struct thread *td; 768df8bae1dSRodney W. Grimes struct setgroups_args *uap; 769df8bae1dSRodney W. Grimes { 770b40ce416SJulian Elischer struct proc *p = td->td_proc; 771b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 772b1fc0ec1SRobert Watson u_int ngrp; 773df8bae1dSRodney W. Grimes int error; 774df8bae1dSRodney W. Grimes 7753956a170SDavid Greenman ngrp = uap->gidsetsize; 7764f5a4612SRobert Watson mtx_lock(&Giant); 777b1fc0ec1SRobert Watson oldcred = p->p_ucred; 778eb725b4eSRobert Watson if ((error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 779835a82eeSMatthew Dillon goto done2; 780835a82eeSMatthew Dillon if (ngrp > NGROUPS) { 781835a82eeSMatthew Dillon error = EINVAL; 782835a82eeSMatthew Dillon goto done2; 783835a82eeSMatthew Dillon } 7848a5d815aSPeter Wemm /* 7858a5d815aSPeter Wemm * XXX A little bit lazy here. We could test if anything has 7868a5d815aSPeter Wemm * changed before crcopy() and setting P_SUGID. 7878a5d815aSPeter Wemm */ 788b1fc0ec1SRobert Watson newcred = crdup(oldcred); 7898a5d815aSPeter Wemm if (ngrp < 1) { 7908a5d815aSPeter Wemm /* 7918a5d815aSPeter Wemm * setgroups(0, NULL) is a legitimate way of clearing the 7928a5d815aSPeter Wemm * groups vector on non-BSD systems (which generally do not 7938a5d815aSPeter Wemm * have the egid in the groups[0]). We risk security holes 7948a5d815aSPeter Wemm * when running non-BSD software if we do not do the same. 7958a5d815aSPeter Wemm */ 796b1fc0ec1SRobert Watson newcred->cr_ngroups = 1; 7978a5d815aSPeter Wemm } else { 798bb56ec4aSPoul-Henning Kamp if ((error = copyin((caddr_t)uap->gidset, 799b1fc0ec1SRobert Watson (caddr_t)newcred->cr_groups, ngrp * sizeof(gid_t)))) { 800b1fc0ec1SRobert Watson crfree(newcred); 801835a82eeSMatthew Dillon goto done2; 802b1fc0ec1SRobert Watson } 803b1fc0ec1SRobert Watson newcred->cr_ngroups = ngrp; 8048a5d815aSPeter Wemm } 805d5f81602SSean Eric Fagan setsugid(p); 806b1fc0ec1SRobert Watson p->p_ucred = newcred; 807b1fc0ec1SRobert Watson crfree(oldcred); 808835a82eeSMatthew Dillon done2: 809835a82eeSMatthew Dillon mtx_unlock(&Giant); 810835a82eeSMatthew Dillon return (error); 811df8bae1dSRodney W. Grimes } 812df8bae1dSRodney W. Grimes 813d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 814df8bae1dSRodney W. Grimes struct setreuid_args { 81500999cd6SAndrey A. Chernov uid_t ruid; 81600999cd6SAndrey A. Chernov uid_t euid; 817df8bae1dSRodney W. Grimes }; 818d2d3e875SBruce Evans #endif 819835a82eeSMatthew Dillon /* 820835a82eeSMatthew Dillon * MPSAFE 821835a82eeSMatthew Dillon */ 822df8bae1dSRodney W. Grimes /* ARGSUSED */ 82326f9a767SRodney W. Grimes int 824b40ce416SJulian Elischer setreuid(td, uap) 825b40ce416SJulian Elischer register struct thread *td; 826df8bae1dSRodney W. Grimes struct setreuid_args *uap; 827df8bae1dSRodney W. Grimes { 828b40ce416SJulian Elischer struct proc *p = td->td_proc; 829b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 830eb725b4eSRobert Watson uid_t euid, ruid; 831eb725b4eSRobert Watson int error; 832df8bae1dSRodney W. Grimes 83300999cd6SAndrey A. Chernov euid = uap->euid; 834eb725b4eSRobert Watson ruid = uap->ruid; 835835a82eeSMatthew Dillon mtx_lock(&Giant); 836eb725b4eSRobert Watson error = 0; 837b1fc0ec1SRobert Watson oldcred = p->p_ucred; 838b1fc0ec1SRobert Watson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 839b1fc0ec1SRobert Watson ruid != oldcred->cr_svuid) || 840b1fc0ec1SRobert Watson (euid != (uid_t)-1 && euid != oldcred->cr_uid && 841b1fc0ec1SRobert Watson euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) && 842eb725b4eSRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 843835a82eeSMatthew Dillon goto done2; 844b1fc0ec1SRobert Watson newcred = crdup(oldcred); 845b1fc0ec1SRobert Watson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 846b1fc0ec1SRobert Watson change_euid(newcred, euid); 847d5f81602SSean Eric Fagan setsugid(p); 848a89a5370SPeter Wemm } 849b1fc0ec1SRobert Watson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 850b1fc0ec1SRobert Watson change_ruid(newcred, ruid); 851d5f81602SSean Eric Fagan setsugid(p); 85200999cd6SAndrey A. Chernov } 853b1fc0ec1SRobert Watson if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) && 854b1fc0ec1SRobert Watson newcred->cr_svuid != newcred->cr_uid) { 855b1fc0ec1SRobert Watson change_svuid(newcred, newcred->cr_uid); 856d5f81602SSean Eric Fagan setsugid(p); 857a89a5370SPeter Wemm } 858b1fc0ec1SRobert Watson p->p_ucred = newcred; 859b1fc0ec1SRobert Watson crfree(oldcred); 860835a82eeSMatthew Dillon done2: 861835a82eeSMatthew Dillon mtx_unlock(&Giant); 862835a82eeSMatthew Dillon return (error); 863df8bae1dSRodney W. Grimes } 864df8bae1dSRodney W. Grimes 865d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 866df8bae1dSRodney W. Grimes struct setregid_args { 86700999cd6SAndrey A. Chernov gid_t rgid; 86800999cd6SAndrey A. Chernov gid_t egid; 869df8bae1dSRodney W. Grimes }; 870d2d3e875SBruce Evans #endif 871835a82eeSMatthew Dillon /* 872835a82eeSMatthew Dillon * MPSAFE 873835a82eeSMatthew Dillon */ 874df8bae1dSRodney W. Grimes /* ARGSUSED */ 87526f9a767SRodney W. Grimes int 876b40ce416SJulian Elischer setregid(td, uap) 877b40ce416SJulian Elischer register struct thread *td; 878df8bae1dSRodney W. Grimes struct setregid_args *uap; 879df8bae1dSRodney W. Grimes { 880b40ce416SJulian Elischer struct proc *p = td->td_proc; 881b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 882eb725b4eSRobert Watson gid_t egid, rgid; 883eb725b4eSRobert Watson int error; 884df8bae1dSRodney W. Grimes 88500999cd6SAndrey A. Chernov egid = uap->egid; 886eb725b4eSRobert Watson rgid = uap->rgid; 887835a82eeSMatthew Dillon mtx_lock(&Giant); 888eb725b4eSRobert Watson error = 0; 889b1fc0ec1SRobert Watson oldcred = p->p_ucred; 890b1fc0ec1SRobert Watson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 891b1fc0ec1SRobert Watson rgid != oldcred->cr_svgid) || 892b1fc0ec1SRobert Watson (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] && 893b1fc0ec1SRobert Watson egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) && 894eb725b4eSRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 895835a82eeSMatthew Dillon goto done2; 896b1fc0ec1SRobert Watson newcred = crdup(oldcred); 897b1fc0ec1SRobert Watson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 898b1fc0ec1SRobert Watson change_egid(newcred, egid); 899d5f81602SSean Eric Fagan setsugid(p); 900a89a5370SPeter Wemm } 901b1fc0ec1SRobert Watson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 902b1fc0ec1SRobert Watson change_rgid(newcred, rgid); 903d5f81602SSean Eric Fagan setsugid(p); 904a89a5370SPeter Wemm } 905b1fc0ec1SRobert Watson if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) && 906b1fc0ec1SRobert Watson newcred->cr_svgid != newcred->cr_groups[0]) { 907b1fc0ec1SRobert Watson change_svgid(newcred, newcred->cr_groups[0]); 908d5f81602SSean Eric Fagan setsugid(p); 909a89a5370SPeter Wemm } 9104589be70SRuslan Ermilov p->p_ucred = newcred; 9114589be70SRuslan Ermilov crfree(oldcred); 912835a82eeSMatthew Dillon done2: 913835a82eeSMatthew Dillon mtx_unlock(&Giant); 914835a82eeSMatthew Dillon return (error); 915df8bae1dSRodney W. Grimes } 916df8bae1dSRodney W. Grimes 9178ccd6334SPeter Wemm /* 9188ccd6334SPeter Wemm * setresuid(ruid, euid, suid) is like setreuid except control over the 9198ccd6334SPeter Wemm * saved uid is explicit. 9208ccd6334SPeter Wemm */ 9218ccd6334SPeter Wemm 9228ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 9238ccd6334SPeter Wemm struct setresuid_args { 9248ccd6334SPeter Wemm uid_t ruid; 9258ccd6334SPeter Wemm uid_t euid; 9268ccd6334SPeter Wemm uid_t suid; 9278ccd6334SPeter Wemm }; 9288ccd6334SPeter Wemm #endif 929835a82eeSMatthew Dillon /* 930835a82eeSMatthew Dillon * MPSAFE 931835a82eeSMatthew Dillon */ 9328ccd6334SPeter Wemm /* ARGSUSED */ 9338ccd6334SPeter Wemm int 934b40ce416SJulian Elischer setresuid(td, uap) 935b40ce416SJulian Elischer register struct thread *td; 9368ccd6334SPeter Wemm struct setresuid_args *uap; 9378ccd6334SPeter Wemm { 938b40ce416SJulian Elischer struct proc *p = td->td_proc; 939b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 940eb725b4eSRobert Watson uid_t euid, ruid, suid; 9418ccd6334SPeter Wemm int error; 9428ccd6334SPeter Wemm 9438ccd6334SPeter Wemm euid = uap->euid; 944eb725b4eSRobert Watson ruid = uap->ruid; 9458ccd6334SPeter Wemm suid = uap->suid; 946835a82eeSMatthew Dillon mtx_lock(&Giant); 947b1fc0ec1SRobert Watson oldcred = p->p_ucred; 948b1fc0ec1SRobert Watson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 949b1fc0ec1SRobert Watson ruid != oldcred->cr_svuid && 950b1fc0ec1SRobert Watson ruid != oldcred->cr_uid) || 951b1fc0ec1SRobert Watson (euid != (uid_t)-1 && euid != oldcred->cr_ruid && 952b1fc0ec1SRobert Watson euid != oldcred->cr_svuid && 953b1fc0ec1SRobert Watson euid != oldcred->cr_uid) || 954b1fc0ec1SRobert Watson (suid != (uid_t)-1 && suid != oldcred->cr_ruid && 955b1fc0ec1SRobert Watson suid != oldcred->cr_svuid && 956b1fc0ec1SRobert Watson suid != oldcred->cr_uid)) && 957eb725b4eSRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 958835a82eeSMatthew Dillon goto done2; 959b1fc0ec1SRobert Watson newcred = crdup(oldcred); 960b1fc0ec1SRobert Watson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 961b1fc0ec1SRobert Watson change_euid(newcred, euid); 9628ccd6334SPeter Wemm setsugid(p); 9638ccd6334SPeter Wemm } 964b1fc0ec1SRobert Watson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 965b1fc0ec1SRobert Watson change_ruid(newcred, ruid); 9668ccd6334SPeter Wemm setsugid(p); 9678ccd6334SPeter Wemm } 968b1fc0ec1SRobert Watson if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) { 969b1fc0ec1SRobert Watson change_svuid(newcred, suid); 9708ccd6334SPeter Wemm setsugid(p); 9718ccd6334SPeter Wemm } 972b1fc0ec1SRobert Watson p->p_ucred = newcred; 973b1fc0ec1SRobert Watson crfree(oldcred); 974835a82eeSMatthew Dillon error = 0; 975835a82eeSMatthew Dillon done2: 976835a82eeSMatthew Dillon mtx_unlock(&Giant); 977835a82eeSMatthew Dillon return (error); 9788ccd6334SPeter Wemm } 9798ccd6334SPeter Wemm 9808ccd6334SPeter Wemm /* 9818ccd6334SPeter Wemm * setresgid(rgid, egid, sgid) is like setregid except control over the 9828ccd6334SPeter Wemm * saved gid is explicit. 9838ccd6334SPeter Wemm */ 9848ccd6334SPeter Wemm 9858ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 9868ccd6334SPeter Wemm struct setresgid_args { 9878ccd6334SPeter Wemm gid_t rgid; 9888ccd6334SPeter Wemm gid_t egid; 9898ccd6334SPeter Wemm gid_t sgid; 9908ccd6334SPeter Wemm }; 9918ccd6334SPeter Wemm #endif 992835a82eeSMatthew Dillon /* 993835a82eeSMatthew Dillon * MPSAFE 994835a82eeSMatthew Dillon */ 9958ccd6334SPeter Wemm /* ARGSUSED */ 9968ccd6334SPeter Wemm int 997b40ce416SJulian Elischer setresgid(td, uap) 998b40ce416SJulian Elischer register struct thread *td; 9998ccd6334SPeter Wemm struct setresgid_args *uap; 10008ccd6334SPeter Wemm { 1001b40ce416SJulian Elischer struct proc *p = td->td_proc; 1002b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 1003eb725b4eSRobert Watson gid_t egid, rgid, sgid; 10048ccd6334SPeter Wemm int error; 10058ccd6334SPeter Wemm 10068ccd6334SPeter Wemm egid = uap->egid; 1007eb725b4eSRobert Watson rgid = uap->rgid; 10088ccd6334SPeter Wemm sgid = uap->sgid; 1009835a82eeSMatthew Dillon mtx_lock(&Giant); 1010b1fc0ec1SRobert Watson oldcred = p->p_ucred; 1011b1fc0ec1SRobert Watson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 1012b1fc0ec1SRobert Watson rgid != oldcred->cr_svgid && 1013b1fc0ec1SRobert Watson rgid != oldcred->cr_groups[0]) || 1014b1fc0ec1SRobert Watson (egid != (gid_t)-1 && egid != oldcred->cr_rgid && 1015b1fc0ec1SRobert Watson egid != oldcred->cr_svgid && 1016b1fc0ec1SRobert Watson egid != oldcred->cr_groups[0]) || 1017b1fc0ec1SRobert Watson (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid && 1018b1fc0ec1SRobert Watson sgid != oldcred->cr_svgid && 1019b1fc0ec1SRobert Watson sgid != oldcred->cr_groups[0])) && 1020835a82eeSMatthew Dillon (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) { 1021835a82eeSMatthew Dillon goto done2; 1022835a82eeSMatthew Dillon } 1023b1fc0ec1SRobert Watson newcred = crdup(oldcred); 1024b1fc0ec1SRobert Watson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 1025b1fc0ec1SRobert Watson change_egid(newcred, egid); 10268ccd6334SPeter Wemm setsugid(p); 10278ccd6334SPeter Wemm } 1028b1fc0ec1SRobert Watson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 1029b1fc0ec1SRobert Watson change_rgid(newcred, rgid); 10308ccd6334SPeter Wemm setsugid(p); 10318ccd6334SPeter Wemm } 1032b1fc0ec1SRobert Watson if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) { 1033b1fc0ec1SRobert Watson change_svgid(newcred, sgid); 10348ccd6334SPeter Wemm setsugid(p); 10358ccd6334SPeter Wemm } 1036b1fc0ec1SRobert Watson p->p_ucred = newcred; 1037b1fc0ec1SRobert Watson crfree(oldcred); 1038835a82eeSMatthew Dillon error = 0; 1039835a82eeSMatthew Dillon done2: 1040835a82eeSMatthew Dillon mtx_unlock(&Giant); 1041835a82eeSMatthew Dillon return (error); 10428ccd6334SPeter Wemm } 10438ccd6334SPeter Wemm 10448ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 10458ccd6334SPeter Wemm struct getresuid_args { 10468ccd6334SPeter Wemm uid_t *ruid; 10478ccd6334SPeter Wemm uid_t *euid; 10488ccd6334SPeter Wemm uid_t *suid; 10498ccd6334SPeter Wemm }; 10508ccd6334SPeter Wemm #endif 1051835a82eeSMatthew Dillon /* 1052835a82eeSMatthew Dillon * MPSAFE 1053835a82eeSMatthew Dillon */ 10548ccd6334SPeter Wemm /* ARGSUSED */ 10558ccd6334SPeter Wemm int 1056b40ce416SJulian Elischer getresuid(td, uap) 1057b40ce416SJulian Elischer register struct thread *td; 10588ccd6334SPeter Wemm struct getresuid_args *uap; 10598ccd6334SPeter Wemm { 1060835a82eeSMatthew Dillon struct ucred *cred; 1061b40ce416SJulian Elischer struct proc *p = td->td_proc; 10628ccd6334SPeter Wemm int error1 = 0, error2 = 0, error3 = 0; 10638ccd6334SPeter Wemm 1064835a82eeSMatthew Dillon mtx_lock(&Giant); 1065835a82eeSMatthew Dillon cred = p->p_ucred; 10668ccd6334SPeter Wemm if (uap->ruid) 1067b1fc0ec1SRobert Watson error1 = copyout((caddr_t)&cred->cr_ruid, 1068b1fc0ec1SRobert Watson (caddr_t)uap->ruid, sizeof(cred->cr_ruid)); 10698ccd6334SPeter Wemm if (uap->euid) 1070b1fc0ec1SRobert Watson error2 = copyout((caddr_t)&cred->cr_uid, 1071b1fc0ec1SRobert Watson (caddr_t)uap->euid, sizeof(cred->cr_uid)); 10728ccd6334SPeter Wemm if (uap->suid) 1073b1fc0ec1SRobert Watson error3 = copyout((caddr_t)&cred->cr_svuid, 1074b1fc0ec1SRobert Watson (caddr_t)uap->suid, sizeof(cred->cr_svuid)); 1075835a82eeSMatthew Dillon mtx_unlock(&Giant); 1076eb725b4eSRobert Watson return (error1 ? error1 : error2 ? error2 : error3); 10778ccd6334SPeter Wemm } 10788ccd6334SPeter Wemm 10798ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 10808ccd6334SPeter Wemm struct getresgid_args { 10818ccd6334SPeter Wemm gid_t *rgid; 10828ccd6334SPeter Wemm gid_t *egid; 10838ccd6334SPeter Wemm gid_t *sgid; 10848ccd6334SPeter Wemm }; 10858ccd6334SPeter Wemm #endif 1086835a82eeSMatthew Dillon /* 1087835a82eeSMatthew Dillon * MPSAFE 1088835a82eeSMatthew Dillon */ 10898ccd6334SPeter Wemm /* ARGSUSED */ 10908ccd6334SPeter Wemm int 1091b40ce416SJulian Elischer getresgid(td, uap) 1092b40ce416SJulian Elischer register struct thread *td; 10938ccd6334SPeter Wemm struct getresgid_args *uap; 10948ccd6334SPeter Wemm { 1095835a82eeSMatthew Dillon struct ucred *cred; 1096b40ce416SJulian Elischer struct proc *p = td->td_proc; 10978ccd6334SPeter Wemm int error1 = 0, error2 = 0, error3 = 0; 10988ccd6334SPeter Wemm 1099835a82eeSMatthew Dillon mtx_lock(&Giant); 1100835a82eeSMatthew Dillon cred = p->p_ucred; 11018ccd6334SPeter Wemm if (uap->rgid) 1102b1fc0ec1SRobert Watson error1 = copyout((caddr_t)&cred->cr_rgid, 1103b1fc0ec1SRobert Watson (caddr_t)uap->rgid, sizeof(cred->cr_rgid)); 11048ccd6334SPeter Wemm if (uap->egid) 1105b1fc0ec1SRobert Watson error2 = copyout((caddr_t)&cred->cr_groups[0], 1106b1fc0ec1SRobert Watson (caddr_t)uap->egid, sizeof(cred->cr_groups[0])); 11078ccd6334SPeter Wemm if (uap->sgid) 1108b1fc0ec1SRobert Watson error3 = copyout((caddr_t)&cred->cr_svgid, 1109b1fc0ec1SRobert Watson (caddr_t)uap->sgid, sizeof(cred->cr_svgid)); 1110835a82eeSMatthew Dillon mtx_unlock(&Giant); 1111eb725b4eSRobert Watson return (error1 ? error1 : error2 ? error2 : error3); 11128ccd6334SPeter Wemm } 11138ccd6334SPeter Wemm 1114b67cbc65SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1115b67cbc65SPeter Wemm struct issetugid_args { 1116b67cbc65SPeter Wemm int dummy; 1117b67cbc65SPeter Wemm }; 1118b67cbc65SPeter Wemm #endif 1119eb725b4eSRobert Watson /* 1120eb725b4eSRobert Watson * NOT MPSAFE? 1121eb725b4eSRobert Watson */ 1122b67cbc65SPeter Wemm /* ARGSUSED */ 1123b67cbc65SPeter Wemm int 1124b40ce416SJulian Elischer issetugid(td, uap) 1125b40ce416SJulian Elischer register struct thread *td; 1126b67cbc65SPeter Wemm struct issetugid_args *uap; 1127b67cbc65SPeter Wemm { 1128b40ce416SJulian Elischer struct proc *p = td->td_proc; 1129b40ce416SJulian Elischer 1130b67cbc65SPeter Wemm /* 1131b67cbc65SPeter Wemm * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 1132b67cbc65SPeter Wemm * we use P_SUGID because we consider changing the owners as 1133b67cbc65SPeter Wemm * "tainting" as well. 1134b67cbc65SPeter Wemm * This is significant for procs that start as root and "become" 1135b67cbc65SPeter Wemm * a user without an exec - programs cannot know *everything* 1136b67cbc65SPeter Wemm * that libc *might* have put in their data segment. 1137b67cbc65SPeter Wemm */ 1138b40ce416SJulian Elischer td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 1139b67cbc65SPeter Wemm return (0); 1140b67cbc65SPeter Wemm } 1141b67cbc65SPeter Wemm 1142835a82eeSMatthew Dillon /* 1143835a82eeSMatthew Dillon * MPSAFE 1144835a82eeSMatthew Dillon */ 1145130d0157SRobert Watson int 1146b40ce416SJulian Elischer __setugid(td, uap) 1147b40ce416SJulian Elischer struct thread *td; 1148130d0157SRobert Watson struct __setugid_args *uap; 1149130d0157SRobert Watson { 1150130d0157SRobert Watson #ifdef REGRESSION 1151eb725b4eSRobert Watson int error; 1152835a82eeSMatthew Dillon 1153835a82eeSMatthew Dillon mtx_lock(&Giant); 1154eb725b4eSRobert Watson error = 0; 1155130d0157SRobert Watson switch (uap->flag) { 1156130d0157SRobert Watson case 0: 1157b40ce416SJulian Elischer td->td_proc->p_flag &= ~P_SUGID; 1158835a82eeSMatthew Dillon break; 1159130d0157SRobert Watson case 1: 1160b40ce416SJulian Elischer td->td_proc->p_flag |= P_SUGID; 1161835a82eeSMatthew Dillon break; 1162130d0157SRobert Watson default: 1163835a82eeSMatthew Dillon error = EINVAL; 1164835a82eeSMatthew Dillon break; 1165130d0157SRobert Watson } 1166835a82eeSMatthew Dillon mtx_unlock(&Giant); 1167835a82eeSMatthew Dillon return (error); 1168130d0157SRobert Watson #else /* !REGRESSION */ 1169eb725b4eSRobert Watson 1170130d0157SRobert Watson return (ENOSYS); 1171eb725b4eSRobert Watson #endif /* REGRESSION */ 1172130d0157SRobert Watson } 1173130d0157SRobert Watson 1174df8bae1dSRodney W. Grimes /* 1175df8bae1dSRodney W. Grimes * Check if gid is a member of the group set. 1176df8bae1dSRodney W. Grimes */ 117726f9a767SRodney W. Grimes int 1178df8bae1dSRodney W. Grimes groupmember(gid, cred) 1179df8bae1dSRodney W. Grimes gid_t gid; 1180b1fc0ec1SRobert Watson struct ucred *cred; 1181df8bae1dSRodney W. Grimes { 1182df8bae1dSRodney W. Grimes register gid_t *gp; 1183df8bae1dSRodney W. Grimes gid_t *egp; 1184df8bae1dSRodney W. Grimes 1185df8bae1dSRodney W. Grimes egp = &(cred->cr_groups[cred->cr_ngroups]); 1186df8bae1dSRodney W. Grimes for (gp = cred->cr_groups; gp < egp; gp++) 1187df8bae1dSRodney W. Grimes if (*gp == gid) 1188df8bae1dSRodney W. Grimes return (1); 1189df8bae1dSRodney W. Grimes return (0); 1190df8bae1dSRodney W. Grimes } 1191df8bae1dSRodney W. Grimes 11923b243b72SRobert Watson /* 119393f4fd1cSRobert Watson * `suser_enabled' (which can be set by the kern.security.suser_enabled 11947fd6a959SRobert Watson * sysctl) determines whether the system 'super-user' policy is in effect. 11957fd6a959SRobert Watson * If it is nonzero, an effective uid of 0 connotes special privilege, 11967fd6a959SRobert Watson * overriding many mandatory and discretionary protections. If it is zero, 11977fd6a959SRobert Watson * uid 0 is offered no special privilege in the kernel security policy. 11987fd6a959SRobert Watson * Setting it to zero may seriously impact the functionality of many 11997fd6a959SRobert Watson * existing userland programs, and should not be done without careful 12007fd6a959SRobert Watson * consideration of the consequences. 12013b243b72SRobert Watson */ 120293f4fd1cSRobert Watson int suser_enabled = 1; 120348713bdcSRobert Watson SYSCTL_INT(_kern_security_bsd, OID_AUTO, suser_enabled, CTLFLAG_RW, 120493f4fd1cSRobert Watson &suser_enabled, 0, "processes with uid 0 have privilege"); 1205579f4eb4SRobert Watson 1206df8bae1dSRodney W. Grimes /* 12077fd6a959SRobert Watson * Test whether the specified credentials imply "super-user" privilege. 12087fd6a959SRobert Watson * Return 0 or EPERM. 1209df8bae1dSRodney W. Grimes */ 121026f9a767SRodney W. Grimes int 1211f711d546SPoul-Henning Kamp suser(p) 121291421ba2SRobert Watson struct proc *p; 1213f711d546SPoul-Henning Kamp { 1214eb725b4eSRobert Watson 1215eb725b4eSRobert Watson return (suser_xxx(0, p, 0)); 1216f711d546SPoul-Henning Kamp } 1217f711d546SPoul-Henning Kamp 1218b40ce416SJulian Elischer /* 1219b40ce416SJulian Elischer * version for when the thread pointer is available and not the proc. 1220b40ce416SJulian Elischer * (saves having to include proc.h into every file that needs to do the change.) 1221b40ce416SJulian Elischer */ 1222b40ce416SJulian Elischer int 1223b40ce416SJulian Elischer suser_td(td) 1224b40ce416SJulian Elischer struct thread *td; 1225b40ce416SJulian Elischer { 1226b40ce416SJulian Elischer return suser_xxx(0, td->td_proc, 0); 1227b40ce416SJulian Elischer } 1228b40ce416SJulian Elischer 1229b40ce416SJulian Elischer /* 1230b40ce416SJulian Elischer * wrapper to use if you have the thread on hand but not the proc. 1231b40ce416SJulian Elischer */ 1232b40ce416SJulian Elischer int 1233b40ce416SJulian Elischer suser_xxx_td(cred, td, flag) 1234b40ce416SJulian Elischer struct ucred *cred; 1235b40ce416SJulian Elischer struct thread *td; 1236b40ce416SJulian Elischer int flag; 1237b40ce416SJulian Elischer { 1238b40ce416SJulian Elischer return(suser_xxx(cred, td->td_proc, flag)); 1239b40ce416SJulian Elischer } 1240b40ce416SJulian Elischer 1241f711d546SPoul-Henning Kamp int 124275c13541SPoul-Henning Kamp suser_xxx(cred, proc, flag) 124391421ba2SRobert Watson struct ucred *cred; 124491421ba2SRobert Watson struct proc *proc; 124575c13541SPoul-Henning Kamp int flag; 1246df8bae1dSRodney W. Grimes { 124793f4fd1cSRobert Watson if (!suser_enabled) 124803095547SRobert Watson return (EPERM); 124975c13541SPoul-Henning Kamp if (!cred && !proc) { 125075c13541SPoul-Henning Kamp printf("suser_xxx(): THINK!\n"); 1251df8bae1dSRodney W. Grimes return (EPERM); 1252df8bae1dSRodney W. Grimes } 1253eb725b4eSRobert Watson if (cred == NULL) 125475c13541SPoul-Henning Kamp cred = proc->p_ucred; 125575c13541SPoul-Henning Kamp if (cred->cr_uid != 0) 125675c13541SPoul-Henning Kamp return (EPERM); 125791421ba2SRobert Watson if (jailed(cred) && !(flag & PRISON_ROOT)) 125875c13541SPoul-Henning Kamp return (EPERM); 125975c13541SPoul-Henning Kamp return (0); 126075c13541SPoul-Henning Kamp } 1261df8bae1dSRodney W. Grimes 12623ca719f1SRobert Watson /* 1263eb725b4eSRobert Watson * Test the active securelevel against a given level. securelevel_gt() 1264eb725b4eSRobert Watson * implements (securelevel > level). securelevel_ge() implements 1265eb725b4eSRobert Watson * (securelevel >= level). Note that the logic is inverted -- these 1266eb725b4eSRobert Watson * functions return EPERM on "success" and 0 on "failure". 12673ca719f1SRobert Watson * 12683ca719f1SRobert Watson * cr is permitted to be NULL for the time being, as there were some 12693ca719f1SRobert Watson * existing securelevel checks that occurred without a process/credential 1270eb725b4eSRobert Watson * context. In the future this will be disallowed, so a kernel message 1271eb725b4eSRobert Watson * is displayed. 12723ca719f1SRobert Watson */ 12733ca719f1SRobert Watson int 12743ca719f1SRobert Watson securelevel_gt(struct ucred *cr, int level) 12753ca719f1SRobert Watson { 1276eb725b4eSRobert Watson int active_securelevel; 12773ca719f1SRobert Watson 1278eb725b4eSRobert Watson active_securelevel = securelevel; 1279eb725b4eSRobert Watson if (cr == NULL) 12803ca719f1SRobert Watson printf("securelevel_gt: cr is NULL\n"); 128101137630SRobert Watson if (cr->cr_prison != NULL) { 128201137630SRobert Watson mtx_lock(&cr->cr_prison->pr_mtx); 1283eb725b4eSRobert Watson active_securelevel = imax(cr->cr_prison->pr_securelevel, 1284eb725b4eSRobert Watson active_securelevel); 128501137630SRobert Watson mtx_unlock(&cr->cr_prison->pr_mtx); 128601137630SRobert Watson } 1287eb725b4eSRobert Watson return (active_securelevel > level ? EPERM : 0); 12883ca719f1SRobert Watson } 12893ca719f1SRobert Watson 12903ca719f1SRobert Watson int 12913ca719f1SRobert Watson securelevel_ge(struct ucred *cr, int level) 12923ca719f1SRobert Watson { 1293eb725b4eSRobert Watson int active_securelevel; 12943ca719f1SRobert Watson 1295eb725b4eSRobert Watson active_securelevel = securelevel; 1296eb725b4eSRobert Watson if (cr == NULL) 1297eb725b4eSRobert Watson printf("securelevel_gt: cr is NULL\n"); 129801137630SRobert Watson if (cr->cr_prison != NULL) { 129901137630SRobert Watson mtx_lock(&cr->cr_prison->pr_mtx); 1300eb725b4eSRobert Watson active_securelevel = imax(cr->cr_prison->pr_securelevel, 1301eb725b4eSRobert Watson active_securelevel); 130201137630SRobert Watson mtx_unlock(&cr->cr_prison->pr_mtx); 130301137630SRobert Watson } 1304eb725b4eSRobert Watson return (active_securelevel >= level ? EPERM : 0); 13053ca719f1SRobert Watson } 13063ca719f1SRobert Watson 13078a7d8cc6SRobert Watson /* 1308e409590dSRobert Watson * 'see_other_uids' determines whether or not visibility of processes 1309eb725b4eSRobert Watson * and sockets with credentials holding different real uids is possible 131048713bdcSRobert Watson * using a variety of system MIBs. 1311eb725b4eSRobert Watson * XXX: data declarations should be together near the beginning of the file. 13128a7d8cc6SRobert Watson */ 1313e409590dSRobert Watson static int see_other_uids = 1; 1314eb725b4eSRobert Watson SYSCTL_INT(_kern_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW, 1315eb725b4eSRobert Watson &see_other_uids, 0, 13168a7d8cc6SRobert Watson "Unprivileged processes may see subjects/objects with different real uid"); 13178a7d8cc6SRobert Watson 13187fd6a959SRobert Watson /*- 13197fd6a959SRobert Watson * Determine if u1 "can see" the subject specified by u2. 1320ed639720SRobert Watson * Returns: 0 for permitted, an errno value otherwise 1321ed639720SRobert Watson * Locks: none 1322eb725b4eSRobert Watson * References: *u1 and *u2 must not change during the call 1323ed639720SRobert Watson * u1 may equal u2, in which case only one reference is required 1324ed639720SRobert Watson */ 1325ed639720SRobert Watson int 132694088977SRobert Watson cr_cansee(struct ucred *u1, struct ucred *u2) 1327a9e0361bSPoul-Henning Kamp { 132891421ba2SRobert Watson int error; 1329a9e0361bSPoul-Henning Kamp 1330ed639720SRobert Watson if ((error = prison_check(u1, u2))) 133191421ba2SRobert Watson return (error); 1332e409590dSRobert Watson if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) { 1333f8e6ab29SRobert Watson if (suser_xxx(u1, NULL, PRISON_ROOT) != 0) 1334387d2c03SRobert Watson return (ESRCH); 1335c52396e3SRobert Watson } 1336387d2c03SRobert Watson return (0); 1337387d2c03SRobert Watson } 1338387d2c03SRobert Watson 13397fd6a959SRobert Watson /*- 13407fd6a959SRobert Watson * Determine if p1 "can see" the subject specified by p2. 13413b243b72SRobert Watson * Returns: 0 for permitted, an errno value otherwise 13427fd6a959SRobert Watson * Locks: Sufficient locks to protect p1->p_ucred and p2->p_ucred must 13433b243b72SRobert Watson * be held. Normally, p1 will be curproc, and a lock must be held 13443b243b72SRobert Watson * for p2. 13453b243b72SRobert Watson * References: p1 and p2 must be valid for the lifetime of the call 13463b243b72SRobert Watson */ 1347a0f75161SRobert Watson int 1348a0f75161SRobert Watson p_cansee(struct proc *p1, struct proc *p2) 1349ed639720SRobert Watson { 1350ed639720SRobert Watson 135194088977SRobert Watson /* Wrap cr_cansee() for all functionality. */ 135294088977SRobert Watson return (cr_cansee(p1->p_ucred, p2->p_ucred)); 1353ed639720SRobert Watson } 1354ed639720SRobert Watson 13557fd6a959SRobert Watson /*- 13567fd6a959SRobert Watson * Determine whether p1 may deliver the specified signal to p2. 13577fd6a959SRobert Watson * Returns: 0 for permitted, an errno value otherwise 13587fd6a959SRobert Watson * Locks: Sufficient locks to protect various components of p1 and p2 13597fd6a959SRobert Watson * must be held. Normally, p1 will be curproc, and a lock must 13607fd6a959SRobert Watson * be held for p2. 13613b243b72SRobert Watson * References: p1 and p2 must be valid for the lifetime of the call 13624c5eb9c3SRobert Watson */ 13634c5eb9c3SRobert Watson int 13644c5eb9c3SRobert Watson p_cansignal(struct proc *p1, struct proc *p2, int signum) 1365387d2c03SRobert Watson { 136691421ba2SRobert Watson int error; 1367387d2c03SRobert Watson 1368a9e0361bSPoul-Henning Kamp if (p1 == p2) 1369a9e0361bSPoul-Henning Kamp return (0); 1370387d2c03SRobert Watson 13714c5eb9c3SRobert Watson /* 13724c5eb9c3SRobert Watson * Jail semantics limit the scope of signalling to p2 in the same 13734c5eb9c3SRobert Watson * jail as p1, if p1 is in jail. 13744c5eb9c3SRobert Watson */ 137591421ba2SRobert Watson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 137691421ba2SRobert Watson return (error); 1377387d2c03SRobert Watson 1378387d2c03SRobert Watson /* 13794c5eb9c3SRobert Watson * UNIX signalling semantics require that processes in the same 13804c5eb9c3SRobert Watson * session always be able to deliver SIGCONT to one another, 13814c5eb9c3SRobert Watson * overriding the remaining protections. 1382387d2c03SRobert Watson */ 13834c5eb9c3SRobert Watson if (signum == SIGCONT && p1->p_session == p2->p_session) 1384a9e0361bSPoul-Henning Kamp return (0); 1385387d2c03SRobert Watson 13864c5eb9c3SRobert Watson /* 13873b243b72SRobert Watson * UNIX signal semantics depend on the status of the P_SUGID 13883b243b72SRobert Watson * bit on the target process. If the bit is set, then additional 13893b243b72SRobert Watson * restrictions are placed on the set of available signals. 13904c5eb9c3SRobert Watson */ 13914c5eb9c3SRobert Watson if (p2->p_flag & P_SUGID) { 13924c5eb9c3SRobert Watson switch (signum) { 13934c5eb9c3SRobert Watson case 0: 13944c5eb9c3SRobert Watson case SIGKILL: 13954c5eb9c3SRobert Watson case SIGINT: 13964c5eb9c3SRobert Watson case SIGTERM: 13974c5eb9c3SRobert Watson case SIGSTOP: 13984c5eb9c3SRobert Watson case SIGTTIN: 13994c5eb9c3SRobert Watson case SIGTTOU: 14004c5eb9c3SRobert Watson case SIGTSTP: 14014c5eb9c3SRobert Watson case SIGHUP: 14024c5eb9c3SRobert Watson case SIGUSR1: 14034c5eb9c3SRobert Watson case SIGUSR2: 14047fd6a959SRobert Watson /* 14057fd6a959SRobert Watson * Generally, permit job and terminal control 14067fd6a959SRobert Watson * signals. 14077fd6a959SRobert Watson */ 14084c5eb9c3SRobert Watson break; 14094c5eb9c3SRobert Watson default: 14103b243b72SRobert Watson /* Not permitted, privilege is required. */ 14114c5eb9c3SRobert Watson error = suser_xxx(NULL, p1, PRISON_ROOT); 14124c5eb9c3SRobert Watson if (error) 14134c5eb9c3SRobert Watson return (error); 14144c5eb9c3SRobert Watson } 1415e9e7ff5bSRobert Watson } 1416e9e7ff5bSRobert Watson 14174c5eb9c3SRobert Watson /* 14183b243b72SRobert Watson * Generally, the target credential's ruid or svuid must match the 1419e9e7ff5bSRobert Watson * subject credential's ruid or euid. 14204c5eb9c3SRobert Watson */ 1421b1fc0ec1SRobert Watson if (p1->p_ucred->cr_ruid != p2->p_ucred->cr_ruid && 1422b1fc0ec1SRobert Watson p1->p_ucred->cr_ruid != p2->p_ucred->cr_svuid && 1423b1fc0ec1SRobert Watson p1->p_ucred->cr_uid != p2->p_ucred->cr_ruid && 1424b1fc0ec1SRobert Watson p1->p_ucred->cr_uid != p2->p_ucred->cr_svuid) { 14254c5eb9c3SRobert Watson /* Not permitted, try privilege. */ 14264c5eb9c3SRobert Watson error = suser_xxx(NULL, p1, PRISON_ROOT); 14274c5eb9c3SRobert Watson if (error) 14284c5eb9c3SRobert Watson return (error); 14294c5eb9c3SRobert Watson } 1430387d2c03SRobert Watson 1431387d2c03SRobert Watson return (0); 1432387d2c03SRobert Watson } 1433a9e0361bSPoul-Henning Kamp 14347fd6a959SRobert Watson /*- 1435eb725b4eSRobert Watson * Determine whether p1 may reschedule p2. 14367fd6a959SRobert Watson * Returns: 0 for permitted, an errno value otherwise 14373b243b72SRobert Watson * Locks: Sufficient locks to protect various components of p1 and p2 14383b243b72SRobert Watson * must be held. Normally, p1 will be curproc, and a lock must 14397fd6a959SRobert Watson * be held for p2. 14403b243b72SRobert Watson * References: p1 and p2 must be valid for the lifetime of the call 14413b243b72SRobert Watson */ 1442a0f75161SRobert Watson int 1443a0f75161SRobert Watson p_cansched(struct proc *p1, struct proc *p2) 1444387d2c03SRobert Watson { 144591421ba2SRobert Watson int error; 1446387d2c03SRobert Watson 1447387d2c03SRobert Watson if (p1 == p2) 1448387d2c03SRobert Watson return (0); 144991421ba2SRobert Watson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 145091421ba2SRobert Watson return (error); 1451b1fc0ec1SRobert Watson if (p1->p_ucred->cr_ruid == p2->p_ucred->cr_ruid) 1452387d2c03SRobert Watson return (0); 1453b1fc0ec1SRobert Watson if (p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid) 1454387d2c03SRobert Watson return (0); 14557fd6a959SRobert Watson if (suser_xxx(0, p1, PRISON_ROOT) == 0) 1456387d2c03SRobert Watson return (0); 1457387d2c03SRobert Watson 1458387d2c03SRobert Watson #ifdef CAPABILITIES 14594df571b1SRobert Watson if (!cap_check(NULL, p1, CAP_SYS_NICE, PRISON_ROOT)) 1460387d2c03SRobert Watson return (0); 1461387d2c03SRobert Watson #endif 1462387d2c03SRobert Watson 1463387d2c03SRobert Watson return (EPERM); 1464387d2c03SRobert Watson } 1465387d2c03SRobert Watson 14663b243b72SRobert Watson /* 14675d476e73SRobert Watson * The 'unprivileged_proc_debug' flag may be used to disable a variety of 14685d476e73SRobert Watson * unprivileged inter-process debugging services, including some procfs 14695d476e73SRobert Watson * functionality, ptrace(), and ktrace(). In the past, inter-process 14705d476e73SRobert Watson * debugging has been involved in a variety of security problems, and sites 14715d476e73SRobert Watson * not requiring the service might choose to disable it when hardening 14725d476e73SRobert Watson * systems. 14733b243b72SRobert Watson * 14743b243b72SRobert Watson * XXX: Should modifying and reading this variable require locking? 1475eb725b4eSRobert Watson * XXX: data declarations should be together near the beginning of the file. 14763b243b72SRobert Watson */ 1477e409590dSRobert Watson static int unprivileged_proc_debug = 1; 1478eb725b4eSRobert Watson SYSCTL_INT(_kern_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW, 1479eb725b4eSRobert Watson &unprivileged_proc_debug, 0, 14800ef5652eSRobert Watson "Unprivileged processes may use process debugging facilities"); 14810ef5652eSRobert Watson 14827fd6a959SRobert Watson /*- 14837fd6a959SRobert Watson * Determine whether p1 may debug p2. 14847fd6a959SRobert Watson * Returns: 0 for permitted, an errno value otherwise 14857fd6a959SRobert Watson * Locks: Sufficient locks to protect various components of p1 and p2 14867fd6a959SRobert Watson * must be held. Normally, p1 will be curproc, and a lock must 14877fd6a959SRobert Watson * be held for p2. 14883b243b72SRobert Watson * References: p1 and p2 must be valid for the lifetime of the call 14893b243b72SRobert Watson */ 1490a0f75161SRobert Watson int 1491a0f75161SRobert Watson p_candebug(struct proc *p1, struct proc *p2) 1492387d2c03SRobert Watson { 1493eb725b4eSRobert Watson int credentialchanged, error, grpsubset, i, uidsubset; 1494387d2c03SRobert Watson 1495e409590dSRobert Watson if (!unprivileged_proc_debug) { 149632d18604SRobert Watson error = suser_xxx(NULL, p1, PRISON_ROOT); 149732d18604SRobert Watson if (error) 149832d18604SRobert Watson return (error); 149932d18604SRobert Watson } 150023fad5b6SDag-Erling Smørgrav if (p1 == p2) 150123fad5b6SDag-Erling Smørgrav return (0); 150291421ba2SRobert Watson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 150391421ba2SRobert Watson return (error); 1504387d2c03SRobert Watson 15057fd6a959SRobert Watson /* 1506db42a33dSRobert Watson * Is p2's group set a subset of p1's effective group set? This 1507db42a33dSRobert Watson * includes p2's egid, group access list, rgid, and svgid. 15087fd6a959SRobert Watson */ 1509db42a33dSRobert Watson grpsubset = 1; 1510db42a33dSRobert Watson for (i = 0; i < p2->p_ucred->cr_ngroups; i++) { 1511db42a33dSRobert Watson if (!groupmember(p2->p_ucred->cr_groups[i], p1->p_ucred)) { 1512db42a33dSRobert Watson grpsubset = 0; 1513db42a33dSRobert Watson break; 1514db42a33dSRobert Watson } 1515db42a33dSRobert Watson } 1516db42a33dSRobert Watson grpsubset = grpsubset && 1517db42a33dSRobert Watson groupmember(p2->p_ucred->cr_rgid, p1->p_ucred) && 1518db42a33dSRobert Watson groupmember(p2->p_ucred->cr_svgid, p1->p_ucred); 1519db42a33dSRobert Watson 1520db42a33dSRobert Watson /* 1521db42a33dSRobert Watson * Are the uids present in p2's credential equal to p1's 1522db42a33dSRobert Watson * effective uid? This includes p2's euid, svuid, and ruid. 1523db42a33dSRobert Watson */ 1524db42a33dSRobert Watson uidsubset = (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid && 1525db42a33dSRobert Watson p1->p_ucred->cr_uid == p2->p_ucred->cr_svuid && 1526db42a33dSRobert Watson p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid); 1527db42a33dSRobert Watson 1528db42a33dSRobert Watson /* 1529db42a33dSRobert Watson * Has the credential of the process changed since the last exec()? 1530db42a33dSRobert Watson */ 1531db42a33dSRobert Watson credentialchanged = (p2->p_flag & P_SUGID); 1532db42a33dSRobert Watson 1533db42a33dSRobert Watson /* 1534db42a33dSRobert Watson * If p2's gids aren't a subset, or the uids aren't a subset, 1535db42a33dSRobert Watson * or the credential has changed, require appropriate privilege 1536db42a33dSRobert Watson * for p1 to debug p2. For POSIX.1e capabilities, this will 1537db42a33dSRobert Watson * require CAP_SYS_PTRACE. 1538db42a33dSRobert Watson */ 1539db42a33dSRobert Watson if (!grpsubset || !uidsubset || credentialchanged) { 154032d18604SRobert Watson error = suser_xxx(NULL, p1, PRISON_ROOT); 154132d18604SRobert Watson if (error) 1542387d2c03SRobert Watson return (error); 15437fd6a959SRobert Watson } 1544387d2c03SRobert Watson 1545eb725b4eSRobert Watson /* Can't trace init when securelevel > 0. */ 1546eb725b4eSRobert Watson if (p2 == initproc) { 15473ca719f1SRobert Watson error = securelevel_gt(p1->p_ucred, 0); 15483ca719f1SRobert Watson if (error) 15493ca719f1SRobert Watson return (error); 15503ca719f1SRobert Watson } 1551387d2c03SRobert Watson 15525fab7614SRobert Watson /* 15535fab7614SRobert Watson * Can't trace a process that's currently exec'ing. 15545fab7614SRobert Watson * XXX: Note, this is not a security policy decision, it's a 15555fab7614SRobert Watson * basic correctness/functionality decision. Therefore, this check 15565fab7614SRobert Watson * should be moved to the caller's of p_candebug(). 15575fab7614SRobert Watson */ 15589ca45e81SDag-Erling Smørgrav if ((p2->p_flag & P_INEXEC) != 0) 15599ca45e81SDag-Erling Smørgrav return (EAGAIN); 15609ca45e81SDag-Erling Smørgrav 1561387d2c03SRobert Watson return (0); 1562387d2c03SRobert Watson } 1563387d2c03SRobert Watson 1564a9e0361bSPoul-Henning Kamp /* 1565df8bae1dSRodney W. Grimes * Allocate a zeroed cred structure. 1566df8bae1dSRodney W. Grimes */ 1567df8bae1dSRodney W. Grimes struct ucred * 1568df8bae1dSRodney W. Grimes crget() 1569df8bae1dSRodney W. Grimes { 1570df8bae1dSRodney W. Grimes register struct ucred *cr; 1571df8bae1dSRodney W. Grimes 15721e5d626aSAlfred Perlstein MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK | M_ZERO); 1573df8bae1dSRodney W. Grimes cr->cr_ref = 1; 15741e5d626aSAlfred Perlstein mtx_init(&cr->cr_mtx, "ucred", MTX_DEF); 1575df8bae1dSRodney W. Grimes return (cr); 1576df8bae1dSRodney W. Grimes } 1577df8bae1dSRodney W. Grimes 1578df8bae1dSRodney W. Grimes /* 15797fd6a959SRobert Watson * Claim another reference to a ucred structure. 15805c3f70d7SAlfred Perlstein */ 1581bd78ceceSJohn Baldwin struct ucred * 15825c3f70d7SAlfred Perlstein crhold(cr) 15835c3f70d7SAlfred Perlstein struct ucred *cr; 15845c3f70d7SAlfred Perlstein { 15855c3f70d7SAlfred Perlstein 15869ed346baSBosko Milekic mtx_lock(&cr->cr_mtx); 15875c3f70d7SAlfred Perlstein cr->cr_ref++; 1588bd78ceceSJohn Baldwin mtx_unlock(&cr->cr_mtx); 1589bd78ceceSJohn Baldwin return (cr); 15905c3f70d7SAlfred Perlstein } 15915c3f70d7SAlfred Perlstein 15925c3f70d7SAlfred Perlstein /* 1593df8bae1dSRodney W. Grimes * Free a cred structure. 1594df8bae1dSRodney W. Grimes * Throws away space when ref count gets to 0. 1595df8bae1dSRodney W. Grimes */ 159626f9a767SRodney W. Grimes void 1597df8bae1dSRodney W. Grimes crfree(cr) 1598df8bae1dSRodney W. Grimes struct ucred *cr; 1599df8bae1dSRodney W. Grimes { 16001e5d626aSAlfred Perlstein 16019ed346baSBosko Milekic mtx_lock(&cr->cr_mtx); 1602e04670b7SAlfred Perlstein KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref)); 1603f535380cSDon Lewis if (--cr->cr_ref == 0) { 16041e5d626aSAlfred Perlstein mtx_destroy(&cr->cr_mtx); 1605f535380cSDon Lewis /* 1606f535380cSDon Lewis * Some callers of crget(), such as nfs_statfs(), 1607f535380cSDon Lewis * allocate a temporary credential, but don't 1608f535380cSDon Lewis * allocate a uidinfo structure. 1609f535380cSDon Lewis */ 1610f535380cSDon Lewis if (cr->cr_uidinfo != NULL) 1611f535380cSDon Lewis uifree(cr->cr_uidinfo); 1612823c224eSRobert Watson if (cr->cr_ruidinfo != NULL) 1613823c224eSRobert Watson uifree(cr->cr_ruidinfo); 161491421ba2SRobert Watson /* 161591421ba2SRobert Watson * Free a prison, if any. 161691421ba2SRobert Watson */ 161791421ba2SRobert Watson if (jailed(cr)) 161891421ba2SRobert Watson prison_free(cr->cr_prison); 1619df8bae1dSRodney W. Grimes FREE((caddr_t)cr, M_CRED); 1620eb725b4eSRobert Watson } else 16219ed346baSBosko Milekic mtx_unlock(&cr->cr_mtx); 1622df8bae1dSRodney W. Grimes } 1623df8bae1dSRodney W. Grimes 1624df8bae1dSRodney W. Grimes /* 1625bd78ceceSJohn Baldwin * Check to see if this ucred is shared. 1626df8bae1dSRodney W. Grimes */ 1627bd78ceceSJohn Baldwin int 1628bd78ceceSJohn Baldwin crshared(cr) 1629df8bae1dSRodney W. Grimes struct ucred *cr; 1630df8bae1dSRodney W. Grimes { 1631bd78ceceSJohn Baldwin int shared; 1632df8bae1dSRodney W. Grimes 16339ed346baSBosko Milekic mtx_lock(&cr->cr_mtx); 1634bd78ceceSJohn Baldwin shared = (cr->cr_ref > 1); 16359ed346baSBosko Milekic mtx_unlock(&cr->cr_mtx); 1636bd78ceceSJohn Baldwin return (shared); 16371e5d626aSAlfred Perlstein } 1638bd78ceceSJohn Baldwin 1639bd78ceceSJohn Baldwin /* 1640bd78ceceSJohn Baldwin * Copy a ucred's contents from a template. Does not block. 1641bd78ceceSJohn Baldwin */ 1642bd78ceceSJohn Baldwin void 1643bd78ceceSJohn Baldwin crcopy(dest, src) 1644bd78ceceSJohn Baldwin struct ucred *dest, *src; 1645bd78ceceSJohn Baldwin { 1646bd78ceceSJohn Baldwin 1647bd78ceceSJohn Baldwin KASSERT(crshared(dest) == 0, ("crcopy of shared ucred")); 1648bd78ceceSJohn Baldwin bcopy(&src->cr_startcopy, &dest->cr_startcopy, 1649bd78ceceSJohn Baldwin (unsigned)((caddr_t)&src->cr_endcopy - 1650bd78ceceSJohn Baldwin (caddr_t)&src->cr_startcopy)); 1651bd78ceceSJohn Baldwin uihold(dest->cr_uidinfo); 1652bd78ceceSJohn Baldwin uihold(dest->cr_ruidinfo); 1653bd78ceceSJohn Baldwin if (jailed(dest)) 1654bd78ceceSJohn Baldwin prison_hold(dest->cr_prison); 1655df8bae1dSRodney W. Grimes } 1656df8bae1dSRodney W. Grimes 1657df8bae1dSRodney W. Grimes /* 1658df8bae1dSRodney W. Grimes * Dup cred struct to a new held one. 1659df8bae1dSRodney W. Grimes */ 1660df8bae1dSRodney W. Grimes struct ucred * 1661df8bae1dSRodney W. Grimes crdup(cr) 1662df8bae1dSRodney W. Grimes struct ucred *cr; 1663df8bae1dSRodney W. Grimes { 1664df8bae1dSRodney W. Grimes struct ucred *newcr; 1665df8bae1dSRodney W. Grimes 1666bd78ceceSJohn Baldwin newcr = crget(); 1667bd78ceceSJohn Baldwin crcopy(newcr, cr); 1668df8bae1dSRodney W. Grimes return (newcr); 1669df8bae1dSRodney W. Grimes } 1670df8bae1dSRodney W. Grimes 1671df8bae1dSRodney W. Grimes /* 1672df8bae1dSRodney W. Grimes * Get login name, if available. 1673df8bae1dSRodney W. Grimes */ 1674d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1675df8bae1dSRodney W. Grimes struct getlogin_args { 1676df8bae1dSRodney W. Grimes char *namebuf; 1677df8bae1dSRodney W. Grimes u_int namelen; 1678df8bae1dSRodney W. Grimes }; 1679d2d3e875SBruce Evans #endif 1680835a82eeSMatthew Dillon /* 1681835a82eeSMatthew Dillon * MPSAFE 1682835a82eeSMatthew Dillon */ 1683df8bae1dSRodney W. Grimes /* ARGSUSED */ 168426f9a767SRodney W. Grimes int 1685b40ce416SJulian Elischer getlogin(td, uap) 1686b40ce416SJulian Elischer struct thread *td; 1687df8bae1dSRodney W. Grimes struct getlogin_args *uap; 1688df8bae1dSRodney W. Grimes { 1689835a82eeSMatthew Dillon int error; 1690b40ce416SJulian Elischer struct proc *p = td->td_proc; 1691df8bae1dSRodney W. Grimes 1692835a82eeSMatthew Dillon mtx_lock(&Giant); 169330cf3ac4SAndrey A. Chernov if (uap->namelen > MAXLOGNAME) 169453490b76SAndrey A. Chernov uap->namelen = MAXLOGNAME; 1695835a82eeSMatthew Dillon error = copyout((caddr_t) p->p_pgrp->pg_session->s_login, 1696835a82eeSMatthew Dillon (caddr_t) uap->namebuf, uap->namelen); 1697835a82eeSMatthew Dillon mtx_unlock(&Giant); 1698835a82eeSMatthew Dillon return(error); 1699df8bae1dSRodney W. Grimes } 1700df8bae1dSRodney W. Grimes 1701df8bae1dSRodney W. Grimes /* 1702df8bae1dSRodney W. Grimes * Set login name. 1703df8bae1dSRodney W. Grimes */ 1704d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1705df8bae1dSRodney W. Grimes struct setlogin_args { 1706df8bae1dSRodney W. Grimes char *namebuf; 1707df8bae1dSRodney W. Grimes }; 1708d2d3e875SBruce Evans #endif 1709835a82eeSMatthew Dillon /* 1710835a82eeSMatthew Dillon * MPSAFE 1711835a82eeSMatthew Dillon */ 1712df8bae1dSRodney W. Grimes /* ARGSUSED */ 171326f9a767SRodney W. Grimes int 1714b40ce416SJulian Elischer setlogin(td, uap) 1715b40ce416SJulian Elischer struct thread *td; 1716df8bae1dSRodney W. Grimes struct setlogin_args *uap; 1717df8bae1dSRodney W. Grimes { 1718b40ce416SJulian Elischer struct proc *p = td->td_proc; 1719df8bae1dSRodney W. Grimes int error; 1720964ca0caSAndrey A. Chernov char logintmp[MAXLOGNAME]; 1721df8bae1dSRodney W. Grimes 1722835a82eeSMatthew Dillon mtx_lock(&Giant); 1723eb725b4eSRobert Watson if ((error = suser_xxx(0, p, PRISON_ROOT)) != 0) 1724835a82eeSMatthew Dillon goto done2; 1725184989c2SDavid Nugent error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 172610d4743fSDoug Rabson sizeof(logintmp), (size_t *)0); 1727eb725b4eSRobert Watson if (error == ENAMETOOLONG) 1728df8bae1dSRodney W. Grimes error = EINVAL; 1729eb725b4eSRobert Watson else if (!error) 1730184989c2SDavid Nugent (void)memcpy(p->p_pgrp->pg_session->s_login, logintmp, 1731964ca0caSAndrey A. Chernov sizeof(logintmp)); 1732835a82eeSMatthew Dillon done2: 1733835a82eeSMatthew Dillon mtx_unlock(&Giant); 1734df8bae1dSRodney W. Grimes return (error); 1735df8bae1dSRodney W. Grimes } 1736d5f81602SSean Eric Fagan 1737d5f81602SSean Eric Fagan void 1738d5f81602SSean Eric Fagan setsugid(p) 1739d5f81602SSean Eric Fagan struct proc *p; 1740d5f81602SSean Eric Fagan { 1741d5f81602SSean Eric Fagan p->p_flag |= P_SUGID; 174289361835SSean Eric Fagan if (!(p->p_pfsflags & PF_ISUGID)) 1743d5f81602SSean Eric Fagan p->p_stops = 0; 1744d5f81602SSean Eric Fagan } 1745f535380cSDon Lewis 17467fd6a959SRobert Watson /*- 17477fd6a959SRobert Watson * Change a process's effective uid. 1748b1fc0ec1SRobert Watson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified. 1749b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1750b1fc0ec1SRobert Watson * duration of the call. 1751f535380cSDon Lewis */ 1752f535380cSDon Lewis void 1753b1fc0ec1SRobert Watson change_euid(newcred, euid) 1754b1fc0ec1SRobert Watson struct ucred *newcred; 1755f535380cSDon Lewis uid_t euid; 1756f535380cSDon Lewis { 1757f535380cSDon Lewis 1758b1fc0ec1SRobert Watson newcred->cr_uid = euid; 1759b1fc0ec1SRobert Watson uifree(newcred->cr_uidinfo); 1760b1fc0ec1SRobert Watson newcred->cr_uidinfo = uifind(euid); 1761f535380cSDon Lewis } 1762f535380cSDon Lewis 17637fd6a959SRobert Watson /*- 17647fd6a959SRobert Watson * Change a process's effective gid. 1765b1fc0ec1SRobert Watson * Side effects: newcred->cr_gid will be modified. 1766b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1767b1fc0ec1SRobert Watson * duration of the call. 1768f535380cSDon Lewis */ 1769810bfc8eSAndrew Gallatin void 1770b1fc0ec1SRobert Watson change_egid(newcred, egid) 1771b1fc0ec1SRobert Watson struct ucred *newcred; 1772b1fc0ec1SRobert Watson gid_t egid; 1773b1fc0ec1SRobert Watson { 1774b1fc0ec1SRobert Watson 1775b1fc0ec1SRobert Watson newcred->cr_groups[0] = egid; 1776b1fc0ec1SRobert Watson } 1777b1fc0ec1SRobert Watson 17787fd6a959SRobert Watson /*- 17797fd6a959SRobert Watson * Change a process's real uid. 1780b1fc0ec1SRobert Watson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo 1781b1fc0ec1SRobert Watson * will be updated, and the old and new cr_ruidinfo proc 1782b1fc0ec1SRobert Watson * counts will be updated. 1783b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1784b1fc0ec1SRobert Watson * duration of the call. 1785b1fc0ec1SRobert Watson */ 1786b1fc0ec1SRobert Watson void 1787b1fc0ec1SRobert Watson change_ruid(newcred, ruid) 1788b1fc0ec1SRobert Watson struct ucred *newcred; 1789f535380cSDon Lewis uid_t ruid; 1790f535380cSDon Lewis { 1791f535380cSDon Lewis 1792b1fc0ec1SRobert Watson (void)chgproccnt(newcred->cr_ruidinfo, -1, 0); 1793b1fc0ec1SRobert Watson newcred->cr_ruid = ruid; 1794b1fc0ec1SRobert Watson uifree(newcred->cr_ruidinfo); 1795b1fc0ec1SRobert Watson newcred->cr_ruidinfo = uifind(ruid); 1796b1fc0ec1SRobert Watson (void)chgproccnt(newcred->cr_ruidinfo, 1, 0); 1797b1fc0ec1SRobert Watson } 1798b1fc0ec1SRobert Watson 17997fd6a959SRobert Watson /*- 18007fd6a959SRobert Watson * Change a process's real gid. 1801b1fc0ec1SRobert Watson * Side effects: newcred->cr_rgid will be updated. 1802b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1803b1fc0ec1SRobert Watson * duration of the call. 1804b1fc0ec1SRobert Watson */ 1805b1fc0ec1SRobert Watson void 1806b1fc0ec1SRobert Watson change_rgid(newcred, rgid) 1807b1fc0ec1SRobert Watson struct ucred *newcred; 1808b1fc0ec1SRobert Watson gid_t rgid; 1809b1fc0ec1SRobert Watson { 1810b1fc0ec1SRobert Watson 1811b1fc0ec1SRobert Watson newcred->cr_rgid = rgid; 1812b1fc0ec1SRobert Watson } 1813b1fc0ec1SRobert Watson 18147fd6a959SRobert Watson /*- 18157fd6a959SRobert Watson * Change a process's saved uid. 1816b1fc0ec1SRobert Watson * Side effects: newcred->cr_svuid will be updated. 1817b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1818b1fc0ec1SRobert Watson * duration of the call. 1819b1fc0ec1SRobert Watson */ 1820b1fc0ec1SRobert Watson void 1821b1fc0ec1SRobert Watson change_svuid(newcred, svuid) 1822b1fc0ec1SRobert Watson struct ucred *newcred; 1823b1fc0ec1SRobert Watson uid_t svuid; 1824b1fc0ec1SRobert Watson { 1825b1fc0ec1SRobert Watson 1826b1fc0ec1SRobert Watson newcred->cr_svuid = svuid; 1827b1fc0ec1SRobert Watson } 1828b1fc0ec1SRobert Watson 18297fd6a959SRobert Watson /*- 18307fd6a959SRobert Watson * Change a process's saved gid. 1831b1fc0ec1SRobert Watson * Side effects: newcred->cr_svgid will be updated. 1832b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1833b1fc0ec1SRobert Watson * duration of the call. 1834b1fc0ec1SRobert Watson */ 1835b1fc0ec1SRobert Watson void 1836b1fc0ec1SRobert Watson change_svgid(newcred, svgid) 1837b1fc0ec1SRobert Watson struct ucred *newcred; 1838b1fc0ec1SRobert Watson gid_t svgid; 1839b1fc0ec1SRobert Watson { 1840b1fc0ec1SRobert Watson 1841b1fc0ec1SRobert Watson newcred->cr_svgid = svgid; 1842f535380cSDon Lewis } 1843