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. 4db42a33dSRobert Watson * Copyright (c) 2000-2001 Robert N. M. Watson. All rights reserved. 5df8bae1dSRodney W. Grimes * (c) UNIX System Laboratories, Inc. 6db42a33dSRobert Watson * 7df8bae1dSRodney W. Grimes * All or some portions of this file are derived from material licensed 8df8bae1dSRodney W. Grimes * to the University of California by American Telephone and Telegraph 9df8bae1dSRodney W. Grimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10df8bae1dSRodney W. Grimes * the permission of UNIX System Laboratories, Inc. 11df8bae1dSRodney W. Grimes * 12df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 13df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 14df8bae1dSRodney W. Grimes * are met: 15df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 17df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 18df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 19df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 20df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 21df8bae1dSRodney W. Grimes * must display the following acknowledgement: 22df8bae1dSRodney W. Grimes * This product includes software developed by the University of 23df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 24df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 25df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 26df8bae1dSRodney W. Grimes * without specific prior written permission. 27df8bae1dSRodney W. Grimes * 28df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38df8bae1dSRodney W. Grimes * SUCH DAMAGE. 39df8bae1dSRodney W. Grimes * 40df8bae1dSRodney W. Grimes * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 41c3aac50fSPeter Wemm * $FreeBSD$ 42df8bae1dSRodney W. Grimes */ 43df8bae1dSRodney W. Grimes 44df8bae1dSRodney W. Grimes /* 45df8bae1dSRodney W. Grimes * System calls related to processes and protection 46df8bae1dSRodney W. Grimes */ 47df8bae1dSRodney W. Grimes 485591b823SEivind Eklund #include "opt_compat.h" 49130d0157SRobert Watson #include "opt_global.h" 505591b823SEivind Eklund 51df8bae1dSRodney W. Grimes #include <sys/param.h> 52df8bae1dSRodney W. Grimes #include <sys/systm.h> 53fb919e4dSMark Murray #include <sys/acct.h> 541c5bb3eaSPeter Wemm #include <sys/kernel.h> 5598f03f90SJake Burkholder #include <sys/lock.h> 56fb919e4dSMark Murray #include <sys/mutex.h> 57df8bae1dSRodney W. Grimes #include <sys/proc.h> 585b29d6e9SJohn Baldwin #include <sys/sx.h> 59fb919e4dSMark Murray #include <sys/sysproto.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> 6491421ba2SRobert Watson #include <sys/jail.h> 65df8bae1dSRodney W. Grimes 66a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_CRED, "cred", "credentials"); 67a1c995b6SPoul-Henning Kamp 680ef5652eSRobert Watson SYSCTL_NODE(_kern, OID_AUTO, security, CTLFLAG_RW, 0, 690ef5652eSRobert Watson "Kernel security policy"); 700ef5652eSRobert Watson 71d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 72ad7507e2SSteven Wallace struct getpid_args { 73df8bae1dSRodney W. Grimes int dummy; 74df8bae1dSRodney W. Grimes }; 75d2d3e875SBruce Evans #endif 76df8bae1dSRodney W. Grimes 7736e9f877SMatthew Dillon /* 78835a82eeSMatthew Dillon * getpid 7936e9f877SMatthew Dillon */ 8098f03f90SJake Burkholder 81835a82eeSMatthew Dillon /* 82835a82eeSMatthew Dillon * MPSAFE 83835a82eeSMatthew Dillon */ 84df8bae1dSRodney W. Grimes /* ARGSUSED */ 8526f9a767SRodney W. Grimes int 86b40ce416SJulian Elischer getpid(td, uap) 87b40ce416SJulian Elischer struct thread *td; 88ad7507e2SSteven Wallace struct getpid_args *uap; 89df8bae1dSRodney W. Grimes { 90b40ce416SJulian Elischer struct proc *p = td->td_proc; 91d23f5958SMatthew Dillon int s; 92df8bae1dSRodney W. Grimes 93d23f5958SMatthew Dillon s = mtx_lock_giant(kern_giant_proc); 94b40ce416SJulian Elischer td->td_retval[0] = p->p_pid; 95df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 96bae3a80bSJohn Baldwin PROC_LOCK(p); 97b40ce416SJulian Elischer td->td_retval[1] = p->p_pptr->p_pid; 98bae3a80bSJohn Baldwin PROC_UNLOCK(p); 99df8bae1dSRodney W. Grimes #endif 100d23f5958SMatthew Dillon mtx_unlock_giant(s); 101df8bae1dSRodney W. Grimes return (0); 102df8bae1dSRodney W. Grimes } 103df8bae1dSRodney W. Grimes 10498f03f90SJake Burkholder /* 105835a82eeSMatthew Dillon * getppid 10698f03f90SJake Burkholder */ 10798f03f90SJake Burkholder 108d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 109ad7507e2SSteven Wallace struct getppid_args { 110ad7507e2SSteven Wallace int dummy; 111ad7507e2SSteven Wallace }; 112d2d3e875SBruce Evans #endif 113835a82eeSMatthew Dillon /* 114835a82eeSMatthew Dillon * MPSAFE 115835a82eeSMatthew Dillon */ 116df8bae1dSRodney W. Grimes /* ARGSUSED */ 11726f9a767SRodney W. Grimes int 118b40ce416SJulian Elischer getppid(td, uap) 119b40ce416SJulian Elischer struct thread *td; 120ad7507e2SSteven Wallace struct getppid_args *uap; 121df8bae1dSRodney W. Grimes { 122b40ce416SJulian Elischer struct proc *p = td->td_proc; 123d23f5958SMatthew Dillon int s; 124df8bae1dSRodney W. Grimes 125d23f5958SMatthew Dillon s = mtx_lock_giant(kern_giant_proc); 126bae3a80bSJohn Baldwin PROC_LOCK(p); 127b40ce416SJulian Elischer td->td_retval[0] = p->p_pptr->p_pid; 128bae3a80bSJohn Baldwin PROC_UNLOCK(p); 129d23f5958SMatthew Dillon mtx_unlock_giant(s); 130df8bae1dSRodney W. Grimes return (0); 131df8bae1dSRodney W. Grimes } 132df8bae1dSRodney W. Grimes 13336e9f877SMatthew Dillon /* 13436e9f877SMatthew Dillon * Get process group ID; note that POSIX getpgrp takes no parameter 13536e9f877SMatthew Dillon * 13636e9f877SMatthew Dillon * MP SAFE 13736e9f877SMatthew Dillon */ 138d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 139ad7507e2SSteven Wallace struct getpgrp_args { 140ad7507e2SSteven Wallace int dummy; 141ad7507e2SSteven Wallace }; 142d2d3e875SBruce Evans #endif 143835a82eeSMatthew Dillon /* 144835a82eeSMatthew Dillon * MPSAFE 145835a82eeSMatthew Dillon */ 14626f9a767SRodney W. Grimes int 147b40ce416SJulian Elischer getpgrp(td, uap) 148b40ce416SJulian Elischer struct thread *td; 149ad7507e2SSteven Wallace struct getpgrp_args *uap; 150df8bae1dSRodney W. Grimes { 151b40ce416SJulian Elischer struct proc *p = td->td_proc; 152df8bae1dSRodney W. Grimes 153835a82eeSMatthew Dillon mtx_lock(&Giant); 154b40ce416SJulian Elischer td->td_retval[0] = p->p_pgrp->pg_id; 155835a82eeSMatthew Dillon mtx_unlock(&Giant); 156df8bae1dSRodney W. Grimes return (0); 157df8bae1dSRodney W. Grimes } 158df8bae1dSRodney W. Grimes 1591a5018a0SPeter Wemm /* Get an arbitary pid's process group id */ 1601a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1611a5018a0SPeter Wemm struct getpgid_args { 1621a5018a0SPeter Wemm pid_t pid; 1631a5018a0SPeter Wemm }; 1641a5018a0SPeter Wemm #endif 1651a5018a0SPeter Wemm 166835a82eeSMatthew Dillon /* 167835a82eeSMatthew Dillon * MPSAFE 168835a82eeSMatthew Dillon */ 1691a5018a0SPeter Wemm int 170b40ce416SJulian Elischer getpgid(td, uap) 171b40ce416SJulian Elischer struct thread *td; 1721a5018a0SPeter Wemm struct getpgid_args *uap; 1731a5018a0SPeter Wemm { 174b40ce416SJulian Elischer struct proc *p = td->td_proc; 17565de0c7aSDon Lewis struct proc *pt; 176835a82eeSMatthew Dillon int error = 0; 177d23f5958SMatthew Dillon int s; 17865de0c7aSDon Lewis 179d23f5958SMatthew Dillon s = mtx_lock_giant(kern_giant_proc); 1801a5018a0SPeter Wemm if (uap->pid == 0) 181b40ce416SJulian Elischer td->td_retval[0] = p->p_pgrp->pg_id; 1826a90c862SJohn Baldwin else if ((pt = pfind(uap->pid)) == NULL) 183835a82eeSMatthew Dillon error = ESRCH; 1846a90c862SJohn Baldwin else { 1856a90c862SJohn Baldwin error = p_cansee(p, pt); 1866a90c862SJohn Baldwin if (error == 0) 187b40ce416SJulian Elischer td->td_retval[0] = pt->p_pgrp->pg_id; 18833a9ed9dSJohn Baldwin PROC_UNLOCK(pt); 18933a9ed9dSJohn Baldwin } 190d23f5958SMatthew Dillon mtx_unlock_giant(s); 191835a82eeSMatthew Dillon return (error); 1921a5018a0SPeter Wemm } 1931a5018a0SPeter Wemm 1941a5018a0SPeter Wemm /* 1951a5018a0SPeter Wemm * Get an arbitary pid's session id. 1961a5018a0SPeter Wemm */ 1971a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1981a5018a0SPeter Wemm struct getsid_args { 1991a5018a0SPeter Wemm pid_t pid; 2001a5018a0SPeter Wemm }; 2011a5018a0SPeter Wemm #endif 2021a5018a0SPeter Wemm 203835a82eeSMatthew Dillon /* 204835a82eeSMatthew Dillon * MPSAFE 205835a82eeSMatthew Dillon */ 2061a5018a0SPeter Wemm int 207b40ce416SJulian Elischer getsid(td, uap) 208b40ce416SJulian Elischer struct thread *td; 2091a5018a0SPeter Wemm struct getsid_args *uap; 2101a5018a0SPeter Wemm { 211b40ce416SJulian Elischer struct proc *p = td->td_proc; 21265de0c7aSDon Lewis struct proc *pt; 213835a82eeSMatthew Dillon int error = 0; 21465de0c7aSDon Lewis 215835a82eeSMatthew Dillon mtx_lock(&Giant); 2166a90c862SJohn Baldwin if (uap->pid == 0) 217b40ce416SJulian Elischer td->td_retval[0] = p->p_session->s_sid; 2186a90c862SJohn Baldwin else if ((pt = pfind(uap->pid)) == NULL) 219835a82eeSMatthew Dillon error = ESRCH; 2206a90c862SJohn Baldwin else { 2216a90c862SJohn Baldwin error = p_cansee(p, pt); 2226a90c862SJohn Baldwin if (error == 0) 223b40ce416SJulian Elischer td->td_retval[0] = pt->p_session->s_sid; 22433a9ed9dSJohn Baldwin PROC_UNLOCK(pt); 22533a9ed9dSJohn Baldwin } 226835a82eeSMatthew Dillon mtx_unlock(&Giant); 227835a82eeSMatthew Dillon return (error); 2281a5018a0SPeter Wemm } 2291a5018a0SPeter Wemm 2301a5018a0SPeter Wemm 2317c8fdcbdSMatthew Dillon /* 2327c8fdcbdSMatthew Dillon * getuid() - MP SAFE 2337c8fdcbdSMatthew Dillon */ 234d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 235ad7507e2SSteven Wallace struct getuid_args { 236ad7507e2SSteven Wallace int dummy; 237ad7507e2SSteven Wallace }; 238d2d3e875SBruce Evans #endif 239ad7507e2SSteven Wallace 240835a82eeSMatthew Dillon /* 241835a82eeSMatthew Dillon * MPSAFE 242835a82eeSMatthew Dillon */ 243df8bae1dSRodney W. Grimes /* ARGSUSED */ 24426f9a767SRodney W. Grimes int 245b40ce416SJulian Elischer getuid(td, uap) 246b40ce416SJulian Elischer struct thread *td; 247ad7507e2SSteven Wallace struct getuid_args *uap; 248df8bae1dSRodney W. Grimes { 249b40ce416SJulian Elischer struct proc *p = td->td_proc; 250df8bae1dSRodney W. Grimes 251835a82eeSMatthew Dillon mtx_lock(&Giant); 252b40ce416SJulian Elischer td->td_retval[0] = p->p_ucred->cr_ruid; 253df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 254b40ce416SJulian Elischer td->td_retval[1] = p->p_ucred->cr_uid; 255df8bae1dSRodney W. Grimes #endif 256835a82eeSMatthew Dillon mtx_unlock(&Giant); 257df8bae1dSRodney W. Grimes return (0); 258df8bae1dSRodney W. Grimes } 259df8bae1dSRodney W. Grimes 2607c8fdcbdSMatthew Dillon /* 2617c8fdcbdSMatthew Dillon * geteuid() - MP SAFE 2627c8fdcbdSMatthew Dillon */ 263d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 264ad7507e2SSteven Wallace struct geteuid_args { 265ad7507e2SSteven Wallace int dummy; 266ad7507e2SSteven Wallace }; 267d2d3e875SBruce Evans #endif 268ad7507e2SSteven Wallace 269df8bae1dSRodney W. Grimes /* ARGSUSED */ 27026f9a767SRodney W. Grimes int 271b40ce416SJulian Elischer geteuid(td, uap) 272b40ce416SJulian Elischer struct thread *td; 273ad7507e2SSteven Wallace struct geteuid_args *uap; 274df8bae1dSRodney W. Grimes { 275835a82eeSMatthew Dillon mtx_lock(&Giant); 276b40ce416SJulian Elischer td->td_retval[0] = td->td_proc->p_ucred->cr_uid; 277835a82eeSMatthew Dillon mtx_unlock(&Giant); 278df8bae1dSRodney W. Grimes return (0); 279df8bae1dSRodney W. Grimes } 280df8bae1dSRodney W. Grimes 2817c8fdcbdSMatthew Dillon /* 2827c8fdcbdSMatthew Dillon * getgid() - MP SAFE 2837c8fdcbdSMatthew Dillon */ 284d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 285ad7507e2SSteven Wallace struct getgid_args { 286ad7507e2SSteven Wallace int dummy; 287ad7507e2SSteven Wallace }; 288d2d3e875SBruce Evans #endif 289ad7507e2SSteven Wallace 290835a82eeSMatthew Dillon /* 291835a82eeSMatthew Dillon * MPSAFE 292835a82eeSMatthew Dillon */ 293df8bae1dSRodney W. Grimes /* ARGSUSED */ 29426f9a767SRodney W. Grimes int 295b40ce416SJulian Elischer getgid(td, uap) 296b40ce416SJulian Elischer struct thread *td; 297ad7507e2SSteven Wallace struct getgid_args *uap; 298df8bae1dSRodney W. Grimes { 299b40ce416SJulian Elischer struct proc *p = td->td_proc; 300df8bae1dSRodney W. Grimes 301835a82eeSMatthew Dillon mtx_lock(&Giant); 302b40ce416SJulian Elischer td->td_retval[0] = p->p_ucred->cr_rgid; 303df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 304b40ce416SJulian Elischer td->td_retval[1] = p->p_ucred->cr_groups[0]; 305df8bae1dSRodney W. Grimes #endif 306835a82eeSMatthew Dillon mtx_unlock(&Giant); 307df8bae1dSRodney W. Grimes return (0); 308df8bae1dSRodney W. Grimes } 309df8bae1dSRodney W. Grimes 310df8bae1dSRodney W. Grimes /* 311df8bae1dSRodney W. Grimes * Get effective group ID. The "egid" is groups[0], and could be obtained 312df8bae1dSRodney W. Grimes * via getgroups. This syscall exists because it is somewhat painful to do 313df8bae1dSRodney W. Grimes * correctly in a library function. 314df8bae1dSRodney W. Grimes */ 315d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 316ad7507e2SSteven Wallace struct getegid_args { 317ad7507e2SSteven Wallace int dummy; 318ad7507e2SSteven Wallace }; 319d2d3e875SBruce Evans #endif 320ad7507e2SSteven Wallace 321835a82eeSMatthew Dillon /* 322835a82eeSMatthew Dillon * MPSAFE 323835a82eeSMatthew Dillon */ 324df8bae1dSRodney W. Grimes /* ARGSUSED */ 32526f9a767SRodney W. Grimes int 326b40ce416SJulian Elischer getegid(td, uap) 327b40ce416SJulian Elischer struct thread *td; 328ad7507e2SSteven Wallace struct getegid_args *uap; 329df8bae1dSRodney W. Grimes { 330b40ce416SJulian Elischer struct proc *p = td->td_proc; 331df8bae1dSRodney W. Grimes 332835a82eeSMatthew Dillon mtx_lock(&Giant); 333b40ce416SJulian Elischer td->td_retval[0] = p->p_ucred->cr_groups[0]; 334835a82eeSMatthew Dillon mtx_unlock(&Giant); 335df8bae1dSRodney W. Grimes return (0); 336df8bae1dSRodney W. Grimes } 337df8bae1dSRodney W. Grimes 338d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 339df8bae1dSRodney W. Grimes struct getgroups_args { 340df8bae1dSRodney W. Grimes u_int gidsetsize; 341df8bae1dSRodney W. Grimes gid_t *gidset; 342df8bae1dSRodney W. Grimes }; 343d2d3e875SBruce Evans #endif 344835a82eeSMatthew Dillon /* 345835a82eeSMatthew Dillon * MPSAFE 346835a82eeSMatthew Dillon */ 34726f9a767SRodney W. Grimes int 348b40ce416SJulian Elischer getgroups(td, uap) 349b40ce416SJulian Elischer struct thread *td; 350df8bae1dSRodney W. Grimes register struct getgroups_args *uap; 351df8bae1dSRodney W. Grimes { 352835a82eeSMatthew Dillon struct ucred *cred; 353b40ce416SJulian Elischer struct proc *p = td->td_proc; 354b1fc0ec1SRobert Watson u_int ngrp; 355835a82eeSMatthew Dillon int error = 0; 356df8bae1dSRodney W. Grimes 357835a82eeSMatthew Dillon mtx_lock(&Giant); 358835a82eeSMatthew Dillon cred = p->p_ucred; 359df8bae1dSRodney W. Grimes if ((ngrp = uap->gidsetsize) == 0) { 360b40ce416SJulian Elischer td->td_retval[0] = cred->cr_ngroups; 361835a82eeSMatthew Dillon error = 0; 362835a82eeSMatthew Dillon goto done2; 363df8bae1dSRodney W. Grimes } 364835a82eeSMatthew Dillon if (ngrp < cred->cr_ngroups) { 365835a82eeSMatthew Dillon error = EINVAL; 366835a82eeSMatthew Dillon goto done2; 367835a82eeSMatthew Dillon } 368b1fc0ec1SRobert Watson ngrp = cred->cr_ngroups; 369b1fc0ec1SRobert Watson if ((error = copyout((caddr_t)cred->cr_groups, 370835a82eeSMatthew Dillon (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))) { 371835a82eeSMatthew Dillon goto done2; 372835a82eeSMatthew Dillon } 373b40ce416SJulian Elischer td->td_retval[0] = ngrp; 374835a82eeSMatthew Dillon done2: 375835a82eeSMatthew Dillon mtx_unlock(&Giant); 376835a82eeSMatthew Dillon return (error); 377df8bae1dSRodney W. Grimes } 378df8bae1dSRodney W. Grimes 379d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 38082970b81SBruce Evans struct setsid_args { 381ad7507e2SSteven Wallace int dummy; 382ad7507e2SSteven Wallace }; 383d2d3e875SBruce Evans #endif 384ad7507e2SSteven Wallace 385835a82eeSMatthew Dillon /* 386835a82eeSMatthew Dillon * MPSAFE 387835a82eeSMatthew Dillon */ 388df8bae1dSRodney W. Grimes /* ARGSUSED */ 38926f9a767SRodney W. Grimes int 390b40ce416SJulian Elischer setsid(td, uap) 391b40ce416SJulian Elischer register struct thread *td; 39282970b81SBruce Evans struct setsid_args *uap; 393df8bae1dSRodney W. Grimes { 394835a82eeSMatthew Dillon int error; 395b40ce416SJulian Elischer struct proc *p = td->td_proc; 396df8bae1dSRodney W. Grimes 397835a82eeSMatthew Dillon mtx_lock(&Giant); 398df8bae1dSRodney W. Grimes if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 399835a82eeSMatthew Dillon error = EPERM; 400df8bae1dSRodney W. Grimes } else { 401df8bae1dSRodney W. Grimes (void)enterpgrp(p, p->p_pid, 1); 402b40ce416SJulian Elischer td->td_retval[0] = p->p_pid; 403835a82eeSMatthew Dillon error = 0; 404df8bae1dSRodney W. Grimes } 405835a82eeSMatthew Dillon mtx_unlock(&Giant); 406835a82eeSMatthew Dillon return (error); 407df8bae1dSRodney W. Grimes } 408df8bae1dSRodney W. Grimes 409df8bae1dSRodney W. Grimes /* 410df8bae1dSRodney W. Grimes * set process group (setpgid/old setpgrp) 411df8bae1dSRodney W. Grimes * 412df8bae1dSRodney W. Grimes * caller does setpgid(targpid, targpgid) 413df8bae1dSRodney W. Grimes * 414df8bae1dSRodney W. Grimes * pid must be caller or child of caller (ESRCH) 415df8bae1dSRodney W. Grimes * if a child 416df8bae1dSRodney W. Grimes * pid must be in same session (EPERM) 417df8bae1dSRodney W. Grimes * pid can't have done an exec (EACCES) 418df8bae1dSRodney W. Grimes * if pgid != pid 419df8bae1dSRodney W. Grimes * there must exist some pid in same session having pgid (EPERM) 420df8bae1dSRodney W. Grimes * pid must not be session leader (EPERM) 421df8bae1dSRodney W. Grimes */ 422d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 423df8bae1dSRodney W. Grimes struct setpgid_args { 424df8bae1dSRodney W. Grimes int pid; /* target process id */ 425df8bae1dSRodney W. Grimes int pgid; /* target pgrp id */ 426df8bae1dSRodney W. Grimes }; 427d2d3e875SBruce Evans #endif 428835a82eeSMatthew Dillon /* 429835a82eeSMatthew Dillon * MPSAFE 430835a82eeSMatthew Dillon */ 431df8bae1dSRodney W. Grimes /* ARGSUSED */ 43226f9a767SRodney W. Grimes int 433b40ce416SJulian Elischer setpgid(td, uap) 434b40ce416SJulian Elischer struct thread *td; 435df8bae1dSRodney W. Grimes register struct setpgid_args *uap; 436df8bae1dSRodney W. Grimes { 437b40ce416SJulian Elischer struct proc *curp = td->td_proc; 438df8bae1dSRodney W. Grimes register struct proc *targp; /* target process */ 439df8bae1dSRodney W. Grimes register struct pgrp *pgrp; /* target pgrp */ 440eb9e5c1dSRobert Watson int error; 441df8bae1dSRodney W. Grimes 44278f64bccSBruce Evans if (uap->pgid < 0) 44378f64bccSBruce Evans return (EINVAL); 444835a82eeSMatthew Dillon 445835a82eeSMatthew Dillon mtx_lock(&Giant); 446835a82eeSMatthew Dillon 4475b29d6e9SJohn Baldwin sx_slock(&proctree_lock); 448df8bae1dSRodney W. Grimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 44933a9ed9dSJohn Baldwin if ((targp = pfind(uap->pid)) == NULL || !inferior(targp)) { 45033a9ed9dSJohn Baldwin if (targp) 45133a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 452835a82eeSMatthew Dillon error = ESRCH; 453835a82eeSMatthew Dillon goto done2; 45433a9ed9dSJohn Baldwin } 455a0f75161SRobert Watson if ((error = p_cansee(curproc, targp))) { 45633a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 457835a82eeSMatthew Dillon goto done2; 45833a9ed9dSJohn Baldwin } 45933a9ed9dSJohn Baldwin if (targp->p_pgrp == NULL || 46033a9ed9dSJohn Baldwin targp->p_session != curp->p_session) { 46133a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 462835a82eeSMatthew Dillon error = EPERM; 463835a82eeSMatthew Dillon goto done2; 46433a9ed9dSJohn Baldwin } 46533a9ed9dSJohn Baldwin if (targp->p_flag & P_EXEC) { 46633a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 467835a82eeSMatthew Dillon error = EACCES; 468835a82eeSMatthew Dillon goto done2; 46933a9ed9dSJohn Baldwin } 47033a9ed9dSJohn Baldwin } else { 471df8bae1dSRodney W. Grimes targp = curp; 47233a9ed9dSJohn Baldwin PROC_LOCK(curp); /* XXX: not needed */ 47333a9ed9dSJohn Baldwin } 47433a9ed9dSJohn Baldwin if (SESS_LEADER(targp)) { 47533a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 476835a82eeSMatthew Dillon error = EPERM; 477835a82eeSMatthew Dillon goto done2; 47833a9ed9dSJohn Baldwin } 479835a82eeSMatthew Dillon if (uap->pgid == 0) { 480df8bae1dSRodney W. Grimes uap->pgid = targp->p_pid; 481835a82eeSMatthew Dillon } else if (uap->pgid != targp->p_pid) { 482df8bae1dSRodney W. Grimes if ((pgrp = pgfind(uap->pgid)) == 0 || 48333a9ed9dSJohn Baldwin pgrp->pg_session != curp->p_session) { 48433a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 485835a82eeSMatthew Dillon error = EPERM; 486835a82eeSMatthew Dillon goto done2; 487835a82eeSMatthew Dillon } 48833a9ed9dSJohn Baldwin } 48933a9ed9dSJohn Baldwin /* XXX: We should probably hold the lock across enterpgrp. */ 49033a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 491835a82eeSMatthew Dillon error = enterpgrp(targp, uap->pgid, 0); 492835a82eeSMatthew Dillon done2: 4935b29d6e9SJohn Baldwin sx_sunlock(&proctree_lock); 494835a82eeSMatthew Dillon mtx_unlock(&Giant); 495835a82eeSMatthew Dillon return (error); 496df8bae1dSRodney W. Grimes } 497df8bae1dSRodney W. Grimes 498a08f4bf6SPeter Wemm /* 499a08f4bf6SPeter Wemm * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 5002fa72ea7SJeroen Ruigrok van der Werven * compatible. It says that setting the uid/gid to euid/egid is a special 501a08f4bf6SPeter Wemm * case of "appropriate privilege". Once the rules are expanded out, this 502a08f4bf6SPeter Wemm * basically means that setuid(nnn) sets all three id's, in all permitted 503a08f4bf6SPeter Wemm * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 504a08f4bf6SPeter Wemm * does not set the saved id - this is dangerous for traditional BSD 505a08f4bf6SPeter Wemm * programs. For this reason, we *really* do not want to set 506a08f4bf6SPeter Wemm * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 507a08f4bf6SPeter Wemm */ 508a08f4bf6SPeter Wemm #define POSIX_APPENDIX_B_4_2_2 509a08f4bf6SPeter Wemm 510d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 511df8bae1dSRodney W. Grimes struct setuid_args { 512df8bae1dSRodney W. Grimes uid_t uid; 513df8bae1dSRodney W. Grimes }; 514d2d3e875SBruce Evans #endif 515835a82eeSMatthew Dillon /* 516835a82eeSMatthew Dillon * MPSAFE 517835a82eeSMatthew Dillon */ 518df8bae1dSRodney W. Grimes /* ARGSUSED */ 51926f9a767SRodney W. Grimes int 520b40ce416SJulian Elischer setuid(td, uap) 521b40ce416SJulian Elischer struct thread *td; 522df8bae1dSRodney W. Grimes struct setuid_args *uap; 523df8bae1dSRodney W. Grimes { 524b40ce416SJulian Elischer struct proc *p = td->td_proc; 525b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 526b1fc0ec1SRobert Watson uid_t uid; 527835a82eeSMatthew Dillon int error = 0; 528df8bae1dSRodney W. Grimes 529b1fc0ec1SRobert Watson uid = uap->uid; 530b1fc0ec1SRobert Watson oldcred = p->p_ucred; 531835a82eeSMatthew Dillon mtx_lock(&Giant); 532835a82eeSMatthew Dillon 533a08f4bf6SPeter Wemm /* 534a08f4bf6SPeter Wemm * See if we have "permission" by POSIX 1003.1 rules. 535a08f4bf6SPeter Wemm * 536a08f4bf6SPeter Wemm * Note that setuid(geteuid()) is a special case of 537a08f4bf6SPeter Wemm * "appropriate privileges" in appendix B.4.2.2. We need 5382fa72ea7SJeroen Ruigrok van der Werven * to use this clause to be compatible with traditional BSD 539a08f4bf6SPeter Wemm * semantics. Basically, it means that "setuid(xx)" sets all 540a08f4bf6SPeter Wemm * three id's (assuming you have privs). 541a08f4bf6SPeter Wemm * 542a08f4bf6SPeter Wemm * Notes on the logic. We do things in three steps. 543a08f4bf6SPeter Wemm * 1: We determine if the euid is going to change, and do EPERM 544a08f4bf6SPeter Wemm * right away. We unconditionally change the euid later if this 545a08f4bf6SPeter Wemm * test is satisfied, simplifying that part of the logic. 546a08f4bf6SPeter Wemm * 2: We determine if the real and/or saved uid's are going to 547a08f4bf6SPeter Wemm * change. Determined by compile options. 548a08f4bf6SPeter Wemm * 3: Change euid last. (after tests in #2 for "appropriate privs") 549a08f4bf6SPeter Wemm */ 550b1fc0ec1SRobert Watson if (uid != oldcred->cr_ruid && /* allow setuid(getuid()) */ 5513f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS 552b1fc0ec1SRobert Watson uid != oldcred->cr_svuid && /* allow setuid(saved gid) */ 553a08f4bf6SPeter Wemm #endif 554a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 555b1fc0ec1SRobert Watson uid != oldcred->cr_uid && /* allow setuid(geteuid()) */ 5563f246666SAndrey A. Chernov #endif 557b1fc0ec1SRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) 558835a82eeSMatthew Dillon goto done2; 559a08f4bf6SPeter Wemm 560b1fc0ec1SRobert Watson newcred = crdup(oldcred); 561a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS 562df8bae1dSRodney W. Grimes /* 563a08f4bf6SPeter Wemm * Do we have "appropriate privileges" (are we root or uid == euid) 564a08f4bf6SPeter Wemm * If so, we are changing the real uid and/or saved uid. 565df8bae1dSRodney W. Grimes */ 5663f246666SAndrey A. Chernov if ( 567a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 568b1fc0ec1SRobert Watson uid == oldcred->cr_uid || 5693f246666SAndrey A. Chernov #endif 570b1fc0ec1SRobert Watson suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */ 571a08f4bf6SPeter Wemm #endif 572a08f4bf6SPeter Wemm { 573a08f4bf6SPeter Wemm /* 574f535380cSDon Lewis * Set the real uid and transfer proc count to new user. 575a08f4bf6SPeter Wemm */ 576b1fc0ec1SRobert Watson if (uid != oldcred->cr_ruid) { 577b1fc0ec1SRobert Watson change_ruid(newcred, uid); 578f535380cSDon Lewis setsugid(p); 579d3cdb93dSAndrey A. Chernov } 580a08f4bf6SPeter Wemm /* 581a08f4bf6SPeter Wemm * Set saved uid 582a08f4bf6SPeter Wemm * 583a08f4bf6SPeter Wemm * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 584a08f4bf6SPeter Wemm * the security of seteuid() depends on it. B.4.2.2 says it 585a08f4bf6SPeter Wemm * is important that we should do this. 586a08f4bf6SPeter Wemm */ 587b1fc0ec1SRobert Watson if (uid != oldcred->cr_svuid) { 588b1fc0ec1SRobert Watson change_svuid(newcred, uid); 589d5f81602SSean Eric Fagan setsugid(p); 590a08f4bf6SPeter Wemm } 591a08f4bf6SPeter Wemm } 592a08f4bf6SPeter Wemm 593a08f4bf6SPeter Wemm /* 594a08f4bf6SPeter Wemm * In all permitted cases, we are changing the euid. 595a08f4bf6SPeter Wemm * Copy credentials so other references do not see our changes. 596a08f4bf6SPeter Wemm */ 597b1fc0ec1SRobert Watson if (uid != oldcred->cr_uid) { 598b1fc0ec1SRobert Watson change_euid(newcred, uid); 599d5f81602SSean Eric Fagan setsugid(p); 600a08f4bf6SPeter Wemm } 601b1fc0ec1SRobert Watson p->p_ucred = newcred; 602b1fc0ec1SRobert Watson crfree(oldcred); 603835a82eeSMatthew Dillon done2: 604835a82eeSMatthew Dillon mtx_unlock(&Giant); 605835a82eeSMatthew Dillon return (error); 606df8bae1dSRodney W. Grimes } 607df8bae1dSRodney W. Grimes 608d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 609df8bae1dSRodney W. Grimes struct seteuid_args { 610df8bae1dSRodney W. Grimes uid_t euid; 611df8bae1dSRodney W. Grimes }; 612d2d3e875SBruce Evans #endif 613835a82eeSMatthew Dillon /* 614835a82eeSMatthew Dillon * MPSAFE 615835a82eeSMatthew Dillon */ 616df8bae1dSRodney W. Grimes /* ARGSUSED */ 61726f9a767SRodney W. Grimes int 618b40ce416SJulian Elischer seteuid(td, uap) 619b40ce416SJulian Elischer struct thread *td; 620df8bae1dSRodney W. Grimes struct seteuid_args *uap; 621df8bae1dSRodney W. Grimes { 622b40ce416SJulian Elischer struct proc *p = td->td_proc; 623b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 624b1fc0ec1SRobert Watson uid_t euid; 625835a82eeSMatthew Dillon int error = 0; 626df8bae1dSRodney W. Grimes 627df8bae1dSRodney W. Grimes euid = uap->euid; 628835a82eeSMatthew Dillon 629835a82eeSMatthew Dillon mtx_lock(&Giant); 630b1fc0ec1SRobert Watson oldcred = p->p_ucred; 631b1fc0ec1SRobert Watson if (euid != oldcred->cr_ruid && /* allow seteuid(getuid()) */ 632b1fc0ec1SRobert Watson euid != oldcred->cr_svuid && /* allow seteuid(saved uid) */ 633835a82eeSMatthew Dillon (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) { 634835a82eeSMatthew Dillon goto done2; 635835a82eeSMatthew Dillon } 636df8bae1dSRodney W. Grimes /* 637df8bae1dSRodney W. Grimes * Everything's okay, do it. Copy credentials so other references do 638df8bae1dSRodney W. Grimes * not see our changes. 639df8bae1dSRodney W. Grimes */ 640b1fc0ec1SRobert Watson newcred = crdup(oldcred); 641b1fc0ec1SRobert Watson if (oldcred->cr_uid != euid) { 642b1fc0ec1SRobert Watson change_euid(newcred, euid); 643d5f81602SSean Eric Fagan setsugid(p); 644229a15f0SPeter Wemm } 645b1fc0ec1SRobert Watson p->p_ucred = newcred; 646b1fc0ec1SRobert Watson crfree(oldcred); 647835a82eeSMatthew Dillon done2: 648835a82eeSMatthew Dillon mtx_unlock(&Giant); 649835a82eeSMatthew Dillon return (error); 650df8bae1dSRodney W. Grimes } 651df8bae1dSRodney W. Grimes 652d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 653df8bae1dSRodney W. Grimes struct setgid_args { 654df8bae1dSRodney W. Grimes gid_t gid; 655df8bae1dSRodney W. Grimes }; 656d2d3e875SBruce Evans #endif 657835a82eeSMatthew Dillon /* 658835a82eeSMatthew Dillon * MPSAFE 659835a82eeSMatthew Dillon */ 660df8bae1dSRodney W. Grimes /* ARGSUSED */ 66126f9a767SRodney W. Grimes int 662b40ce416SJulian Elischer setgid(td, uap) 663b40ce416SJulian Elischer struct thread *td; 664df8bae1dSRodney W. Grimes struct setgid_args *uap; 665df8bae1dSRodney W. Grimes { 666b40ce416SJulian Elischer struct proc *p = td->td_proc; 667b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 668b1fc0ec1SRobert Watson gid_t gid; 669835a82eeSMatthew Dillon int error = 0; 670df8bae1dSRodney W. Grimes 671b1fc0ec1SRobert Watson gid = uap->gid; 672835a82eeSMatthew Dillon 673835a82eeSMatthew Dillon mtx_lock(&Giant); 674b1fc0ec1SRobert Watson oldcred = p->p_ucred; 675a08f4bf6SPeter Wemm /* 676a08f4bf6SPeter Wemm * See if we have "permission" by POSIX 1003.1 rules. 677a08f4bf6SPeter Wemm * 678a08f4bf6SPeter Wemm * Note that setgid(getegid()) is a special case of 679a08f4bf6SPeter Wemm * "appropriate privileges" in appendix B.4.2.2. We need 6802fa72ea7SJeroen Ruigrok van der Werven * to use this clause to be compatible with traditional BSD 681a08f4bf6SPeter Wemm * semantics. Basically, it means that "setgid(xx)" sets all 682a08f4bf6SPeter Wemm * three id's (assuming you have privs). 683a08f4bf6SPeter Wemm * 684a08f4bf6SPeter Wemm * For notes on the logic here, see setuid() above. 685a08f4bf6SPeter Wemm */ 686b1fc0ec1SRobert Watson if (gid != oldcred->cr_rgid && /* allow setgid(getgid()) */ 6873f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS 688b1fc0ec1SRobert Watson gid != oldcred->cr_svgid && /* allow setgid(saved gid) */ 689a08f4bf6SPeter Wemm #endif 690a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 691b1fc0ec1SRobert Watson gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */ 6923f246666SAndrey A. Chernov #endif 693835a82eeSMatthew Dillon (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) { 694835a82eeSMatthew Dillon goto done2; 695835a82eeSMatthew Dillon } 696a08f4bf6SPeter Wemm 697b1fc0ec1SRobert Watson newcred = crdup(oldcred); 698a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS 699a08f4bf6SPeter Wemm /* 700a08f4bf6SPeter Wemm * Do we have "appropriate privileges" (are we root or gid == egid) 701a08f4bf6SPeter Wemm * If so, we are changing the real uid and saved gid. 702a08f4bf6SPeter Wemm */ 703a08f4bf6SPeter Wemm if ( 704a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 705b1fc0ec1SRobert Watson gid == oldcred->cr_groups[0] || 706a08f4bf6SPeter Wemm #endif 707b1fc0ec1SRobert Watson suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */ 708a08f4bf6SPeter Wemm #endif 709a08f4bf6SPeter Wemm { 710a08f4bf6SPeter Wemm /* 711a08f4bf6SPeter Wemm * Set real gid 712a08f4bf6SPeter Wemm */ 713b1fc0ec1SRobert Watson if (oldcred->cr_rgid != gid) { 714b1fc0ec1SRobert Watson change_rgid(newcred, gid); 715d5f81602SSean Eric Fagan setsugid(p); 716a08f4bf6SPeter Wemm } 717a08f4bf6SPeter Wemm /* 718a08f4bf6SPeter Wemm * Set saved gid 719a08f4bf6SPeter Wemm * 720a08f4bf6SPeter Wemm * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 721a08f4bf6SPeter Wemm * the security of setegid() depends on it. B.4.2.2 says it 722a08f4bf6SPeter Wemm * is important that we should do this. 723a08f4bf6SPeter Wemm */ 724b1fc0ec1SRobert Watson if (oldcred->cr_svgid != gid) { 725b1fc0ec1SRobert Watson change_svgid(newcred, gid); 726d5f81602SSean Eric Fagan setsugid(p); 727a08f4bf6SPeter Wemm } 728a08f4bf6SPeter Wemm } 729a08f4bf6SPeter Wemm /* 730a08f4bf6SPeter Wemm * In all cases permitted cases, we are changing the egid. 731a08f4bf6SPeter Wemm * Copy credentials so other references do not see our changes. 732a08f4bf6SPeter Wemm */ 733b1fc0ec1SRobert Watson if (oldcred->cr_groups[0] != gid) { 734b1fc0ec1SRobert Watson change_egid(newcred, gid); 735d5f81602SSean Eric Fagan setsugid(p); 736a08f4bf6SPeter Wemm } 737b1fc0ec1SRobert Watson p->p_ucred = newcred; 738b1fc0ec1SRobert Watson crfree(oldcred); 739835a82eeSMatthew Dillon done2: 740835a82eeSMatthew Dillon mtx_unlock(&Giant); 741835a82eeSMatthew Dillon return (error); 742df8bae1dSRodney W. Grimes } 743df8bae1dSRodney W. Grimes 744d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 745df8bae1dSRodney W. Grimes struct setegid_args { 746df8bae1dSRodney W. Grimes gid_t egid; 747df8bae1dSRodney W. Grimes }; 748d2d3e875SBruce Evans #endif 749835a82eeSMatthew Dillon /* 750835a82eeSMatthew Dillon * MPSAFE 751835a82eeSMatthew Dillon */ 752df8bae1dSRodney W. Grimes /* ARGSUSED */ 75326f9a767SRodney W. Grimes int 754b40ce416SJulian Elischer setegid(td, uap) 755b40ce416SJulian Elischer struct thread *td; 756df8bae1dSRodney W. Grimes struct setegid_args *uap; 757df8bae1dSRodney W. Grimes { 758b40ce416SJulian Elischer struct proc *p = td->td_proc; 759b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 760b1fc0ec1SRobert Watson gid_t egid; 761835a82eeSMatthew Dillon int error = 0; 762df8bae1dSRodney W. Grimes 763df8bae1dSRodney W. Grimes egid = uap->egid; 764835a82eeSMatthew Dillon 765835a82eeSMatthew Dillon mtx_lock(&Giant); 766b1fc0ec1SRobert Watson oldcred = p->p_ucred; 767b1fc0ec1SRobert Watson if (egid != oldcred->cr_rgid && /* allow setegid(getgid()) */ 768b1fc0ec1SRobert Watson egid != oldcred->cr_svgid && /* allow setegid(saved gid) */ 769835a82eeSMatthew Dillon (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) { 770835a82eeSMatthew Dillon goto done2; 771835a82eeSMatthew Dillon } 772b1fc0ec1SRobert Watson newcred = crdup(oldcred); 773b1fc0ec1SRobert Watson if (oldcred->cr_groups[0] != egid) { 774b1fc0ec1SRobert Watson change_egid(newcred, egid); 775d5f81602SSean Eric Fagan setsugid(p); 776229a15f0SPeter Wemm } 777b1fc0ec1SRobert Watson p->p_ucred = newcred; 778b1fc0ec1SRobert Watson crfree(oldcred); 779835a82eeSMatthew Dillon done2: 780835a82eeSMatthew Dillon mtx_unlock(&Giant); 781835a82eeSMatthew Dillon return (error); 782df8bae1dSRodney W. Grimes } 783df8bae1dSRodney W. Grimes 784d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 785df8bae1dSRodney W. Grimes struct setgroups_args { 786df8bae1dSRodney W. Grimes u_int gidsetsize; 787df8bae1dSRodney W. Grimes gid_t *gidset; 788df8bae1dSRodney W. Grimes }; 789d2d3e875SBruce Evans #endif 790835a82eeSMatthew Dillon /* 791835a82eeSMatthew Dillon * MPSAFE 792835a82eeSMatthew Dillon */ 793df8bae1dSRodney W. Grimes /* ARGSUSED */ 79426f9a767SRodney W. Grimes int 795b40ce416SJulian Elischer setgroups(td, uap) 796b40ce416SJulian Elischer struct thread *td; 797df8bae1dSRodney W. Grimes struct setgroups_args *uap; 798df8bae1dSRodney W. Grimes { 799b40ce416SJulian Elischer struct proc *p = td->td_proc; 800b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 801b1fc0ec1SRobert Watson u_int ngrp; 802df8bae1dSRodney W. Grimes int error; 803df8bae1dSRodney W. Grimes 804835a82eeSMatthew Dillon mtx_lock(&Giant); 805835a82eeSMatthew Dillon 8063956a170SDavid Greenman ngrp = uap->gidsetsize; 807b1fc0ec1SRobert Watson oldcred = p->p_ucred; 808b1fc0ec1SRobert Watson if ((error = suser_xxx(oldcred, NULL, PRISON_ROOT))) 809835a82eeSMatthew Dillon goto done2; 810835a82eeSMatthew Dillon if (ngrp > NGROUPS) { 811835a82eeSMatthew Dillon error = EINVAL; 812835a82eeSMatthew Dillon goto done2; 813835a82eeSMatthew Dillon } 8148a5d815aSPeter Wemm /* 8158a5d815aSPeter Wemm * XXX A little bit lazy here. We could test if anything has 8168a5d815aSPeter Wemm * changed before crcopy() and setting P_SUGID. 8178a5d815aSPeter Wemm */ 818b1fc0ec1SRobert Watson newcred = crdup(oldcred); 8198a5d815aSPeter Wemm if (ngrp < 1) { 8208a5d815aSPeter Wemm /* 8218a5d815aSPeter Wemm * setgroups(0, NULL) is a legitimate way of clearing the 8228a5d815aSPeter Wemm * groups vector on non-BSD systems (which generally do not 8238a5d815aSPeter Wemm * have the egid in the groups[0]). We risk security holes 8248a5d815aSPeter Wemm * when running non-BSD software if we do not do the same. 8258a5d815aSPeter Wemm */ 826b1fc0ec1SRobert Watson newcred->cr_ngroups = 1; 8278a5d815aSPeter Wemm } else { 828bb56ec4aSPoul-Henning Kamp if ((error = copyin((caddr_t)uap->gidset, 829b1fc0ec1SRobert Watson (caddr_t)newcred->cr_groups, ngrp * sizeof(gid_t)))) { 830b1fc0ec1SRobert Watson crfree(newcred); 831835a82eeSMatthew Dillon goto done2; 832b1fc0ec1SRobert Watson } 833b1fc0ec1SRobert Watson newcred->cr_ngroups = ngrp; 8348a5d815aSPeter Wemm } 835d5f81602SSean Eric Fagan setsugid(p); 836b1fc0ec1SRobert Watson p->p_ucred = newcred; 837b1fc0ec1SRobert Watson crfree(oldcred); 838835a82eeSMatthew Dillon done2: 839835a82eeSMatthew Dillon mtx_unlock(&Giant); 840835a82eeSMatthew Dillon return (error); 841df8bae1dSRodney W. Grimes } 842df8bae1dSRodney W. Grimes 843d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 844df8bae1dSRodney W. Grimes struct setreuid_args { 84500999cd6SAndrey A. Chernov uid_t ruid; 84600999cd6SAndrey A. Chernov uid_t euid; 847df8bae1dSRodney W. Grimes }; 848d2d3e875SBruce Evans #endif 849835a82eeSMatthew Dillon /* 850835a82eeSMatthew Dillon * MPSAFE 851835a82eeSMatthew Dillon */ 852df8bae1dSRodney W. Grimes /* ARGSUSED */ 85326f9a767SRodney W. Grimes int 854b40ce416SJulian Elischer setreuid(td, uap) 855b40ce416SJulian Elischer register struct thread *td; 856df8bae1dSRodney W. Grimes struct setreuid_args *uap; 857df8bae1dSRodney W. Grimes { 858b40ce416SJulian Elischer struct proc *p = td->td_proc; 859b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 860b1fc0ec1SRobert Watson uid_t ruid, euid; 861835a82eeSMatthew Dillon int error = 0; 862df8bae1dSRodney W. Grimes 86300999cd6SAndrey A. Chernov ruid = uap->ruid; 86400999cd6SAndrey A. Chernov euid = uap->euid; 865835a82eeSMatthew Dillon 866835a82eeSMatthew Dillon mtx_lock(&Giant); 867835a82eeSMatthew Dillon 868b1fc0ec1SRobert Watson oldcred = p->p_ucred; 869b1fc0ec1SRobert Watson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 870b1fc0ec1SRobert Watson ruid != oldcred->cr_svuid) || 871b1fc0ec1SRobert Watson (euid != (uid_t)-1 && euid != oldcred->cr_uid && 872b1fc0ec1SRobert Watson euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) && 873835a82eeSMatthew Dillon (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) { 874835a82eeSMatthew Dillon goto done2; 875835a82eeSMatthew Dillon } 876b1fc0ec1SRobert Watson newcred = crdup(oldcred); 877b1fc0ec1SRobert Watson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 878b1fc0ec1SRobert Watson change_euid(newcred, euid); 879d5f81602SSean Eric Fagan setsugid(p); 880a89a5370SPeter Wemm } 881b1fc0ec1SRobert Watson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 882b1fc0ec1SRobert Watson change_ruid(newcred, ruid); 883d5f81602SSean Eric Fagan setsugid(p); 88400999cd6SAndrey A. Chernov } 885b1fc0ec1SRobert Watson if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) && 886b1fc0ec1SRobert Watson newcred->cr_svuid != newcred->cr_uid) { 887b1fc0ec1SRobert Watson change_svuid(newcred, newcred->cr_uid); 888d5f81602SSean Eric Fagan setsugid(p); 889a89a5370SPeter Wemm } 890b1fc0ec1SRobert Watson p->p_ucred = newcred; 891b1fc0ec1SRobert Watson crfree(oldcred); 892835a82eeSMatthew Dillon done2: 893835a82eeSMatthew Dillon mtx_unlock(&Giant); 894835a82eeSMatthew Dillon return (error); 895df8bae1dSRodney W. Grimes } 896df8bae1dSRodney W. Grimes 897d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 898df8bae1dSRodney W. Grimes struct setregid_args { 89900999cd6SAndrey A. Chernov gid_t rgid; 90000999cd6SAndrey A. Chernov gid_t egid; 901df8bae1dSRodney W. Grimes }; 902d2d3e875SBruce Evans #endif 903835a82eeSMatthew Dillon /* 904835a82eeSMatthew Dillon * MPSAFE 905835a82eeSMatthew Dillon */ 906df8bae1dSRodney W. Grimes /* ARGSUSED */ 90726f9a767SRodney W. Grimes int 908b40ce416SJulian Elischer setregid(td, uap) 909b40ce416SJulian Elischer register struct thread *td; 910df8bae1dSRodney W. Grimes struct setregid_args *uap; 911df8bae1dSRodney W. Grimes { 912b40ce416SJulian Elischer struct proc *p = td->td_proc; 913b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 914b1fc0ec1SRobert Watson gid_t rgid, egid; 915835a82eeSMatthew Dillon int error = 0; 916df8bae1dSRodney W. Grimes 91700999cd6SAndrey A. Chernov rgid = uap->rgid; 91800999cd6SAndrey A. Chernov egid = uap->egid; 919835a82eeSMatthew Dillon 920835a82eeSMatthew Dillon mtx_lock(&Giant); 921835a82eeSMatthew Dillon 922b1fc0ec1SRobert Watson oldcred = p->p_ucred; 923b1fc0ec1SRobert Watson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 924b1fc0ec1SRobert Watson rgid != oldcred->cr_svgid) || 925b1fc0ec1SRobert Watson (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] && 926b1fc0ec1SRobert Watson egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) && 927835a82eeSMatthew Dillon (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) { 928835a82eeSMatthew Dillon goto done2; 929835a82eeSMatthew Dillon } 93000999cd6SAndrey A. Chernov 931b1fc0ec1SRobert Watson newcred = crdup(oldcred); 932b1fc0ec1SRobert Watson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 933b1fc0ec1SRobert Watson change_egid(newcred, egid); 934d5f81602SSean Eric Fagan setsugid(p); 935a89a5370SPeter Wemm } 936b1fc0ec1SRobert Watson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 937b1fc0ec1SRobert Watson change_rgid(newcred, rgid); 938d5f81602SSean Eric Fagan setsugid(p); 939a89a5370SPeter Wemm } 940b1fc0ec1SRobert Watson if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) && 941b1fc0ec1SRobert Watson newcred->cr_svgid != newcred->cr_groups[0]) { 942b1fc0ec1SRobert Watson change_svgid(newcred, newcred->cr_groups[0]); 943d5f81602SSean Eric Fagan setsugid(p); 944a89a5370SPeter Wemm } 9454589be70SRuslan Ermilov p->p_ucred = newcred; 9464589be70SRuslan Ermilov crfree(oldcred); 947835a82eeSMatthew Dillon done2: 948835a82eeSMatthew Dillon mtx_unlock(&Giant); 949835a82eeSMatthew Dillon return (error); 950df8bae1dSRodney W. Grimes } 951df8bae1dSRodney W. Grimes 9528ccd6334SPeter Wemm /* 9538ccd6334SPeter Wemm * setresuid(ruid, euid, suid) is like setreuid except control over the 9548ccd6334SPeter Wemm * saved uid is explicit. 9558ccd6334SPeter Wemm */ 9568ccd6334SPeter Wemm 9578ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 9588ccd6334SPeter Wemm struct setresuid_args { 9598ccd6334SPeter Wemm uid_t ruid; 9608ccd6334SPeter Wemm uid_t euid; 9618ccd6334SPeter Wemm uid_t suid; 9628ccd6334SPeter Wemm }; 9638ccd6334SPeter Wemm #endif 964835a82eeSMatthew Dillon /* 965835a82eeSMatthew Dillon * MPSAFE 966835a82eeSMatthew Dillon */ 9678ccd6334SPeter Wemm /* ARGSUSED */ 9688ccd6334SPeter Wemm int 969b40ce416SJulian Elischer setresuid(td, uap) 970b40ce416SJulian Elischer register struct thread *td; 9718ccd6334SPeter Wemm struct setresuid_args *uap; 9728ccd6334SPeter Wemm { 973b40ce416SJulian Elischer struct proc *p = td->td_proc; 974b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 975b1fc0ec1SRobert Watson uid_t ruid, euid, suid; 9768ccd6334SPeter Wemm int error; 9778ccd6334SPeter Wemm 9788ccd6334SPeter Wemm ruid = uap->ruid; 9798ccd6334SPeter Wemm euid = uap->euid; 9808ccd6334SPeter Wemm suid = uap->suid; 981835a82eeSMatthew Dillon 982835a82eeSMatthew Dillon mtx_lock(&Giant); 983b1fc0ec1SRobert Watson oldcred = p->p_ucred; 984b1fc0ec1SRobert Watson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 985b1fc0ec1SRobert Watson ruid != oldcred->cr_svuid && 986b1fc0ec1SRobert Watson ruid != oldcred->cr_uid) || 987b1fc0ec1SRobert Watson (euid != (uid_t)-1 && euid != oldcred->cr_ruid && 988b1fc0ec1SRobert Watson euid != oldcred->cr_svuid && 989b1fc0ec1SRobert Watson euid != oldcred->cr_uid) || 990b1fc0ec1SRobert Watson (suid != (uid_t)-1 && suid != oldcred->cr_ruid && 991b1fc0ec1SRobert Watson suid != oldcred->cr_svuid && 992b1fc0ec1SRobert Watson suid != oldcred->cr_uid)) && 993835a82eeSMatthew Dillon (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) { 994835a82eeSMatthew Dillon goto done2; 995835a82eeSMatthew Dillon } 996b1fc0ec1SRobert Watson 997b1fc0ec1SRobert Watson newcred = crdup(oldcred); 998b1fc0ec1SRobert Watson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 999b1fc0ec1SRobert Watson change_euid(newcred, euid); 10008ccd6334SPeter Wemm setsugid(p); 10018ccd6334SPeter Wemm } 1002b1fc0ec1SRobert Watson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 1003b1fc0ec1SRobert Watson change_ruid(newcred, ruid); 10048ccd6334SPeter Wemm setsugid(p); 10058ccd6334SPeter Wemm } 1006b1fc0ec1SRobert Watson if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) { 1007b1fc0ec1SRobert Watson change_svuid(newcred, suid); 10088ccd6334SPeter Wemm setsugid(p); 10098ccd6334SPeter Wemm } 1010b1fc0ec1SRobert Watson p->p_ucred = newcred; 1011b1fc0ec1SRobert Watson crfree(oldcred); 1012835a82eeSMatthew Dillon error = 0; 1013835a82eeSMatthew Dillon done2: 1014835a82eeSMatthew Dillon mtx_unlock(&Giant); 1015835a82eeSMatthew Dillon return (error); 10168ccd6334SPeter Wemm } 10178ccd6334SPeter Wemm 10188ccd6334SPeter Wemm /* 10198ccd6334SPeter Wemm * setresgid(rgid, egid, sgid) is like setregid except control over the 10208ccd6334SPeter Wemm * saved gid is explicit. 10218ccd6334SPeter Wemm */ 10228ccd6334SPeter Wemm 10238ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 10248ccd6334SPeter Wemm struct setresgid_args { 10258ccd6334SPeter Wemm gid_t rgid; 10268ccd6334SPeter Wemm gid_t egid; 10278ccd6334SPeter Wemm gid_t sgid; 10288ccd6334SPeter Wemm }; 10298ccd6334SPeter Wemm #endif 1030835a82eeSMatthew Dillon /* 1031835a82eeSMatthew Dillon * MPSAFE 1032835a82eeSMatthew Dillon */ 10338ccd6334SPeter Wemm /* ARGSUSED */ 10348ccd6334SPeter Wemm int 1035b40ce416SJulian Elischer setresgid(td, uap) 1036b40ce416SJulian Elischer register struct thread *td; 10378ccd6334SPeter Wemm struct setresgid_args *uap; 10388ccd6334SPeter Wemm { 1039b40ce416SJulian Elischer struct proc *p = td->td_proc; 1040b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 1041b1fc0ec1SRobert Watson gid_t rgid, egid, sgid; 10428ccd6334SPeter Wemm int error; 10438ccd6334SPeter Wemm 10448ccd6334SPeter Wemm rgid = uap->rgid; 10458ccd6334SPeter Wemm egid = uap->egid; 10468ccd6334SPeter Wemm sgid = uap->sgid; 1047835a82eeSMatthew Dillon 1048835a82eeSMatthew Dillon mtx_lock(&Giant); 1049b1fc0ec1SRobert Watson oldcred = p->p_ucred; 1050b1fc0ec1SRobert Watson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 1051b1fc0ec1SRobert Watson rgid != oldcred->cr_svgid && 1052b1fc0ec1SRobert Watson rgid != oldcred->cr_groups[0]) || 1053b1fc0ec1SRobert Watson (egid != (gid_t)-1 && egid != oldcred->cr_rgid && 1054b1fc0ec1SRobert Watson egid != oldcred->cr_svgid && 1055b1fc0ec1SRobert Watson egid != oldcred->cr_groups[0]) || 1056b1fc0ec1SRobert Watson (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid && 1057b1fc0ec1SRobert Watson sgid != oldcred->cr_svgid && 1058b1fc0ec1SRobert Watson sgid != oldcred->cr_groups[0])) && 1059835a82eeSMatthew Dillon (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) { 1060835a82eeSMatthew Dillon goto done2; 1061835a82eeSMatthew Dillon } 1062b1fc0ec1SRobert Watson newcred = crdup(oldcred); 1063b1fc0ec1SRobert Watson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 1064b1fc0ec1SRobert Watson change_egid(newcred, egid); 10658ccd6334SPeter Wemm setsugid(p); 10668ccd6334SPeter Wemm } 1067b1fc0ec1SRobert Watson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 1068b1fc0ec1SRobert Watson change_rgid(newcred, rgid); 10698ccd6334SPeter Wemm setsugid(p); 10708ccd6334SPeter Wemm } 1071b1fc0ec1SRobert Watson if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) { 1072b1fc0ec1SRobert Watson change_svgid(newcred, sgid); 10738ccd6334SPeter Wemm setsugid(p); 10748ccd6334SPeter Wemm } 1075b1fc0ec1SRobert Watson p->p_ucred = newcred; 1076b1fc0ec1SRobert Watson crfree(oldcred); 1077835a82eeSMatthew Dillon error = 0; 1078835a82eeSMatthew Dillon done2: 1079835a82eeSMatthew Dillon mtx_unlock(&Giant); 1080835a82eeSMatthew Dillon return (error); 10818ccd6334SPeter Wemm } 10828ccd6334SPeter Wemm 10838ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 10848ccd6334SPeter Wemm struct getresuid_args { 10858ccd6334SPeter Wemm uid_t *ruid; 10868ccd6334SPeter Wemm uid_t *euid; 10878ccd6334SPeter Wemm uid_t *suid; 10888ccd6334SPeter Wemm }; 10898ccd6334SPeter Wemm #endif 1090835a82eeSMatthew Dillon /* 1091835a82eeSMatthew Dillon * MPSAFE 1092835a82eeSMatthew Dillon */ 10938ccd6334SPeter Wemm /* ARGSUSED */ 10948ccd6334SPeter Wemm int 1095b40ce416SJulian Elischer getresuid(td, uap) 1096b40ce416SJulian Elischer register struct thread *td; 10978ccd6334SPeter Wemm struct getresuid_args *uap; 10988ccd6334SPeter Wemm { 1099835a82eeSMatthew Dillon struct ucred *cred; 1100b40ce416SJulian Elischer struct proc *p = td->td_proc; 11018ccd6334SPeter Wemm int error1 = 0, error2 = 0, error3 = 0; 11028ccd6334SPeter Wemm 1103835a82eeSMatthew Dillon mtx_lock(&Giant); 1104835a82eeSMatthew Dillon cred = p->p_ucred; 1105835a82eeSMatthew Dillon 11068ccd6334SPeter Wemm if (uap->ruid) 1107b1fc0ec1SRobert Watson error1 = copyout((caddr_t)&cred->cr_ruid, 1108b1fc0ec1SRobert Watson (caddr_t)uap->ruid, sizeof(cred->cr_ruid)); 11098ccd6334SPeter Wemm if (uap->euid) 1110b1fc0ec1SRobert Watson error2 = copyout((caddr_t)&cred->cr_uid, 1111b1fc0ec1SRobert Watson (caddr_t)uap->euid, sizeof(cred->cr_uid)); 11128ccd6334SPeter Wemm if (uap->suid) 1113b1fc0ec1SRobert Watson error3 = copyout((caddr_t)&cred->cr_svuid, 1114b1fc0ec1SRobert Watson (caddr_t)uap->suid, sizeof(cred->cr_svuid)); 1115835a82eeSMatthew Dillon mtx_unlock(&Giant); 11168ccd6334SPeter Wemm return error1 ? error1 : (error2 ? error2 : error3); 11178ccd6334SPeter Wemm } 11188ccd6334SPeter Wemm 11198ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 11208ccd6334SPeter Wemm struct getresgid_args { 11218ccd6334SPeter Wemm gid_t *rgid; 11228ccd6334SPeter Wemm gid_t *egid; 11238ccd6334SPeter Wemm gid_t *sgid; 11248ccd6334SPeter Wemm }; 11258ccd6334SPeter Wemm #endif 1126835a82eeSMatthew Dillon /* 1127835a82eeSMatthew Dillon * MPSAFE 1128835a82eeSMatthew Dillon */ 11298ccd6334SPeter Wemm /* ARGSUSED */ 11308ccd6334SPeter Wemm int 1131b40ce416SJulian Elischer getresgid(td, uap) 1132b40ce416SJulian Elischer register struct thread *td; 11338ccd6334SPeter Wemm struct getresgid_args *uap; 11348ccd6334SPeter Wemm { 1135835a82eeSMatthew Dillon struct ucred *cred; 1136b40ce416SJulian Elischer struct proc *p = td->td_proc; 11378ccd6334SPeter Wemm int error1 = 0, error2 = 0, error3 = 0; 11388ccd6334SPeter Wemm 1139835a82eeSMatthew Dillon mtx_lock(&Giant); 1140835a82eeSMatthew Dillon cred = p->p_ucred; 1141835a82eeSMatthew Dillon 11428ccd6334SPeter Wemm if (uap->rgid) 1143b1fc0ec1SRobert Watson error1 = copyout((caddr_t)&cred->cr_rgid, 1144b1fc0ec1SRobert Watson (caddr_t)uap->rgid, sizeof(cred->cr_rgid)); 11458ccd6334SPeter Wemm if (uap->egid) 1146b1fc0ec1SRobert Watson error2 = copyout((caddr_t)&cred->cr_groups[0], 1147b1fc0ec1SRobert Watson (caddr_t)uap->egid, sizeof(cred->cr_groups[0])); 11488ccd6334SPeter Wemm if (uap->sgid) 1149b1fc0ec1SRobert Watson error3 = copyout((caddr_t)&cred->cr_svgid, 1150b1fc0ec1SRobert Watson (caddr_t)uap->sgid, sizeof(cred->cr_svgid)); 1151835a82eeSMatthew Dillon mtx_unlock(&Giant); 11528ccd6334SPeter Wemm return error1 ? error1 : (error2 ? error2 : error3); 11538ccd6334SPeter Wemm } 11548ccd6334SPeter Wemm 11558ccd6334SPeter Wemm 1156b67cbc65SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1157b67cbc65SPeter Wemm struct issetugid_args { 1158b67cbc65SPeter Wemm int dummy; 1159b67cbc65SPeter Wemm }; 1160b67cbc65SPeter Wemm #endif 1161b67cbc65SPeter Wemm /* ARGSUSED */ 1162b67cbc65SPeter Wemm int 1163b40ce416SJulian Elischer issetugid(td, uap) 1164b40ce416SJulian Elischer register struct thread *td; 1165b67cbc65SPeter Wemm struct issetugid_args *uap; 1166b67cbc65SPeter Wemm { 1167b40ce416SJulian Elischer struct proc *p = td->td_proc; 1168b40ce416SJulian Elischer 1169b67cbc65SPeter Wemm /* 1170b67cbc65SPeter Wemm * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 1171b67cbc65SPeter Wemm * we use P_SUGID because we consider changing the owners as 1172b67cbc65SPeter Wemm * "tainting" as well. 1173b67cbc65SPeter Wemm * This is significant for procs that start as root and "become" 1174b67cbc65SPeter Wemm * a user without an exec - programs cannot know *everything* 1175b67cbc65SPeter Wemm * that libc *might* have put in their data segment. 1176b67cbc65SPeter Wemm */ 1177b40ce416SJulian Elischer td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 1178b67cbc65SPeter Wemm return (0); 1179b67cbc65SPeter Wemm } 1180b67cbc65SPeter Wemm 1181835a82eeSMatthew Dillon /* 1182835a82eeSMatthew Dillon * MPSAFE 1183835a82eeSMatthew Dillon */ 1184130d0157SRobert Watson int 1185b40ce416SJulian Elischer __setugid(td, uap) 1186b40ce416SJulian Elischer struct thread *td; 1187130d0157SRobert Watson struct __setugid_args *uap; 1188130d0157SRobert Watson { 1189130d0157SRobert Watson #ifdef REGRESSION 1190835a82eeSMatthew Dillon int error = 0; 1191835a82eeSMatthew Dillon 1192835a82eeSMatthew Dillon mtx_lock(&Giant); 1193130d0157SRobert Watson switch (uap->flag) { 1194130d0157SRobert Watson case 0: 1195b40ce416SJulian Elischer td->td_proc->p_flag &= ~P_SUGID; 1196835a82eeSMatthew Dillon break; 1197130d0157SRobert Watson case 1: 1198b40ce416SJulian Elischer td->td_proc->p_flag |= P_SUGID; 1199835a82eeSMatthew Dillon break; 1200130d0157SRobert Watson default: 1201835a82eeSMatthew Dillon error = EINVAL; 1202835a82eeSMatthew Dillon break; 1203130d0157SRobert Watson } 1204835a82eeSMatthew Dillon mtx_unlock(&Giant); 1205835a82eeSMatthew Dillon return (error); 1206130d0157SRobert Watson #else /* !REGRESSION */ 1207130d0157SRobert Watson return (ENOSYS); 1208130d0157SRobert Watson #endif /* !REGRESSION */ 1209130d0157SRobert Watson } 1210130d0157SRobert Watson 1211df8bae1dSRodney W. Grimes /* 1212df8bae1dSRodney W. Grimes * Check if gid is a member of the group set. 1213df8bae1dSRodney W. Grimes */ 121426f9a767SRodney W. Grimes int 1215df8bae1dSRodney W. Grimes groupmember(gid, cred) 1216df8bae1dSRodney W. Grimes gid_t gid; 1217b1fc0ec1SRobert Watson struct ucred *cred; 1218df8bae1dSRodney W. Grimes { 1219df8bae1dSRodney W. Grimes register gid_t *gp; 1220df8bae1dSRodney W. Grimes gid_t *egp; 1221df8bae1dSRodney W. Grimes 1222df8bae1dSRodney W. Grimes egp = &(cred->cr_groups[cred->cr_ngroups]); 1223df8bae1dSRodney W. Grimes for (gp = cred->cr_groups; gp < egp; gp++) 1224df8bae1dSRodney W. Grimes if (*gp == gid) 1225df8bae1dSRodney W. Grimes return (1); 1226df8bae1dSRodney W. Grimes return (0); 1227df8bae1dSRodney W. Grimes } 1228df8bae1dSRodney W. Grimes 12293b243b72SRobert Watson /* 123093f4fd1cSRobert Watson * `suser_enabled' (which can be set by the kern.security.suser_enabled 12317fd6a959SRobert Watson * sysctl) determines whether the system 'super-user' policy is in effect. 12327fd6a959SRobert Watson * If it is nonzero, an effective uid of 0 connotes special privilege, 12337fd6a959SRobert Watson * overriding many mandatory and discretionary protections. If it is zero, 12347fd6a959SRobert Watson * uid 0 is offered no special privilege in the kernel security policy. 12357fd6a959SRobert Watson * Setting it to zero may seriously impact the functionality of many 12367fd6a959SRobert Watson * existing userland programs, and should not be done without careful 12377fd6a959SRobert Watson * consideration of the consequences. 12383b243b72SRobert Watson */ 123993f4fd1cSRobert Watson int suser_enabled = 1; 124093f4fd1cSRobert Watson SYSCTL_INT(_kern_security, OID_AUTO, suser_enabled, CTLFLAG_RW, 124193f4fd1cSRobert Watson &suser_enabled, 0, "processes with uid 0 have privilege"); 1242579f4eb4SRobert Watson 1243df8bae1dSRodney W. Grimes /* 12447fd6a959SRobert Watson * Test whether the specified credentials imply "super-user" privilege. 12457fd6a959SRobert Watson * Return 0 or EPERM. 1246df8bae1dSRodney W. Grimes */ 124726f9a767SRodney W. Grimes int 1248f711d546SPoul-Henning Kamp suser(p) 124991421ba2SRobert Watson struct proc *p; 1250f711d546SPoul-Henning Kamp { 125175c13541SPoul-Henning Kamp return suser_xxx(0, p, 0); 1252f711d546SPoul-Henning Kamp } 1253f711d546SPoul-Henning Kamp 1254b40ce416SJulian Elischer /* 1255b40ce416SJulian Elischer * version for when the thread pointer is available and not the proc. 1256b40ce416SJulian Elischer * (saves having to include proc.h into every file that needs to do the change.) 1257b40ce416SJulian Elischer */ 1258b40ce416SJulian Elischer int 1259b40ce416SJulian Elischer suser_td(td) 1260b40ce416SJulian Elischer 1261b40ce416SJulian Elischer struct thread *td; 1262b40ce416SJulian Elischer { 1263b40ce416SJulian Elischer return suser_xxx(0, td->td_proc, 0); 1264b40ce416SJulian Elischer } 1265b40ce416SJulian Elischer 1266b40ce416SJulian Elischer /* 1267b40ce416SJulian Elischer * wrapper to use if you have the thread on hand but not the proc. 1268b40ce416SJulian Elischer */ 1269b40ce416SJulian Elischer int 1270b40ce416SJulian Elischer suser_xxx_td(cred, td, flag) 1271b40ce416SJulian Elischer struct ucred *cred; 1272b40ce416SJulian Elischer struct thread *td; 1273b40ce416SJulian Elischer int flag; 1274b40ce416SJulian Elischer { 1275b40ce416SJulian Elischer return(suser_xxx(cred, td->td_proc, flag)); 1276b40ce416SJulian Elischer } 1277b40ce416SJulian Elischer 1278f711d546SPoul-Henning Kamp int 127975c13541SPoul-Henning Kamp suser_xxx(cred, proc, flag) 128091421ba2SRobert Watson struct ucred *cred; 128191421ba2SRobert Watson struct proc *proc; 128275c13541SPoul-Henning Kamp int flag; 1283df8bae1dSRodney W. Grimes { 128493f4fd1cSRobert Watson if (!suser_enabled) 128503095547SRobert Watson return (EPERM); 128675c13541SPoul-Henning Kamp if (!cred && !proc) { 128775c13541SPoul-Henning Kamp printf("suser_xxx(): THINK!\n"); 1288df8bae1dSRodney W. Grimes return (EPERM); 1289df8bae1dSRodney W. Grimes } 129075c13541SPoul-Henning Kamp if (!cred) 129175c13541SPoul-Henning Kamp cred = proc->p_ucred; 129275c13541SPoul-Henning Kamp if (cred->cr_uid != 0) 129375c13541SPoul-Henning Kamp return (EPERM); 129491421ba2SRobert Watson if (jailed(cred) && !(flag & PRISON_ROOT)) 129575c13541SPoul-Henning Kamp return (EPERM); 129675c13541SPoul-Henning Kamp return (0); 129775c13541SPoul-Henning Kamp } 1298df8bae1dSRodney W. Grimes 12993ca719f1SRobert Watson /* 130087fce2bbSRobert Watson * Test (local, globale) securelevel values against passed required 130187fce2bbSRobert Watson * securelevel. _gt implements (level > securelevel), and _ge implements 130275bc5b3fSRobert Watson * (level >= securelevel). Returns 0 oer EPERM. 13033ca719f1SRobert Watson * 13043ca719f1SRobert Watson * cr is permitted to be NULL for the time being, as there were some 13053ca719f1SRobert Watson * existing securelevel checks that occurred without a process/credential 13063ca719f1SRobert Watson * context. In the future this will be disallowed, so a kernel 13073ca719f1SRobert Watson * message is displayed. 13083ca719f1SRobert Watson */ 13093ca719f1SRobert Watson int 13103ca719f1SRobert Watson securelevel_gt(struct ucred *cr, int level) 13113ca719f1SRobert Watson { 13123ca719f1SRobert Watson 13133ca719f1SRobert Watson if (cr == NULL) { 13143ca719f1SRobert Watson printf("securelevel_gt: cr is NULL\n"); 131575bc5b3fSRobert Watson if (level > securelevel) 13163ca719f1SRobert Watson return (0); 13173ca719f1SRobert Watson else 13183ca719f1SRobert Watson return (EPERM); 131987fce2bbSRobert Watson } else if (cr->cr_prison == NULL) { 132075bc5b3fSRobert Watson if (level > securelevel) 13213ca719f1SRobert Watson return (0); 13223ca719f1SRobert Watson else 13233ca719f1SRobert Watson return (EPERM); 132487fce2bbSRobert Watson } else { 132587fce2bbSRobert Watson if (level > imax(cr->cr_prison->pr_securelevel, securelevel)) 132687fce2bbSRobert Watson return (0); 132787fce2bbSRobert Watson else 132887fce2bbSRobert Watson return (EPERM); 13293ca719f1SRobert Watson } 133087fce2bbSRobert Watson 13313ca719f1SRobert Watson } 13323ca719f1SRobert Watson 13333ca719f1SRobert Watson int 13343ca719f1SRobert Watson securelevel_ge(struct ucred *cr, int level) 13353ca719f1SRobert Watson { 13363ca719f1SRobert Watson 13373ca719f1SRobert Watson if (cr == NULL) { 13383ca719f1SRobert Watson printf("securelevel_ge: cr is NULL\n"); 133975bc5b3fSRobert Watson if (level >= securelevel) 13403ca719f1SRobert Watson return (0); 13413ca719f1SRobert Watson else 13423ca719f1SRobert Watson return (EPERM); 134387fce2bbSRobert Watson } if (cr->cr_prison == NULL) { 134475bc5b3fSRobert Watson if (level >= securelevel) 13453ca719f1SRobert Watson return (0); 13463ca719f1SRobert Watson else 13473ca719f1SRobert Watson return (EPERM); 134887fce2bbSRobert Watson } else { 134987fce2bbSRobert Watson if (level >= imax(cr->cr_prison->pr_securelevel, securelevel)) 135087fce2bbSRobert Watson return (0); 135187fce2bbSRobert Watson else 135287fce2bbSRobert Watson return (EPERM); 13533ca719f1SRobert Watson } 13543ca719f1SRobert Watson } 13553ca719f1SRobert Watson 13568a7d8cc6SRobert Watson /* 13578a7d8cc6SRobert Watson * kern_security_seeotheruids_permitted determines whether or not visibility 13588a7d8cc6SRobert Watson * of processes and sockets with credentials holding different real uid's 13598a7d8cc6SRobert Watson * is possible using a variety of system MIBs. 13608a7d8cc6SRobert Watson */ 13618a7d8cc6SRobert Watson static int kern_security_seeotheruids_permitted = 1; 13628a7d8cc6SRobert Watson SYSCTL_INT(_kern_security, OID_AUTO, seeotheruids_permitted, 13638a7d8cc6SRobert Watson CTLFLAG_RW, &kern_security_seeotheruids_permitted, 0, 13648a7d8cc6SRobert Watson "Unprivileged processes may see subjects/objects with different real uid"); 13658a7d8cc6SRobert Watson 13667fd6a959SRobert Watson /*- 13677fd6a959SRobert Watson * Determine if u1 "can see" the subject specified by u2. 1368ed639720SRobert Watson * Returns: 0 for permitted, an errno value otherwise 1369ed639720SRobert Watson * Locks: none 13707fd6a959SRobert Watson * References: u1 and u2 must be immutable credentials 13717fd6a959SRobert Watson * u1 and u2 must be valid for the lifetime of the call 1372ed639720SRobert Watson * u1 may equal u2, in which case only one reference is required 1373ed639720SRobert Watson */ 1374ed639720SRobert Watson int 137594088977SRobert Watson cr_cansee(struct ucred *u1, struct ucred *u2) 1376a9e0361bSPoul-Henning Kamp { 137791421ba2SRobert Watson int error; 1378a9e0361bSPoul-Henning Kamp 1379ed639720SRobert Watson if ((error = prison_check(u1, u2))) 138091421ba2SRobert Watson return (error); 13818a7d8cc6SRobert Watson if (!kern_security_seeotheruids_permitted && 13828a7d8cc6SRobert Watson u1->cr_ruid != u2->cr_ruid) { 1383f8e6ab29SRobert Watson if (suser_xxx(u1, NULL, PRISON_ROOT) != 0) 1384387d2c03SRobert Watson return (ESRCH); 1385c52396e3SRobert Watson } 1386387d2c03SRobert Watson return (0); 1387387d2c03SRobert Watson } 1388387d2c03SRobert Watson 13897fd6a959SRobert Watson /*- 13907fd6a959SRobert Watson * Determine if p1 "can see" the subject specified by p2. 13913b243b72SRobert Watson * Returns: 0 for permitted, an errno value otherwise 13927fd6a959SRobert Watson * Locks: Sufficient locks to protect p1->p_ucred and p2->p_ucred must 13933b243b72SRobert Watson * be held. Normally, p1 will be curproc, and a lock must be held 13943b243b72SRobert Watson * for p2. 13953b243b72SRobert Watson * References: p1 and p2 must be valid for the lifetime of the call 13963b243b72SRobert Watson */ 1397a0f75161SRobert Watson int 1398a0f75161SRobert Watson p_cansee(struct proc *p1, struct proc *p2) 1399ed639720SRobert Watson { 1400ed639720SRobert Watson 140194088977SRobert Watson /* Wrap cr_cansee() for all functionality. */ 140294088977SRobert Watson return (cr_cansee(p1->p_ucred, p2->p_ucred)); 1403ed639720SRobert Watson } 1404ed639720SRobert Watson 14057fd6a959SRobert Watson /*- 14067fd6a959SRobert Watson * Determine whether p1 may deliver the specified signal to p2. 14077fd6a959SRobert Watson * Returns: 0 for permitted, an errno value otherwise 14087fd6a959SRobert Watson * Locks: Sufficient locks to protect various components of p1 and p2 14097fd6a959SRobert Watson * must be held. Normally, p1 will be curproc, and a lock must 14107fd6a959SRobert Watson * be held for p2. 14113b243b72SRobert Watson * References: p1 and p2 must be valid for the lifetime of the call 14124c5eb9c3SRobert Watson */ 14134c5eb9c3SRobert Watson int 14144c5eb9c3SRobert Watson p_cansignal(struct proc *p1, struct proc *p2, int signum) 1415387d2c03SRobert Watson { 141691421ba2SRobert Watson int error; 1417387d2c03SRobert Watson 1418a9e0361bSPoul-Henning Kamp if (p1 == p2) 1419a9e0361bSPoul-Henning Kamp return (0); 1420387d2c03SRobert Watson 14214c5eb9c3SRobert Watson /* 14224c5eb9c3SRobert Watson * Jail semantics limit the scope of signalling to p2 in the same 14234c5eb9c3SRobert Watson * jail as p1, if p1 is in jail. 14244c5eb9c3SRobert Watson */ 142591421ba2SRobert Watson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 142691421ba2SRobert Watson return (error); 1427387d2c03SRobert Watson 1428387d2c03SRobert Watson /* 14294c5eb9c3SRobert Watson * UNIX signalling semantics require that processes in the same 14304c5eb9c3SRobert Watson * session always be able to deliver SIGCONT to one another, 14314c5eb9c3SRobert Watson * overriding the remaining protections. 1432387d2c03SRobert Watson */ 14334c5eb9c3SRobert Watson if (signum == SIGCONT && p1->p_session == p2->p_session) 1434a9e0361bSPoul-Henning Kamp return (0); 1435387d2c03SRobert Watson 14364c5eb9c3SRobert Watson /* 14373b243b72SRobert Watson * UNIX signal semantics depend on the status of the P_SUGID 14383b243b72SRobert Watson * bit on the target process. If the bit is set, then additional 14393b243b72SRobert Watson * restrictions are placed on the set of available signals. 14404c5eb9c3SRobert Watson */ 14414c5eb9c3SRobert Watson if (p2->p_flag & P_SUGID) { 14424c5eb9c3SRobert Watson switch (signum) { 14434c5eb9c3SRobert Watson case 0: 14444c5eb9c3SRobert Watson case SIGKILL: 14454c5eb9c3SRobert Watson case SIGINT: 14464c5eb9c3SRobert Watson case SIGTERM: 14474c5eb9c3SRobert Watson case SIGSTOP: 14484c5eb9c3SRobert Watson case SIGTTIN: 14494c5eb9c3SRobert Watson case SIGTTOU: 14504c5eb9c3SRobert Watson case SIGTSTP: 14514c5eb9c3SRobert Watson case SIGHUP: 14524c5eb9c3SRobert Watson case SIGUSR1: 14534c5eb9c3SRobert Watson case SIGUSR2: 14547fd6a959SRobert Watson /* 14557fd6a959SRobert Watson * Generally, permit job and terminal control 14567fd6a959SRobert Watson * signals. 14577fd6a959SRobert Watson */ 14584c5eb9c3SRobert Watson break; 14594c5eb9c3SRobert Watson default: 14603b243b72SRobert Watson /* Not permitted, privilege is required. */ 14614c5eb9c3SRobert Watson error = suser_xxx(NULL, p1, PRISON_ROOT); 14624c5eb9c3SRobert Watson if (error) 14634c5eb9c3SRobert Watson return (error); 14644c5eb9c3SRobert Watson } 1465e9e7ff5bSRobert Watson } 1466e9e7ff5bSRobert Watson 14674c5eb9c3SRobert Watson /* 14683b243b72SRobert Watson * Generally, the target credential's ruid or svuid must match the 1469e9e7ff5bSRobert Watson * subject credential's ruid or euid. 14704c5eb9c3SRobert Watson */ 1471b1fc0ec1SRobert Watson if (p1->p_ucred->cr_ruid != p2->p_ucred->cr_ruid && 1472b1fc0ec1SRobert Watson p1->p_ucred->cr_ruid != p2->p_ucred->cr_svuid && 1473b1fc0ec1SRobert Watson p1->p_ucred->cr_uid != p2->p_ucred->cr_ruid && 1474b1fc0ec1SRobert Watson p1->p_ucred->cr_uid != p2->p_ucred->cr_svuid) { 14754c5eb9c3SRobert Watson /* Not permitted, try privilege. */ 14764c5eb9c3SRobert Watson error = suser_xxx(NULL, p1, PRISON_ROOT); 14774c5eb9c3SRobert Watson if (error) 14784c5eb9c3SRobert Watson return (error); 14794c5eb9c3SRobert Watson } 1480387d2c03SRobert Watson 1481387d2c03SRobert Watson return (0); 1482387d2c03SRobert Watson } 1483a9e0361bSPoul-Henning Kamp 14847fd6a959SRobert Watson /*- 14857fd6a959SRobert Watson * Determine whether p1 may reschedule p2 14867fd6a959SRobert Watson * Returns: 0 for permitted, an errno value otherwise 14873b243b72SRobert Watson * Locks: Sufficient locks to protect various components of p1 and p2 14883b243b72SRobert Watson * must be held. Normally, p1 will be curproc, and a lock must 14897fd6a959SRobert Watson * be held for p2. 14903b243b72SRobert Watson * References: p1 and p2 must be valid for the lifetime of the call 14913b243b72SRobert Watson */ 1492a0f75161SRobert Watson int 1493a0f75161SRobert Watson p_cansched(struct proc *p1, struct proc *p2) 1494387d2c03SRobert Watson { 149591421ba2SRobert Watson int error; 1496387d2c03SRobert Watson 1497387d2c03SRobert Watson if (p1 == p2) 1498387d2c03SRobert Watson return (0); 149991421ba2SRobert Watson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 150091421ba2SRobert Watson return (error); 1501b1fc0ec1SRobert Watson if (p1->p_ucred->cr_ruid == p2->p_ucred->cr_ruid) 1502387d2c03SRobert Watson return (0); 1503b1fc0ec1SRobert Watson if (p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid) 1504387d2c03SRobert Watson return (0); 15057fd6a959SRobert Watson if (suser_xxx(0, p1, PRISON_ROOT) == 0) 1506387d2c03SRobert Watson return (0); 1507387d2c03SRobert Watson 1508387d2c03SRobert Watson #ifdef CAPABILITIES 15094df571b1SRobert Watson if (!cap_check(NULL, p1, CAP_SYS_NICE, PRISON_ROOT)) 1510387d2c03SRobert Watson return (0); 1511387d2c03SRobert Watson #endif 1512387d2c03SRobert Watson 1513387d2c03SRobert Watson return (EPERM); 1514387d2c03SRobert Watson } 1515387d2c03SRobert Watson 15163b243b72SRobert Watson /* 15177fd6a959SRobert Watson * The kern_unprivileged_procdebug_permitted flag may be used to disable 15183b243b72SRobert Watson * a variety of unprivileged inter-process debugging services, including 15193b243b72SRobert Watson * some procfs functionality, ptrace(), and ktrace(). In the past, 15203b243b72SRobert Watson * inter-process debugging has been involved in a variety of security 15213b243b72SRobert Watson * problems, and sites not requiring the service might choose to disable it 15223b243b72SRobert Watson * when hardening systems. 15233b243b72SRobert Watson * 15243b243b72SRobert Watson * XXX: Should modifying and reading this variable require locking? 15253b243b72SRobert Watson */ 15260ef5652eSRobert Watson static int kern_unprivileged_procdebug_permitted = 1; 15270ef5652eSRobert Watson SYSCTL_INT(_kern_security, OID_AUTO, unprivileged_procdebug_permitted, 15280ef5652eSRobert Watson CTLFLAG_RW, &kern_unprivileged_procdebug_permitted, 0, 15290ef5652eSRobert Watson "Unprivileged processes may use process debugging facilities"); 15300ef5652eSRobert Watson 15317fd6a959SRobert Watson /*- 15327fd6a959SRobert Watson * Determine whether p1 may debug p2. 15337fd6a959SRobert Watson * Returns: 0 for permitted, an errno value otherwise 15347fd6a959SRobert Watson * Locks: Sufficient locks to protect various components of p1 and p2 15357fd6a959SRobert Watson * must be held. Normally, p1 will be curproc, and a lock must 15367fd6a959SRobert Watson * be held for p2. 15373b243b72SRobert Watson * References: p1 and p2 must be valid for the lifetime of the call 15383b243b72SRobert Watson */ 1539a0f75161SRobert Watson int 1540a0f75161SRobert Watson p_candebug(struct proc *p1, struct proc *p2) 1541387d2c03SRobert Watson { 1542db42a33dSRobert Watson int error, i, grpsubset, uidsubset, credentialchanged; 1543387d2c03SRobert Watson 154432d18604SRobert Watson if (!kern_unprivileged_procdebug_permitted) { 154532d18604SRobert Watson error = suser_xxx(NULL, p1, PRISON_ROOT); 154632d18604SRobert Watson if (error) 154732d18604SRobert Watson return (error); 154832d18604SRobert Watson } 154932d18604SRobert Watson 155023fad5b6SDag-Erling Smørgrav if (p1 == p2) 155123fad5b6SDag-Erling Smørgrav return (0); 155223fad5b6SDag-Erling Smørgrav 155391421ba2SRobert Watson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 155491421ba2SRobert Watson return (error); 1555387d2c03SRobert Watson 15567fd6a959SRobert Watson /* 1557db42a33dSRobert Watson * Is p2's group set a subset of p1's effective group set? This 1558db42a33dSRobert Watson * includes p2's egid, group access list, rgid, and svgid. 15597fd6a959SRobert Watson */ 1560db42a33dSRobert Watson grpsubset = 1; 1561db42a33dSRobert Watson for (i = 0; i < p2->p_ucred->cr_ngroups; i++) { 1562db42a33dSRobert Watson if (!groupmember(p2->p_ucred->cr_groups[i], p1->p_ucred)) { 1563db42a33dSRobert Watson grpsubset = 0; 1564db42a33dSRobert Watson break; 1565db42a33dSRobert Watson } 1566db42a33dSRobert Watson } 1567db42a33dSRobert Watson grpsubset = grpsubset && 1568db42a33dSRobert Watson groupmember(p2->p_ucred->cr_rgid, p1->p_ucred) && 1569db42a33dSRobert Watson groupmember(p2->p_ucred->cr_svgid, p1->p_ucred); 1570db42a33dSRobert Watson 1571db42a33dSRobert Watson /* 1572db42a33dSRobert Watson * Are the uids present in p2's credential equal to p1's 1573db42a33dSRobert Watson * effective uid? This includes p2's euid, svuid, and ruid. 1574db42a33dSRobert Watson */ 1575db42a33dSRobert Watson uidsubset = (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid && 1576db42a33dSRobert Watson p1->p_ucred->cr_uid == p2->p_ucred->cr_svuid && 1577db42a33dSRobert Watson p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid); 1578db42a33dSRobert Watson 1579db42a33dSRobert Watson /* 1580db42a33dSRobert Watson * Has the credential of the process changed since the last exec()? 1581db42a33dSRobert Watson */ 1582db42a33dSRobert Watson credentialchanged = (p2->p_flag & P_SUGID); 1583db42a33dSRobert Watson 1584db42a33dSRobert Watson /* 1585db42a33dSRobert Watson * If p2's gids aren't a subset, or the uids aren't a subset, 1586db42a33dSRobert Watson * or the credential has changed, require appropriate privilege 1587db42a33dSRobert Watson * for p1 to debug p2. For POSIX.1e capabilities, this will 1588db42a33dSRobert Watson * require CAP_SYS_PTRACE. 1589db42a33dSRobert Watson */ 1590db42a33dSRobert Watson if (!grpsubset || !uidsubset || credentialchanged) { 159132d18604SRobert Watson error = suser_xxx(NULL, p1, PRISON_ROOT); 159232d18604SRobert Watson if (error) 1593387d2c03SRobert Watson return (error); 15947fd6a959SRobert Watson } 1595387d2c03SRobert Watson 15963ca719f1SRobert Watson /* can't trace init when securelevel > 0 */ 15973ca719f1SRobert Watson if (p2->p_pid == 1) { 15983ca719f1SRobert Watson error = securelevel_gt(p1->p_ucred, 0); 15993ca719f1SRobert Watson if (error) 16003ca719f1SRobert Watson return (error); 16013ca719f1SRobert Watson } 1602387d2c03SRobert Watson 16035fab7614SRobert Watson /* 16045fab7614SRobert Watson * Can't trace a process that's currently exec'ing. 16055fab7614SRobert Watson * XXX: Note, this is not a security policy decision, it's a 16065fab7614SRobert Watson * basic correctness/functionality decision. Therefore, this check 16075fab7614SRobert Watson * should be moved to the caller's of p_candebug(). 16085fab7614SRobert Watson */ 16099ca45e81SDag-Erling Smørgrav if ((p2->p_flag & P_INEXEC) != 0) 16109ca45e81SDag-Erling Smørgrav return (EAGAIN); 16119ca45e81SDag-Erling Smørgrav 1612387d2c03SRobert Watson return (0); 1613387d2c03SRobert Watson } 1614387d2c03SRobert Watson 1615a9e0361bSPoul-Henning Kamp /* 1616df8bae1dSRodney W. Grimes * Allocate a zeroed cred structure. 1617df8bae1dSRodney W. Grimes */ 1618df8bae1dSRodney W. Grimes struct ucred * 1619df8bae1dSRodney W. Grimes crget() 1620df8bae1dSRodney W. Grimes { 1621df8bae1dSRodney W. Grimes register struct ucred *cr; 1622df8bae1dSRodney W. Grimes 16231e5d626aSAlfred Perlstein MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK | M_ZERO); 1624df8bae1dSRodney W. Grimes cr->cr_ref = 1; 16251e5d626aSAlfred Perlstein mtx_init(&cr->cr_mtx, "ucred", MTX_DEF); 1626df8bae1dSRodney W. Grimes return (cr); 1627df8bae1dSRodney W. Grimes } 1628df8bae1dSRodney W. Grimes 1629df8bae1dSRodney W. Grimes /* 16307fd6a959SRobert Watson * Claim another reference to a ucred structure. 16315c3f70d7SAlfred Perlstein */ 1632bd78ceceSJohn Baldwin struct ucred * 16335c3f70d7SAlfred Perlstein crhold(cr) 16345c3f70d7SAlfred Perlstein struct ucred *cr; 16355c3f70d7SAlfred Perlstein { 16365c3f70d7SAlfred Perlstein 16379ed346baSBosko Milekic mtx_lock(&cr->cr_mtx); 16385c3f70d7SAlfred Perlstein cr->cr_ref++; 1639bd78ceceSJohn Baldwin mtx_unlock(&cr->cr_mtx); 1640bd78ceceSJohn Baldwin return (cr); 16415c3f70d7SAlfred Perlstein } 16425c3f70d7SAlfred Perlstein 16435c3f70d7SAlfred Perlstein 16445c3f70d7SAlfred Perlstein /* 1645df8bae1dSRodney W. Grimes * Free a cred structure. 1646df8bae1dSRodney W. Grimes * Throws away space when ref count gets to 0. 1647df8bae1dSRodney W. Grimes */ 164826f9a767SRodney W. Grimes void 1649df8bae1dSRodney W. Grimes crfree(cr) 1650df8bae1dSRodney W. Grimes struct ucred *cr; 1651df8bae1dSRodney W. Grimes { 16521e5d626aSAlfred Perlstein 16539ed346baSBosko Milekic mtx_lock(&cr->cr_mtx); 1654e04670b7SAlfred Perlstein KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref)); 1655f535380cSDon Lewis if (--cr->cr_ref == 0) { 16561e5d626aSAlfred Perlstein mtx_destroy(&cr->cr_mtx); 1657f535380cSDon Lewis /* 1658f535380cSDon Lewis * Some callers of crget(), such as nfs_statfs(), 1659f535380cSDon Lewis * allocate a temporary credential, but don't 1660f535380cSDon Lewis * allocate a uidinfo structure. 1661f535380cSDon Lewis */ 1662f535380cSDon Lewis if (cr->cr_uidinfo != NULL) 1663f535380cSDon Lewis uifree(cr->cr_uidinfo); 1664823c224eSRobert Watson if (cr->cr_ruidinfo != NULL) 1665823c224eSRobert Watson uifree(cr->cr_ruidinfo); 166691421ba2SRobert Watson /* 166791421ba2SRobert Watson * Free a prison, if any. 166891421ba2SRobert Watson */ 166991421ba2SRobert Watson if (jailed(cr)) 167091421ba2SRobert Watson prison_free(cr->cr_prison); 1671df8bae1dSRodney W. Grimes FREE((caddr_t)cr, M_CRED); 16721e5d626aSAlfred Perlstein } else { 16739ed346baSBosko Milekic mtx_unlock(&cr->cr_mtx); 1674df8bae1dSRodney W. Grimes } 1675f535380cSDon Lewis } 1676df8bae1dSRodney W. Grimes 1677df8bae1dSRodney W. Grimes /* 1678bd78ceceSJohn Baldwin * Check to see if this ucred is shared. 1679df8bae1dSRodney W. Grimes */ 1680bd78ceceSJohn Baldwin int 1681bd78ceceSJohn Baldwin crshared(cr) 1682df8bae1dSRodney W. Grimes struct ucred *cr; 1683df8bae1dSRodney W. Grimes { 1684bd78ceceSJohn Baldwin int shared; 1685df8bae1dSRodney W. Grimes 16869ed346baSBosko Milekic mtx_lock(&cr->cr_mtx); 1687bd78ceceSJohn Baldwin shared = (cr->cr_ref > 1); 16889ed346baSBosko Milekic mtx_unlock(&cr->cr_mtx); 1689bd78ceceSJohn Baldwin return (shared); 16901e5d626aSAlfred Perlstein } 1691bd78ceceSJohn Baldwin 1692bd78ceceSJohn Baldwin /* 1693bd78ceceSJohn Baldwin * Copy a ucred's contents from a template. Does not block. 1694bd78ceceSJohn Baldwin */ 1695bd78ceceSJohn Baldwin void 1696bd78ceceSJohn Baldwin crcopy(dest, src) 1697bd78ceceSJohn Baldwin struct ucred *dest, *src; 1698bd78ceceSJohn Baldwin { 1699bd78ceceSJohn Baldwin 1700bd78ceceSJohn Baldwin KASSERT(crshared(dest) == 0, ("crcopy of shared ucred")); 1701bd78ceceSJohn Baldwin bcopy(&src->cr_startcopy, &dest->cr_startcopy, 1702bd78ceceSJohn Baldwin (unsigned)((caddr_t)&src->cr_endcopy - 1703bd78ceceSJohn Baldwin (caddr_t)&src->cr_startcopy)); 1704bd78ceceSJohn Baldwin uihold(dest->cr_uidinfo); 1705bd78ceceSJohn Baldwin uihold(dest->cr_ruidinfo); 1706bd78ceceSJohn Baldwin if (jailed(dest)) 1707bd78ceceSJohn Baldwin prison_hold(dest->cr_prison); 1708df8bae1dSRodney W. Grimes } 1709df8bae1dSRodney W. Grimes 1710df8bae1dSRodney W. Grimes /* 1711df8bae1dSRodney W. Grimes * Dup cred struct to a new held one. 1712df8bae1dSRodney W. Grimes */ 1713df8bae1dSRodney W. Grimes struct ucred * 1714df8bae1dSRodney W. Grimes crdup(cr) 1715df8bae1dSRodney W. Grimes struct ucred *cr; 1716df8bae1dSRodney W. Grimes { 1717df8bae1dSRodney W. Grimes struct ucred *newcr; 1718df8bae1dSRodney W. Grimes 1719bd78ceceSJohn Baldwin newcr = crget(); 1720bd78ceceSJohn Baldwin crcopy(newcr, cr); 1721df8bae1dSRodney W. Grimes return (newcr); 1722df8bae1dSRodney W. Grimes } 1723df8bae1dSRodney W. Grimes 1724df8bae1dSRodney W. Grimes /* 1725df8bae1dSRodney W. Grimes * Get login name, if available. 1726df8bae1dSRodney W. Grimes */ 1727d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1728df8bae1dSRodney W. Grimes struct getlogin_args { 1729df8bae1dSRodney W. Grimes char *namebuf; 1730df8bae1dSRodney W. Grimes u_int namelen; 1731df8bae1dSRodney W. Grimes }; 1732d2d3e875SBruce Evans #endif 1733835a82eeSMatthew Dillon /* 1734835a82eeSMatthew Dillon * MPSAFE 1735835a82eeSMatthew Dillon */ 1736df8bae1dSRodney W. Grimes /* ARGSUSED */ 173726f9a767SRodney W. Grimes int 1738b40ce416SJulian Elischer getlogin(td, uap) 1739b40ce416SJulian Elischer struct thread *td; 1740df8bae1dSRodney W. Grimes struct getlogin_args *uap; 1741df8bae1dSRodney W. Grimes { 1742835a82eeSMatthew Dillon int error; 1743b40ce416SJulian Elischer struct proc *p = td->td_proc; 1744df8bae1dSRodney W. Grimes 1745835a82eeSMatthew Dillon mtx_lock(&Giant); 174630cf3ac4SAndrey A. Chernov if (uap->namelen > MAXLOGNAME) 174753490b76SAndrey A. Chernov uap->namelen = MAXLOGNAME; 1748835a82eeSMatthew Dillon error = copyout((caddr_t) p->p_pgrp->pg_session->s_login, 1749835a82eeSMatthew Dillon (caddr_t) uap->namebuf, uap->namelen); 1750835a82eeSMatthew Dillon mtx_unlock(&Giant); 1751835a82eeSMatthew Dillon return(error); 1752df8bae1dSRodney W. Grimes } 1753df8bae1dSRodney W. Grimes 1754df8bae1dSRodney W. Grimes /* 1755df8bae1dSRodney W. Grimes * Set login name. 1756df8bae1dSRodney W. Grimes */ 1757d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1758df8bae1dSRodney W. Grimes struct setlogin_args { 1759df8bae1dSRodney W. Grimes char *namebuf; 1760df8bae1dSRodney W. Grimes }; 1761d2d3e875SBruce Evans #endif 1762835a82eeSMatthew Dillon /* 1763835a82eeSMatthew Dillon * MPSAFE 1764835a82eeSMatthew Dillon */ 1765df8bae1dSRodney W. Grimes /* ARGSUSED */ 176626f9a767SRodney W. Grimes int 1767b40ce416SJulian Elischer setlogin(td, uap) 1768b40ce416SJulian Elischer struct thread *td; 1769df8bae1dSRodney W. Grimes struct setlogin_args *uap; 1770df8bae1dSRodney W. Grimes { 1771b40ce416SJulian Elischer struct proc *p = td->td_proc; 1772df8bae1dSRodney W. Grimes int error; 1773964ca0caSAndrey A. Chernov char logintmp[MAXLOGNAME]; 1774df8bae1dSRodney W. Grimes 1775835a82eeSMatthew Dillon mtx_lock(&Giant); 177675c13541SPoul-Henning Kamp if ((error = suser_xxx(0, p, PRISON_ROOT))) 1777835a82eeSMatthew Dillon goto done2; 1778184989c2SDavid Nugent error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 177910d4743fSDoug Rabson sizeof(logintmp), (size_t *)0); 1780835a82eeSMatthew Dillon if (error == ENAMETOOLONG) { 1781df8bae1dSRodney W. Grimes error = EINVAL; 1782835a82eeSMatthew Dillon } else if (!error) { 1783184989c2SDavid Nugent (void) memcpy(p->p_pgrp->pg_session->s_login, logintmp, 1784964ca0caSAndrey A. Chernov sizeof(logintmp)); 1785835a82eeSMatthew Dillon } 1786835a82eeSMatthew Dillon done2: 1787835a82eeSMatthew Dillon mtx_unlock(&Giant); 1788df8bae1dSRodney W. Grimes return (error); 1789df8bae1dSRodney W. Grimes } 1790d5f81602SSean Eric Fagan 1791d5f81602SSean Eric Fagan void 1792d5f81602SSean Eric Fagan setsugid(p) 1793d5f81602SSean Eric Fagan struct proc *p; 1794d5f81602SSean Eric Fagan { 1795d5f81602SSean Eric Fagan p->p_flag |= P_SUGID; 179689361835SSean Eric Fagan if (!(p->p_pfsflags & PF_ISUGID)) 1797d5f81602SSean Eric Fagan p->p_stops = 0; 1798d5f81602SSean Eric Fagan } 1799f535380cSDon Lewis 18007fd6a959SRobert Watson /*- 18017fd6a959SRobert Watson * Change a process's effective uid. 1802b1fc0ec1SRobert Watson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified. 1803b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1804b1fc0ec1SRobert Watson * duration of the call. 1805f535380cSDon Lewis */ 1806f535380cSDon Lewis void 1807b1fc0ec1SRobert Watson change_euid(newcred, euid) 1808b1fc0ec1SRobert Watson struct ucred *newcred; 1809f535380cSDon Lewis uid_t euid; 1810f535380cSDon Lewis { 1811f535380cSDon Lewis 1812b1fc0ec1SRobert Watson newcred->cr_uid = euid; 1813b1fc0ec1SRobert Watson uifree(newcred->cr_uidinfo); 1814b1fc0ec1SRobert Watson newcred->cr_uidinfo = uifind(euid); 1815f535380cSDon Lewis } 1816f535380cSDon Lewis 18177fd6a959SRobert Watson /*- 18187fd6a959SRobert Watson * Change a process's effective gid. 1819b1fc0ec1SRobert Watson * Side effects: newcred->cr_gid will be modified. 1820b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1821b1fc0ec1SRobert Watson * duration of the call. 1822f535380cSDon Lewis */ 1823810bfc8eSAndrew Gallatin void 1824b1fc0ec1SRobert Watson change_egid(newcred, egid) 1825b1fc0ec1SRobert Watson struct ucred *newcred; 1826b1fc0ec1SRobert Watson gid_t egid; 1827b1fc0ec1SRobert Watson { 1828b1fc0ec1SRobert Watson 1829b1fc0ec1SRobert Watson newcred->cr_groups[0] = egid; 1830b1fc0ec1SRobert Watson } 1831b1fc0ec1SRobert Watson 18327fd6a959SRobert Watson /*- 18337fd6a959SRobert Watson * Change a process's real uid. 1834b1fc0ec1SRobert Watson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo 1835b1fc0ec1SRobert Watson * will be updated, and the old and new cr_ruidinfo proc 1836b1fc0ec1SRobert Watson * counts will be updated. 1837b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1838b1fc0ec1SRobert Watson * duration of the call. 1839b1fc0ec1SRobert Watson */ 1840b1fc0ec1SRobert Watson void 1841b1fc0ec1SRobert Watson change_ruid(newcred, ruid) 1842b1fc0ec1SRobert Watson struct ucred *newcred; 1843f535380cSDon Lewis uid_t ruid; 1844f535380cSDon Lewis { 1845f535380cSDon Lewis 1846b1fc0ec1SRobert Watson (void)chgproccnt(newcred->cr_ruidinfo, -1, 0); 1847b1fc0ec1SRobert Watson newcred->cr_ruid = ruid; 1848b1fc0ec1SRobert Watson uifree(newcred->cr_ruidinfo); 1849b1fc0ec1SRobert Watson newcred->cr_ruidinfo = uifind(ruid); 1850b1fc0ec1SRobert Watson (void)chgproccnt(newcred->cr_ruidinfo, 1, 0); 1851b1fc0ec1SRobert Watson } 1852b1fc0ec1SRobert Watson 18537fd6a959SRobert Watson /*- 18547fd6a959SRobert Watson * Change a process's real gid. 1855b1fc0ec1SRobert Watson * Side effects: newcred->cr_rgid will be updated. 1856b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1857b1fc0ec1SRobert Watson * duration of the call. 1858b1fc0ec1SRobert Watson */ 1859b1fc0ec1SRobert Watson void 1860b1fc0ec1SRobert Watson change_rgid(newcred, rgid) 1861b1fc0ec1SRobert Watson struct ucred *newcred; 1862b1fc0ec1SRobert Watson gid_t rgid; 1863b1fc0ec1SRobert Watson { 1864b1fc0ec1SRobert Watson 1865b1fc0ec1SRobert Watson newcred->cr_rgid = rgid; 1866b1fc0ec1SRobert Watson } 1867b1fc0ec1SRobert Watson 18687fd6a959SRobert Watson /*- 18697fd6a959SRobert Watson * Change a process's saved uid. 1870b1fc0ec1SRobert Watson * Side effects: newcred->cr_svuid will be updated. 1871b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1872b1fc0ec1SRobert Watson * duration of the call. 1873b1fc0ec1SRobert Watson */ 1874b1fc0ec1SRobert Watson void 1875b1fc0ec1SRobert Watson change_svuid(newcred, svuid) 1876b1fc0ec1SRobert Watson struct ucred *newcred; 1877b1fc0ec1SRobert Watson uid_t svuid; 1878b1fc0ec1SRobert Watson { 1879b1fc0ec1SRobert Watson 1880b1fc0ec1SRobert Watson newcred->cr_svuid = svuid; 1881b1fc0ec1SRobert Watson } 1882b1fc0ec1SRobert Watson 18837fd6a959SRobert Watson /*- 18847fd6a959SRobert Watson * Change a process's saved gid. 1885b1fc0ec1SRobert Watson * Side effects: newcred->cr_svgid will be updated. 1886b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1887b1fc0ec1SRobert Watson * duration of the call. 1888b1fc0ec1SRobert Watson */ 1889b1fc0ec1SRobert Watson void 1890b1fc0ec1SRobert Watson change_svgid(newcred, svgid) 1891b1fc0ec1SRobert Watson struct ucred *newcred; 1892b1fc0ec1SRobert Watson gid_t svgid; 1893b1fc0ec1SRobert Watson { 1894b1fc0ec1SRobert Watson 1895b1fc0ec1SRobert Watson newcred->cr_svgid = svgid; 1896f535380cSDon Lewis } 1897