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 503b1fc0ec1SRobert Watson oldcred = p->p_ucred; 504eb725b4eSRobert Watson uid = uap->uid; 505835a82eeSMatthew Dillon mtx_lock(&Giant); 506eb725b4eSRobert Watson error = 0; 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 646835a82eeSMatthew Dillon mtx_lock(&Giant); 647eb725b4eSRobert Watson error = 0; 648b1fc0ec1SRobert Watson oldcred = p->p_ucred; 649a08f4bf6SPeter Wemm /* 650a08f4bf6SPeter Wemm * See if we have "permission" by POSIX 1003.1 rules. 651a08f4bf6SPeter Wemm * 652a08f4bf6SPeter Wemm * Note that setgid(getegid()) is a special case of 653a08f4bf6SPeter Wemm * "appropriate privileges" in appendix B.4.2.2. We need 6542fa72ea7SJeroen Ruigrok van der Werven * to use this clause to be compatible with traditional BSD 655a08f4bf6SPeter Wemm * semantics. Basically, it means that "setgid(xx)" sets all 656a08f4bf6SPeter Wemm * three id's (assuming you have privs). 657a08f4bf6SPeter Wemm * 658a08f4bf6SPeter Wemm * For notes on the logic here, see setuid() above. 659a08f4bf6SPeter Wemm */ 660b1fc0ec1SRobert Watson if (gid != oldcred->cr_rgid && /* allow setgid(getgid()) */ 6613f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS 662b1fc0ec1SRobert Watson gid != oldcred->cr_svgid && /* allow setgid(saved gid) */ 663a08f4bf6SPeter Wemm #endif 664a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 665b1fc0ec1SRobert Watson gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */ 6663f246666SAndrey A. Chernov #endif 667eb725b4eSRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 668835a82eeSMatthew Dillon goto done2; 669a08f4bf6SPeter Wemm 670b1fc0ec1SRobert Watson newcred = crdup(oldcred); 671a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS 672a08f4bf6SPeter Wemm /* 673a08f4bf6SPeter Wemm * Do we have "appropriate privileges" (are we root or gid == egid) 674a08f4bf6SPeter Wemm * If so, we are changing the real uid and saved gid. 675a08f4bf6SPeter Wemm */ 676a08f4bf6SPeter Wemm if ( 677a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 678b1fc0ec1SRobert Watson gid == oldcred->cr_groups[0] || 679a08f4bf6SPeter Wemm #endif 680b1fc0ec1SRobert Watson suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */ 681a08f4bf6SPeter Wemm #endif 682a08f4bf6SPeter Wemm { 683a08f4bf6SPeter Wemm /* 684a08f4bf6SPeter Wemm * Set real gid 685a08f4bf6SPeter Wemm */ 686b1fc0ec1SRobert Watson if (oldcred->cr_rgid != gid) { 687b1fc0ec1SRobert Watson change_rgid(newcred, gid); 688d5f81602SSean Eric Fagan setsugid(p); 689a08f4bf6SPeter Wemm } 690a08f4bf6SPeter Wemm /* 691a08f4bf6SPeter Wemm * Set saved gid 692a08f4bf6SPeter Wemm * 693a08f4bf6SPeter Wemm * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 694a08f4bf6SPeter Wemm * the security of setegid() depends on it. B.4.2.2 says it 695a08f4bf6SPeter Wemm * is important that we should do this. 696a08f4bf6SPeter Wemm */ 697b1fc0ec1SRobert Watson if (oldcred->cr_svgid != gid) { 698b1fc0ec1SRobert Watson change_svgid(newcred, gid); 699d5f81602SSean Eric Fagan setsugid(p); 700a08f4bf6SPeter Wemm } 701a08f4bf6SPeter Wemm } 702a08f4bf6SPeter Wemm /* 703a08f4bf6SPeter Wemm * In all cases permitted cases, we are changing the egid. 704a08f4bf6SPeter Wemm * Copy credentials so other references do not see our changes. 705a08f4bf6SPeter Wemm */ 706b1fc0ec1SRobert Watson if (oldcred->cr_groups[0] != gid) { 707b1fc0ec1SRobert Watson change_egid(newcred, gid); 708d5f81602SSean Eric Fagan setsugid(p); 709a08f4bf6SPeter Wemm } 710b1fc0ec1SRobert Watson p->p_ucred = newcred; 711b1fc0ec1SRobert Watson crfree(oldcred); 712835a82eeSMatthew Dillon done2: 713835a82eeSMatthew Dillon mtx_unlock(&Giant); 714835a82eeSMatthew Dillon return (error); 715df8bae1dSRodney W. Grimes } 716df8bae1dSRodney W. Grimes 717d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 718df8bae1dSRodney W. Grimes struct setegid_args { 719df8bae1dSRodney W. Grimes gid_t egid; 720df8bae1dSRodney W. Grimes }; 721d2d3e875SBruce Evans #endif 722835a82eeSMatthew Dillon /* 723835a82eeSMatthew Dillon * MPSAFE 724835a82eeSMatthew Dillon */ 725df8bae1dSRodney W. Grimes /* ARGSUSED */ 72626f9a767SRodney W. Grimes int 727b40ce416SJulian Elischer setegid(td, uap) 728b40ce416SJulian Elischer struct thread *td; 729df8bae1dSRodney W. Grimes struct setegid_args *uap; 730df8bae1dSRodney W. Grimes { 731b40ce416SJulian Elischer struct proc *p = td->td_proc; 732b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 733b1fc0ec1SRobert Watson gid_t egid; 734eb725b4eSRobert Watson int error; 735df8bae1dSRodney W. Grimes 736df8bae1dSRodney W. Grimes egid = uap->egid; 737835a82eeSMatthew Dillon mtx_lock(&Giant); 738eb725b4eSRobert Watson error = 0; 739b1fc0ec1SRobert Watson oldcred = p->p_ucred; 740b1fc0ec1SRobert Watson if (egid != oldcred->cr_rgid && /* allow setegid(getgid()) */ 741b1fc0ec1SRobert Watson egid != oldcred->cr_svgid && /* allow setegid(saved gid) */ 742eb725b4eSRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 743835a82eeSMatthew Dillon goto done2; 744b1fc0ec1SRobert Watson newcred = crdup(oldcred); 745b1fc0ec1SRobert Watson if (oldcred->cr_groups[0] != egid) { 746b1fc0ec1SRobert Watson change_egid(newcred, egid); 747d5f81602SSean Eric Fagan setsugid(p); 748229a15f0SPeter Wemm } 749b1fc0ec1SRobert Watson p->p_ucred = newcred; 750b1fc0ec1SRobert Watson crfree(oldcred); 751835a82eeSMatthew Dillon done2: 752835a82eeSMatthew Dillon mtx_unlock(&Giant); 753835a82eeSMatthew Dillon return (error); 754df8bae1dSRodney W. Grimes } 755df8bae1dSRodney W. Grimes 756d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 757df8bae1dSRodney W. Grimes struct setgroups_args { 758df8bae1dSRodney W. Grimes u_int gidsetsize; 759df8bae1dSRodney W. Grimes gid_t *gidset; 760df8bae1dSRodney W. Grimes }; 761d2d3e875SBruce Evans #endif 762835a82eeSMatthew Dillon /* 763835a82eeSMatthew Dillon * MPSAFE 764835a82eeSMatthew Dillon */ 765df8bae1dSRodney W. Grimes /* ARGSUSED */ 76626f9a767SRodney W. Grimes int 767b40ce416SJulian Elischer setgroups(td, uap) 768b40ce416SJulian Elischer struct thread *td; 769df8bae1dSRodney W. Grimes struct setgroups_args *uap; 770df8bae1dSRodney W. Grimes { 771b40ce416SJulian Elischer struct proc *p = td->td_proc; 772b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 773b1fc0ec1SRobert Watson u_int ngrp; 774df8bae1dSRodney W. Grimes int error; 775df8bae1dSRodney W. Grimes 776835a82eeSMatthew Dillon mtx_lock(&Giant); 7773956a170SDavid Greenman ngrp = uap->gidsetsize; 778b1fc0ec1SRobert Watson oldcred = p->p_ucred; 779eb725b4eSRobert Watson if ((error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 780835a82eeSMatthew Dillon goto done2; 781835a82eeSMatthew Dillon if (ngrp > NGROUPS) { 782835a82eeSMatthew Dillon error = EINVAL; 783835a82eeSMatthew Dillon goto done2; 784835a82eeSMatthew Dillon } 7858a5d815aSPeter Wemm /* 7868a5d815aSPeter Wemm * XXX A little bit lazy here. We could test if anything has 7878a5d815aSPeter Wemm * changed before crcopy() and setting P_SUGID. 7888a5d815aSPeter Wemm */ 789b1fc0ec1SRobert Watson newcred = crdup(oldcred); 7908a5d815aSPeter Wemm if (ngrp < 1) { 7918a5d815aSPeter Wemm /* 7928a5d815aSPeter Wemm * setgroups(0, NULL) is a legitimate way of clearing the 7938a5d815aSPeter Wemm * groups vector on non-BSD systems (which generally do not 7948a5d815aSPeter Wemm * have the egid in the groups[0]). We risk security holes 7958a5d815aSPeter Wemm * when running non-BSD software if we do not do the same. 7968a5d815aSPeter Wemm */ 797b1fc0ec1SRobert Watson newcred->cr_ngroups = 1; 7988a5d815aSPeter Wemm } else { 799bb56ec4aSPoul-Henning Kamp if ((error = copyin((caddr_t)uap->gidset, 800b1fc0ec1SRobert Watson (caddr_t)newcred->cr_groups, ngrp * sizeof(gid_t)))) { 801b1fc0ec1SRobert Watson crfree(newcred); 802835a82eeSMatthew Dillon goto done2; 803b1fc0ec1SRobert Watson } 804b1fc0ec1SRobert Watson newcred->cr_ngroups = ngrp; 8058a5d815aSPeter Wemm } 806d5f81602SSean Eric Fagan setsugid(p); 807b1fc0ec1SRobert Watson p->p_ucred = newcred; 808b1fc0ec1SRobert Watson crfree(oldcred); 809835a82eeSMatthew Dillon done2: 810835a82eeSMatthew Dillon mtx_unlock(&Giant); 811835a82eeSMatthew Dillon return (error); 812df8bae1dSRodney W. Grimes } 813df8bae1dSRodney W. Grimes 814d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 815df8bae1dSRodney W. Grimes struct setreuid_args { 81600999cd6SAndrey A. Chernov uid_t ruid; 81700999cd6SAndrey A. Chernov uid_t euid; 818df8bae1dSRodney W. Grimes }; 819d2d3e875SBruce Evans #endif 820835a82eeSMatthew Dillon /* 821835a82eeSMatthew Dillon * MPSAFE 822835a82eeSMatthew Dillon */ 823df8bae1dSRodney W. Grimes /* ARGSUSED */ 82426f9a767SRodney W. Grimes int 825b40ce416SJulian Elischer setreuid(td, uap) 826b40ce416SJulian Elischer register struct thread *td; 827df8bae1dSRodney W. Grimes struct setreuid_args *uap; 828df8bae1dSRodney W. Grimes { 829b40ce416SJulian Elischer struct proc *p = td->td_proc; 830b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 831eb725b4eSRobert Watson uid_t euid, ruid; 832eb725b4eSRobert Watson int error; 833df8bae1dSRodney W. Grimes 83400999cd6SAndrey A. Chernov euid = uap->euid; 835eb725b4eSRobert Watson ruid = uap->ruid; 836835a82eeSMatthew Dillon mtx_lock(&Giant); 837eb725b4eSRobert Watson error = 0; 838b1fc0ec1SRobert Watson oldcred = p->p_ucred; 839b1fc0ec1SRobert Watson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 840b1fc0ec1SRobert Watson ruid != oldcred->cr_svuid) || 841b1fc0ec1SRobert Watson (euid != (uid_t)-1 && euid != oldcred->cr_uid && 842b1fc0ec1SRobert Watson euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) && 843eb725b4eSRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 844835a82eeSMatthew Dillon goto done2; 845b1fc0ec1SRobert Watson newcred = crdup(oldcred); 846b1fc0ec1SRobert Watson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 847b1fc0ec1SRobert Watson change_euid(newcred, euid); 848d5f81602SSean Eric Fagan setsugid(p); 849a89a5370SPeter Wemm } 850b1fc0ec1SRobert Watson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 851b1fc0ec1SRobert Watson change_ruid(newcred, ruid); 852d5f81602SSean Eric Fagan setsugid(p); 85300999cd6SAndrey A. Chernov } 854b1fc0ec1SRobert Watson if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) && 855b1fc0ec1SRobert Watson newcred->cr_svuid != newcred->cr_uid) { 856b1fc0ec1SRobert Watson change_svuid(newcred, newcred->cr_uid); 857d5f81602SSean Eric Fagan setsugid(p); 858a89a5370SPeter Wemm } 859b1fc0ec1SRobert Watson p->p_ucred = newcred; 860b1fc0ec1SRobert Watson crfree(oldcred); 861835a82eeSMatthew Dillon done2: 862835a82eeSMatthew Dillon mtx_unlock(&Giant); 863835a82eeSMatthew Dillon return (error); 864df8bae1dSRodney W. Grimes } 865df8bae1dSRodney W. Grimes 866d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 867df8bae1dSRodney W. Grimes struct setregid_args { 86800999cd6SAndrey A. Chernov gid_t rgid; 86900999cd6SAndrey A. Chernov gid_t egid; 870df8bae1dSRodney W. Grimes }; 871d2d3e875SBruce Evans #endif 872835a82eeSMatthew Dillon /* 873835a82eeSMatthew Dillon * MPSAFE 874835a82eeSMatthew Dillon */ 875df8bae1dSRodney W. Grimes /* ARGSUSED */ 87626f9a767SRodney W. Grimes int 877b40ce416SJulian Elischer setregid(td, uap) 878b40ce416SJulian Elischer register struct thread *td; 879df8bae1dSRodney W. Grimes struct setregid_args *uap; 880df8bae1dSRodney W. Grimes { 881b40ce416SJulian Elischer struct proc *p = td->td_proc; 882b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 883eb725b4eSRobert Watson gid_t egid, rgid; 884eb725b4eSRobert Watson int error; 885df8bae1dSRodney W. Grimes 88600999cd6SAndrey A. Chernov egid = uap->egid; 887eb725b4eSRobert Watson rgid = uap->rgid; 888835a82eeSMatthew Dillon mtx_lock(&Giant); 889eb725b4eSRobert Watson error = 0; 890b1fc0ec1SRobert Watson oldcred = p->p_ucred; 891b1fc0ec1SRobert Watson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 892b1fc0ec1SRobert Watson rgid != oldcred->cr_svgid) || 893b1fc0ec1SRobert Watson (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] && 894b1fc0ec1SRobert Watson egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) && 895eb725b4eSRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 896835a82eeSMatthew Dillon goto done2; 897b1fc0ec1SRobert Watson newcred = crdup(oldcred); 898b1fc0ec1SRobert Watson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 899b1fc0ec1SRobert Watson change_egid(newcred, egid); 900d5f81602SSean Eric Fagan setsugid(p); 901a89a5370SPeter Wemm } 902b1fc0ec1SRobert Watson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 903b1fc0ec1SRobert Watson change_rgid(newcred, rgid); 904d5f81602SSean Eric Fagan setsugid(p); 905a89a5370SPeter Wemm } 906b1fc0ec1SRobert Watson if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) && 907b1fc0ec1SRobert Watson newcred->cr_svgid != newcred->cr_groups[0]) { 908b1fc0ec1SRobert Watson change_svgid(newcred, newcred->cr_groups[0]); 909d5f81602SSean Eric Fagan setsugid(p); 910a89a5370SPeter Wemm } 9114589be70SRuslan Ermilov p->p_ucred = newcred; 9124589be70SRuslan Ermilov crfree(oldcred); 913835a82eeSMatthew Dillon done2: 914835a82eeSMatthew Dillon mtx_unlock(&Giant); 915835a82eeSMatthew Dillon return (error); 916df8bae1dSRodney W. Grimes } 917df8bae1dSRodney W. Grimes 9188ccd6334SPeter Wemm /* 9198ccd6334SPeter Wemm * setresuid(ruid, euid, suid) is like setreuid except control over the 9208ccd6334SPeter Wemm * saved uid is explicit. 9218ccd6334SPeter Wemm */ 9228ccd6334SPeter Wemm 9238ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 9248ccd6334SPeter Wemm struct setresuid_args { 9258ccd6334SPeter Wemm uid_t ruid; 9268ccd6334SPeter Wemm uid_t euid; 9278ccd6334SPeter Wemm uid_t suid; 9288ccd6334SPeter Wemm }; 9298ccd6334SPeter Wemm #endif 930835a82eeSMatthew Dillon /* 931835a82eeSMatthew Dillon * MPSAFE 932835a82eeSMatthew Dillon */ 9338ccd6334SPeter Wemm /* ARGSUSED */ 9348ccd6334SPeter Wemm int 935b40ce416SJulian Elischer setresuid(td, uap) 936b40ce416SJulian Elischer register struct thread *td; 9378ccd6334SPeter Wemm struct setresuid_args *uap; 9388ccd6334SPeter Wemm { 939b40ce416SJulian Elischer struct proc *p = td->td_proc; 940b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 941eb725b4eSRobert Watson uid_t euid, ruid, suid; 9428ccd6334SPeter Wemm int error; 9438ccd6334SPeter Wemm 9448ccd6334SPeter Wemm euid = uap->euid; 945eb725b4eSRobert Watson ruid = uap->ruid; 9468ccd6334SPeter Wemm suid = uap->suid; 947835a82eeSMatthew Dillon mtx_lock(&Giant); 948b1fc0ec1SRobert Watson oldcred = p->p_ucred; 949b1fc0ec1SRobert Watson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 950b1fc0ec1SRobert Watson ruid != oldcred->cr_svuid && 951b1fc0ec1SRobert Watson ruid != oldcred->cr_uid) || 952b1fc0ec1SRobert Watson (euid != (uid_t)-1 && euid != oldcred->cr_ruid && 953b1fc0ec1SRobert Watson euid != oldcred->cr_svuid && 954b1fc0ec1SRobert Watson euid != oldcred->cr_uid) || 955b1fc0ec1SRobert Watson (suid != (uid_t)-1 && suid != oldcred->cr_ruid && 956b1fc0ec1SRobert Watson suid != oldcred->cr_svuid && 957b1fc0ec1SRobert Watson suid != oldcred->cr_uid)) && 958eb725b4eSRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 959835a82eeSMatthew Dillon goto done2; 960b1fc0ec1SRobert Watson newcred = crdup(oldcred); 961b1fc0ec1SRobert Watson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 962b1fc0ec1SRobert Watson change_euid(newcred, euid); 9638ccd6334SPeter Wemm setsugid(p); 9648ccd6334SPeter Wemm } 965b1fc0ec1SRobert Watson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 966b1fc0ec1SRobert Watson change_ruid(newcred, ruid); 9678ccd6334SPeter Wemm setsugid(p); 9688ccd6334SPeter Wemm } 969b1fc0ec1SRobert Watson if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) { 970b1fc0ec1SRobert Watson change_svuid(newcred, suid); 9718ccd6334SPeter Wemm setsugid(p); 9728ccd6334SPeter Wemm } 973b1fc0ec1SRobert Watson p->p_ucred = newcred; 974b1fc0ec1SRobert Watson crfree(oldcred); 975835a82eeSMatthew Dillon error = 0; 976835a82eeSMatthew Dillon done2: 977835a82eeSMatthew Dillon mtx_unlock(&Giant); 978835a82eeSMatthew Dillon return (error); 9798ccd6334SPeter Wemm } 9808ccd6334SPeter Wemm 9818ccd6334SPeter Wemm /* 9828ccd6334SPeter Wemm * setresgid(rgid, egid, sgid) is like setregid except control over the 9838ccd6334SPeter Wemm * saved gid is explicit. 9848ccd6334SPeter Wemm */ 9858ccd6334SPeter Wemm 9868ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 9878ccd6334SPeter Wemm struct setresgid_args { 9888ccd6334SPeter Wemm gid_t rgid; 9898ccd6334SPeter Wemm gid_t egid; 9908ccd6334SPeter Wemm gid_t sgid; 9918ccd6334SPeter Wemm }; 9928ccd6334SPeter Wemm #endif 993835a82eeSMatthew Dillon /* 994835a82eeSMatthew Dillon * MPSAFE 995835a82eeSMatthew Dillon */ 9968ccd6334SPeter Wemm /* ARGSUSED */ 9978ccd6334SPeter Wemm int 998b40ce416SJulian Elischer setresgid(td, uap) 999b40ce416SJulian Elischer register struct thread *td; 10008ccd6334SPeter Wemm struct setresgid_args *uap; 10018ccd6334SPeter Wemm { 1002b40ce416SJulian Elischer struct proc *p = td->td_proc; 1003b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 1004eb725b4eSRobert Watson gid_t egid, rgid, sgid; 10058ccd6334SPeter Wemm int error; 10068ccd6334SPeter Wemm 10078ccd6334SPeter Wemm egid = uap->egid; 1008eb725b4eSRobert Watson rgid = uap->rgid; 10098ccd6334SPeter Wemm sgid = uap->sgid; 1010835a82eeSMatthew Dillon 1011835a82eeSMatthew Dillon mtx_lock(&Giant); 1012b1fc0ec1SRobert Watson oldcred = p->p_ucred; 1013b1fc0ec1SRobert Watson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 1014b1fc0ec1SRobert Watson rgid != oldcred->cr_svgid && 1015b1fc0ec1SRobert Watson rgid != oldcred->cr_groups[0]) || 1016b1fc0ec1SRobert Watson (egid != (gid_t)-1 && egid != oldcred->cr_rgid && 1017b1fc0ec1SRobert Watson egid != oldcred->cr_svgid && 1018b1fc0ec1SRobert Watson egid != oldcred->cr_groups[0]) || 1019b1fc0ec1SRobert Watson (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid && 1020b1fc0ec1SRobert Watson sgid != oldcred->cr_svgid && 1021b1fc0ec1SRobert Watson sgid != oldcred->cr_groups[0])) && 1022835a82eeSMatthew Dillon (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) { 1023835a82eeSMatthew Dillon goto done2; 1024835a82eeSMatthew Dillon } 1025b1fc0ec1SRobert Watson newcred = crdup(oldcred); 1026b1fc0ec1SRobert Watson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 1027b1fc0ec1SRobert Watson change_egid(newcred, egid); 10288ccd6334SPeter Wemm setsugid(p); 10298ccd6334SPeter Wemm } 1030b1fc0ec1SRobert Watson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 1031b1fc0ec1SRobert Watson change_rgid(newcred, rgid); 10328ccd6334SPeter Wemm setsugid(p); 10338ccd6334SPeter Wemm } 1034b1fc0ec1SRobert Watson if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) { 1035b1fc0ec1SRobert Watson change_svgid(newcred, sgid); 10368ccd6334SPeter Wemm setsugid(p); 10378ccd6334SPeter Wemm } 1038b1fc0ec1SRobert Watson p->p_ucred = newcred; 1039b1fc0ec1SRobert Watson crfree(oldcred); 1040835a82eeSMatthew Dillon error = 0; 1041835a82eeSMatthew Dillon done2: 1042835a82eeSMatthew Dillon mtx_unlock(&Giant); 1043835a82eeSMatthew Dillon return (error); 10448ccd6334SPeter Wemm } 10458ccd6334SPeter Wemm 10468ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 10478ccd6334SPeter Wemm struct getresuid_args { 10488ccd6334SPeter Wemm uid_t *ruid; 10498ccd6334SPeter Wemm uid_t *euid; 10508ccd6334SPeter Wemm uid_t *suid; 10518ccd6334SPeter Wemm }; 10528ccd6334SPeter Wemm #endif 1053835a82eeSMatthew Dillon /* 1054835a82eeSMatthew Dillon * MPSAFE 1055835a82eeSMatthew Dillon */ 10568ccd6334SPeter Wemm /* ARGSUSED */ 10578ccd6334SPeter Wemm int 1058b40ce416SJulian Elischer getresuid(td, uap) 1059b40ce416SJulian Elischer register struct thread *td; 10608ccd6334SPeter Wemm struct getresuid_args *uap; 10618ccd6334SPeter Wemm { 1062835a82eeSMatthew Dillon struct ucred *cred; 1063b40ce416SJulian Elischer struct proc *p = td->td_proc; 10648ccd6334SPeter Wemm int error1 = 0, error2 = 0, error3 = 0; 10658ccd6334SPeter Wemm 1066835a82eeSMatthew Dillon mtx_lock(&Giant); 1067835a82eeSMatthew Dillon cred = p->p_ucred; 10688ccd6334SPeter Wemm if (uap->ruid) 1069b1fc0ec1SRobert Watson error1 = copyout((caddr_t)&cred->cr_ruid, 1070b1fc0ec1SRobert Watson (caddr_t)uap->ruid, sizeof(cred->cr_ruid)); 10718ccd6334SPeter Wemm if (uap->euid) 1072b1fc0ec1SRobert Watson error2 = copyout((caddr_t)&cred->cr_uid, 1073b1fc0ec1SRobert Watson (caddr_t)uap->euid, sizeof(cred->cr_uid)); 10748ccd6334SPeter Wemm if (uap->suid) 1075b1fc0ec1SRobert Watson error3 = copyout((caddr_t)&cred->cr_svuid, 1076b1fc0ec1SRobert Watson (caddr_t)uap->suid, sizeof(cred->cr_svuid)); 1077835a82eeSMatthew Dillon mtx_unlock(&Giant); 1078eb725b4eSRobert Watson return (error1 ? error1 : error2 ? error2 : error3); 10798ccd6334SPeter Wemm } 10808ccd6334SPeter Wemm 10818ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 10828ccd6334SPeter Wemm struct getresgid_args { 10838ccd6334SPeter Wemm gid_t *rgid; 10848ccd6334SPeter Wemm gid_t *egid; 10858ccd6334SPeter Wemm gid_t *sgid; 10868ccd6334SPeter Wemm }; 10878ccd6334SPeter Wemm #endif 1088835a82eeSMatthew Dillon /* 1089835a82eeSMatthew Dillon * MPSAFE 1090835a82eeSMatthew Dillon */ 10918ccd6334SPeter Wemm /* ARGSUSED */ 10928ccd6334SPeter Wemm int 1093b40ce416SJulian Elischer getresgid(td, uap) 1094b40ce416SJulian Elischer register struct thread *td; 10958ccd6334SPeter Wemm struct getresgid_args *uap; 10968ccd6334SPeter Wemm { 1097835a82eeSMatthew Dillon struct ucred *cred; 1098b40ce416SJulian Elischer struct proc *p = td->td_proc; 10998ccd6334SPeter Wemm int error1 = 0, error2 = 0, error3 = 0; 11008ccd6334SPeter Wemm 1101835a82eeSMatthew Dillon mtx_lock(&Giant); 1102835a82eeSMatthew Dillon cred = p->p_ucred; 11038ccd6334SPeter Wemm if (uap->rgid) 1104b1fc0ec1SRobert Watson error1 = copyout((caddr_t)&cred->cr_rgid, 1105b1fc0ec1SRobert Watson (caddr_t)uap->rgid, sizeof(cred->cr_rgid)); 11068ccd6334SPeter Wemm if (uap->egid) 1107b1fc0ec1SRobert Watson error2 = copyout((caddr_t)&cred->cr_groups[0], 1108b1fc0ec1SRobert Watson (caddr_t)uap->egid, sizeof(cred->cr_groups[0])); 11098ccd6334SPeter Wemm if (uap->sgid) 1110b1fc0ec1SRobert Watson error3 = copyout((caddr_t)&cred->cr_svgid, 1111b1fc0ec1SRobert Watson (caddr_t)uap->sgid, sizeof(cred->cr_svgid)); 1112835a82eeSMatthew Dillon mtx_unlock(&Giant); 1113eb725b4eSRobert Watson return (error1 ? error1 : error2 ? error2 : error3); 11148ccd6334SPeter Wemm } 11158ccd6334SPeter Wemm 1116b67cbc65SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1117b67cbc65SPeter Wemm struct issetugid_args { 1118b67cbc65SPeter Wemm int dummy; 1119b67cbc65SPeter Wemm }; 1120b67cbc65SPeter Wemm #endif 1121eb725b4eSRobert Watson /* 1122eb725b4eSRobert Watson * NOT MPSAFE? 1123eb725b4eSRobert Watson */ 1124b67cbc65SPeter Wemm /* ARGSUSED */ 1125b67cbc65SPeter Wemm int 1126b40ce416SJulian Elischer issetugid(td, uap) 1127b40ce416SJulian Elischer register struct thread *td; 1128b67cbc65SPeter Wemm struct issetugid_args *uap; 1129b67cbc65SPeter Wemm { 1130b40ce416SJulian Elischer struct proc *p = td->td_proc; 1131b40ce416SJulian Elischer 1132b67cbc65SPeter Wemm /* 1133b67cbc65SPeter Wemm * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 1134b67cbc65SPeter Wemm * we use P_SUGID because we consider changing the owners as 1135b67cbc65SPeter Wemm * "tainting" as well. 1136b67cbc65SPeter Wemm * This is significant for procs that start as root and "become" 1137b67cbc65SPeter Wemm * a user without an exec - programs cannot know *everything* 1138b67cbc65SPeter Wemm * that libc *might* have put in their data segment. 1139b67cbc65SPeter Wemm */ 1140b40ce416SJulian Elischer td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 1141b67cbc65SPeter Wemm return (0); 1142b67cbc65SPeter Wemm } 1143b67cbc65SPeter Wemm 1144835a82eeSMatthew Dillon /* 1145835a82eeSMatthew Dillon * MPSAFE 1146835a82eeSMatthew Dillon */ 1147130d0157SRobert Watson int 1148b40ce416SJulian Elischer __setugid(td, uap) 1149b40ce416SJulian Elischer struct thread *td; 1150130d0157SRobert Watson struct __setugid_args *uap; 1151130d0157SRobert Watson { 1152130d0157SRobert Watson #ifdef REGRESSION 1153eb725b4eSRobert Watson int error; 1154835a82eeSMatthew Dillon 1155835a82eeSMatthew Dillon mtx_lock(&Giant); 1156eb725b4eSRobert Watson error = 0; 1157130d0157SRobert Watson switch (uap->flag) { 1158130d0157SRobert Watson case 0: 1159b40ce416SJulian Elischer td->td_proc->p_flag &= ~P_SUGID; 1160835a82eeSMatthew Dillon break; 1161130d0157SRobert Watson case 1: 1162b40ce416SJulian Elischer td->td_proc->p_flag |= P_SUGID; 1163835a82eeSMatthew Dillon break; 1164130d0157SRobert Watson default: 1165835a82eeSMatthew Dillon error = EINVAL; 1166835a82eeSMatthew Dillon break; 1167130d0157SRobert Watson } 1168835a82eeSMatthew Dillon mtx_unlock(&Giant); 1169835a82eeSMatthew Dillon return (error); 1170130d0157SRobert Watson #else /* !REGRESSION */ 1171eb725b4eSRobert Watson 1172130d0157SRobert Watson return (ENOSYS); 1173eb725b4eSRobert Watson #endif /* REGRESSION */ 1174130d0157SRobert Watson } 1175130d0157SRobert Watson 1176df8bae1dSRodney W. Grimes /* 1177df8bae1dSRodney W. Grimes * Check if gid is a member of the group set. 1178df8bae1dSRodney W. Grimes */ 117926f9a767SRodney W. Grimes int 1180df8bae1dSRodney W. Grimes groupmember(gid, cred) 1181df8bae1dSRodney W. Grimes gid_t gid; 1182b1fc0ec1SRobert Watson struct ucred *cred; 1183df8bae1dSRodney W. Grimes { 1184df8bae1dSRodney W. Grimes register gid_t *gp; 1185df8bae1dSRodney W. Grimes gid_t *egp; 1186df8bae1dSRodney W. Grimes 1187df8bae1dSRodney W. Grimes egp = &(cred->cr_groups[cred->cr_ngroups]); 1188df8bae1dSRodney W. Grimes for (gp = cred->cr_groups; gp < egp; gp++) 1189df8bae1dSRodney W. Grimes if (*gp == gid) 1190df8bae1dSRodney W. Grimes return (1); 1191df8bae1dSRodney W. Grimes return (0); 1192df8bae1dSRodney W. Grimes } 1193df8bae1dSRodney W. Grimes 11943b243b72SRobert Watson /* 119593f4fd1cSRobert Watson * `suser_enabled' (which can be set by the kern.security.suser_enabled 11967fd6a959SRobert Watson * sysctl) determines whether the system 'super-user' policy is in effect. 11977fd6a959SRobert Watson * If it is nonzero, an effective uid of 0 connotes special privilege, 11987fd6a959SRobert Watson * overriding many mandatory and discretionary protections. If it is zero, 11997fd6a959SRobert Watson * uid 0 is offered no special privilege in the kernel security policy. 12007fd6a959SRobert Watson * Setting it to zero may seriously impact the functionality of many 12017fd6a959SRobert Watson * existing userland programs, and should not be done without careful 12027fd6a959SRobert Watson * consideration of the consequences. 12033b243b72SRobert Watson */ 120493f4fd1cSRobert Watson int suser_enabled = 1; 120548713bdcSRobert Watson SYSCTL_INT(_kern_security_bsd, OID_AUTO, suser_enabled, CTLFLAG_RW, 120693f4fd1cSRobert Watson &suser_enabled, 0, "processes with uid 0 have privilege"); 1207579f4eb4SRobert Watson 1208df8bae1dSRodney W. Grimes /* 12097fd6a959SRobert Watson * Test whether the specified credentials imply "super-user" privilege. 12107fd6a959SRobert Watson * Return 0 or EPERM. 1211df8bae1dSRodney W. Grimes */ 121226f9a767SRodney W. Grimes int 1213f711d546SPoul-Henning Kamp suser(p) 121491421ba2SRobert Watson struct proc *p; 1215f711d546SPoul-Henning Kamp { 1216eb725b4eSRobert Watson 1217eb725b4eSRobert Watson return (suser_xxx(0, p, 0)); 1218f711d546SPoul-Henning Kamp } 1219f711d546SPoul-Henning Kamp 1220b40ce416SJulian Elischer /* 1221b40ce416SJulian Elischer * version for when the thread pointer is available and not the proc. 1222b40ce416SJulian Elischer * (saves having to include proc.h into every file that needs to do the change.) 1223b40ce416SJulian Elischer */ 1224b40ce416SJulian Elischer int 1225b40ce416SJulian Elischer suser_td(td) 1226b40ce416SJulian Elischer struct thread *td; 1227b40ce416SJulian Elischer { 1228b40ce416SJulian Elischer return suser_xxx(0, td->td_proc, 0); 1229b40ce416SJulian Elischer } 1230b40ce416SJulian Elischer 1231b40ce416SJulian Elischer /* 1232b40ce416SJulian Elischer * wrapper to use if you have the thread on hand but not the proc. 1233b40ce416SJulian Elischer */ 1234b40ce416SJulian Elischer int 1235b40ce416SJulian Elischer suser_xxx_td(cred, td, flag) 1236b40ce416SJulian Elischer struct ucred *cred; 1237b40ce416SJulian Elischer struct thread *td; 1238b40ce416SJulian Elischer int flag; 1239b40ce416SJulian Elischer { 1240b40ce416SJulian Elischer return(suser_xxx(cred, td->td_proc, flag)); 1241b40ce416SJulian Elischer } 1242b40ce416SJulian Elischer 1243f711d546SPoul-Henning Kamp int 124475c13541SPoul-Henning Kamp suser_xxx(cred, proc, flag) 124591421ba2SRobert Watson struct ucred *cred; 124691421ba2SRobert Watson struct proc *proc; 124775c13541SPoul-Henning Kamp int flag; 1248df8bae1dSRodney W. Grimes { 124993f4fd1cSRobert Watson if (!suser_enabled) 125003095547SRobert Watson return (EPERM); 125175c13541SPoul-Henning Kamp if (!cred && !proc) { 125275c13541SPoul-Henning Kamp printf("suser_xxx(): THINK!\n"); 1253df8bae1dSRodney W. Grimes return (EPERM); 1254df8bae1dSRodney W. Grimes } 1255eb725b4eSRobert Watson if (cred == NULL) 125675c13541SPoul-Henning Kamp cred = proc->p_ucred; 125775c13541SPoul-Henning Kamp if (cred->cr_uid != 0) 125875c13541SPoul-Henning Kamp return (EPERM); 125991421ba2SRobert Watson if (jailed(cred) && !(flag & PRISON_ROOT)) 126075c13541SPoul-Henning Kamp return (EPERM); 126175c13541SPoul-Henning Kamp return (0); 126275c13541SPoul-Henning Kamp } 1263df8bae1dSRodney W. Grimes 12643ca719f1SRobert Watson /* 1265eb725b4eSRobert Watson * Test the active securelevel against a given level. securelevel_gt() 1266eb725b4eSRobert Watson * implements (securelevel > level). securelevel_ge() implements 1267eb725b4eSRobert Watson * (securelevel >= level). Note that the logic is inverted -- these 1268eb725b4eSRobert Watson * functions return EPERM on "success" and 0 on "failure". 12693ca719f1SRobert Watson * 12703ca719f1SRobert Watson * cr is permitted to be NULL for the time being, as there were some 12713ca719f1SRobert Watson * existing securelevel checks that occurred without a process/credential 1272eb725b4eSRobert Watson * context. In the future this will be disallowed, so a kernel message 1273eb725b4eSRobert Watson * is displayed. 12743ca719f1SRobert Watson */ 12753ca719f1SRobert Watson int 12763ca719f1SRobert Watson securelevel_gt(struct ucred *cr, int level) 12773ca719f1SRobert Watson { 1278eb725b4eSRobert Watson int active_securelevel; 12793ca719f1SRobert Watson 1280eb725b4eSRobert Watson active_securelevel = securelevel; 1281eb725b4eSRobert Watson if (cr == NULL) 12823ca719f1SRobert Watson printf("securelevel_gt: cr is NULL\n"); 1283eb725b4eSRobert Watson if (cr->cr_prison != NULL) 1284eb725b4eSRobert Watson active_securelevel = imax(cr->cr_prison->pr_securelevel, 1285eb725b4eSRobert Watson active_securelevel); 1286eb725b4eSRobert Watson return (active_securelevel > level ? EPERM : 0); 12873ca719f1SRobert Watson } 12883ca719f1SRobert Watson 12893ca719f1SRobert Watson int 12903ca719f1SRobert Watson securelevel_ge(struct ucred *cr, int level) 12913ca719f1SRobert Watson { 1292eb725b4eSRobert Watson int active_securelevel; 12933ca719f1SRobert Watson 1294eb725b4eSRobert Watson active_securelevel = securelevel; 1295eb725b4eSRobert Watson if (cr == NULL) 1296eb725b4eSRobert Watson printf("securelevel_gt: cr is NULL\n"); 1297eb725b4eSRobert Watson if (cr->cr_prison != NULL) 1298eb725b4eSRobert Watson active_securelevel = imax(cr->cr_prison->pr_securelevel, 1299eb725b4eSRobert Watson active_securelevel); 1300eb725b4eSRobert Watson return (active_securelevel >= level ? EPERM : 0); 13013ca719f1SRobert Watson } 13023ca719f1SRobert Watson 13038a7d8cc6SRobert Watson /* 1304e409590dSRobert Watson * 'see_other_uids' determines whether or not visibility of processes 1305eb725b4eSRobert Watson * and sockets with credentials holding different real uids is possible 130648713bdcSRobert Watson * using a variety of system MIBs. 1307eb725b4eSRobert Watson * XXX: data declarations should be together near the beginning of the file. 13088a7d8cc6SRobert Watson */ 1309e409590dSRobert Watson static int see_other_uids = 1; 1310eb725b4eSRobert Watson SYSCTL_INT(_kern_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW, 1311eb725b4eSRobert Watson &see_other_uids, 0, 13128a7d8cc6SRobert Watson "Unprivileged processes may see subjects/objects with different real uid"); 13138a7d8cc6SRobert Watson 13147fd6a959SRobert Watson /*- 13157fd6a959SRobert Watson * Determine if u1 "can see" the subject specified by u2. 1316ed639720SRobert Watson * Returns: 0 for permitted, an errno value otherwise 1317ed639720SRobert Watson * Locks: none 1318eb725b4eSRobert Watson * References: *u1 and *u2 must not change during the call 1319ed639720SRobert Watson * u1 may equal u2, in which case only one reference is required 1320ed639720SRobert Watson */ 1321ed639720SRobert Watson int 132294088977SRobert Watson cr_cansee(struct ucred *u1, struct ucred *u2) 1323a9e0361bSPoul-Henning Kamp { 132491421ba2SRobert Watson int error; 1325a9e0361bSPoul-Henning Kamp 1326ed639720SRobert Watson if ((error = prison_check(u1, u2))) 132791421ba2SRobert Watson return (error); 1328e409590dSRobert Watson if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) { 1329f8e6ab29SRobert Watson if (suser_xxx(u1, NULL, PRISON_ROOT) != 0) 1330387d2c03SRobert Watson return (ESRCH); 1331c52396e3SRobert Watson } 1332387d2c03SRobert Watson return (0); 1333387d2c03SRobert Watson } 1334387d2c03SRobert Watson 13357fd6a959SRobert Watson /*- 13367fd6a959SRobert Watson * Determine if p1 "can see" the subject specified by p2. 13373b243b72SRobert Watson * Returns: 0 for permitted, an errno value otherwise 13387fd6a959SRobert Watson * Locks: Sufficient locks to protect p1->p_ucred and p2->p_ucred must 13393b243b72SRobert Watson * be held. Normally, p1 will be curproc, and a lock must be held 13403b243b72SRobert Watson * for p2. 13413b243b72SRobert Watson * References: p1 and p2 must be valid for the lifetime of the call 13423b243b72SRobert Watson */ 1343a0f75161SRobert Watson int 1344a0f75161SRobert Watson p_cansee(struct proc *p1, struct proc *p2) 1345ed639720SRobert Watson { 1346ed639720SRobert Watson 134794088977SRobert Watson /* Wrap cr_cansee() for all functionality. */ 134894088977SRobert Watson return (cr_cansee(p1->p_ucred, p2->p_ucred)); 1349ed639720SRobert Watson } 1350ed639720SRobert Watson 13517fd6a959SRobert Watson /*- 13527fd6a959SRobert Watson * Determine whether p1 may deliver the specified signal to p2. 13537fd6a959SRobert Watson * Returns: 0 for permitted, an errno value otherwise 13547fd6a959SRobert Watson * Locks: Sufficient locks to protect various components of p1 and p2 13557fd6a959SRobert Watson * must be held. Normally, p1 will be curproc, and a lock must 13567fd6a959SRobert Watson * be held for p2. 13573b243b72SRobert Watson * References: p1 and p2 must be valid for the lifetime of the call 13584c5eb9c3SRobert Watson */ 13594c5eb9c3SRobert Watson int 13604c5eb9c3SRobert Watson p_cansignal(struct proc *p1, struct proc *p2, int signum) 1361387d2c03SRobert Watson { 136291421ba2SRobert Watson int error; 1363387d2c03SRobert Watson 1364a9e0361bSPoul-Henning Kamp if (p1 == p2) 1365a9e0361bSPoul-Henning Kamp return (0); 1366387d2c03SRobert Watson 13674c5eb9c3SRobert Watson /* 13684c5eb9c3SRobert Watson * Jail semantics limit the scope of signalling to p2 in the same 13694c5eb9c3SRobert Watson * jail as p1, if p1 is in jail. 13704c5eb9c3SRobert Watson */ 137191421ba2SRobert Watson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 137291421ba2SRobert Watson return (error); 1373387d2c03SRobert Watson 1374387d2c03SRobert Watson /* 13754c5eb9c3SRobert Watson * UNIX signalling semantics require that processes in the same 13764c5eb9c3SRobert Watson * session always be able to deliver SIGCONT to one another, 13774c5eb9c3SRobert Watson * overriding the remaining protections. 1378387d2c03SRobert Watson */ 13794c5eb9c3SRobert Watson if (signum == SIGCONT && p1->p_session == p2->p_session) 1380a9e0361bSPoul-Henning Kamp return (0); 1381387d2c03SRobert Watson 13824c5eb9c3SRobert Watson /* 13833b243b72SRobert Watson * UNIX signal semantics depend on the status of the P_SUGID 13843b243b72SRobert Watson * bit on the target process. If the bit is set, then additional 13853b243b72SRobert Watson * restrictions are placed on the set of available signals. 13864c5eb9c3SRobert Watson */ 13874c5eb9c3SRobert Watson if (p2->p_flag & P_SUGID) { 13884c5eb9c3SRobert Watson switch (signum) { 13894c5eb9c3SRobert Watson case 0: 13904c5eb9c3SRobert Watson case SIGKILL: 13914c5eb9c3SRobert Watson case SIGINT: 13924c5eb9c3SRobert Watson case SIGTERM: 13934c5eb9c3SRobert Watson case SIGSTOP: 13944c5eb9c3SRobert Watson case SIGTTIN: 13954c5eb9c3SRobert Watson case SIGTTOU: 13964c5eb9c3SRobert Watson case SIGTSTP: 13974c5eb9c3SRobert Watson case SIGHUP: 13984c5eb9c3SRobert Watson case SIGUSR1: 13994c5eb9c3SRobert Watson case SIGUSR2: 14007fd6a959SRobert Watson /* 14017fd6a959SRobert Watson * Generally, permit job and terminal control 14027fd6a959SRobert Watson * signals. 14037fd6a959SRobert Watson */ 14044c5eb9c3SRobert Watson break; 14054c5eb9c3SRobert Watson default: 14063b243b72SRobert Watson /* Not permitted, privilege is required. */ 14074c5eb9c3SRobert Watson error = suser_xxx(NULL, p1, PRISON_ROOT); 14084c5eb9c3SRobert Watson if (error) 14094c5eb9c3SRobert Watson return (error); 14104c5eb9c3SRobert Watson } 1411e9e7ff5bSRobert Watson } 1412e9e7ff5bSRobert Watson 14134c5eb9c3SRobert Watson /* 14143b243b72SRobert Watson * Generally, the target credential's ruid or svuid must match the 1415e9e7ff5bSRobert Watson * subject credential's ruid or euid. 14164c5eb9c3SRobert Watson */ 1417b1fc0ec1SRobert Watson if (p1->p_ucred->cr_ruid != p2->p_ucred->cr_ruid && 1418b1fc0ec1SRobert Watson p1->p_ucred->cr_ruid != p2->p_ucred->cr_svuid && 1419b1fc0ec1SRobert Watson p1->p_ucred->cr_uid != p2->p_ucred->cr_ruid && 1420b1fc0ec1SRobert Watson p1->p_ucred->cr_uid != p2->p_ucred->cr_svuid) { 14214c5eb9c3SRobert Watson /* Not permitted, try privilege. */ 14224c5eb9c3SRobert Watson error = suser_xxx(NULL, p1, PRISON_ROOT); 14234c5eb9c3SRobert Watson if (error) 14244c5eb9c3SRobert Watson return (error); 14254c5eb9c3SRobert Watson } 1426387d2c03SRobert Watson 1427387d2c03SRobert Watson return (0); 1428387d2c03SRobert Watson } 1429a9e0361bSPoul-Henning Kamp 14307fd6a959SRobert Watson /*- 1431eb725b4eSRobert Watson * Determine whether p1 may reschedule p2. 14327fd6a959SRobert Watson * Returns: 0 for permitted, an errno value otherwise 14333b243b72SRobert Watson * Locks: Sufficient locks to protect various components of p1 and p2 14343b243b72SRobert Watson * must be held. Normally, p1 will be curproc, and a lock must 14357fd6a959SRobert Watson * be held for p2. 14363b243b72SRobert Watson * References: p1 and p2 must be valid for the lifetime of the call 14373b243b72SRobert Watson */ 1438a0f75161SRobert Watson int 1439a0f75161SRobert Watson p_cansched(struct proc *p1, struct proc *p2) 1440387d2c03SRobert Watson { 144191421ba2SRobert Watson int error; 1442387d2c03SRobert Watson 1443387d2c03SRobert Watson if (p1 == p2) 1444387d2c03SRobert Watson return (0); 144591421ba2SRobert Watson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 144691421ba2SRobert Watson return (error); 1447b1fc0ec1SRobert Watson if (p1->p_ucred->cr_ruid == p2->p_ucred->cr_ruid) 1448387d2c03SRobert Watson return (0); 1449b1fc0ec1SRobert Watson if (p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid) 1450387d2c03SRobert Watson return (0); 14517fd6a959SRobert Watson if (suser_xxx(0, p1, PRISON_ROOT) == 0) 1452387d2c03SRobert Watson return (0); 1453387d2c03SRobert Watson 1454387d2c03SRobert Watson #ifdef CAPABILITIES 14554df571b1SRobert Watson if (!cap_check(NULL, p1, CAP_SYS_NICE, PRISON_ROOT)) 1456387d2c03SRobert Watson return (0); 1457387d2c03SRobert Watson #endif 1458387d2c03SRobert Watson 1459387d2c03SRobert Watson return (EPERM); 1460387d2c03SRobert Watson } 1461387d2c03SRobert Watson 14623b243b72SRobert Watson /* 146348713bdcSRobert Watson * The 'unprivileged_procdebug_permitted' flag may be used to disable 14643b243b72SRobert Watson * a variety of unprivileged inter-process debugging services, including 14653b243b72SRobert Watson * some procfs functionality, ptrace(), and ktrace(). In the past, 14663b243b72SRobert Watson * inter-process debugging has been involved in a variety of security 14673b243b72SRobert Watson * problems, and sites not requiring the service might choose to disable it 14683b243b72SRobert Watson * when hardening systems. 14693b243b72SRobert Watson * 14703b243b72SRobert Watson * XXX: Should modifying and reading this variable require locking? 1471eb725b4eSRobert Watson * XXX: data declarations should be together near the beginning of the file. 14723b243b72SRobert Watson */ 1473e409590dSRobert Watson static int unprivileged_proc_debug = 1; 1474eb725b4eSRobert Watson SYSCTL_INT(_kern_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW, 1475eb725b4eSRobert Watson &unprivileged_proc_debug, 0, 14760ef5652eSRobert Watson "Unprivileged processes may use process debugging facilities"); 14770ef5652eSRobert Watson 14787fd6a959SRobert Watson /*- 14797fd6a959SRobert Watson * Determine whether p1 may debug p2. 14807fd6a959SRobert Watson * Returns: 0 for permitted, an errno value otherwise 14817fd6a959SRobert Watson * Locks: Sufficient locks to protect various components of p1 and p2 14827fd6a959SRobert Watson * must be held. Normally, p1 will be curproc, and a lock must 14837fd6a959SRobert Watson * be held for p2. 14843b243b72SRobert Watson * References: p1 and p2 must be valid for the lifetime of the call 14853b243b72SRobert Watson */ 1486a0f75161SRobert Watson int 1487a0f75161SRobert Watson p_candebug(struct proc *p1, struct proc *p2) 1488387d2c03SRobert Watson { 1489eb725b4eSRobert Watson int credentialchanged, error, grpsubset, i, uidsubset; 1490387d2c03SRobert Watson 1491e409590dSRobert Watson if (!unprivileged_proc_debug) { 149232d18604SRobert Watson error = suser_xxx(NULL, p1, PRISON_ROOT); 149332d18604SRobert Watson if (error) 149432d18604SRobert Watson return (error); 149532d18604SRobert Watson } 149623fad5b6SDag-Erling Smørgrav if (p1 == p2) 149723fad5b6SDag-Erling Smørgrav return (0); 149891421ba2SRobert Watson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 149991421ba2SRobert Watson return (error); 1500387d2c03SRobert Watson 15017fd6a959SRobert Watson /* 1502db42a33dSRobert Watson * Is p2's group set a subset of p1's effective group set? This 1503db42a33dSRobert Watson * includes p2's egid, group access list, rgid, and svgid. 15047fd6a959SRobert Watson */ 1505db42a33dSRobert Watson grpsubset = 1; 1506db42a33dSRobert Watson for (i = 0; i < p2->p_ucred->cr_ngroups; i++) { 1507db42a33dSRobert Watson if (!groupmember(p2->p_ucred->cr_groups[i], p1->p_ucred)) { 1508db42a33dSRobert Watson grpsubset = 0; 1509db42a33dSRobert Watson break; 1510db42a33dSRobert Watson } 1511db42a33dSRobert Watson } 1512db42a33dSRobert Watson grpsubset = grpsubset && 1513db42a33dSRobert Watson groupmember(p2->p_ucred->cr_rgid, p1->p_ucred) && 1514db42a33dSRobert Watson groupmember(p2->p_ucred->cr_svgid, p1->p_ucred); 1515db42a33dSRobert Watson 1516db42a33dSRobert Watson /* 1517db42a33dSRobert Watson * Are the uids present in p2's credential equal to p1's 1518db42a33dSRobert Watson * effective uid? This includes p2's euid, svuid, and ruid. 1519db42a33dSRobert Watson */ 1520db42a33dSRobert Watson uidsubset = (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid && 1521db42a33dSRobert Watson p1->p_ucred->cr_uid == p2->p_ucred->cr_svuid && 1522db42a33dSRobert Watson p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid); 1523db42a33dSRobert Watson 1524db42a33dSRobert Watson /* 1525db42a33dSRobert Watson * Has the credential of the process changed since the last exec()? 1526db42a33dSRobert Watson */ 1527db42a33dSRobert Watson credentialchanged = (p2->p_flag & P_SUGID); 1528db42a33dSRobert Watson 1529db42a33dSRobert Watson /* 1530db42a33dSRobert Watson * If p2's gids aren't a subset, or the uids aren't a subset, 1531db42a33dSRobert Watson * or the credential has changed, require appropriate privilege 1532db42a33dSRobert Watson * for p1 to debug p2. For POSIX.1e capabilities, this will 1533db42a33dSRobert Watson * require CAP_SYS_PTRACE. 1534db42a33dSRobert Watson */ 1535db42a33dSRobert Watson if (!grpsubset || !uidsubset || credentialchanged) { 153632d18604SRobert Watson error = suser_xxx(NULL, p1, PRISON_ROOT); 153732d18604SRobert Watson if (error) 1538387d2c03SRobert Watson return (error); 15397fd6a959SRobert Watson } 1540387d2c03SRobert Watson 1541eb725b4eSRobert Watson /* Can't trace init when securelevel > 0. */ 1542eb725b4eSRobert Watson if (p2 == initproc) { 15433ca719f1SRobert Watson error = securelevel_gt(p1->p_ucred, 0); 15443ca719f1SRobert Watson if (error) 15453ca719f1SRobert Watson return (error); 15463ca719f1SRobert Watson } 1547387d2c03SRobert Watson 15485fab7614SRobert Watson /* 15495fab7614SRobert Watson * Can't trace a process that's currently exec'ing. 15505fab7614SRobert Watson * XXX: Note, this is not a security policy decision, it's a 15515fab7614SRobert Watson * basic correctness/functionality decision. Therefore, this check 15525fab7614SRobert Watson * should be moved to the caller's of p_candebug(). 15535fab7614SRobert Watson */ 15549ca45e81SDag-Erling Smørgrav if ((p2->p_flag & P_INEXEC) != 0) 15559ca45e81SDag-Erling Smørgrav return (EAGAIN); 15569ca45e81SDag-Erling Smørgrav 1557387d2c03SRobert Watson return (0); 1558387d2c03SRobert Watson } 1559387d2c03SRobert Watson 1560a9e0361bSPoul-Henning Kamp /* 1561df8bae1dSRodney W. Grimes * Allocate a zeroed cred structure. 1562df8bae1dSRodney W. Grimes */ 1563df8bae1dSRodney W. Grimes struct ucred * 1564df8bae1dSRodney W. Grimes crget() 1565df8bae1dSRodney W. Grimes { 1566df8bae1dSRodney W. Grimes register struct ucred *cr; 1567df8bae1dSRodney W. Grimes 15681e5d626aSAlfred Perlstein MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK | M_ZERO); 1569df8bae1dSRodney W. Grimes cr->cr_ref = 1; 15701e5d626aSAlfred Perlstein mtx_init(&cr->cr_mtx, "ucred", MTX_DEF); 1571df8bae1dSRodney W. Grimes return (cr); 1572df8bae1dSRodney W. Grimes } 1573df8bae1dSRodney W. Grimes 1574df8bae1dSRodney W. Grimes /* 15757fd6a959SRobert Watson * Claim another reference to a ucred structure. 15765c3f70d7SAlfred Perlstein */ 1577bd78ceceSJohn Baldwin struct ucred * 15785c3f70d7SAlfred Perlstein crhold(cr) 15795c3f70d7SAlfred Perlstein struct ucred *cr; 15805c3f70d7SAlfred Perlstein { 15815c3f70d7SAlfred Perlstein 15829ed346baSBosko Milekic mtx_lock(&cr->cr_mtx); 15835c3f70d7SAlfred Perlstein cr->cr_ref++; 1584bd78ceceSJohn Baldwin mtx_unlock(&cr->cr_mtx); 1585bd78ceceSJohn Baldwin return (cr); 15865c3f70d7SAlfred Perlstein } 15875c3f70d7SAlfred Perlstein 15885c3f70d7SAlfred Perlstein /* 1589df8bae1dSRodney W. Grimes * Free a cred structure. 1590df8bae1dSRodney W. Grimes * Throws away space when ref count gets to 0. 1591df8bae1dSRodney W. Grimes */ 159226f9a767SRodney W. Grimes void 1593df8bae1dSRodney W. Grimes crfree(cr) 1594df8bae1dSRodney W. Grimes struct ucred *cr; 1595df8bae1dSRodney W. Grimes { 15961e5d626aSAlfred Perlstein 15979ed346baSBosko Milekic mtx_lock(&cr->cr_mtx); 1598e04670b7SAlfred Perlstein KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref)); 1599f535380cSDon Lewis if (--cr->cr_ref == 0) { 16001e5d626aSAlfred Perlstein mtx_destroy(&cr->cr_mtx); 1601f535380cSDon Lewis /* 1602f535380cSDon Lewis * Some callers of crget(), such as nfs_statfs(), 1603f535380cSDon Lewis * allocate a temporary credential, but don't 1604f535380cSDon Lewis * allocate a uidinfo structure. 1605f535380cSDon Lewis */ 1606f535380cSDon Lewis if (cr->cr_uidinfo != NULL) 1607f535380cSDon Lewis uifree(cr->cr_uidinfo); 1608823c224eSRobert Watson if (cr->cr_ruidinfo != NULL) 1609823c224eSRobert Watson uifree(cr->cr_ruidinfo); 161091421ba2SRobert Watson /* 161191421ba2SRobert Watson * Free a prison, if any. 161291421ba2SRobert Watson */ 161391421ba2SRobert Watson if (jailed(cr)) 161491421ba2SRobert Watson prison_free(cr->cr_prison); 1615df8bae1dSRodney W. Grimes FREE((caddr_t)cr, M_CRED); 1616eb725b4eSRobert Watson } else 16179ed346baSBosko Milekic mtx_unlock(&cr->cr_mtx); 1618df8bae1dSRodney W. Grimes } 1619df8bae1dSRodney W. Grimes 1620df8bae1dSRodney W. Grimes /* 1621bd78ceceSJohn Baldwin * Check to see if this ucred is shared. 1622df8bae1dSRodney W. Grimes */ 1623bd78ceceSJohn Baldwin int 1624bd78ceceSJohn Baldwin crshared(cr) 1625df8bae1dSRodney W. Grimes struct ucred *cr; 1626df8bae1dSRodney W. Grimes { 1627bd78ceceSJohn Baldwin int shared; 1628df8bae1dSRodney W. Grimes 16299ed346baSBosko Milekic mtx_lock(&cr->cr_mtx); 1630bd78ceceSJohn Baldwin shared = (cr->cr_ref > 1); 16319ed346baSBosko Milekic mtx_unlock(&cr->cr_mtx); 1632bd78ceceSJohn Baldwin return (shared); 16331e5d626aSAlfred Perlstein } 1634bd78ceceSJohn Baldwin 1635bd78ceceSJohn Baldwin /* 1636bd78ceceSJohn Baldwin * Copy a ucred's contents from a template. Does not block. 1637bd78ceceSJohn Baldwin */ 1638bd78ceceSJohn Baldwin void 1639bd78ceceSJohn Baldwin crcopy(dest, src) 1640bd78ceceSJohn Baldwin struct ucred *dest, *src; 1641bd78ceceSJohn Baldwin { 1642bd78ceceSJohn Baldwin 1643bd78ceceSJohn Baldwin KASSERT(crshared(dest) == 0, ("crcopy of shared ucred")); 1644bd78ceceSJohn Baldwin bcopy(&src->cr_startcopy, &dest->cr_startcopy, 1645bd78ceceSJohn Baldwin (unsigned)((caddr_t)&src->cr_endcopy - 1646bd78ceceSJohn Baldwin (caddr_t)&src->cr_startcopy)); 1647bd78ceceSJohn Baldwin uihold(dest->cr_uidinfo); 1648bd78ceceSJohn Baldwin uihold(dest->cr_ruidinfo); 1649bd78ceceSJohn Baldwin if (jailed(dest)) 1650bd78ceceSJohn Baldwin prison_hold(dest->cr_prison); 1651df8bae1dSRodney W. Grimes } 1652df8bae1dSRodney W. Grimes 1653df8bae1dSRodney W. Grimes /* 1654df8bae1dSRodney W. Grimes * Dup cred struct to a new held one. 1655df8bae1dSRodney W. Grimes */ 1656df8bae1dSRodney W. Grimes struct ucred * 1657df8bae1dSRodney W. Grimes crdup(cr) 1658df8bae1dSRodney W. Grimes struct ucred *cr; 1659df8bae1dSRodney W. Grimes { 1660df8bae1dSRodney W. Grimes struct ucred *newcr; 1661df8bae1dSRodney W. Grimes 1662bd78ceceSJohn Baldwin newcr = crget(); 1663bd78ceceSJohn Baldwin crcopy(newcr, cr); 1664df8bae1dSRodney W. Grimes return (newcr); 1665df8bae1dSRodney W. Grimes } 1666df8bae1dSRodney W. Grimes 1667df8bae1dSRodney W. Grimes /* 1668df8bae1dSRodney W. Grimes * Get login name, if available. 1669df8bae1dSRodney W. Grimes */ 1670d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1671df8bae1dSRodney W. Grimes struct getlogin_args { 1672df8bae1dSRodney W. Grimes char *namebuf; 1673df8bae1dSRodney W. Grimes u_int namelen; 1674df8bae1dSRodney W. Grimes }; 1675d2d3e875SBruce Evans #endif 1676835a82eeSMatthew Dillon /* 1677835a82eeSMatthew Dillon * MPSAFE 1678835a82eeSMatthew Dillon */ 1679df8bae1dSRodney W. Grimes /* ARGSUSED */ 168026f9a767SRodney W. Grimes int 1681b40ce416SJulian Elischer getlogin(td, uap) 1682b40ce416SJulian Elischer struct thread *td; 1683df8bae1dSRodney W. Grimes struct getlogin_args *uap; 1684df8bae1dSRodney W. Grimes { 1685835a82eeSMatthew Dillon int error; 1686b40ce416SJulian Elischer struct proc *p = td->td_proc; 1687df8bae1dSRodney W. Grimes 1688835a82eeSMatthew Dillon mtx_lock(&Giant); 168930cf3ac4SAndrey A. Chernov if (uap->namelen > MAXLOGNAME) 169053490b76SAndrey A. Chernov uap->namelen = MAXLOGNAME; 1691835a82eeSMatthew Dillon error = copyout((caddr_t) p->p_pgrp->pg_session->s_login, 1692835a82eeSMatthew Dillon (caddr_t) uap->namebuf, uap->namelen); 1693835a82eeSMatthew Dillon mtx_unlock(&Giant); 1694835a82eeSMatthew Dillon return(error); 1695df8bae1dSRodney W. Grimes } 1696df8bae1dSRodney W. Grimes 1697df8bae1dSRodney W. Grimes /* 1698df8bae1dSRodney W. Grimes * Set login name. 1699df8bae1dSRodney W. Grimes */ 1700d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1701df8bae1dSRodney W. Grimes struct setlogin_args { 1702df8bae1dSRodney W. Grimes char *namebuf; 1703df8bae1dSRodney W. Grimes }; 1704d2d3e875SBruce Evans #endif 1705835a82eeSMatthew Dillon /* 1706835a82eeSMatthew Dillon * MPSAFE 1707835a82eeSMatthew Dillon */ 1708df8bae1dSRodney W. Grimes /* ARGSUSED */ 170926f9a767SRodney W. Grimes int 1710b40ce416SJulian Elischer setlogin(td, uap) 1711b40ce416SJulian Elischer struct thread *td; 1712df8bae1dSRodney W. Grimes struct setlogin_args *uap; 1713df8bae1dSRodney W. Grimes { 1714b40ce416SJulian Elischer struct proc *p = td->td_proc; 1715df8bae1dSRodney W. Grimes int error; 1716964ca0caSAndrey A. Chernov char logintmp[MAXLOGNAME]; 1717df8bae1dSRodney W. Grimes 1718835a82eeSMatthew Dillon mtx_lock(&Giant); 1719eb725b4eSRobert Watson if ((error = suser_xxx(0, p, PRISON_ROOT)) != 0) 1720835a82eeSMatthew Dillon goto done2; 1721184989c2SDavid Nugent error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 172210d4743fSDoug Rabson sizeof(logintmp), (size_t *)0); 1723eb725b4eSRobert Watson if (error == ENAMETOOLONG) 1724df8bae1dSRodney W. Grimes error = EINVAL; 1725eb725b4eSRobert Watson else if (!error) 1726184989c2SDavid Nugent (void)memcpy(p->p_pgrp->pg_session->s_login, logintmp, 1727964ca0caSAndrey A. Chernov sizeof(logintmp)); 1728835a82eeSMatthew Dillon done2: 1729835a82eeSMatthew Dillon mtx_unlock(&Giant); 1730df8bae1dSRodney W. Grimes return (error); 1731df8bae1dSRodney W. Grimes } 1732d5f81602SSean Eric Fagan 1733d5f81602SSean Eric Fagan void 1734d5f81602SSean Eric Fagan setsugid(p) 1735d5f81602SSean Eric Fagan struct proc *p; 1736d5f81602SSean Eric Fagan { 1737d5f81602SSean Eric Fagan p->p_flag |= P_SUGID; 173889361835SSean Eric Fagan if (!(p->p_pfsflags & PF_ISUGID)) 1739d5f81602SSean Eric Fagan p->p_stops = 0; 1740d5f81602SSean Eric Fagan } 1741f535380cSDon Lewis 17427fd6a959SRobert Watson /*- 17437fd6a959SRobert Watson * Change a process's effective uid. 1744b1fc0ec1SRobert Watson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified. 1745b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1746b1fc0ec1SRobert Watson * duration of the call. 1747f535380cSDon Lewis */ 1748f535380cSDon Lewis void 1749b1fc0ec1SRobert Watson change_euid(newcred, euid) 1750b1fc0ec1SRobert Watson struct ucred *newcred; 1751f535380cSDon Lewis uid_t euid; 1752f535380cSDon Lewis { 1753f535380cSDon Lewis 1754b1fc0ec1SRobert Watson newcred->cr_uid = euid; 1755b1fc0ec1SRobert Watson uifree(newcred->cr_uidinfo); 1756b1fc0ec1SRobert Watson newcred->cr_uidinfo = uifind(euid); 1757f535380cSDon Lewis } 1758f535380cSDon Lewis 17597fd6a959SRobert Watson /*- 17607fd6a959SRobert Watson * Change a process's effective gid. 1761b1fc0ec1SRobert Watson * Side effects: newcred->cr_gid will be modified. 1762b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1763b1fc0ec1SRobert Watson * duration of the call. 1764f535380cSDon Lewis */ 1765810bfc8eSAndrew Gallatin void 1766b1fc0ec1SRobert Watson change_egid(newcred, egid) 1767b1fc0ec1SRobert Watson struct ucred *newcred; 1768b1fc0ec1SRobert Watson gid_t egid; 1769b1fc0ec1SRobert Watson { 1770b1fc0ec1SRobert Watson 1771b1fc0ec1SRobert Watson newcred->cr_groups[0] = egid; 1772b1fc0ec1SRobert Watson } 1773b1fc0ec1SRobert Watson 17747fd6a959SRobert Watson /*- 17757fd6a959SRobert Watson * Change a process's real uid. 1776b1fc0ec1SRobert Watson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo 1777b1fc0ec1SRobert Watson * will be updated, and the old and new cr_ruidinfo proc 1778b1fc0ec1SRobert Watson * counts will be updated. 1779b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1780b1fc0ec1SRobert Watson * duration of the call. 1781b1fc0ec1SRobert Watson */ 1782b1fc0ec1SRobert Watson void 1783b1fc0ec1SRobert Watson change_ruid(newcred, ruid) 1784b1fc0ec1SRobert Watson struct ucred *newcred; 1785f535380cSDon Lewis uid_t ruid; 1786f535380cSDon Lewis { 1787f535380cSDon Lewis 1788b1fc0ec1SRobert Watson (void)chgproccnt(newcred->cr_ruidinfo, -1, 0); 1789b1fc0ec1SRobert Watson newcred->cr_ruid = ruid; 1790b1fc0ec1SRobert Watson uifree(newcred->cr_ruidinfo); 1791b1fc0ec1SRobert Watson newcred->cr_ruidinfo = uifind(ruid); 1792b1fc0ec1SRobert Watson (void)chgproccnt(newcred->cr_ruidinfo, 1, 0); 1793b1fc0ec1SRobert Watson } 1794b1fc0ec1SRobert Watson 17957fd6a959SRobert Watson /*- 17967fd6a959SRobert Watson * Change a process's real gid. 1797b1fc0ec1SRobert Watson * Side effects: newcred->cr_rgid will be updated. 1798b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1799b1fc0ec1SRobert Watson * duration of the call. 1800b1fc0ec1SRobert Watson */ 1801b1fc0ec1SRobert Watson void 1802b1fc0ec1SRobert Watson change_rgid(newcred, rgid) 1803b1fc0ec1SRobert Watson struct ucred *newcred; 1804b1fc0ec1SRobert Watson gid_t rgid; 1805b1fc0ec1SRobert Watson { 1806b1fc0ec1SRobert Watson 1807b1fc0ec1SRobert Watson newcred->cr_rgid = rgid; 1808b1fc0ec1SRobert Watson } 1809b1fc0ec1SRobert Watson 18107fd6a959SRobert Watson /*- 18117fd6a959SRobert Watson * Change a process's saved uid. 1812b1fc0ec1SRobert Watson * Side effects: newcred->cr_svuid will be updated. 1813b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1814b1fc0ec1SRobert Watson * duration of the call. 1815b1fc0ec1SRobert Watson */ 1816b1fc0ec1SRobert Watson void 1817b1fc0ec1SRobert Watson change_svuid(newcred, svuid) 1818b1fc0ec1SRobert Watson struct ucred *newcred; 1819b1fc0ec1SRobert Watson uid_t svuid; 1820b1fc0ec1SRobert Watson { 1821b1fc0ec1SRobert Watson 1822b1fc0ec1SRobert Watson newcred->cr_svuid = svuid; 1823b1fc0ec1SRobert Watson } 1824b1fc0ec1SRobert Watson 18257fd6a959SRobert Watson /*- 18267fd6a959SRobert Watson * Change a process's saved gid. 1827b1fc0ec1SRobert Watson * Side effects: newcred->cr_svgid will be updated. 1828b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1829b1fc0ec1SRobert Watson * duration of the call. 1830b1fc0ec1SRobert Watson */ 1831b1fc0ec1SRobert Watson void 1832b1fc0ec1SRobert Watson change_svgid(newcred, svgid) 1833b1fc0ec1SRobert Watson struct ucred *newcred; 1834b1fc0ec1SRobert Watson gid_t svgid; 1835b1fc0ec1SRobert Watson { 1836b1fc0ec1SRobert Watson 1837b1fc0ec1SRobert Watson newcred->cr_svgid = svgid; 1838f535380cSDon Lewis } 1839