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. 43b243b72SRobert Watson * Copyright (c) 2000, 2001 Robert N. M. Watson. All rights reserved. 5df8bae1dSRodney W. Grimes * (c) UNIX System Laboratories, Inc. 6df8bae1dSRodney W. Grimes * All or some portions of this file are derived from material licensed 7df8bae1dSRodney W. Grimes * to the University of California by American Telephone and Telegraph 8df8bae1dSRodney W. Grimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 9df8bae1dSRodney W. Grimes * the permission of UNIX System Laboratories, Inc. 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> 57fb919e4dSMark Murray #include <sys/sysproto.h> 58df8bae1dSRodney W. Grimes #include <sys/malloc.h> 59d5f81602SSean Eric Fagan #include <sys/pioctl.h> 60f535380cSDon Lewis #include <sys/resourcevar.h> 61579f4eb4SRobert Watson #include <sys/sysctl.h> 6291421ba2SRobert Watson #include <sys/jail.h> 63df8bae1dSRodney W. Grimes 64a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_CRED, "cred", "credentials"); 65a1c995b6SPoul-Henning Kamp 660ef5652eSRobert Watson SYSCTL_NODE(_kern, OID_AUTO, security, CTLFLAG_RW, 0, 670ef5652eSRobert Watson "Kernel security policy"); 680ef5652eSRobert Watson 69d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 70ad7507e2SSteven Wallace struct getpid_args { 71df8bae1dSRodney W. Grimes int dummy; 72df8bae1dSRodney W. Grimes }; 73d2d3e875SBruce Evans #endif 74df8bae1dSRodney W. Grimes 7536e9f877SMatthew Dillon /* 76835a82eeSMatthew Dillon * getpid 7736e9f877SMatthew Dillon */ 7898f03f90SJake Burkholder 79835a82eeSMatthew Dillon /* 80835a82eeSMatthew Dillon * MPSAFE 81835a82eeSMatthew Dillon */ 82df8bae1dSRodney W. Grimes /* ARGSUSED */ 8326f9a767SRodney W. Grimes int 84b40ce416SJulian Elischer getpid(td, uap) 85b40ce416SJulian Elischer struct thread *td; 86ad7507e2SSteven Wallace struct getpid_args *uap; 87df8bae1dSRodney W. Grimes { 88b40ce416SJulian Elischer struct proc *p = td->td_proc; 89df8bae1dSRodney W. Grimes 90835a82eeSMatthew Dillon mtx_lock(&Giant); 91b40ce416SJulian Elischer td->td_retval[0] = p->p_pid; 92df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 93bae3a80bSJohn Baldwin PROC_LOCK(p); 94b40ce416SJulian Elischer td->td_retval[1] = p->p_pptr->p_pid; 95bae3a80bSJohn Baldwin PROC_UNLOCK(p); 96df8bae1dSRodney W. Grimes #endif 97835a82eeSMatthew Dillon mtx_unlock(&Giant); 98df8bae1dSRodney W. Grimes return (0); 99df8bae1dSRodney W. Grimes } 100df8bae1dSRodney W. Grimes 10198f03f90SJake Burkholder /* 102835a82eeSMatthew Dillon * getppid 10398f03f90SJake Burkholder */ 10498f03f90SJake Burkholder 105d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 106ad7507e2SSteven Wallace struct getppid_args { 107ad7507e2SSteven Wallace int dummy; 108ad7507e2SSteven Wallace }; 109d2d3e875SBruce Evans #endif 110835a82eeSMatthew Dillon /* 111835a82eeSMatthew Dillon * MPSAFE 112835a82eeSMatthew Dillon */ 113df8bae1dSRodney W. Grimes /* ARGSUSED */ 11426f9a767SRodney W. Grimes int 115b40ce416SJulian Elischer getppid(td, uap) 116b40ce416SJulian Elischer struct thread *td; 117ad7507e2SSteven Wallace struct getppid_args *uap; 118df8bae1dSRodney W. Grimes { 119b40ce416SJulian Elischer struct proc *p = td->td_proc; 120df8bae1dSRodney W. Grimes 121835a82eeSMatthew Dillon mtx_lock(&Giant); 122bae3a80bSJohn Baldwin PROC_LOCK(p); 123b40ce416SJulian Elischer td->td_retval[0] = p->p_pptr->p_pid; 124bae3a80bSJohn Baldwin PROC_UNLOCK(p); 125835a82eeSMatthew Dillon mtx_unlock(&Giant); 126df8bae1dSRodney W. Grimes return (0); 127df8bae1dSRodney W. Grimes } 128df8bae1dSRodney W. Grimes 12936e9f877SMatthew Dillon /* 13036e9f877SMatthew Dillon * Get process group ID; note that POSIX getpgrp takes no parameter 13136e9f877SMatthew Dillon * 13236e9f877SMatthew Dillon * MP SAFE 13336e9f877SMatthew Dillon */ 134d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 135ad7507e2SSteven Wallace struct getpgrp_args { 136ad7507e2SSteven Wallace int dummy; 137ad7507e2SSteven Wallace }; 138d2d3e875SBruce Evans #endif 139835a82eeSMatthew Dillon /* 140835a82eeSMatthew Dillon * MPSAFE 141835a82eeSMatthew Dillon */ 14226f9a767SRodney W. Grimes int 143b40ce416SJulian Elischer getpgrp(td, uap) 144b40ce416SJulian Elischer struct thread *td; 145ad7507e2SSteven Wallace struct getpgrp_args *uap; 146df8bae1dSRodney W. Grimes { 147b40ce416SJulian Elischer struct proc *p = td->td_proc; 148df8bae1dSRodney W. Grimes 149835a82eeSMatthew Dillon mtx_lock(&Giant); 150b40ce416SJulian Elischer td->td_retval[0] = p->p_pgrp->pg_id; 151835a82eeSMatthew Dillon mtx_unlock(&Giant); 152df8bae1dSRodney W. Grimes return (0); 153df8bae1dSRodney W. Grimes } 154df8bae1dSRodney W. Grimes 1551a5018a0SPeter Wemm /* Get an arbitary pid's process group id */ 1561a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1571a5018a0SPeter Wemm struct getpgid_args { 1581a5018a0SPeter Wemm pid_t pid; 1591a5018a0SPeter Wemm }; 1601a5018a0SPeter Wemm #endif 1611a5018a0SPeter Wemm 162835a82eeSMatthew Dillon /* 163835a82eeSMatthew Dillon * MPSAFE 164835a82eeSMatthew Dillon */ 1651a5018a0SPeter Wemm int 166b40ce416SJulian Elischer getpgid(td, uap) 167b40ce416SJulian Elischer struct thread *td; 1681a5018a0SPeter Wemm struct getpgid_args *uap; 1691a5018a0SPeter Wemm { 170b40ce416SJulian Elischer struct proc *p = td->td_proc; 17165de0c7aSDon Lewis struct proc *pt; 172835a82eeSMatthew Dillon int error = 0; 17365de0c7aSDon Lewis 174835a82eeSMatthew Dillon mtx_lock(&Giant); 1751a5018a0SPeter Wemm if (uap->pid == 0) 176b40ce416SJulian Elischer td->td_retval[0] = p->p_pgrp->pg_id; 17733a9ed9dSJohn Baldwin else { 178835a82eeSMatthew Dillon if ((pt = pfind(uap->pid)) == NULL) { 179835a82eeSMatthew Dillon error = ESRCH; 180835a82eeSMatthew Dillon goto done2; 181835a82eeSMatthew Dillon } 182a0f75161SRobert Watson if ((error = p_cansee(p, pt))) { 18333a9ed9dSJohn Baldwin PROC_UNLOCK(pt); 184835a82eeSMatthew Dillon goto done2; 18533a9ed9dSJohn Baldwin } 186b40ce416SJulian Elischer td->td_retval[0] = pt->p_pgrp->pg_id; 18733a9ed9dSJohn Baldwin PROC_UNLOCK(pt); 18833a9ed9dSJohn Baldwin } 189835a82eeSMatthew Dillon done2: 190835a82eeSMatthew Dillon mtx_unlock(&Giant); 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); 216835a82eeSMatthew Dillon if (uap->pid == 0) { 217b40ce416SJulian Elischer td->td_retval[0] = p->p_session->s_sid; 218835a82eeSMatthew Dillon } else { 219835a82eeSMatthew Dillon if ((pt = pfind(uap->pid)) == NULL) { 220835a82eeSMatthew Dillon error = ESRCH; 221835a82eeSMatthew Dillon goto done2; 222835a82eeSMatthew Dillon } 223a0f75161SRobert Watson if ((error = p_cansee(p, pt))) { 22433a9ed9dSJohn Baldwin PROC_UNLOCK(pt); 225835a82eeSMatthew Dillon goto done2; 22633a9ed9dSJohn Baldwin } 227b40ce416SJulian Elischer td->td_retval[0] = pt->p_session->s_sid; 22833a9ed9dSJohn Baldwin PROC_UNLOCK(pt); 22933a9ed9dSJohn Baldwin } 230835a82eeSMatthew Dillon done2: 231835a82eeSMatthew Dillon mtx_unlock(&Giant); 232835a82eeSMatthew Dillon return (error); 2331a5018a0SPeter Wemm } 2341a5018a0SPeter Wemm 2351a5018a0SPeter Wemm 2367c8fdcbdSMatthew Dillon /* 2377c8fdcbdSMatthew Dillon * getuid() - MP SAFE 2387c8fdcbdSMatthew Dillon */ 239d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 240ad7507e2SSteven Wallace struct getuid_args { 241ad7507e2SSteven Wallace int dummy; 242ad7507e2SSteven Wallace }; 243d2d3e875SBruce Evans #endif 244ad7507e2SSteven Wallace 245835a82eeSMatthew Dillon /* 246835a82eeSMatthew Dillon * MPSAFE 247835a82eeSMatthew Dillon */ 248df8bae1dSRodney W. Grimes /* ARGSUSED */ 24926f9a767SRodney W. Grimes int 250b40ce416SJulian Elischer getuid(td, uap) 251b40ce416SJulian Elischer struct thread *td; 252ad7507e2SSteven Wallace struct getuid_args *uap; 253df8bae1dSRodney W. Grimes { 254b40ce416SJulian Elischer struct proc *p = td->td_proc; 255df8bae1dSRodney W. Grimes 256835a82eeSMatthew Dillon mtx_lock(&Giant); 257b40ce416SJulian Elischer td->td_retval[0] = p->p_ucred->cr_ruid; 258df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 259b40ce416SJulian Elischer td->td_retval[1] = p->p_ucred->cr_uid; 260df8bae1dSRodney W. Grimes #endif 261835a82eeSMatthew Dillon mtx_unlock(&Giant); 262df8bae1dSRodney W. Grimes return (0); 263df8bae1dSRodney W. Grimes } 264df8bae1dSRodney W. Grimes 2657c8fdcbdSMatthew Dillon /* 2667c8fdcbdSMatthew Dillon * geteuid() - MP SAFE 2677c8fdcbdSMatthew Dillon */ 268d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 269ad7507e2SSteven Wallace struct geteuid_args { 270ad7507e2SSteven Wallace int dummy; 271ad7507e2SSteven Wallace }; 272d2d3e875SBruce Evans #endif 273ad7507e2SSteven Wallace 274df8bae1dSRodney W. Grimes /* ARGSUSED */ 27526f9a767SRodney W. Grimes int 276b40ce416SJulian Elischer geteuid(td, uap) 277b40ce416SJulian Elischer struct thread *td; 278ad7507e2SSteven Wallace struct geteuid_args *uap; 279df8bae1dSRodney W. Grimes { 280835a82eeSMatthew Dillon mtx_lock(&Giant); 281b40ce416SJulian Elischer td->td_retval[0] = td->td_proc->p_ucred->cr_uid; 282835a82eeSMatthew Dillon mtx_unlock(&Giant); 283df8bae1dSRodney W. Grimes return (0); 284df8bae1dSRodney W. Grimes } 285df8bae1dSRodney W. Grimes 2867c8fdcbdSMatthew Dillon /* 2877c8fdcbdSMatthew Dillon * getgid() - MP SAFE 2887c8fdcbdSMatthew Dillon */ 289d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 290ad7507e2SSteven Wallace struct getgid_args { 291ad7507e2SSteven Wallace int dummy; 292ad7507e2SSteven Wallace }; 293d2d3e875SBruce Evans #endif 294ad7507e2SSteven Wallace 295835a82eeSMatthew Dillon /* 296835a82eeSMatthew Dillon * MPSAFE 297835a82eeSMatthew Dillon */ 298df8bae1dSRodney W. Grimes /* ARGSUSED */ 29926f9a767SRodney W. Grimes int 300b40ce416SJulian Elischer getgid(td, uap) 301b40ce416SJulian Elischer struct thread *td; 302ad7507e2SSteven Wallace struct getgid_args *uap; 303df8bae1dSRodney W. Grimes { 304b40ce416SJulian Elischer struct proc *p = td->td_proc; 305df8bae1dSRodney W. Grimes 306835a82eeSMatthew Dillon mtx_lock(&Giant); 307b40ce416SJulian Elischer td->td_retval[0] = p->p_ucred->cr_rgid; 308df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 309b40ce416SJulian Elischer td->td_retval[1] = p->p_ucred->cr_groups[0]; 310df8bae1dSRodney W. Grimes #endif 311835a82eeSMatthew Dillon mtx_unlock(&Giant); 312df8bae1dSRodney W. Grimes return (0); 313df8bae1dSRodney W. Grimes } 314df8bae1dSRodney W. Grimes 315df8bae1dSRodney W. Grimes /* 316df8bae1dSRodney W. Grimes * Get effective group ID. The "egid" is groups[0], and could be obtained 317df8bae1dSRodney W. Grimes * via getgroups. This syscall exists because it is somewhat painful to do 318df8bae1dSRodney W. Grimes * correctly in a library function. 319df8bae1dSRodney W. Grimes */ 320d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 321ad7507e2SSteven Wallace struct getegid_args { 322ad7507e2SSteven Wallace int dummy; 323ad7507e2SSteven Wallace }; 324d2d3e875SBruce Evans #endif 325ad7507e2SSteven Wallace 326835a82eeSMatthew Dillon /* 327835a82eeSMatthew Dillon * MPSAFE 328835a82eeSMatthew Dillon */ 329df8bae1dSRodney W. Grimes /* ARGSUSED */ 33026f9a767SRodney W. Grimes int 331b40ce416SJulian Elischer getegid(td, uap) 332b40ce416SJulian Elischer struct thread *td; 333ad7507e2SSteven Wallace struct getegid_args *uap; 334df8bae1dSRodney W. Grimes { 335b40ce416SJulian Elischer struct proc *p = td->td_proc; 336df8bae1dSRodney W. Grimes 337835a82eeSMatthew Dillon mtx_lock(&Giant); 338b40ce416SJulian Elischer td->td_retval[0] = p->p_ucred->cr_groups[0]; 339835a82eeSMatthew Dillon mtx_unlock(&Giant); 340df8bae1dSRodney W. Grimes return (0); 341df8bae1dSRodney W. Grimes } 342df8bae1dSRodney W. Grimes 343d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 344df8bae1dSRodney W. Grimes struct getgroups_args { 345df8bae1dSRodney W. Grimes u_int gidsetsize; 346df8bae1dSRodney W. Grimes gid_t *gidset; 347df8bae1dSRodney W. Grimes }; 348d2d3e875SBruce Evans #endif 349835a82eeSMatthew Dillon /* 350835a82eeSMatthew Dillon * MPSAFE 351835a82eeSMatthew Dillon */ 35226f9a767SRodney W. Grimes int 353b40ce416SJulian Elischer getgroups(td, uap) 354b40ce416SJulian Elischer struct thread *td; 355df8bae1dSRodney W. Grimes register struct getgroups_args *uap; 356df8bae1dSRodney W. Grimes { 357835a82eeSMatthew Dillon struct ucred *cred; 358b40ce416SJulian Elischer struct proc *p = td->td_proc; 359b1fc0ec1SRobert Watson u_int ngrp; 360835a82eeSMatthew Dillon int error = 0; 361df8bae1dSRodney W. Grimes 362835a82eeSMatthew Dillon mtx_lock(&Giant); 363835a82eeSMatthew Dillon cred = p->p_ucred; 364df8bae1dSRodney W. Grimes if ((ngrp = uap->gidsetsize) == 0) { 365b40ce416SJulian Elischer td->td_retval[0] = cred->cr_ngroups; 366835a82eeSMatthew Dillon error = 0; 367835a82eeSMatthew Dillon goto done2; 368df8bae1dSRodney W. Grimes } 369835a82eeSMatthew Dillon if (ngrp < cred->cr_ngroups) { 370835a82eeSMatthew Dillon error = EINVAL; 371835a82eeSMatthew Dillon goto done2; 372835a82eeSMatthew Dillon } 373b1fc0ec1SRobert Watson ngrp = cred->cr_ngroups; 374b1fc0ec1SRobert Watson if ((error = copyout((caddr_t)cred->cr_groups, 375835a82eeSMatthew Dillon (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))) { 376835a82eeSMatthew Dillon goto done2; 377835a82eeSMatthew Dillon } 378b40ce416SJulian Elischer td->td_retval[0] = ngrp; 379835a82eeSMatthew Dillon done2: 380835a82eeSMatthew Dillon mtx_unlock(&Giant); 381835a82eeSMatthew Dillon return (error); 382df8bae1dSRodney W. Grimes } 383df8bae1dSRodney W. Grimes 384d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 38582970b81SBruce Evans struct setsid_args { 386ad7507e2SSteven Wallace int dummy; 387ad7507e2SSteven Wallace }; 388d2d3e875SBruce Evans #endif 389ad7507e2SSteven Wallace 390835a82eeSMatthew Dillon /* 391835a82eeSMatthew Dillon * MPSAFE 392835a82eeSMatthew Dillon */ 393df8bae1dSRodney W. Grimes /* ARGSUSED */ 39426f9a767SRodney W. Grimes int 395b40ce416SJulian Elischer setsid(td, uap) 396b40ce416SJulian Elischer register struct thread *td; 39782970b81SBruce Evans struct setsid_args *uap; 398df8bae1dSRodney W. Grimes { 399835a82eeSMatthew Dillon int error; 400b40ce416SJulian Elischer struct proc *p = td->td_proc; 401df8bae1dSRodney W. Grimes 402835a82eeSMatthew Dillon mtx_lock(&Giant); 403df8bae1dSRodney W. Grimes if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 404835a82eeSMatthew Dillon error = EPERM; 405df8bae1dSRodney W. Grimes } else { 406df8bae1dSRodney W. Grimes (void)enterpgrp(p, p->p_pid, 1); 407b40ce416SJulian Elischer td->td_retval[0] = p->p_pid; 408835a82eeSMatthew Dillon error = 0; 409df8bae1dSRodney W. Grimes } 410835a82eeSMatthew Dillon mtx_unlock(&Giant); 411835a82eeSMatthew Dillon return (error); 412df8bae1dSRodney W. Grimes } 413df8bae1dSRodney W. Grimes 414df8bae1dSRodney W. Grimes /* 415df8bae1dSRodney W. Grimes * set process group (setpgid/old setpgrp) 416df8bae1dSRodney W. Grimes * 417df8bae1dSRodney W. Grimes * caller does setpgid(targpid, targpgid) 418df8bae1dSRodney W. Grimes * 419df8bae1dSRodney W. Grimes * pid must be caller or child of caller (ESRCH) 420df8bae1dSRodney W. Grimes * if a child 421df8bae1dSRodney W. Grimes * pid must be in same session (EPERM) 422df8bae1dSRodney W. Grimes * pid can't have done an exec (EACCES) 423df8bae1dSRodney W. Grimes * if pgid != pid 424df8bae1dSRodney W. Grimes * there must exist some pid in same session having pgid (EPERM) 425df8bae1dSRodney W. Grimes * pid must not be session leader (EPERM) 426df8bae1dSRodney W. Grimes */ 427d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 428df8bae1dSRodney W. Grimes struct setpgid_args { 429df8bae1dSRodney W. Grimes int pid; /* target process id */ 430df8bae1dSRodney W. Grimes int pgid; /* target pgrp id */ 431df8bae1dSRodney W. Grimes }; 432d2d3e875SBruce Evans #endif 433835a82eeSMatthew Dillon /* 434835a82eeSMatthew Dillon * MPSAFE 435835a82eeSMatthew Dillon */ 436df8bae1dSRodney W. Grimes /* ARGSUSED */ 43726f9a767SRodney W. Grimes int 438b40ce416SJulian Elischer setpgid(td, uap) 439b40ce416SJulian Elischer struct thread *td; 440df8bae1dSRodney W. Grimes register struct setpgid_args *uap; 441df8bae1dSRodney W. Grimes { 442b40ce416SJulian Elischer struct proc *curp = td->td_proc; 443df8bae1dSRodney W. Grimes register struct proc *targp; /* target process */ 444df8bae1dSRodney W. Grimes register struct pgrp *pgrp; /* target pgrp */ 445eb9e5c1dSRobert Watson int error; 446df8bae1dSRodney W. Grimes 44778f64bccSBruce Evans if (uap->pgid < 0) 44878f64bccSBruce Evans return (EINVAL); 449835a82eeSMatthew Dillon 450835a82eeSMatthew Dillon mtx_lock(&Giant); 451835a82eeSMatthew Dillon 452df8bae1dSRodney W. Grimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 45333a9ed9dSJohn Baldwin if ((targp = pfind(uap->pid)) == NULL || !inferior(targp)) { 45433a9ed9dSJohn Baldwin if (targp) 45533a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 456835a82eeSMatthew Dillon error = ESRCH; 457835a82eeSMatthew Dillon goto done2; 45833a9ed9dSJohn Baldwin } 459a0f75161SRobert Watson if ((error = p_cansee(curproc, targp))) { 46033a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 461835a82eeSMatthew Dillon goto done2; 46233a9ed9dSJohn Baldwin } 46333a9ed9dSJohn Baldwin if (targp->p_pgrp == NULL || 46433a9ed9dSJohn Baldwin targp->p_session != curp->p_session) { 46533a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 466835a82eeSMatthew Dillon error = EPERM; 467835a82eeSMatthew Dillon goto done2; 46833a9ed9dSJohn Baldwin } 46933a9ed9dSJohn Baldwin if (targp->p_flag & P_EXEC) { 47033a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 471835a82eeSMatthew Dillon error = EACCES; 472835a82eeSMatthew Dillon goto done2; 47333a9ed9dSJohn Baldwin } 47433a9ed9dSJohn Baldwin } else { 475df8bae1dSRodney W. Grimes targp = curp; 47633a9ed9dSJohn Baldwin PROC_LOCK(curp); /* XXX: not needed */ 47733a9ed9dSJohn Baldwin } 47833a9ed9dSJohn Baldwin if (SESS_LEADER(targp)) { 47933a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 480835a82eeSMatthew Dillon error = EPERM; 481835a82eeSMatthew Dillon goto done2; 48233a9ed9dSJohn Baldwin } 483835a82eeSMatthew Dillon if (uap->pgid == 0) { 484df8bae1dSRodney W. Grimes uap->pgid = targp->p_pid; 485835a82eeSMatthew Dillon } else if (uap->pgid != targp->p_pid) { 486df8bae1dSRodney W. Grimes if ((pgrp = pgfind(uap->pgid)) == 0 || 48733a9ed9dSJohn Baldwin pgrp->pg_session != curp->p_session) { 48833a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 489835a82eeSMatthew Dillon error = EPERM; 490835a82eeSMatthew Dillon goto done2; 491835a82eeSMatthew Dillon } 49233a9ed9dSJohn Baldwin } 49333a9ed9dSJohn Baldwin /* XXX: We should probably hold the lock across enterpgrp. */ 49433a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 495835a82eeSMatthew Dillon error = enterpgrp(targp, uap->pgid, 0); 496835a82eeSMatthew Dillon done2: 497835a82eeSMatthew Dillon mtx_unlock(&Giant); 498835a82eeSMatthew Dillon return (error); 499df8bae1dSRodney W. Grimes } 500df8bae1dSRodney W. Grimes 501a08f4bf6SPeter Wemm /* 502a08f4bf6SPeter Wemm * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 5032fa72ea7SJeroen Ruigrok van der Werven * compatible. It says that setting the uid/gid to euid/egid is a special 504a08f4bf6SPeter Wemm * case of "appropriate privilege". Once the rules are expanded out, this 505a08f4bf6SPeter Wemm * basically means that setuid(nnn) sets all three id's, in all permitted 506a08f4bf6SPeter Wemm * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 507a08f4bf6SPeter Wemm * does not set the saved id - this is dangerous for traditional BSD 508a08f4bf6SPeter Wemm * programs. For this reason, we *really* do not want to set 509a08f4bf6SPeter Wemm * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 510a08f4bf6SPeter Wemm */ 511a08f4bf6SPeter Wemm #define POSIX_APPENDIX_B_4_2_2 512a08f4bf6SPeter Wemm 513d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 514df8bae1dSRodney W. Grimes struct setuid_args { 515df8bae1dSRodney W. Grimes uid_t uid; 516df8bae1dSRodney W. Grimes }; 517d2d3e875SBruce Evans #endif 518835a82eeSMatthew Dillon /* 519835a82eeSMatthew Dillon * MPSAFE 520835a82eeSMatthew Dillon */ 521df8bae1dSRodney W. Grimes /* ARGSUSED */ 52226f9a767SRodney W. Grimes int 523b40ce416SJulian Elischer setuid(td, uap) 524b40ce416SJulian Elischer struct thread *td; 525df8bae1dSRodney W. Grimes struct setuid_args *uap; 526df8bae1dSRodney W. Grimes { 527b40ce416SJulian Elischer struct proc *p = td->td_proc; 528b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 529b1fc0ec1SRobert Watson uid_t uid; 530835a82eeSMatthew Dillon int error = 0; 531df8bae1dSRodney W. Grimes 532b1fc0ec1SRobert Watson uid = uap->uid; 533b1fc0ec1SRobert Watson oldcred = p->p_ucred; 534835a82eeSMatthew Dillon mtx_lock(&Giant); 535835a82eeSMatthew Dillon 536a08f4bf6SPeter Wemm /* 537a08f4bf6SPeter Wemm * See if we have "permission" by POSIX 1003.1 rules. 538a08f4bf6SPeter Wemm * 539a08f4bf6SPeter Wemm * Note that setuid(geteuid()) is a special case of 540a08f4bf6SPeter Wemm * "appropriate privileges" in appendix B.4.2.2. We need 5412fa72ea7SJeroen Ruigrok van der Werven * to use this clause to be compatible with traditional BSD 542a08f4bf6SPeter Wemm * semantics. Basically, it means that "setuid(xx)" sets all 543a08f4bf6SPeter Wemm * three id's (assuming you have privs). 544a08f4bf6SPeter Wemm * 545a08f4bf6SPeter Wemm * Notes on the logic. We do things in three steps. 546a08f4bf6SPeter Wemm * 1: We determine if the euid is going to change, and do EPERM 547a08f4bf6SPeter Wemm * right away. We unconditionally change the euid later if this 548a08f4bf6SPeter Wemm * test is satisfied, simplifying that part of the logic. 549a08f4bf6SPeter Wemm * 2: We determine if the real and/or saved uid's are going to 550a08f4bf6SPeter Wemm * change. Determined by compile options. 551a08f4bf6SPeter Wemm * 3: Change euid last. (after tests in #2 for "appropriate privs") 552a08f4bf6SPeter Wemm */ 553b1fc0ec1SRobert Watson if (uid != oldcred->cr_ruid && /* allow setuid(getuid()) */ 5543f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS 555b1fc0ec1SRobert Watson uid != oldcred->cr_svuid && /* allow setuid(saved gid) */ 556a08f4bf6SPeter Wemm #endif 557a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 558b1fc0ec1SRobert Watson uid != oldcred->cr_uid && /* allow setuid(geteuid()) */ 5593f246666SAndrey A. Chernov #endif 560b1fc0ec1SRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) 561835a82eeSMatthew Dillon goto done2; 562a08f4bf6SPeter Wemm 563b1fc0ec1SRobert Watson newcred = crdup(oldcred); 564a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS 565df8bae1dSRodney W. Grimes /* 566a08f4bf6SPeter Wemm * Do we have "appropriate privileges" (are we root or uid == euid) 567a08f4bf6SPeter Wemm * If so, we are changing the real uid and/or saved uid. 568df8bae1dSRodney W. Grimes */ 5693f246666SAndrey A. Chernov if ( 570a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 571b1fc0ec1SRobert Watson uid == oldcred->cr_uid || 5723f246666SAndrey A. Chernov #endif 573b1fc0ec1SRobert Watson suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */ 574a08f4bf6SPeter Wemm #endif 575a08f4bf6SPeter Wemm { 576a08f4bf6SPeter Wemm /* 577f535380cSDon Lewis * Set the real uid and transfer proc count to new user. 578a08f4bf6SPeter Wemm */ 579b1fc0ec1SRobert Watson if (uid != oldcred->cr_ruid) { 580b1fc0ec1SRobert Watson change_ruid(newcred, uid); 581f535380cSDon Lewis setsugid(p); 582d3cdb93dSAndrey A. Chernov } 583a08f4bf6SPeter Wemm /* 584a08f4bf6SPeter Wemm * Set saved uid 585a08f4bf6SPeter Wemm * 586a08f4bf6SPeter Wemm * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 587a08f4bf6SPeter Wemm * the security of seteuid() depends on it. B.4.2.2 says it 588a08f4bf6SPeter Wemm * is important that we should do this. 589a08f4bf6SPeter Wemm */ 590b1fc0ec1SRobert Watson if (uid != oldcred->cr_svuid) { 591b1fc0ec1SRobert Watson change_svuid(newcred, uid); 592d5f81602SSean Eric Fagan setsugid(p); 593a08f4bf6SPeter Wemm } 594a08f4bf6SPeter Wemm } 595a08f4bf6SPeter Wemm 596a08f4bf6SPeter Wemm /* 597a08f4bf6SPeter Wemm * In all permitted cases, we are changing the euid. 598a08f4bf6SPeter Wemm * Copy credentials so other references do not see our changes. 599a08f4bf6SPeter Wemm */ 600b1fc0ec1SRobert Watson if (uid != oldcred->cr_uid) { 601b1fc0ec1SRobert Watson change_euid(newcred, uid); 602d5f81602SSean Eric Fagan setsugid(p); 603a08f4bf6SPeter Wemm } 604b1fc0ec1SRobert Watson p->p_ucred = newcred; 605b1fc0ec1SRobert Watson crfree(oldcred); 606835a82eeSMatthew Dillon done2: 607835a82eeSMatthew Dillon mtx_unlock(&Giant); 608835a82eeSMatthew Dillon return (error); 609df8bae1dSRodney W. Grimes } 610df8bae1dSRodney W. Grimes 611d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 612df8bae1dSRodney W. Grimes struct seteuid_args { 613df8bae1dSRodney W. Grimes uid_t euid; 614df8bae1dSRodney W. Grimes }; 615d2d3e875SBruce Evans #endif 616835a82eeSMatthew Dillon /* 617835a82eeSMatthew Dillon * MPSAFE 618835a82eeSMatthew Dillon */ 619df8bae1dSRodney W. Grimes /* ARGSUSED */ 62026f9a767SRodney W. Grimes int 621b40ce416SJulian Elischer seteuid(td, uap) 622b40ce416SJulian Elischer struct thread *td; 623df8bae1dSRodney W. Grimes struct seteuid_args *uap; 624df8bae1dSRodney W. Grimes { 625b40ce416SJulian Elischer struct proc *p = td->td_proc; 626b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 627b1fc0ec1SRobert Watson uid_t euid; 628835a82eeSMatthew Dillon int error = 0; 629df8bae1dSRodney W. Grimes 630df8bae1dSRodney W. Grimes euid = uap->euid; 631835a82eeSMatthew Dillon 632835a82eeSMatthew Dillon mtx_lock(&Giant); 633b1fc0ec1SRobert Watson oldcred = p->p_ucred; 634b1fc0ec1SRobert Watson if (euid != oldcred->cr_ruid && /* allow seteuid(getuid()) */ 635b1fc0ec1SRobert Watson euid != oldcred->cr_svuid && /* allow seteuid(saved uid) */ 636835a82eeSMatthew Dillon (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) { 637835a82eeSMatthew Dillon goto done2; 638835a82eeSMatthew Dillon } 639df8bae1dSRodney W. Grimes /* 640df8bae1dSRodney W. Grimes * Everything's okay, do it. Copy credentials so other references do 641df8bae1dSRodney W. Grimes * not see our changes. 642df8bae1dSRodney W. Grimes */ 643b1fc0ec1SRobert Watson newcred = crdup(oldcred); 644b1fc0ec1SRobert Watson if (oldcred->cr_uid != euid) { 645b1fc0ec1SRobert Watson change_euid(newcred, euid); 646d5f81602SSean Eric Fagan setsugid(p); 647229a15f0SPeter Wemm } 648b1fc0ec1SRobert Watson p->p_ucred = newcred; 649b1fc0ec1SRobert Watson crfree(oldcred); 650835a82eeSMatthew Dillon done2: 651835a82eeSMatthew Dillon mtx_unlock(&Giant); 652835a82eeSMatthew Dillon return (error); 653df8bae1dSRodney W. Grimes } 654df8bae1dSRodney W. Grimes 655d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 656df8bae1dSRodney W. Grimes struct setgid_args { 657df8bae1dSRodney W. Grimes gid_t gid; 658df8bae1dSRodney W. Grimes }; 659d2d3e875SBruce Evans #endif 660835a82eeSMatthew Dillon /* 661835a82eeSMatthew Dillon * MPSAFE 662835a82eeSMatthew Dillon */ 663df8bae1dSRodney W. Grimes /* ARGSUSED */ 66426f9a767SRodney W. Grimes int 665b40ce416SJulian Elischer setgid(td, uap) 666b40ce416SJulian Elischer struct thread *td; 667df8bae1dSRodney W. Grimes struct setgid_args *uap; 668df8bae1dSRodney W. Grimes { 669b40ce416SJulian Elischer struct proc *p = td->td_proc; 670b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 671b1fc0ec1SRobert Watson gid_t gid; 672835a82eeSMatthew Dillon int error = 0; 673df8bae1dSRodney W. Grimes 674b1fc0ec1SRobert Watson gid = uap->gid; 675835a82eeSMatthew Dillon 676835a82eeSMatthew Dillon mtx_lock(&Giant); 677b1fc0ec1SRobert Watson oldcred = p->p_ucred; 678a08f4bf6SPeter Wemm /* 679a08f4bf6SPeter Wemm * See if we have "permission" by POSIX 1003.1 rules. 680a08f4bf6SPeter Wemm * 681a08f4bf6SPeter Wemm * Note that setgid(getegid()) is a special case of 682a08f4bf6SPeter Wemm * "appropriate privileges" in appendix B.4.2.2. We need 6832fa72ea7SJeroen Ruigrok van der Werven * to use this clause to be compatible with traditional BSD 684a08f4bf6SPeter Wemm * semantics. Basically, it means that "setgid(xx)" sets all 685a08f4bf6SPeter Wemm * three id's (assuming you have privs). 686a08f4bf6SPeter Wemm * 687a08f4bf6SPeter Wemm * For notes on the logic here, see setuid() above. 688a08f4bf6SPeter Wemm */ 689b1fc0ec1SRobert Watson if (gid != oldcred->cr_rgid && /* allow setgid(getgid()) */ 6903f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS 691b1fc0ec1SRobert Watson gid != oldcred->cr_svgid && /* allow setgid(saved gid) */ 692a08f4bf6SPeter Wemm #endif 693a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 694b1fc0ec1SRobert Watson gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */ 6953f246666SAndrey A. Chernov #endif 696835a82eeSMatthew Dillon (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) { 697835a82eeSMatthew Dillon goto done2; 698835a82eeSMatthew Dillon } 699a08f4bf6SPeter Wemm 700b1fc0ec1SRobert Watson newcred = crdup(oldcred); 701a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS 702a08f4bf6SPeter Wemm /* 703a08f4bf6SPeter Wemm * Do we have "appropriate privileges" (are we root or gid == egid) 704a08f4bf6SPeter Wemm * If so, we are changing the real uid and saved gid. 705a08f4bf6SPeter Wemm */ 706a08f4bf6SPeter Wemm if ( 707a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 708b1fc0ec1SRobert Watson gid == oldcred->cr_groups[0] || 709a08f4bf6SPeter Wemm #endif 710b1fc0ec1SRobert Watson suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */ 711a08f4bf6SPeter Wemm #endif 712a08f4bf6SPeter Wemm { 713a08f4bf6SPeter Wemm /* 714a08f4bf6SPeter Wemm * Set real gid 715a08f4bf6SPeter Wemm */ 716b1fc0ec1SRobert Watson if (oldcred->cr_rgid != gid) { 717b1fc0ec1SRobert Watson change_rgid(newcred, gid); 718d5f81602SSean Eric Fagan setsugid(p); 719a08f4bf6SPeter Wemm } 720a08f4bf6SPeter Wemm /* 721a08f4bf6SPeter Wemm * Set saved gid 722a08f4bf6SPeter Wemm * 723a08f4bf6SPeter Wemm * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 724a08f4bf6SPeter Wemm * the security of setegid() depends on it. B.4.2.2 says it 725a08f4bf6SPeter Wemm * is important that we should do this. 726a08f4bf6SPeter Wemm */ 727b1fc0ec1SRobert Watson if (oldcred->cr_svgid != gid) { 728b1fc0ec1SRobert Watson change_svgid(newcred, gid); 729d5f81602SSean Eric Fagan setsugid(p); 730a08f4bf6SPeter Wemm } 731a08f4bf6SPeter Wemm } 732a08f4bf6SPeter Wemm /* 733a08f4bf6SPeter Wemm * In all cases permitted cases, we are changing the egid. 734a08f4bf6SPeter Wemm * Copy credentials so other references do not see our changes. 735a08f4bf6SPeter Wemm */ 736b1fc0ec1SRobert Watson if (oldcred->cr_groups[0] != gid) { 737b1fc0ec1SRobert Watson change_egid(newcred, gid); 738d5f81602SSean Eric Fagan setsugid(p); 739a08f4bf6SPeter Wemm } 740b1fc0ec1SRobert Watson p->p_ucred = newcred; 741b1fc0ec1SRobert Watson crfree(oldcred); 742835a82eeSMatthew Dillon done2: 743835a82eeSMatthew Dillon mtx_unlock(&Giant); 744835a82eeSMatthew Dillon return (error); 745df8bae1dSRodney W. Grimes } 746df8bae1dSRodney W. Grimes 747d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 748df8bae1dSRodney W. Grimes struct setegid_args { 749df8bae1dSRodney W. Grimes gid_t egid; 750df8bae1dSRodney W. Grimes }; 751d2d3e875SBruce Evans #endif 752835a82eeSMatthew Dillon /* 753835a82eeSMatthew Dillon * MPSAFE 754835a82eeSMatthew Dillon */ 755df8bae1dSRodney W. Grimes /* ARGSUSED */ 75626f9a767SRodney W. Grimes int 757b40ce416SJulian Elischer setegid(td, uap) 758b40ce416SJulian Elischer struct thread *td; 759df8bae1dSRodney W. Grimes struct setegid_args *uap; 760df8bae1dSRodney W. Grimes { 761b40ce416SJulian Elischer struct proc *p = td->td_proc; 762b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 763b1fc0ec1SRobert Watson gid_t egid; 764835a82eeSMatthew Dillon int error = 0; 765df8bae1dSRodney W. Grimes 766df8bae1dSRodney W. Grimes egid = uap->egid; 767835a82eeSMatthew Dillon 768835a82eeSMatthew Dillon mtx_lock(&Giant); 769b1fc0ec1SRobert Watson oldcred = p->p_ucred; 770b1fc0ec1SRobert Watson if (egid != oldcred->cr_rgid && /* allow setegid(getgid()) */ 771b1fc0ec1SRobert Watson egid != oldcred->cr_svgid && /* allow setegid(saved gid) */ 772835a82eeSMatthew Dillon (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) { 773835a82eeSMatthew Dillon goto done2; 774835a82eeSMatthew Dillon } 775b1fc0ec1SRobert Watson newcred = crdup(oldcred); 776b1fc0ec1SRobert Watson if (oldcred->cr_groups[0] != egid) { 777b1fc0ec1SRobert Watson change_egid(newcred, egid); 778d5f81602SSean Eric Fagan setsugid(p); 779229a15f0SPeter Wemm } 780b1fc0ec1SRobert Watson p->p_ucred = newcred; 781b1fc0ec1SRobert Watson crfree(oldcred); 782835a82eeSMatthew Dillon done2: 783835a82eeSMatthew Dillon mtx_unlock(&Giant); 784835a82eeSMatthew Dillon return (error); 785df8bae1dSRodney W. Grimes } 786df8bae1dSRodney W. Grimes 787d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 788df8bae1dSRodney W. Grimes struct setgroups_args { 789df8bae1dSRodney W. Grimes u_int gidsetsize; 790df8bae1dSRodney W. Grimes gid_t *gidset; 791df8bae1dSRodney W. Grimes }; 792d2d3e875SBruce Evans #endif 793835a82eeSMatthew Dillon /* 794835a82eeSMatthew Dillon * MPSAFE 795835a82eeSMatthew Dillon */ 796df8bae1dSRodney W. Grimes /* ARGSUSED */ 79726f9a767SRodney W. Grimes int 798b40ce416SJulian Elischer setgroups(td, uap) 799b40ce416SJulian Elischer struct thread *td; 800df8bae1dSRodney W. Grimes struct setgroups_args *uap; 801df8bae1dSRodney W. Grimes { 802b40ce416SJulian Elischer struct proc *p = td->td_proc; 803b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 804b1fc0ec1SRobert Watson u_int ngrp; 805df8bae1dSRodney W. Grimes int error; 806df8bae1dSRodney W. Grimes 807835a82eeSMatthew Dillon mtx_lock(&Giant); 808835a82eeSMatthew Dillon 8093956a170SDavid Greenman ngrp = uap->gidsetsize; 810b1fc0ec1SRobert Watson oldcred = p->p_ucred; 811b1fc0ec1SRobert Watson if ((error = suser_xxx(oldcred, NULL, PRISON_ROOT))) 812835a82eeSMatthew Dillon goto done2; 813835a82eeSMatthew Dillon if (ngrp > NGROUPS) { 814835a82eeSMatthew Dillon error = EINVAL; 815835a82eeSMatthew Dillon goto done2; 816835a82eeSMatthew Dillon } 8178a5d815aSPeter Wemm /* 8188a5d815aSPeter Wemm * XXX A little bit lazy here. We could test if anything has 8198a5d815aSPeter Wemm * changed before crcopy() and setting P_SUGID. 8208a5d815aSPeter Wemm */ 821b1fc0ec1SRobert Watson newcred = crdup(oldcred); 8228a5d815aSPeter Wemm if (ngrp < 1) { 8238a5d815aSPeter Wemm /* 8248a5d815aSPeter Wemm * setgroups(0, NULL) is a legitimate way of clearing the 8258a5d815aSPeter Wemm * groups vector on non-BSD systems (which generally do not 8268a5d815aSPeter Wemm * have the egid in the groups[0]). We risk security holes 8278a5d815aSPeter Wemm * when running non-BSD software if we do not do the same. 8288a5d815aSPeter Wemm */ 829b1fc0ec1SRobert Watson newcred->cr_ngroups = 1; 8308a5d815aSPeter Wemm } else { 831bb56ec4aSPoul-Henning Kamp if ((error = copyin((caddr_t)uap->gidset, 832b1fc0ec1SRobert Watson (caddr_t)newcred->cr_groups, ngrp * sizeof(gid_t)))) { 833b1fc0ec1SRobert Watson crfree(newcred); 834835a82eeSMatthew Dillon goto done2; 835b1fc0ec1SRobert Watson } 836b1fc0ec1SRobert Watson newcred->cr_ngroups = ngrp; 8378a5d815aSPeter Wemm } 838d5f81602SSean Eric Fagan setsugid(p); 839b1fc0ec1SRobert Watson p->p_ucred = newcred; 840b1fc0ec1SRobert Watson crfree(oldcred); 841835a82eeSMatthew Dillon done2: 842835a82eeSMatthew Dillon mtx_unlock(&Giant); 843835a82eeSMatthew Dillon return (error); 844df8bae1dSRodney W. Grimes } 845df8bae1dSRodney W. Grimes 846d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 847df8bae1dSRodney W. Grimes struct setreuid_args { 84800999cd6SAndrey A. Chernov uid_t ruid; 84900999cd6SAndrey A. Chernov uid_t euid; 850df8bae1dSRodney W. Grimes }; 851d2d3e875SBruce Evans #endif 852835a82eeSMatthew Dillon /* 853835a82eeSMatthew Dillon * MPSAFE 854835a82eeSMatthew Dillon */ 855df8bae1dSRodney W. Grimes /* ARGSUSED */ 85626f9a767SRodney W. Grimes int 857b40ce416SJulian Elischer setreuid(td, uap) 858b40ce416SJulian Elischer register struct thread *td; 859df8bae1dSRodney W. Grimes struct setreuid_args *uap; 860df8bae1dSRodney W. Grimes { 861b40ce416SJulian Elischer struct proc *p = td->td_proc; 862b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 863b1fc0ec1SRobert Watson uid_t ruid, euid; 864835a82eeSMatthew Dillon int error = 0; 865df8bae1dSRodney W. Grimes 86600999cd6SAndrey A. Chernov ruid = uap->ruid; 86700999cd6SAndrey A. Chernov euid = uap->euid; 868835a82eeSMatthew Dillon 869835a82eeSMatthew Dillon mtx_lock(&Giant); 870835a82eeSMatthew Dillon 871b1fc0ec1SRobert Watson oldcred = p->p_ucred; 872b1fc0ec1SRobert Watson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 873b1fc0ec1SRobert Watson ruid != oldcred->cr_svuid) || 874b1fc0ec1SRobert Watson (euid != (uid_t)-1 && euid != oldcred->cr_uid && 875b1fc0ec1SRobert Watson euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) && 876835a82eeSMatthew Dillon (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) { 877835a82eeSMatthew Dillon goto done2; 878835a82eeSMatthew Dillon } 879b1fc0ec1SRobert Watson newcred = crdup(oldcred); 880b1fc0ec1SRobert Watson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 881b1fc0ec1SRobert Watson change_euid(newcred, euid); 882d5f81602SSean Eric Fagan setsugid(p); 883a89a5370SPeter Wemm } 884b1fc0ec1SRobert Watson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 885b1fc0ec1SRobert Watson change_ruid(newcred, ruid); 886d5f81602SSean Eric Fagan setsugid(p); 88700999cd6SAndrey A. Chernov } 888b1fc0ec1SRobert Watson if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) && 889b1fc0ec1SRobert Watson newcred->cr_svuid != newcred->cr_uid) { 890b1fc0ec1SRobert Watson change_svuid(newcred, newcred->cr_uid); 891d5f81602SSean Eric Fagan setsugid(p); 892a89a5370SPeter Wemm } 893b1fc0ec1SRobert Watson p->p_ucred = newcred; 894b1fc0ec1SRobert Watson crfree(oldcred); 895835a82eeSMatthew Dillon done2: 896835a82eeSMatthew Dillon mtx_unlock(&Giant); 897835a82eeSMatthew Dillon return (error); 898df8bae1dSRodney W. Grimes } 899df8bae1dSRodney W. Grimes 900d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 901df8bae1dSRodney W. Grimes struct setregid_args { 90200999cd6SAndrey A. Chernov gid_t rgid; 90300999cd6SAndrey A. Chernov gid_t egid; 904df8bae1dSRodney W. Grimes }; 905d2d3e875SBruce Evans #endif 906835a82eeSMatthew Dillon /* 907835a82eeSMatthew Dillon * MPSAFE 908835a82eeSMatthew Dillon */ 909df8bae1dSRodney W. Grimes /* ARGSUSED */ 91026f9a767SRodney W. Grimes int 911b40ce416SJulian Elischer setregid(td, uap) 912b40ce416SJulian Elischer register struct thread *td; 913df8bae1dSRodney W. Grimes struct setregid_args *uap; 914df8bae1dSRodney W. Grimes { 915b40ce416SJulian Elischer struct proc *p = td->td_proc; 916b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 917b1fc0ec1SRobert Watson gid_t rgid, egid; 918835a82eeSMatthew Dillon int error = 0; 919df8bae1dSRodney W. Grimes 92000999cd6SAndrey A. Chernov rgid = uap->rgid; 92100999cd6SAndrey A. Chernov egid = uap->egid; 922835a82eeSMatthew Dillon 923835a82eeSMatthew Dillon mtx_lock(&Giant); 924835a82eeSMatthew Dillon 925b1fc0ec1SRobert Watson oldcred = p->p_ucred; 926b1fc0ec1SRobert Watson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 927b1fc0ec1SRobert Watson rgid != oldcred->cr_svgid) || 928b1fc0ec1SRobert Watson (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] && 929b1fc0ec1SRobert Watson egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) && 930835a82eeSMatthew Dillon (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) { 931835a82eeSMatthew Dillon goto done2; 932835a82eeSMatthew Dillon } 93300999cd6SAndrey A. Chernov 934b1fc0ec1SRobert Watson newcred = crdup(oldcred); 935b1fc0ec1SRobert Watson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 936b1fc0ec1SRobert Watson change_egid(newcred, egid); 937d5f81602SSean Eric Fagan setsugid(p); 938a89a5370SPeter Wemm } 939b1fc0ec1SRobert Watson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 940b1fc0ec1SRobert Watson change_rgid(newcred, rgid); 941d5f81602SSean Eric Fagan setsugid(p); 942a89a5370SPeter Wemm } 943b1fc0ec1SRobert Watson if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) && 944b1fc0ec1SRobert Watson newcred->cr_svgid != newcred->cr_groups[0]) { 945b1fc0ec1SRobert Watson change_svgid(newcred, newcred->cr_groups[0]); 946d5f81602SSean Eric Fagan setsugid(p); 947a89a5370SPeter Wemm } 9484589be70SRuslan Ermilov p->p_ucred = newcred; 9494589be70SRuslan Ermilov crfree(oldcred); 950835a82eeSMatthew Dillon done2: 951835a82eeSMatthew Dillon mtx_unlock(&Giant); 952835a82eeSMatthew Dillon return (error); 953df8bae1dSRodney W. Grimes } 954df8bae1dSRodney W. Grimes 9558ccd6334SPeter Wemm /* 9568ccd6334SPeter Wemm * setresuid(ruid, euid, suid) is like setreuid except control over the 9578ccd6334SPeter Wemm * saved uid is explicit. 9588ccd6334SPeter Wemm */ 9598ccd6334SPeter Wemm 9608ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 9618ccd6334SPeter Wemm struct setresuid_args { 9628ccd6334SPeter Wemm uid_t ruid; 9638ccd6334SPeter Wemm uid_t euid; 9648ccd6334SPeter Wemm uid_t suid; 9658ccd6334SPeter Wemm }; 9668ccd6334SPeter Wemm #endif 967835a82eeSMatthew Dillon /* 968835a82eeSMatthew Dillon * MPSAFE 969835a82eeSMatthew Dillon */ 9708ccd6334SPeter Wemm /* ARGSUSED */ 9718ccd6334SPeter Wemm int 972b40ce416SJulian Elischer setresuid(td, uap) 973b40ce416SJulian Elischer register struct thread *td; 9748ccd6334SPeter Wemm struct setresuid_args *uap; 9758ccd6334SPeter Wemm { 976b40ce416SJulian Elischer struct proc *p = td->td_proc; 977b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 978b1fc0ec1SRobert Watson uid_t ruid, euid, suid; 9798ccd6334SPeter Wemm int error; 9808ccd6334SPeter Wemm 9818ccd6334SPeter Wemm ruid = uap->ruid; 9828ccd6334SPeter Wemm euid = uap->euid; 9838ccd6334SPeter Wemm suid = uap->suid; 984835a82eeSMatthew Dillon 985835a82eeSMatthew Dillon mtx_lock(&Giant); 986b1fc0ec1SRobert Watson oldcred = p->p_ucred; 987b1fc0ec1SRobert Watson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 988b1fc0ec1SRobert Watson ruid != oldcred->cr_svuid && 989b1fc0ec1SRobert Watson ruid != oldcred->cr_uid) || 990b1fc0ec1SRobert Watson (euid != (uid_t)-1 && euid != oldcred->cr_ruid && 991b1fc0ec1SRobert Watson euid != oldcred->cr_svuid && 992b1fc0ec1SRobert Watson euid != oldcred->cr_uid) || 993b1fc0ec1SRobert Watson (suid != (uid_t)-1 && suid != oldcred->cr_ruid && 994b1fc0ec1SRobert Watson suid != oldcred->cr_svuid && 995b1fc0ec1SRobert Watson suid != oldcred->cr_uid)) && 996835a82eeSMatthew Dillon (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) { 997835a82eeSMatthew Dillon goto done2; 998835a82eeSMatthew Dillon } 999b1fc0ec1SRobert Watson 1000b1fc0ec1SRobert Watson newcred = crdup(oldcred); 1001b1fc0ec1SRobert Watson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 1002b1fc0ec1SRobert Watson change_euid(newcred, euid); 10038ccd6334SPeter Wemm setsugid(p); 10048ccd6334SPeter Wemm } 1005b1fc0ec1SRobert Watson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 1006b1fc0ec1SRobert Watson change_ruid(newcred, ruid); 10078ccd6334SPeter Wemm setsugid(p); 10088ccd6334SPeter Wemm } 1009b1fc0ec1SRobert Watson if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) { 1010b1fc0ec1SRobert Watson change_svuid(newcred, suid); 10118ccd6334SPeter Wemm setsugid(p); 10128ccd6334SPeter Wemm } 1013b1fc0ec1SRobert Watson p->p_ucred = newcred; 1014b1fc0ec1SRobert Watson crfree(oldcred); 1015835a82eeSMatthew Dillon error = 0; 1016835a82eeSMatthew Dillon done2: 1017835a82eeSMatthew Dillon mtx_unlock(&Giant); 1018835a82eeSMatthew Dillon return (error); 10198ccd6334SPeter Wemm } 10208ccd6334SPeter Wemm 10218ccd6334SPeter Wemm /* 10228ccd6334SPeter Wemm * setresgid(rgid, egid, sgid) is like setregid except control over the 10238ccd6334SPeter Wemm * saved gid is explicit. 10248ccd6334SPeter Wemm */ 10258ccd6334SPeter Wemm 10268ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 10278ccd6334SPeter Wemm struct setresgid_args { 10288ccd6334SPeter Wemm gid_t rgid; 10298ccd6334SPeter Wemm gid_t egid; 10308ccd6334SPeter Wemm gid_t sgid; 10318ccd6334SPeter Wemm }; 10328ccd6334SPeter Wemm #endif 1033835a82eeSMatthew Dillon /* 1034835a82eeSMatthew Dillon * MPSAFE 1035835a82eeSMatthew Dillon */ 10368ccd6334SPeter Wemm /* ARGSUSED */ 10378ccd6334SPeter Wemm int 1038b40ce416SJulian Elischer setresgid(td, uap) 1039b40ce416SJulian Elischer register struct thread *td; 10408ccd6334SPeter Wemm struct setresgid_args *uap; 10418ccd6334SPeter Wemm { 1042b40ce416SJulian Elischer struct proc *p = td->td_proc; 1043b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 1044b1fc0ec1SRobert Watson gid_t rgid, egid, sgid; 10458ccd6334SPeter Wemm int error; 10468ccd6334SPeter Wemm 10478ccd6334SPeter Wemm rgid = uap->rgid; 10488ccd6334SPeter Wemm egid = uap->egid; 10498ccd6334SPeter Wemm sgid = uap->sgid; 1050835a82eeSMatthew Dillon 1051835a82eeSMatthew Dillon mtx_lock(&Giant); 1052b1fc0ec1SRobert Watson oldcred = p->p_ucred; 1053b1fc0ec1SRobert Watson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 1054b1fc0ec1SRobert Watson rgid != oldcred->cr_svgid && 1055b1fc0ec1SRobert Watson rgid != oldcred->cr_groups[0]) || 1056b1fc0ec1SRobert Watson (egid != (gid_t)-1 && egid != oldcred->cr_rgid && 1057b1fc0ec1SRobert Watson egid != oldcred->cr_svgid && 1058b1fc0ec1SRobert Watson egid != oldcred->cr_groups[0]) || 1059b1fc0ec1SRobert Watson (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid && 1060b1fc0ec1SRobert Watson sgid != oldcred->cr_svgid && 1061b1fc0ec1SRobert Watson sgid != oldcred->cr_groups[0])) && 1062835a82eeSMatthew Dillon (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) { 1063835a82eeSMatthew Dillon goto done2; 1064835a82eeSMatthew Dillon } 1065b1fc0ec1SRobert Watson newcred = crdup(oldcred); 1066b1fc0ec1SRobert Watson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 1067b1fc0ec1SRobert Watson change_egid(newcred, egid); 10688ccd6334SPeter Wemm setsugid(p); 10698ccd6334SPeter Wemm } 1070b1fc0ec1SRobert Watson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 1071b1fc0ec1SRobert Watson change_rgid(newcred, rgid); 10728ccd6334SPeter Wemm setsugid(p); 10738ccd6334SPeter Wemm } 1074b1fc0ec1SRobert Watson if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) { 1075b1fc0ec1SRobert Watson change_svgid(newcred, sgid); 10768ccd6334SPeter Wemm setsugid(p); 10778ccd6334SPeter Wemm } 1078b1fc0ec1SRobert Watson p->p_ucred = newcred; 1079b1fc0ec1SRobert Watson crfree(oldcred); 1080835a82eeSMatthew Dillon error = 0; 1081835a82eeSMatthew Dillon done2: 1082835a82eeSMatthew Dillon mtx_unlock(&Giant); 1083835a82eeSMatthew Dillon return (error); 10848ccd6334SPeter Wemm } 10858ccd6334SPeter Wemm 10868ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 10878ccd6334SPeter Wemm struct getresuid_args { 10888ccd6334SPeter Wemm uid_t *ruid; 10898ccd6334SPeter Wemm uid_t *euid; 10908ccd6334SPeter Wemm uid_t *suid; 10918ccd6334SPeter Wemm }; 10928ccd6334SPeter Wemm #endif 1093835a82eeSMatthew Dillon /* 1094835a82eeSMatthew Dillon * MPSAFE 1095835a82eeSMatthew Dillon */ 10968ccd6334SPeter Wemm /* ARGSUSED */ 10978ccd6334SPeter Wemm int 1098b40ce416SJulian Elischer getresuid(td, uap) 1099b40ce416SJulian Elischer register struct thread *td; 11008ccd6334SPeter Wemm struct getresuid_args *uap; 11018ccd6334SPeter Wemm { 1102835a82eeSMatthew Dillon struct ucred *cred; 1103b40ce416SJulian Elischer struct proc *p = td->td_proc; 11048ccd6334SPeter Wemm int error1 = 0, error2 = 0, error3 = 0; 11058ccd6334SPeter Wemm 1106835a82eeSMatthew Dillon mtx_lock(&Giant); 1107835a82eeSMatthew Dillon cred = p->p_ucred; 1108835a82eeSMatthew Dillon 11098ccd6334SPeter Wemm if (uap->ruid) 1110b1fc0ec1SRobert Watson error1 = copyout((caddr_t)&cred->cr_ruid, 1111b1fc0ec1SRobert Watson (caddr_t)uap->ruid, sizeof(cred->cr_ruid)); 11128ccd6334SPeter Wemm if (uap->euid) 1113b1fc0ec1SRobert Watson error2 = copyout((caddr_t)&cred->cr_uid, 1114b1fc0ec1SRobert Watson (caddr_t)uap->euid, sizeof(cred->cr_uid)); 11158ccd6334SPeter Wemm if (uap->suid) 1116b1fc0ec1SRobert Watson error3 = copyout((caddr_t)&cred->cr_svuid, 1117b1fc0ec1SRobert Watson (caddr_t)uap->suid, sizeof(cred->cr_svuid)); 1118835a82eeSMatthew Dillon mtx_unlock(&Giant); 11198ccd6334SPeter Wemm return error1 ? error1 : (error2 ? error2 : error3); 11208ccd6334SPeter Wemm } 11218ccd6334SPeter Wemm 11228ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 11238ccd6334SPeter Wemm struct getresgid_args { 11248ccd6334SPeter Wemm gid_t *rgid; 11258ccd6334SPeter Wemm gid_t *egid; 11268ccd6334SPeter Wemm gid_t *sgid; 11278ccd6334SPeter Wemm }; 11288ccd6334SPeter Wemm #endif 1129835a82eeSMatthew Dillon /* 1130835a82eeSMatthew Dillon * MPSAFE 1131835a82eeSMatthew Dillon */ 11328ccd6334SPeter Wemm /* ARGSUSED */ 11338ccd6334SPeter Wemm int 1134b40ce416SJulian Elischer getresgid(td, uap) 1135b40ce416SJulian Elischer register struct thread *td; 11368ccd6334SPeter Wemm struct getresgid_args *uap; 11378ccd6334SPeter Wemm { 1138835a82eeSMatthew Dillon struct ucred *cred; 1139b40ce416SJulian Elischer struct proc *p = td->td_proc; 11408ccd6334SPeter Wemm int error1 = 0, error2 = 0, error3 = 0; 11418ccd6334SPeter Wemm 1142835a82eeSMatthew Dillon mtx_lock(&Giant); 1143835a82eeSMatthew Dillon cred = p->p_ucred; 1144835a82eeSMatthew Dillon 11458ccd6334SPeter Wemm if (uap->rgid) 1146b1fc0ec1SRobert Watson error1 = copyout((caddr_t)&cred->cr_rgid, 1147b1fc0ec1SRobert Watson (caddr_t)uap->rgid, sizeof(cred->cr_rgid)); 11488ccd6334SPeter Wemm if (uap->egid) 1149b1fc0ec1SRobert Watson error2 = copyout((caddr_t)&cred->cr_groups[0], 1150b1fc0ec1SRobert Watson (caddr_t)uap->egid, sizeof(cred->cr_groups[0])); 11518ccd6334SPeter Wemm if (uap->sgid) 1152b1fc0ec1SRobert Watson error3 = copyout((caddr_t)&cred->cr_svgid, 1153b1fc0ec1SRobert Watson (caddr_t)uap->sgid, sizeof(cred->cr_svgid)); 1154835a82eeSMatthew Dillon mtx_unlock(&Giant); 11558ccd6334SPeter Wemm return error1 ? error1 : (error2 ? error2 : error3); 11568ccd6334SPeter Wemm } 11578ccd6334SPeter Wemm 11588ccd6334SPeter Wemm 1159b67cbc65SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1160b67cbc65SPeter Wemm struct issetugid_args { 1161b67cbc65SPeter Wemm int dummy; 1162b67cbc65SPeter Wemm }; 1163b67cbc65SPeter Wemm #endif 1164b67cbc65SPeter Wemm /* ARGSUSED */ 1165b67cbc65SPeter Wemm int 1166b40ce416SJulian Elischer issetugid(td, uap) 1167b40ce416SJulian Elischer register struct thread *td; 1168b67cbc65SPeter Wemm struct issetugid_args *uap; 1169b67cbc65SPeter Wemm { 1170b40ce416SJulian Elischer struct proc *p = td->td_proc; 1171b40ce416SJulian Elischer 1172b67cbc65SPeter Wemm /* 1173b67cbc65SPeter Wemm * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 1174b67cbc65SPeter Wemm * we use P_SUGID because we consider changing the owners as 1175b67cbc65SPeter Wemm * "tainting" as well. 1176b67cbc65SPeter Wemm * This is significant for procs that start as root and "become" 1177b67cbc65SPeter Wemm * a user without an exec - programs cannot know *everything* 1178b67cbc65SPeter Wemm * that libc *might* have put in their data segment. 1179b67cbc65SPeter Wemm */ 1180b40ce416SJulian Elischer td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 1181b67cbc65SPeter Wemm return (0); 1182b67cbc65SPeter Wemm } 1183b67cbc65SPeter Wemm 1184835a82eeSMatthew Dillon /* 1185835a82eeSMatthew Dillon * MPSAFE 1186835a82eeSMatthew Dillon */ 1187130d0157SRobert Watson int 1188b40ce416SJulian Elischer __setugid(td, uap) 1189b40ce416SJulian Elischer struct thread *td; 1190130d0157SRobert Watson struct __setugid_args *uap; 1191130d0157SRobert Watson { 1192130d0157SRobert Watson #ifdef REGRESSION 1193835a82eeSMatthew Dillon int error = 0; 1194835a82eeSMatthew Dillon 1195835a82eeSMatthew Dillon mtx_lock(&Giant); 1196130d0157SRobert Watson switch (uap->flag) { 1197130d0157SRobert Watson case 0: 1198b40ce416SJulian Elischer td->td_proc->p_flag &= ~P_SUGID; 1199835a82eeSMatthew Dillon break; 1200130d0157SRobert Watson case 1: 1201b40ce416SJulian Elischer td->td_proc->p_flag |= P_SUGID; 1202835a82eeSMatthew Dillon break; 1203130d0157SRobert Watson default: 1204835a82eeSMatthew Dillon error = EINVAL; 1205835a82eeSMatthew Dillon break; 1206130d0157SRobert Watson } 1207835a82eeSMatthew Dillon mtx_unlock(&Giant); 1208835a82eeSMatthew Dillon return (error); 1209130d0157SRobert Watson #else /* !REGRESSION */ 1210130d0157SRobert Watson return (ENOSYS); 1211130d0157SRobert Watson #endif /* !REGRESSION */ 1212130d0157SRobert Watson } 1213130d0157SRobert Watson 1214df8bae1dSRodney W. Grimes /* 1215df8bae1dSRodney W. Grimes * Check if gid is a member of the group set. 1216df8bae1dSRodney W. Grimes */ 121726f9a767SRodney W. Grimes int 1218df8bae1dSRodney W. Grimes groupmember(gid, cred) 1219df8bae1dSRodney W. Grimes gid_t gid; 1220b1fc0ec1SRobert Watson struct ucred *cred; 1221df8bae1dSRodney W. Grimes { 1222df8bae1dSRodney W. Grimes register gid_t *gp; 1223df8bae1dSRodney W. Grimes gid_t *egp; 1224df8bae1dSRodney W. Grimes 1225df8bae1dSRodney W. Grimes egp = &(cred->cr_groups[cred->cr_ngroups]); 1226df8bae1dSRodney W. Grimes for (gp = cred->cr_groups; gp < egp; gp++) 1227df8bae1dSRodney W. Grimes if (*gp == gid) 1228df8bae1dSRodney W. Grimes return (1); 1229df8bae1dSRodney W. Grimes return (0); 1230df8bae1dSRodney W. Grimes } 1231df8bae1dSRodney W. Grimes 12323b243b72SRobert Watson /* 123393f4fd1cSRobert Watson * `suser_enabled' (which can be set by the kern.security.suser_enabled 12347fd6a959SRobert Watson * sysctl) determines whether the system 'super-user' policy is in effect. 12357fd6a959SRobert Watson * If it is nonzero, an effective uid of 0 connotes special privilege, 12367fd6a959SRobert Watson * overriding many mandatory and discretionary protections. If it is zero, 12377fd6a959SRobert Watson * uid 0 is offered no special privilege in the kernel security policy. 12387fd6a959SRobert Watson * Setting it to zero may seriously impact the functionality of many 12397fd6a959SRobert Watson * existing userland programs, and should not be done without careful 12407fd6a959SRobert Watson * consideration of the consequences. 12413b243b72SRobert Watson */ 124293f4fd1cSRobert Watson int suser_enabled = 1; 124393f4fd1cSRobert Watson SYSCTL_INT(_kern_security, OID_AUTO, suser_enabled, CTLFLAG_RW, 124493f4fd1cSRobert Watson &suser_enabled, 0, "processes with uid 0 have privilege"); 1245579f4eb4SRobert Watson 1246df8bae1dSRodney W. Grimes /* 12477fd6a959SRobert Watson * Test whether the specified credentials imply "super-user" privilege. 12487fd6a959SRobert Watson * Return 0 or EPERM. 1249df8bae1dSRodney W. Grimes */ 125026f9a767SRodney W. Grimes int 1251f711d546SPoul-Henning Kamp suser(p) 125291421ba2SRobert Watson struct proc *p; 1253f711d546SPoul-Henning Kamp { 125475c13541SPoul-Henning Kamp return suser_xxx(0, p, 0); 1255f711d546SPoul-Henning Kamp } 1256f711d546SPoul-Henning Kamp 1257b40ce416SJulian Elischer /* 1258b40ce416SJulian Elischer * version for when the thread pointer is available and not the proc. 1259b40ce416SJulian Elischer * (saves having to include proc.h into every file that needs to do the change.) 1260b40ce416SJulian Elischer */ 1261b40ce416SJulian Elischer int 1262b40ce416SJulian Elischer suser_td(td) 1263b40ce416SJulian Elischer 1264b40ce416SJulian Elischer struct thread *td; 1265b40ce416SJulian Elischer { 1266b40ce416SJulian Elischer return suser_xxx(0, td->td_proc, 0); 1267b40ce416SJulian Elischer } 1268b40ce416SJulian Elischer 1269b40ce416SJulian Elischer /* 1270b40ce416SJulian Elischer * wrapper to use if you have the thread on hand but not the proc. 1271b40ce416SJulian Elischer */ 1272b40ce416SJulian Elischer int 1273b40ce416SJulian Elischer suser_xxx_td(cred, td, flag) 1274b40ce416SJulian Elischer struct ucred *cred; 1275b40ce416SJulian Elischer struct thread *td; 1276b40ce416SJulian Elischer int flag; 1277b40ce416SJulian Elischer { 1278b40ce416SJulian Elischer return(suser_xxx(cred, td->td_proc, flag)); 1279b40ce416SJulian Elischer } 1280b40ce416SJulian Elischer 1281f711d546SPoul-Henning Kamp int 128275c13541SPoul-Henning Kamp suser_xxx(cred, proc, flag) 128391421ba2SRobert Watson struct ucred *cred; 128491421ba2SRobert Watson struct proc *proc; 128575c13541SPoul-Henning Kamp int flag; 1286df8bae1dSRodney W. Grimes { 128793f4fd1cSRobert Watson if (!suser_enabled) 128803095547SRobert Watson return (EPERM); 128975c13541SPoul-Henning Kamp if (!cred && !proc) { 129075c13541SPoul-Henning Kamp printf("suser_xxx(): THINK!\n"); 1291df8bae1dSRodney W. Grimes return (EPERM); 1292df8bae1dSRodney W. Grimes } 129375c13541SPoul-Henning Kamp if (!cred) 129475c13541SPoul-Henning Kamp cred = proc->p_ucred; 129575c13541SPoul-Henning Kamp if (cred->cr_uid != 0) 129675c13541SPoul-Henning Kamp return (EPERM); 129791421ba2SRobert Watson if (jailed(cred) && !(flag & PRISON_ROOT)) 129875c13541SPoul-Henning Kamp return (EPERM); 129975c13541SPoul-Henning Kamp return (0); 130075c13541SPoul-Henning Kamp } 1301df8bae1dSRodney W. Grimes 13023ca719f1SRobert Watson 13033ca719f1SRobert Watson /* 130487fce2bbSRobert Watson * Test (local, globale) securelevel values against passed required 130587fce2bbSRobert Watson * securelevel. _gt implements (level > securelevel), and _ge implements 130675bc5b3fSRobert Watson * (level >= securelevel). Returns 0 oer EPERM. 13073ca719f1SRobert Watson * 13083ca719f1SRobert Watson * cr is permitted to be NULL for the time being, as there were some 13093ca719f1SRobert Watson * existing securelevel checks that occurred without a process/credential 13103ca719f1SRobert Watson * context. In the future this will be disallowed, so a kernel 13113ca719f1SRobert Watson * message is displayed. 13123ca719f1SRobert Watson */ 13133ca719f1SRobert Watson int 13143ca719f1SRobert Watson securelevel_gt(struct ucred *cr, int level) 13153ca719f1SRobert Watson { 13163ca719f1SRobert Watson 13173ca719f1SRobert Watson if (cr == NULL) { 13183ca719f1SRobert Watson printf("securelevel_gt: cr is NULL\n"); 131975bc5b3fSRobert Watson if (level > securelevel) 13203ca719f1SRobert Watson return (0); 13213ca719f1SRobert Watson else 13223ca719f1SRobert Watson return (EPERM); 132387fce2bbSRobert Watson } else if (cr->cr_prison == NULL) { 132475bc5b3fSRobert Watson if (level > securelevel) 13253ca719f1SRobert Watson return (0); 13263ca719f1SRobert Watson else 13273ca719f1SRobert Watson return (EPERM); 132887fce2bbSRobert Watson } else { 132987fce2bbSRobert Watson if (level > imax(cr->cr_prison->pr_securelevel, securelevel)) 133087fce2bbSRobert Watson return (0); 133187fce2bbSRobert Watson else 133287fce2bbSRobert Watson return (EPERM); 13333ca719f1SRobert Watson } 133487fce2bbSRobert Watson 13353ca719f1SRobert Watson } 13363ca719f1SRobert Watson 13373ca719f1SRobert Watson int 13383ca719f1SRobert Watson securelevel_ge(struct ucred *cr, int level) 13393ca719f1SRobert Watson { 13403ca719f1SRobert Watson 13413ca719f1SRobert Watson if (cr == NULL) { 13423ca719f1SRobert Watson printf("securelevel_ge: cr is NULL\n"); 134375bc5b3fSRobert Watson if (level >= securelevel) 13443ca719f1SRobert Watson return (0); 13453ca719f1SRobert Watson else 13463ca719f1SRobert Watson return (EPERM); 134787fce2bbSRobert Watson } if (cr->cr_prison == NULL) { 134875bc5b3fSRobert Watson if (level >= securelevel) 13493ca719f1SRobert Watson return (0); 13503ca719f1SRobert Watson else 13513ca719f1SRobert Watson return (EPERM); 135287fce2bbSRobert Watson } else { 135387fce2bbSRobert Watson if (level >= imax(cr->cr_prison->pr_securelevel, securelevel)) 135487fce2bbSRobert Watson return (0); 135587fce2bbSRobert Watson else 135687fce2bbSRobert Watson return (EPERM); 13573ca719f1SRobert Watson } 13583ca719f1SRobert Watson } 13593ca719f1SRobert Watson 13607fd6a959SRobert Watson /*- 13617fd6a959SRobert Watson * Determine if u1 "can see" the subject specified by u2. 1362ed639720SRobert Watson * Returns: 0 for permitted, an errno value otherwise 1363ed639720SRobert Watson * Locks: none 13647fd6a959SRobert Watson * References: u1 and u2 must be immutable credentials 13657fd6a959SRobert Watson * u1 and u2 must be valid for the lifetime of the call 1366ed639720SRobert Watson * u1 may equal u2, in which case only one reference is required 1367ed639720SRobert Watson */ 1368ed639720SRobert Watson int 136994088977SRobert Watson cr_cansee(struct ucred *u1, struct ucred *u2) 1370a9e0361bSPoul-Henning Kamp { 137191421ba2SRobert Watson int error; 1372a9e0361bSPoul-Henning Kamp 1373ed639720SRobert Watson if ((error = prison_check(u1, u2))) 137491421ba2SRobert Watson return (error); 1375b1fc0ec1SRobert Watson if (!ps_showallprocs && u1->cr_ruid != u2->cr_ruid) { 1376f8e6ab29SRobert Watson if (suser_xxx(u1, NULL, PRISON_ROOT) != 0) 1377387d2c03SRobert Watson return (ESRCH); 1378c52396e3SRobert Watson } 1379387d2c03SRobert Watson return (0); 1380387d2c03SRobert Watson } 1381387d2c03SRobert Watson 13827fd6a959SRobert Watson /*- 13837fd6a959SRobert Watson * Determine if p1 "can see" the subject specified by p2. 13843b243b72SRobert Watson * Returns: 0 for permitted, an errno value otherwise 13857fd6a959SRobert Watson * Locks: Sufficient locks to protect p1->p_ucred and p2->p_ucred must 13863b243b72SRobert Watson * be held. Normally, p1 will be curproc, and a lock must be held 13873b243b72SRobert Watson * for p2. 13883b243b72SRobert Watson * References: p1 and p2 must be valid for the lifetime of the call 13893b243b72SRobert Watson */ 1390a0f75161SRobert Watson int 1391a0f75161SRobert Watson p_cansee(struct proc *p1, struct proc *p2) 1392ed639720SRobert Watson { 1393ed639720SRobert Watson 139494088977SRobert Watson /* Wrap cr_cansee() for all functionality. */ 139594088977SRobert Watson return (cr_cansee(p1->p_ucred, p2->p_ucred)); 1396ed639720SRobert Watson } 1397ed639720SRobert Watson 13987fd6a959SRobert Watson /*- 13997fd6a959SRobert Watson * Determine whether p1 may deliver the specified signal to p2. 14007fd6a959SRobert Watson * Returns: 0 for permitted, an errno value otherwise 14017fd6a959SRobert Watson * Locks: Sufficient locks to protect various components of p1 and p2 14027fd6a959SRobert Watson * must be held. Normally, p1 will be curproc, and a lock must 14037fd6a959SRobert Watson * be held for p2. 14043b243b72SRobert Watson * References: p1 and p2 must be valid for the lifetime of the call 14054c5eb9c3SRobert Watson */ 14064c5eb9c3SRobert Watson int 14074c5eb9c3SRobert Watson p_cansignal(struct proc *p1, struct proc *p2, int signum) 1408387d2c03SRobert Watson { 140991421ba2SRobert Watson int error; 1410387d2c03SRobert Watson 1411a9e0361bSPoul-Henning Kamp if (p1 == p2) 1412a9e0361bSPoul-Henning Kamp return (0); 1413387d2c03SRobert Watson 14144c5eb9c3SRobert Watson /* 14154c5eb9c3SRobert Watson * Jail semantics limit the scope of signalling to p2 in the same 14164c5eb9c3SRobert Watson * jail as p1, if p1 is in jail. 14174c5eb9c3SRobert Watson */ 141891421ba2SRobert Watson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 141991421ba2SRobert Watson return (error); 1420387d2c03SRobert Watson 1421387d2c03SRobert Watson /* 14224c5eb9c3SRobert Watson * UNIX signalling semantics require that processes in the same 14234c5eb9c3SRobert Watson * session always be able to deliver SIGCONT to one another, 14244c5eb9c3SRobert Watson * overriding the remaining protections. 1425387d2c03SRobert Watson */ 14264c5eb9c3SRobert Watson if (signum == SIGCONT && p1->p_session == p2->p_session) 1427a9e0361bSPoul-Henning Kamp return (0); 1428387d2c03SRobert Watson 14294c5eb9c3SRobert Watson /* 14303b243b72SRobert Watson * UNIX signal semantics depend on the status of the P_SUGID 14313b243b72SRobert Watson * bit on the target process. If the bit is set, then additional 14323b243b72SRobert Watson * restrictions are placed on the set of available signals. 14334c5eb9c3SRobert Watson */ 14344c5eb9c3SRobert Watson if (p2->p_flag & P_SUGID) { 14354c5eb9c3SRobert Watson switch (signum) { 14364c5eb9c3SRobert Watson case 0: 14374c5eb9c3SRobert Watson case SIGKILL: 14384c5eb9c3SRobert Watson case SIGINT: 14394c5eb9c3SRobert Watson case SIGTERM: 14404c5eb9c3SRobert Watson case SIGSTOP: 14414c5eb9c3SRobert Watson case SIGTTIN: 14424c5eb9c3SRobert Watson case SIGTTOU: 14434c5eb9c3SRobert Watson case SIGTSTP: 14444c5eb9c3SRobert Watson case SIGHUP: 14454c5eb9c3SRobert Watson case SIGUSR1: 14464c5eb9c3SRobert Watson case SIGUSR2: 14477fd6a959SRobert Watson /* 14487fd6a959SRobert Watson * Generally, permit job and terminal control 14497fd6a959SRobert Watson * signals. 14507fd6a959SRobert Watson */ 14514c5eb9c3SRobert Watson break; 14524c5eb9c3SRobert Watson default: 14533b243b72SRobert Watson /* Not permitted, privilege is required. */ 14544c5eb9c3SRobert Watson error = suser_xxx(NULL, p1, PRISON_ROOT); 14554c5eb9c3SRobert Watson if (error) 14564c5eb9c3SRobert Watson return (error); 14574c5eb9c3SRobert Watson } 1458e9e7ff5bSRobert Watson } 1459e9e7ff5bSRobert Watson 14604c5eb9c3SRobert Watson /* 14613b243b72SRobert Watson * Generally, the target credential's ruid or svuid must match the 1462e9e7ff5bSRobert Watson * subject credential's ruid or euid. 14634c5eb9c3SRobert Watson */ 1464b1fc0ec1SRobert Watson if (p1->p_ucred->cr_ruid != p2->p_ucred->cr_ruid && 1465b1fc0ec1SRobert Watson p1->p_ucred->cr_ruid != p2->p_ucred->cr_svuid && 1466b1fc0ec1SRobert Watson p1->p_ucred->cr_uid != p2->p_ucred->cr_ruid && 1467b1fc0ec1SRobert Watson p1->p_ucred->cr_uid != p2->p_ucred->cr_svuid) { 14684c5eb9c3SRobert Watson /* Not permitted, try privilege. */ 14694c5eb9c3SRobert Watson error = suser_xxx(NULL, p1, PRISON_ROOT); 14704c5eb9c3SRobert Watson if (error) 14714c5eb9c3SRobert Watson return (error); 14724c5eb9c3SRobert Watson } 1473387d2c03SRobert Watson 1474387d2c03SRobert Watson return (0); 1475387d2c03SRobert Watson } 1476a9e0361bSPoul-Henning Kamp 14777fd6a959SRobert Watson /*- 14787fd6a959SRobert Watson * Determine whether p1 may reschedule p2 14797fd6a959SRobert Watson * Returns: 0 for permitted, an errno value otherwise 14803b243b72SRobert Watson * Locks: Sufficient locks to protect various components of p1 and p2 14813b243b72SRobert Watson * must be held. Normally, p1 will be curproc, and a lock must 14827fd6a959SRobert Watson * be held for p2. 14833b243b72SRobert Watson * References: p1 and p2 must be valid for the lifetime of the call 14843b243b72SRobert Watson */ 1485a0f75161SRobert Watson int 1486a0f75161SRobert Watson p_cansched(struct proc *p1, struct proc *p2) 1487387d2c03SRobert Watson { 148891421ba2SRobert Watson int error; 1489387d2c03SRobert Watson 1490387d2c03SRobert Watson if (p1 == p2) 1491387d2c03SRobert Watson return (0); 149291421ba2SRobert Watson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 149391421ba2SRobert Watson return (error); 1494b1fc0ec1SRobert Watson if (p1->p_ucred->cr_ruid == p2->p_ucred->cr_ruid) 1495387d2c03SRobert Watson return (0); 1496b1fc0ec1SRobert Watson if (p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid) 1497387d2c03SRobert Watson return (0); 14987fd6a959SRobert Watson if (suser_xxx(0, p1, PRISON_ROOT) == 0) 1499387d2c03SRobert Watson return (0); 1500387d2c03SRobert Watson 1501387d2c03SRobert Watson #ifdef CAPABILITIES 1502a0f75161SRobert Watson if (!cap_check_xxx(0, p1, CAP_SYS_NICE, PRISON_ROOT)) 1503387d2c03SRobert Watson return (0); 1504387d2c03SRobert Watson #endif 1505387d2c03SRobert Watson 1506387d2c03SRobert Watson return (EPERM); 1507387d2c03SRobert Watson } 1508387d2c03SRobert Watson 15093b243b72SRobert Watson /* 15107fd6a959SRobert Watson * The kern_unprivileged_procdebug_permitted flag may be used to disable 15113b243b72SRobert Watson * a variety of unprivileged inter-process debugging services, including 15123b243b72SRobert Watson * some procfs functionality, ptrace(), and ktrace(). In the past, 15133b243b72SRobert Watson * inter-process debugging has been involved in a variety of security 15143b243b72SRobert Watson * problems, and sites not requiring the service might choose to disable it 15153b243b72SRobert Watson * when hardening systems. 15163b243b72SRobert Watson * 15173b243b72SRobert Watson * XXX: Should modifying and reading this variable require locking? 15183b243b72SRobert Watson */ 15190ef5652eSRobert Watson static int kern_unprivileged_procdebug_permitted = 1; 15200ef5652eSRobert Watson SYSCTL_INT(_kern_security, OID_AUTO, unprivileged_procdebug_permitted, 15210ef5652eSRobert Watson CTLFLAG_RW, &kern_unprivileged_procdebug_permitted, 0, 15220ef5652eSRobert Watson "Unprivileged processes may use process debugging facilities"); 15230ef5652eSRobert Watson 15247fd6a959SRobert Watson /*- 15257fd6a959SRobert Watson * Determine whether p1 may debug p2. 15267fd6a959SRobert Watson * Returns: 0 for permitted, an errno value otherwise 15277fd6a959SRobert Watson * Locks: Sufficient locks to protect various components of p1 and p2 15287fd6a959SRobert Watson * must be held. Normally, p1 will be curproc, and a lock must 15297fd6a959SRobert Watson * be held for p2. 15303b243b72SRobert Watson * References: p1 and p2 must be valid for the lifetime of the call 15313b243b72SRobert Watson */ 1532a0f75161SRobert Watson int 1533a0f75161SRobert Watson p_candebug(struct proc *p1, struct proc *p2) 1534387d2c03SRobert Watson { 1535387d2c03SRobert Watson int error; 1536387d2c03SRobert Watson 153791421ba2SRobert Watson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 153891421ba2SRobert Watson return (error); 1539387d2c03SRobert Watson 15407fd6a959SRobert Watson /* 15417fd6a959SRobert Watson * Not owned by you, has done setuid (unless you're root). 15427fd6a959SRobert Watson * XXX add a CAP_SYS_PTRACE here? 15437fd6a959SRobert Watson */ 1544b1fc0ec1SRobert Watson if (p1->p_ucred->cr_uid != p2->p_ucred->cr_uid || 1545b1fc0ec1SRobert Watson p1->p_ucred->cr_uid != p2->p_ucred->cr_svuid || 1546b1fc0ec1SRobert Watson p1->p_ucred->cr_uid != p2->p_ucred->cr_ruid || 15477fd6a959SRobert Watson p2->p_flag & P_SUGID || !kern_unprivileged_procdebug_permitted) { 15487fd6a959SRobert Watson if ((error = suser_xxx(0, p1, PRISON_ROOT)) != 0) 1549387d2c03SRobert Watson return (error); 15507fd6a959SRobert Watson } 1551387d2c03SRobert Watson 15523ca719f1SRobert Watson /* can't trace init when securelevel > 0 */ 15533ca719f1SRobert Watson if (p2->p_pid == 1) { 15543ca719f1SRobert Watson error = securelevel_gt(p1->p_ucred, 0); 15553ca719f1SRobert Watson if (error) 15563ca719f1SRobert Watson return (error); 15573ca719f1SRobert Watson } 1558387d2c03SRobert Watson 1559387d2c03SRobert Watson return (0); 1560387d2c03SRobert Watson } 1561387d2c03SRobert Watson 1562a9e0361bSPoul-Henning Kamp /* 1563df8bae1dSRodney W. Grimes * Allocate a zeroed cred structure. 1564df8bae1dSRodney W. Grimes */ 1565df8bae1dSRodney W. Grimes struct ucred * 1566df8bae1dSRodney W. Grimes crget() 1567df8bae1dSRodney W. Grimes { 1568df8bae1dSRodney W. Grimes register struct ucred *cr; 1569df8bae1dSRodney W. Grimes 15701e5d626aSAlfred Perlstein MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK|M_ZERO); 1571df8bae1dSRodney W. Grimes cr->cr_ref = 1; 15721e5d626aSAlfred Perlstein mtx_init(&cr->cr_mtx, "ucred", MTX_DEF); 1573df8bae1dSRodney W. Grimes return (cr); 1574df8bae1dSRodney W. Grimes } 1575df8bae1dSRodney W. Grimes 1576df8bae1dSRodney W. Grimes /* 15777fd6a959SRobert Watson * Claim another reference to a ucred structure. 15785c3f70d7SAlfred Perlstein */ 15795c3f70d7SAlfred Perlstein void 15805c3f70d7SAlfred Perlstein crhold(cr) 15815c3f70d7SAlfred Perlstein struct ucred *cr; 15825c3f70d7SAlfred Perlstein { 15835c3f70d7SAlfred Perlstein 15849ed346baSBosko Milekic mtx_lock(&cr->cr_mtx); 15855c3f70d7SAlfred Perlstein cr->cr_ref++; 15869ed346baSBosko Milekic mtx_unlock(&(cr)->cr_mtx); 15875c3f70d7SAlfred Perlstein } 15885c3f70d7SAlfred Perlstein 15895c3f70d7SAlfred Perlstein 15905c3f70d7SAlfred Perlstein /* 1591df8bae1dSRodney W. Grimes * Free a cred structure. 1592df8bae1dSRodney W. Grimes * Throws away space when ref count gets to 0. 1593df8bae1dSRodney W. Grimes */ 159426f9a767SRodney W. Grimes void 1595df8bae1dSRodney W. Grimes crfree(cr) 1596df8bae1dSRodney W. Grimes struct ucred *cr; 1597df8bae1dSRodney W. Grimes { 15981e5d626aSAlfred Perlstein 15999ed346baSBosko Milekic mtx_lock(&cr->cr_mtx); 1600e04670b7SAlfred Perlstein KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref)); 1601f535380cSDon Lewis if (--cr->cr_ref == 0) { 16021e5d626aSAlfred Perlstein mtx_destroy(&cr->cr_mtx); 1603f535380cSDon Lewis /* 1604f535380cSDon Lewis * Some callers of crget(), such as nfs_statfs(), 1605f535380cSDon Lewis * allocate a temporary credential, but don't 1606f535380cSDon Lewis * allocate a uidinfo structure. 1607f535380cSDon Lewis */ 1608f535380cSDon Lewis if (cr->cr_uidinfo != NULL) 1609f535380cSDon Lewis uifree(cr->cr_uidinfo); 1610823c224eSRobert Watson if (cr->cr_ruidinfo != NULL) 1611823c224eSRobert Watson uifree(cr->cr_ruidinfo); 161291421ba2SRobert Watson /* 161391421ba2SRobert Watson * Free a prison, if any. 161491421ba2SRobert Watson */ 161591421ba2SRobert Watson if (jailed(cr)) 161691421ba2SRobert Watson prison_free(cr->cr_prison); 1617df8bae1dSRodney W. Grimes FREE((caddr_t)cr, M_CRED); 16181e5d626aSAlfred Perlstein } else { 16199ed346baSBosko Milekic mtx_unlock(&cr->cr_mtx); 1620df8bae1dSRodney W. Grimes } 1621f535380cSDon Lewis } 1622df8bae1dSRodney W. Grimes 1623df8bae1dSRodney W. Grimes /* 1624df8bae1dSRodney W. Grimes * Copy cred structure to a new one and free the old one. 1625df8bae1dSRodney W. Grimes */ 1626df8bae1dSRodney W. Grimes struct ucred * 1627df8bae1dSRodney W. Grimes crcopy(cr) 1628df8bae1dSRodney W. Grimes struct ucred *cr; 1629df8bae1dSRodney W. Grimes { 1630df8bae1dSRodney W. Grimes struct ucred *newcr; 1631df8bae1dSRodney W. Grimes 16329ed346baSBosko Milekic mtx_lock(&cr->cr_mtx); 16331e5d626aSAlfred Perlstein if (cr->cr_ref == 1) { 16349ed346baSBosko Milekic mtx_unlock(&cr->cr_mtx); 1635df8bae1dSRodney W. Grimes return (cr); 16361e5d626aSAlfred Perlstein } 16379ed346baSBosko Milekic mtx_unlock(&cr->cr_mtx); 16381e5d626aSAlfred Perlstein newcr = crdup(cr); 1639df8bae1dSRodney W. Grimes crfree(cr); 1640df8bae1dSRodney W. Grimes return (newcr); 1641df8bae1dSRodney W. Grimes } 1642df8bae1dSRodney W. Grimes 1643df8bae1dSRodney W. Grimes /* 1644df8bae1dSRodney W. Grimes * Dup cred struct to a new held one. 1645df8bae1dSRodney W. Grimes */ 1646df8bae1dSRodney W. Grimes struct ucred * 1647df8bae1dSRodney W. Grimes crdup(cr) 1648df8bae1dSRodney W. Grimes struct ucred *cr; 1649df8bae1dSRodney W. Grimes { 1650df8bae1dSRodney W. Grimes struct ucred *newcr; 1651df8bae1dSRodney W. Grimes 16521e5d626aSAlfred Perlstein MALLOC(newcr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 1653df8bae1dSRodney W. Grimes *newcr = *cr; 16541e5d626aSAlfred Perlstein mtx_init(&newcr->cr_mtx, "ucred", MTX_DEF); 1655f535380cSDon Lewis uihold(newcr->cr_uidinfo); 1656b1fc0ec1SRobert Watson uihold(newcr->cr_ruidinfo); 165791421ba2SRobert Watson if (jailed(newcr)) 165891421ba2SRobert Watson prison_hold(newcr->cr_prison); 1659df8bae1dSRodney W. Grimes newcr->cr_ref = 1; 1660df8bae1dSRodney W. Grimes return (newcr); 1661df8bae1dSRodney W. Grimes } 1662df8bae1dSRodney W. Grimes 1663df8bae1dSRodney W. Grimes /* 1664df8bae1dSRodney W. Grimes * Get login name, if available. 1665df8bae1dSRodney W. Grimes */ 1666d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1667df8bae1dSRodney W. Grimes struct getlogin_args { 1668df8bae1dSRodney W. Grimes char *namebuf; 1669df8bae1dSRodney W. Grimes u_int namelen; 1670df8bae1dSRodney W. Grimes }; 1671d2d3e875SBruce Evans #endif 1672835a82eeSMatthew Dillon /* 1673835a82eeSMatthew Dillon * MPSAFE 1674835a82eeSMatthew Dillon */ 1675df8bae1dSRodney W. Grimes /* ARGSUSED */ 167626f9a767SRodney W. Grimes int 1677b40ce416SJulian Elischer getlogin(td, uap) 1678b40ce416SJulian Elischer struct thread *td; 1679df8bae1dSRodney W. Grimes struct getlogin_args *uap; 1680df8bae1dSRodney W. Grimes { 1681835a82eeSMatthew Dillon int error; 1682b40ce416SJulian Elischer struct proc *p = td->td_proc; 1683df8bae1dSRodney W. Grimes 1684835a82eeSMatthew Dillon mtx_lock(&Giant); 168530cf3ac4SAndrey A. Chernov if (uap->namelen > MAXLOGNAME) 168653490b76SAndrey A. Chernov uap->namelen = MAXLOGNAME; 1687835a82eeSMatthew Dillon error = copyout((caddr_t) p->p_pgrp->pg_session->s_login, 1688835a82eeSMatthew Dillon (caddr_t) uap->namebuf, uap->namelen); 1689835a82eeSMatthew Dillon mtx_unlock(&Giant); 1690835a82eeSMatthew Dillon return(error); 1691df8bae1dSRodney W. Grimes } 1692df8bae1dSRodney W. Grimes 1693df8bae1dSRodney W. Grimes /* 1694df8bae1dSRodney W. Grimes * Set login name. 1695df8bae1dSRodney W. Grimes */ 1696d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1697df8bae1dSRodney W. Grimes struct setlogin_args { 1698df8bae1dSRodney W. Grimes char *namebuf; 1699df8bae1dSRodney W. Grimes }; 1700d2d3e875SBruce Evans #endif 1701835a82eeSMatthew Dillon /* 1702835a82eeSMatthew Dillon * MPSAFE 1703835a82eeSMatthew Dillon */ 1704df8bae1dSRodney W. Grimes /* ARGSUSED */ 170526f9a767SRodney W. Grimes int 1706b40ce416SJulian Elischer setlogin(td, uap) 1707b40ce416SJulian Elischer struct thread *td; 1708df8bae1dSRodney W. Grimes struct setlogin_args *uap; 1709df8bae1dSRodney W. Grimes { 1710b40ce416SJulian Elischer struct proc *p = td->td_proc; 1711df8bae1dSRodney W. Grimes int error; 1712964ca0caSAndrey A. Chernov char logintmp[MAXLOGNAME]; 1713df8bae1dSRodney W. Grimes 1714835a82eeSMatthew Dillon mtx_lock(&Giant); 171575c13541SPoul-Henning Kamp if ((error = suser_xxx(0, p, PRISON_ROOT))) 1716835a82eeSMatthew Dillon goto done2; 1717184989c2SDavid Nugent error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 171810d4743fSDoug Rabson sizeof(logintmp), (size_t *)0); 1719835a82eeSMatthew Dillon if (error == ENAMETOOLONG) { 1720df8bae1dSRodney W. Grimes error = EINVAL; 1721835a82eeSMatthew Dillon } else if (!error) { 1722184989c2SDavid Nugent (void) memcpy(p->p_pgrp->pg_session->s_login, logintmp, 1723964ca0caSAndrey A. Chernov sizeof(logintmp)); 1724835a82eeSMatthew Dillon } 1725835a82eeSMatthew Dillon done2: 1726835a82eeSMatthew Dillon mtx_unlock(&Giant); 1727df8bae1dSRodney W. Grimes return (error); 1728df8bae1dSRodney W. Grimes } 1729d5f81602SSean Eric Fagan 1730d5f81602SSean Eric Fagan void 1731d5f81602SSean Eric Fagan setsugid(p) 1732d5f81602SSean Eric Fagan struct proc *p; 1733d5f81602SSean Eric Fagan { 1734d5f81602SSean Eric Fagan p->p_flag |= P_SUGID; 173589361835SSean Eric Fagan if (!(p->p_pfsflags & PF_ISUGID)) 1736d5f81602SSean Eric Fagan p->p_stops = 0; 1737d5f81602SSean Eric Fagan } 1738f535380cSDon Lewis 17397fd6a959SRobert Watson /*- 17407fd6a959SRobert Watson * Change a process's effective uid. 1741b1fc0ec1SRobert Watson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified. 1742b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1743b1fc0ec1SRobert Watson * duration of the call. 1744f535380cSDon Lewis */ 1745f535380cSDon Lewis void 1746b1fc0ec1SRobert Watson change_euid(newcred, euid) 1747b1fc0ec1SRobert Watson struct ucred *newcred; 1748f535380cSDon Lewis uid_t euid; 1749f535380cSDon Lewis { 1750f535380cSDon Lewis 1751b1fc0ec1SRobert Watson newcred->cr_uid = euid; 1752b1fc0ec1SRobert Watson uifree(newcred->cr_uidinfo); 1753b1fc0ec1SRobert Watson newcred->cr_uidinfo = uifind(euid); 1754f535380cSDon Lewis } 1755f535380cSDon Lewis 17567fd6a959SRobert Watson /*- 17577fd6a959SRobert Watson * Change a process's effective gid. 1758b1fc0ec1SRobert Watson * Side effects: newcred->cr_gid will be modified. 1759b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1760b1fc0ec1SRobert Watson * duration of the call. 1761f535380cSDon Lewis */ 1762810bfc8eSAndrew Gallatin void 1763b1fc0ec1SRobert Watson change_egid(newcred, egid) 1764b1fc0ec1SRobert Watson struct ucred *newcred; 1765b1fc0ec1SRobert Watson gid_t egid; 1766b1fc0ec1SRobert Watson { 1767b1fc0ec1SRobert Watson 1768b1fc0ec1SRobert Watson newcred->cr_groups[0] = egid; 1769b1fc0ec1SRobert Watson } 1770b1fc0ec1SRobert Watson 17717fd6a959SRobert Watson /*- 17727fd6a959SRobert Watson * Change a process's real uid. 1773b1fc0ec1SRobert Watson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo 1774b1fc0ec1SRobert Watson * will be updated, and the old and new cr_ruidinfo proc 1775b1fc0ec1SRobert Watson * counts will be updated. 1776b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1777b1fc0ec1SRobert Watson * duration of the call. 1778b1fc0ec1SRobert Watson */ 1779b1fc0ec1SRobert Watson void 1780b1fc0ec1SRobert Watson change_ruid(newcred, ruid) 1781b1fc0ec1SRobert Watson struct ucred *newcred; 1782f535380cSDon Lewis uid_t ruid; 1783f535380cSDon Lewis { 1784f535380cSDon Lewis 1785b1fc0ec1SRobert Watson (void)chgproccnt(newcred->cr_ruidinfo, -1, 0); 1786b1fc0ec1SRobert Watson newcred->cr_ruid = ruid; 1787b1fc0ec1SRobert Watson uifree(newcred->cr_ruidinfo); 1788b1fc0ec1SRobert Watson newcred->cr_ruidinfo = uifind(ruid); 1789b1fc0ec1SRobert Watson (void)chgproccnt(newcred->cr_ruidinfo, 1, 0); 1790b1fc0ec1SRobert Watson } 1791b1fc0ec1SRobert Watson 17927fd6a959SRobert Watson /*- 17937fd6a959SRobert Watson * Change a process's real gid. 1794b1fc0ec1SRobert Watson * Side effects: newcred->cr_rgid will be updated. 1795b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1796b1fc0ec1SRobert Watson * duration of the call. 1797b1fc0ec1SRobert Watson */ 1798b1fc0ec1SRobert Watson void 1799b1fc0ec1SRobert Watson change_rgid(newcred, rgid) 1800b1fc0ec1SRobert Watson struct ucred *newcred; 1801b1fc0ec1SRobert Watson gid_t rgid; 1802b1fc0ec1SRobert Watson { 1803b1fc0ec1SRobert Watson 1804b1fc0ec1SRobert Watson newcred->cr_rgid = rgid; 1805b1fc0ec1SRobert Watson } 1806b1fc0ec1SRobert Watson 18077fd6a959SRobert Watson /*- 18087fd6a959SRobert Watson * Change a process's saved uid. 1809b1fc0ec1SRobert Watson * Side effects: newcred->cr_svuid will be updated. 1810b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1811b1fc0ec1SRobert Watson * duration of the call. 1812b1fc0ec1SRobert Watson */ 1813b1fc0ec1SRobert Watson void 1814b1fc0ec1SRobert Watson change_svuid(newcred, svuid) 1815b1fc0ec1SRobert Watson struct ucred *newcred; 1816b1fc0ec1SRobert Watson uid_t svuid; 1817b1fc0ec1SRobert Watson { 1818b1fc0ec1SRobert Watson 1819b1fc0ec1SRobert Watson newcred->cr_svuid = svuid; 1820b1fc0ec1SRobert Watson } 1821b1fc0ec1SRobert Watson 18227fd6a959SRobert Watson /*- 18237fd6a959SRobert Watson * Change a process's saved gid. 1824b1fc0ec1SRobert Watson * Side effects: newcred->cr_svgid will be updated. 1825b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1826b1fc0ec1SRobert Watson * duration of the call. 1827b1fc0ec1SRobert Watson */ 1828b1fc0ec1SRobert Watson void 1829b1fc0ec1SRobert Watson change_svgid(newcred, svgid) 1830b1fc0ec1SRobert Watson struct ucred *newcred; 1831b1fc0ec1SRobert Watson gid_t svgid; 1832b1fc0ec1SRobert Watson { 1833b1fc0ec1SRobert Watson 1834b1fc0ec1SRobert Watson newcred->cr_svgid = svgid; 1835f535380cSDon Lewis } 1836