1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * (c) UNIX System Laboratories, Inc. 5df8bae1dSRodney W. Grimes * All or some portions of this file are derived from material licensed 6df8bae1dSRodney W. Grimes * to the University of California by American Telephone and Telegraph 7df8bae1dSRodney W. Grimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8df8bae1dSRodney W. Grimes * the permission of UNIX System Laboratories, Inc. 9eb725b4eSRobert Watson * Copyright (c) 2000-2001 Robert N. M. Watson. All rights reserved. 10df8bae1dSRodney W. Grimes * 11df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 12df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 13df8bae1dSRodney W. Grimes * are met: 14df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 15df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 16df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 17df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 18df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 19df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 20df8bae1dSRodney W. Grimes * must display the following acknowledgement: 21df8bae1dSRodney W. Grimes * This product includes software developed by the University of 22df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 23df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 24df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 25df8bae1dSRodney W. Grimes * without specific prior written permission. 26df8bae1dSRodney W. Grimes * 27df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37df8bae1dSRodney W. Grimes * SUCH DAMAGE. 38df8bae1dSRodney W. Grimes * 39df8bae1dSRodney W. Grimes * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 40c3aac50fSPeter Wemm * $FreeBSD$ 41df8bae1dSRodney W. Grimes */ 42df8bae1dSRodney W. Grimes 43df8bae1dSRodney W. Grimes /* 44df8bae1dSRodney W. Grimes * System calls related to processes and protection 45df8bae1dSRodney W. Grimes */ 46df8bae1dSRodney W. Grimes 475591b823SEivind Eklund #include "opt_compat.h" 485591b823SEivind Eklund 49df8bae1dSRodney W. Grimes #include <sys/param.h> 50df8bae1dSRodney W. Grimes #include <sys/systm.h> 51fb919e4dSMark Murray #include <sys/acct.h> 521c5bb3eaSPeter Wemm #include <sys/kernel.h> 5398f03f90SJake Burkholder #include <sys/lock.h> 54fb919e4dSMark Murray #include <sys/mutex.h> 55df8bae1dSRodney W. Grimes #include <sys/proc.h> 565b29d6e9SJohn Baldwin #include <sys/sx.h> 57fb919e4dSMark Murray #include <sys/sysproto.h> 58eb725b4eSRobert Watson #include <sys/jail.h> 59df8bae1dSRodney W. Grimes #include <sys/malloc.h> 60d5f81602SSean Eric Fagan #include <sys/pioctl.h> 61f535380cSDon Lewis #include <sys/resourcevar.h> 62579f4eb4SRobert Watson #include <sys/sysctl.h> 63df8bae1dSRodney W. Grimes 64a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_CRED, "cred", "credentials"); 65a1c995b6SPoul-Henning Kamp 66d0615c64SAndrew R. Reiter SYSCTL_DECL(_security); 67d0615c64SAndrew R. Reiter SYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0, 6848713bdcSRobert Watson "BSD security policy"); 6948713bdcSRobert Watson 70d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 71ad7507e2SSteven Wallace struct getpid_args { 72df8bae1dSRodney W. Grimes int dummy; 73df8bae1dSRodney W. Grimes }; 74d2d3e875SBruce Evans #endif 75835a82eeSMatthew Dillon /* 76835a82eeSMatthew Dillon * MPSAFE 77835a82eeSMatthew Dillon */ 78df8bae1dSRodney W. Grimes /* ARGSUSED */ 7926f9a767SRodney W. Grimes int 80b40ce416SJulian Elischer getpid(td, uap) 81b40ce416SJulian Elischer struct thread *td; 82ad7507e2SSteven Wallace struct getpid_args *uap; 83df8bae1dSRodney W. Grimes { 84b40ce416SJulian Elischer struct proc *p = td->td_proc; 85d23f5958SMatthew Dillon int s; 86df8bae1dSRodney W. Grimes 87d23f5958SMatthew Dillon s = mtx_lock_giant(kern_giant_proc); 88b40ce416SJulian Elischer td->td_retval[0] = p->p_pid; 89df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 90bae3a80bSJohn Baldwin PROC_LOCK(p); 91b40ce416SJulian Elischer td->td_retval[1] = p->p_pptr->p_pid; 92bae3a80bSJohn Baldwin PROC_UNLOCK(p); 93df8bae1dSRodney W. Grimes #endif 94d23f5958SMatthew Dillon mtx_unlock_giant(s); 95df8bae1dSRodney W. Grimes return (0); 96df8bae1dSRodney W. Grimes } 97df8bae1dSRodney W. Grimes 98d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 99ad7507e2SSteven Wallace struct getppid_args { 100ad7507e2SSteven Wallace int dummy; 101ad7507e2SSteven Wallace }; 102d2d3e875SBruce Evans #endif 103835a82eeSMatthew Dillon /* 104835a82eeSMatthew Dillon * MPSAFE 105835a82eeSMatthew Dillon */ 106df8bae1dSRodney W. Grimes /* ARGSUSED */ 10726f9a767SRodney W. Grimes int 108b40ce416SJulian Elischer getppid(td, uap) 109b40ce416SJulian Elischer struct thread *td; 110ad7507e2SSteven Wallace struct getppid_args *uap; 111df8bae1dSRodney W. Grimes { 112b40ce416SJulian Elischer struct proc *p = td->td_proc; 113d23f5958SMatthew Dillon int s; 114df8bae1dSRodney W. Grimes 115d23f5958SMatthew Dillon s = mtx_lock_giant(kern_giant_proc); 116bae3a80bSJohn Baldwin PROC_LOCK(p); 117b40ce416SJulian Elischer td->td_retval[0] = p->p_pptr->p_pid; 118bae3a80bSJohn Baldwin PROC_UNLOCK(p); 119d23f5958SMatthew Dillon mtx_unlock_giant(s); 120df8bae1dSRodney W. Grimes return (0); 121df8bae1dSRodney W. Grimes } 122df8bae1dSRodney W. Grimes 12336e9f877SMatthew Dillon /* 124eb725b4eSRobert Watson * Get process group ID; note that POSIX getpgrp takes no parameter. 12536e9f877SMatthew Dillon */ 126d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 127ad7507e2SSteven Wallace struct getpgrp_args { 128ad7507e2SSteven Wallace int dummy; 129ad7507e2SSteven Wallace }; 130d2d3e875SBruce Evans #endif 131835a82eeSMatthew Dillon /* 132835a82eeSMatthew Dillon * MPSAFE 133835a82eeSMatthew Dillon */ 13426f9a767SRodney W. Grimes int 135b40ce416SJulian Elischer getpgrp(td, uap) 136b40ce416SJulian Elischer struct thread *td; 137ad7507e2SSteven Wallace struct getpgrp_args *uap; 138df8bae1dSRodney W. Grimes { 139b40ce416SJulian Elischer struct proc *p = td->td_proc; 140df8bae1dSRodney W. Grimes 141835a82eeSMatthew Dillon mtx_lock(&Giant); 142b40ce416SJulian Elischer td->td_retval[0] = p->p_pgrp->pg_id; 143835a82eeSMatthew Dillon mtx_unlock(&Giant); 144df8bae1dSRodney W. Grimes return (0); 145df8bae1dSRodney W. Grimes } 146df8bae1dSRodney W. Grimes 1471a5018a0SPeter Wemm /* Get an arbitary pid's process group id */ 1481a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1491a5018a0SPeter Wemm struct getpgid_args { 1501a5018a0SPeter Wemm pid_t pid; 1511a5018a0SPeter Wemm }; 1521a5018a0SPeter Wemm #endif 153835a82eeSMatthew Dillon /* 154835a82eeSMatthew Dillon * MPSAFE 155835a82eeSMatthew Dillon */ 1561a5018a0SPeter Wemm int 157b40ce416SJulian Elischer getpgid(td, uap) 158b40ce416SJulian Elischer struct thread *td; 1591a5018a0SPeter Wemm struct getpgid_args *uap; 1601a5018a0SPeter Wemm { 161b40ce416SJulian Elischer struct proc *p = td->td_proc; 16265de0c7aSDon Lewis struct proc *pt; 163eb725b4eSRobert Watson int error, s; 16465de0c7aSDon Lewis 165d23f5958SMatthew Dillon s = mtx_lock_giant(kern_giant_proc); 166eb725b4eSRobert Watson error = 0; 1671a5018a0SPeter Wemm if (uap->pid == 0) 168b40ce416SJulian Elischer td->td_retval[0] = p->p_pgrp->pg_id; 1696a90c862SJohn Baldwin else if ((pt = pfind(uap->pid)) == NULL) 170835a82eeSMatthew Dillon error = ESRCH; 1716a90c862SJohn Baldwin else { 1726a90c862SJohn Baldwin error = p_cansee(p, pt); 1736a90c862SJohn Baldwin if (error == 0) 174b40ce416SJulian Elischer td->td_retval[0] = pt->p_pgrp->pg_id; 17533a9ed9dSJohn Baldwin PROC_UNLOCK(pt); 17633a9ed9dSJohn Baldwin } 177d23f5958SMatthew Dillon mtx_unlock_giant(s); 178835a82eeSMatthew Dillon return (error); 1791a5018a0SPeter Wemm } 1801a5018a0SPeter Wemm 1811a5018a0SPeter Wemm /* 1821a5018a0SPeter Wemm * Get an arbitary pid's session id. 1831a5018a0SPeter Wemm */ 1841a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1851a5018a0SPeter Wemm struct getsid_args { 1861a5018a0SPeter Wemm pid_t pid; 1871a5018a0SPeter Wemm }; 1881a5018a0SPeter Wemm #endif 189835a82eeSMatthew Dillon /* 190835a82eeSMatthew Dillon * MPSAFE 191835a82eeSMatthew Dillon */ 1921a5018a0SPeter Wemm int 193b40ce416SJulian Elischer getsid(td, uap) 194b40ce416SJulian Elischer struct thread *td; 1951a5018a0SPeter Wemm struct getsid_args *uap; 1961a5018a0SPeter Wemm { 197b40ce416SJulian Elischer struct proc *p = td->td_proc; 19865de0c7aSDon Lewis struct proc *pt; 199eb725b4eSRobert Watson int error; 20065de0c7aSDon Lewis 201835a82eeSMatthew Dillon mtx_lock(&Giant); 202eb725b4eSRobert Watson error = 0; 2036a90c862SJohn Baldwin if (uap->pid == 0) 204b40ce416SJulian Elischer td->td_retval[0] = p->p_session->s_sid; 2056a90c862SJohn Baldwin else if ((pt = pfind(uap->pid)) == NULL) 206835a82eeSMatthew Dillon error = ESRCH; 2076a90c862SJohn Baldwin else { 2086a90c862SJohn Baldwin error = p_cansee(p, pt); 2096a90c862SJohn Baldwin if (error == 0) 210b40ce416SJulian Elischer td->td_retval[0] = pt->p_session->s_sid; 21133a9ed9dSJohn Baldwin PROC_UNLOCK(pt); 21233a9ed9dSJohn Baldwin } 213835a82eeSMatthew Dillon mtx_unlock(&Giant); 214835a82eeSMatthew Dillon return (error); 2151a5018a0SPeter Wemm } 2161a5018a0SPeter Wemm 217d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 218ad7507e2SSteven Wallace struct getuid_args { 219ad7507e2SSteven Wallace int dummy; 220ad7507e2SSteven Wallace }; 221d2d3e875SBruce Evans #endif 222835a82eeSMatthew Dillon /* 223835a82eeSMatthew Dillon * MPSAFE 224835a82eeSMatthew Dillon */ 225df8bae1dSRodney W. Grimes /* ARGSUSED */ 22626f9a767SRodney W. Grimes int 227b40ce416SJulian Elischer getuid(td, uap) 228b40ce416SJulian Elischer struct thread *td; 229ad7507e2SSteven Wallace struct getuid_args *uap; 230df8bae1dSRodney W. Grimes { 231b40ce416SJulian Elischer struct proc *p = td->td_proc; 232df8bae1dSRodney W. Grimes 233835a82eeSMatthew Dillon mtx_lock(&Giant); 234b40ce416SJulian Elischer td->td_retval[0] = p->p_ucred->cr_ruid; 235df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 236b40ce416SJulian Elischer td->td_retval[1] = p->p_ucred->cr_uid; 237df8bae1dSRodney W. Grimes #endif 238835a82eeSMatthew Dillon mtx_unlock(&Giant); 239df8bae1dSRodney W. Grimes return (0); 240df8bae1dSRodney W. Grimes } 241df8bae1dSRodney W. Grimes 242d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 243ad7507e2SSteven Wallace struct geteuid_args { 244ad7507e2SSteven Wallace int dummy; 245ad7507e2SSteven Wallace }; 246d2d3e875SBruce Evans #endif 247eb725b4eSRobert Watson /* 248eb725b4eSRobert Watson * MPSAFE 249eb725b4eSRobert Watson */ 250df8bae1dSRodney W. Grimes /* ARGSUSED */ 25126f9a767SRodney W. Grimes int 252b40ce416SJulian Elischer geteuid(td, uap) 253b40ce416SJulian Elischer struct thread *td; 254ad7507e2SSteven Wallace struct geteuid_args *uap; 255df8bae1dSRodney W. Grimes { 256835a82eeSMatthew Dillon mtx_lock(&Giant); 257b40ce416SJulian Elischer td->td_retval[0] = td->td_proc->p_ucred->cr_uid; 258835a82eeSMatthew Dillon mtx_unlock(&Giant); 259df8bae1dSRodney W. Grimes return (0); 260df8bae1dSRodney W. Grimes } 261df8bae1dSRodney W. Grimes 262d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 263ad7507e2SSteven Wallace struct getgid_args { 264ad7507e2SSteven Wallace int dummy; 265ad7507e2SSteven Wallace }; 266d2d3e875SBruce Evans #endif 267835a82eeSMatthew Dillon /* 268835a82eeSMatthew Dillon * MPSAFE 269835a82eeSMatthew Dillon */ 270df8bae1dSRodney W. Grimes /* ARGSUSED */ 27126f9a767SRodney W. Grimes int 272b40ce416SJulian Elischer getgid(td, uap) 273b40ce416SJulian Elischer struct thread *td; 274ad7507e2SSteven Wallace struct getgid_args *uap; 275df8bae1dSRodney W. Grimes { 276b40ce416SJulian Elischer struct proc *p = td->td_proc; 277df8bae1dSRodney W. Grimes 278835a82eeSMatthew Dillon mtx_lock(&Giant); 279b40ce416SJulian Elischer td->td_retval[0] = p->p_ucred->cr_rgid; 280df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 281b40ce416SJulian Elischer td->td_retval[1] = p->p_ucred->cr_groups[0]; 282df8bae1dSRodney W. Grimes #endif 283835a82eeSMatthew Dillon mtx_unlock(&Giant); 284df8bae1dSRodney W. Grimes return (0); 285df8bae1dSRodney W. Grimes } 286df8bae1dSRodney W. Grimes 287df8bae1dSRodney W. Grimes /* 288df8bae1dSRodney W. Grimes * Get effective group ID. The "egid" is groups[0], and could be obtained 289df8bae1dSRodney W. Grimes * via getgroups. This syscall exists because it is somewhat painful to do 290df8bae1dSRodney W. Grimes * correctly in a library function. 291df8bae1dSRodney W. Grimes */ 292d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 293ad7507e2SSteven Wallace struct getegid_args { 294ad7507e2SSteven Wallace int dummy; 295ad7507e2SSteven Wallace }; 296d2d3e875SBruce Evans #endif 297835a82eeSMatthew Dillon /* 298835a82eeSMatthew Dillon * MPSAFE 299835a82eeSMatthew Dillon */ 300df8bae1dSRodney W. Grimes /* ARGSUSED */ 30126f9a767SRodney W. Grimes int 302b40ce416SJulian Elischer getegid(td, uap) 303b40ce416SJulian Elischer struct thread *td; 304ad7507e2SSteven Wallace struct getegid_args *uap; 305df8bae1dSRodney W. Grimes { 306b40ce416SJulian Elischer struct proc *p = td->td_proc; 307df8bae1dSRodney W. Grimes 308835a82eeSMatthew Dillon mtx_lock(&Giant); 309b40ce416SJulian Elischer td->td_retval[0] = p->p_ucred->cr_groups[0]; 310835a82eeSMatthew Dillon mtx_unlock(&Giant); 311df8bae1dSRodney W. Grimes return (0); 312df8bae1dSRodney W. Grimes } 313df8bae1dSRodney W. Grimes 314d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 315df8bae1dSRodney W. Grimes struct getgroups_args { 316df8bae1dSRodney W. Grimes u_int gidsetsize; 317df8bae1dSRodney W. Grimes gid_t *gidset; 318df8bae1dSRodney W. Grimes }; 319d2d3e875SBruce Evans #endif 320835a82eeSMatthew Dillon /* 321835a82eeSMatthew Dillon * MPSAFE 322835a82eeSMatthew Dillon */ 32326f9a767SRodney W. Grimes int 324b40ce416SJulian Elischer getgroups(td, uap) 325b40ce416SJulian Elischer struct thread *td; 326df8bae1dSRodney W. Grimes register struct getgroups_args *uap; 327df8bae1dSRodney W. Grimes { 328835a82eeSMatthew Dillon struct ucred *cred; 329b40ce416SJulian Elischer struct proc *p = td->td_proc; 330b1fc0ec1SRobert Watson u_int ngrp; 331eb725b4eSRobert Watson int error; 332df8bae1dSRodney W. Grimes 333835a82eeSMatthew Dillon mtx_lock(&Giant); 334eb725b4eSRobert Watson error = 0; 335835a82eeSMatthew Dillon cred = p->p_ucred; 336df8bae1dSRodney W. Grimes if ((ngrp = uap->gidsetsize) == 0) { 337b40ce416SJulian Elischer td->td_retval[0] = cred->cr_ngroups; 338835a82eeSMatthew Dillon goto done2; 339df8bae1dSRodney W. Grimes } 340835a82eeSMatthew Dillon if (ngrp < cred->cr_ngroups) { 341835a82eeSMatthew Dillon error = EINVAL; 342835a82eeSMatthew Dillon goto done2; 343835a82eeSMatthew Dillon } 344b1fc0ec1SRobert Watson ngrp = cred->cr_ngroups; 345b1fc0ec1SRobert Watson if ((error = copyout((caddr_t)cred->cr_groups, 346eb725b4eSRobert Watson (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))) 347835a82eeSMatthew Dillon goto done2; 348b40ce416SJulian Elischer td->td_retval[0] = ngrp; 349835a82eeSMatthew Dillon done2: 350835a82eeSMatthew Dillon mtx_unlock(&Giant); 351835a82eeSMatthew Dillon return (error); 352df8bae1dSRodney W. Grimes } 353df8bae1dSRodney W. Grimes 354d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 35582970b81SBruce Evans struct setsid_args { 356ad7507e2SSteven Wallace int dummy; 357ad7507e2SSteven Wallace }; 358d2d3e875SBruce Evans #endif 359835a82eeSMatthew Dillon /* 360835a82eeSMatthew Dillon * MPSAFE 361835a82eeSMatthew Dillon */ 362df8bae1dSRodney W. Grimes /* ARGSUSED */ 36326f9a767SRodney W. Grimes int 364b40ce416SJulian Elischer setsid(td, uap) 365b40ce416SJulian Elischer register struct thread *td; 36682970b81SBruce Evans struct setsid_args *uap; 367df8bae1dSRodney W. Grimes { 368835a82eeSMatthew Dillon int error; 369b40ce416SJulian Elischer struct proc *p = td->td_proc; 370df8bae1dSRodney W. Grimes 371835a82eeSMatthew Dillon mtx_lock(&Giant); 372eb725b4eSRobert Watson if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) 373835a82eeSMatthew Dillon error = EPERM; 374eb725b4eSRobert Watson else { 375df8bae1dSRodney W. Grimes (void)enterpgrp(p, p->p_pid, 1); 376b40ce416SJulian Elischer td->td_retval[0] = p->p_pid; 377835a82eeSMatthew Dillon error = 0; 378df8bae1dSRodney W. Grimes } 379835a82eeSMatthew Dillon mtx_unlock(&Giant); 380835a82eeSMatthew Dillon return (error); 381df8bae1dSRodney W. Grimes } 382df8bae1dSRodney W. Grimes 383df8bae1dSRodney W. Grimes /* 384df8bae1dSRodney W. Grimes * set process group (setpgid/old setpgrp) 385df8bae1dSRodney W. Grimes * 386df8bae1dSRodney W. Grimes * caller does setpgid(targpid, targpgid) 387df8bae1dSRodney W. Grimes * 388df8bae1dSRodney W. Grimes * pid must be caller or child of caller (ESRCH) 389df8bae1dSRodney W. Grimes * if a child 390df8bae1dSRodney W. Grimes * pid must be in same session (EPERM) 391df8bae1dSRodney W. Grimes * pid can't have done an exec (EACCES) 392df8bae1dSRodney W. Grimes * if pgid != pid 393df8bae1dSRodney W. Grimes * there must exist some pid in same session having pgid (EPERM) 394df8bae1dSRodney W. Grimes * pid must not be session leader (EPERM) 395df8bae1dSRodney W. Grimes */ 396d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 397df8bae1dSRodney W. Grimes struct setpgid_args { 398df8bae1dSRodney W. Grimes int pid; /* target process id */ 399df8bae1dSRodney W. Grimes int pgid; /* target pgrp id */ 400df8bae1dSRodney W. Grimes }; 401d2d3e875SBruce Evans #endif 402835a82eeSMatthew Dillon /* 403835a82eeSMatthew Dillon * MPSAFE 404835a82eeSMatthew Dillon */ 405df8bae1dSRodney W. Grimes /* ARGSUSED */ 40626f9a767SRodney W. Grimes int 407b40ce416SJulian Elischer setpgid(td, uap) 408b40ce416SJulian Elischer struct thread *td; 409df8bae1dSRodney W. Grimes register struct setpgid_args *uap; 410df8bae1dSRodney W. Grimes { 411b40ce416SJulian Elischer struct proc *curp = td->td_proc; 412df8bae1dSRodney W. Grimes register struct proc *targp; /* target process */ 413df8bae1dSRodney W. Grimes register struct pgrp *pgrp; /* target pgrp */ 414eb9e5c1dSRobert Watson int error; 415df8bae1dSRodney W. Grimes 41678f64bccSBruce Evans if (uap->pgid < 0) 41778f64bccSBruce Evans return (EINVAL); 418835a82eeSMatthew Dillon mtx_lock(&Giant); 4195b29d6e9SJohn Baldwin sx_slock(&proctree_lock); 420df8bae1dSRodney W. Grimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 42133a9ed9dSJohn Baldwin if ((targp = pfind(uap->pid)) == NULL || !inferior(targp)) { 42233a9ed9dSJohn Baldwin if (targp) 42333a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 424835a82eeSMatthew Dillon error = ESRCH; 425835a82eeSMatthew Dillon goto done2; 42633a9ed9dSJohn Baldwin } 427a0f75161SRobert Watson if ((error = p_cansee(curproc, targp))) { 42833a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 429835a82eeSMatthew Dillon goto done2; 43033a9ed9dSJohn Baldwin } 43133a9ed9dSJohn Baldwin if (targp->p_pgrp == NULL || 43233a9ed9dSJohn Baldwin targp->p_session != curp->p_session) { 43333a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 434835a82eeSMatthew Dillon error = EPERM; 435835a82eeSMatthew Dillon goto done2; 43633a9ed9dSJohn Baldwin } 43733a9ed9dSJohn Baldwin if (targp->p_flag & P_EXEC) { 43833a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 439835a82eeSMatthew Dillon error = EACCES; 440835a82eeSMatthew Dillon goto done2; 44133a9ed9dSJohn Baldwin } 44233a9ed9dSJohn Baldwin } else { 443df8bae1dSRodney W. Grimes targp = curp; 44433a9ed9dSJohn Baldwin PROC_LOCK(curp); /* XXX: not needed */ 44533a9ed9dSJohn Baldwin } 44633a9ed9dSJohn Baldwin if (SESS_LEADER(targp)) { 44733a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 448835a82eeSMatthew Dillon error = EPERM; 449835a82eeSMatthew Dillon goto done2; 45033a9ed9dSJohn Baldwin } 451eb725b4eSRobert Watson if (uap->pgid == 0) 452df8bae1dSRodney W. Grimes uap->pgid = targp->p_pid; 453eb725b4eSRobert Watson else if (uap->pgid != targp->p_pid) { 454df8bae1dSRodney W. Grimes if ((pgrp = pgfind(uap->pgid)) == 0 || 45533a9ed9dSJohn Baldwin pgrp->pg_session != curp->p_session) { 45633a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 457835a82eeSMatthew Dillon error = EPERM; 458835a82eeSMatthew Dillon goto done2; 459835a82eeSMatthew Dillon } 46033a9ed9dSJohn Baldwin } 46133a9ed9dSJohn Baldwin /* XXX: We should probably hold the lock across enterpgrp. */ 46233a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 463835a82eeSMatthew Dillon error = enterpgrp(targp, uap->pgid, 0); 464835a82eeSMatthew Dillon done2: 4655b29d6e9SJohn Baldwin sx_sunlock(&proctree_lock); 466835a82eeSMatthew Dillon mtx_unlock(&Giant); 467835a82eeSMatthew Dillon return (error); 468df8bae1dSRodney W. Grimes } 469df8bae1dSRodney W. Grimes 470a08f4bf6SPeter Wemm /* 471a08f4bf6SPeter Wemm * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 4722fa72ea7SJeroen Ruigrok van der Werven * compatible. It says that setting the uid/gid to euid/egid is a special 473a08f4bf6SPeter Wemm * case of "appropriate privilege". Once the rules are expanded out, this 474a08f4bf6SPeter Wemm * basically means that setuid(nnn) sets all three id's, in all permitted 475a08f4bf6SPeter Wemm * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 476a08f4bf6SPeter Wemm * does not set the saved id - this is dangerous for traditional BSD 477a08f4bf6SPeter Wemm * programs. For this reason, we *really* do not want to set 478a08f4bf6SPeter Wemm * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 479a08f4bf6SPeter Wemm */ 480a08f4bf6SPeter Wemm #define POSIX_APPENDIX_B_4_2_2 481a08f4bf6SPeter Wemm 482d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 483df8bae1dSRodney W. Grimes struct setuid_args { 484df8bae1dSRodney W. Grimes uid_t uid; 485df8bae1dSRodney W. Grimes }; 486d2d3e875SBruce Evans #endif 487835a82eeSMatthew Dillon /* 488835a82eeSMatthew Dillon * MPSAFE 489835a82eeSMatthew Dillon */ 490df8bae1dSRodney W. Grimes /* ARGSUSED */ 49126f9a767SRodney W. Grimes int 492b40ce416SJulian Elischer setuid(td, uap) 493b40ce416SJulian Elischer struct thread *td; 494df8bae1dSRodney W. Grimes struct setuid_args *uap; 495df8bae1dSRodney W. Grimes { 496b40ce416SJulian Elischer struct proc *p = td->td_proc; 497b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 498b1fc0ec1SRobert Watson uid_t uid; 499eb725b4eSRobert Watson int error; 500df8bae1dSRodney W. Grimes 501eb725b4eSRobert Watson uid = uap->uid; 502835a82eeSMatthew Dillon mtx_lock(&Giant); 503eb725b4eSRobert Watson error = 0; 504f605567cSRobert Watson oldcred = p->p_ucred; 5055a92ee3cSRobert Watson 506a08f4bf6SPeter Wemm /* 507a08f4bf6SPeter Wemm * See if we have "permission" by POSIX 1003.1 rules. 508a08f4bf6SPeter Wemm * 509a08f4bf6SPeter Wemm * Note that setuid(geteuid()) is a special case of 510a08f4bf6SPeter Wemm * "appropriate privileges" in appendix B.4.2.2. We need 5112fa72ea7SJeroen Ruigrok van der Werven * to use this clause to be compatible with traditional BSD 512a08f4bf6SPeter Wemm * semantics. Basically, it means that "setuid(xx)" sets all 513a08f4bf6SPeter Wemm * three id's (assuming you have privs). 514a08f4bf6SPeter Wemm * 515a08f4bf6SPeter Wemm * Notes on the logic. We do things in three steps. 516a08f4bf6SPeter Wemm * 1: We determine if the euid is going to change, and do EPERM 517a08f4bf6SPeter Wemm * right away. We unconditionally change the euid later if this 518a08f4bf6SPeter Wemm * test is satisfied, simplifying that part of the logic. 519eb725b4eSRobert Watson * 2: We determine if the real and/or saved uids are going to 520a08f4bf6SPeter Wemm * change. Determined by compile options. 521a08f4bf6SPeter Wemm * 3: Change euid last. (after tests in #2 for "appropriate privs") 522a08f4bf6SPeter Wemm */ 523b1fc0ec1SRobert Watson if (uid != oldcred->cr_ruid && /* allow setuid(getuid()) */ 5243f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS 525b1fc0ec1SRobert Watson uid != oldcred->cr_svuid && /* allow setuid(saved gid) */ 526a08f4bf6SPeter Wemm #endif 527a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 528b1fc0ec1SRobert Watson uid != oldcred->cr_uid && /* allow setuid(geteuid()) */ 5293f246666SAndrey A. Chernov #endif 530eb725b4eSRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 531835a82eeSMatthew Dillon goto done2; 532a08f4bf6SPeter Wemm 533b1fc0ec1SRobert Watson newcred = crdup(oldcred); 534a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS 535df8bae1dSRodney W. Grimes /* 536a08f4bf6SPeter Wemm * Do we have "appropriate privileges" (are we root or uid == euid) 537a08f4bf6SPeter Wemm * If so, we are changing the real uid and/or saved uid. 538df8bae1dSRodney W. Grimes */ 5393f246666SAndrey A. Chernov if ( 540a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 541b1fc0ec1SRobert Watson uid == oldcred->cr_uid || 5423f246666SAndrey A. Chernov #endif 543b1fc0ec1SRobert Watson suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */ 544a08f4bf6SPeter Wemm #endif 545a08f4bf6SPeter Wemm { 546a08f4bf6SPeter Wemm /* 547f535380cSDon Lewis * Set the real uid and transfer proc count to new user. 548a08f4bf6SPeter Wemm */ 549b1fc0ec1SRobert Watson if (uid != oldcred->cr_ruid) { 550b1fc0ec1SRobert Watson change_ruid(newcred, uid); 551f535380cSDon Lewis setsugid(p); 552d3cdb93dSAndrey A. Chernov } 553a08f4bf6SPeter Wemm /* 554a08f4bf6SPeter Wemm * Set saved uid 555a08f4bf6SPeter Wemm * 556a08f4bf6SPeter Wemm * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 557a08f4bf6SPeter Wemm * the security of seteuid() depends on it. B.4.2.2 says it 558a08f4bf6SPeter Wemm * is important that we should do this. 559a08f4bf6SPeter Wemm */ 560b1fc0ec1SRobert Watson if (uid != oldcred->cr_svuid) { 561b1fc0ec1SRobert Watson change_svuid(newcred, uid); 562d5f81602SSean Eric Fagan setsugid(p); 563a08f4bf6SPeter Wemm } 564a08f4bf6SPeter Wemm } 565a08f4bf6SPeter Wemm 566a08f4bf6SPeter Wemm /* 567a08f4bf6SPeter Wemm * In all permitted cases, we are changing the euid. 568a08f4bf6SPeter Wemm * Copy credentials so other references do not see our changes. 569a08f4bf6SPeter Wemm */ 570b1fc0ec1SRobert Watson if (uid != oldcred->cr_uid) { 571b1fc0ec1SRobert Watson change_euid(newcred, uid); 572d5f81602SSean Eric Fagan setsugid(p); 573a08f4bf6SPeter Wemm } 574b1fc0ec1SRobert Watson p->p_ucred = newcred; 575b1fc0ec1SRobert Watson crfree(oldcred); 576835a82eeSMatthew Dillon done2: 577835a82eeSMatthew Dillon mtx_unlock(&Giant); 578835a82eeSMatthew Dillon return (error); 579df8bae1dSRodney W. Grimes } 580df8bae1dSRodney W. Grimes 581d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 582df8bae1dSRodney W. Grimes struct seteuid_args { 583df8bae1dSRodney W. Grimes uid_t euid; 584df8bae1dSRodney W. Grimes }; 585d2d3e875SBruce Evans #endif 586835a82eeSMatthew Dillon /* 587835a82eeSMatthew Dillon * MPSAFE 588835a82eeSMatthew Dillon */ 589df8bae1dSRodney W. Grimes /* ARGSUSED */ 59026f9a767SRodney W. Grimes int 591b40ce416SJulian Elischer seteuid(td, uap) 592b40ce416SJulian Elischer struct thread *td; 593df8bae1dSRodney W. Grimes struct seteuid_args *uap; 594df8bae1dSRodney W. Grimes { 595b40ce416SJulian Elischer struct proc *p = td->td_proc; 596b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 597b1fc0ec1SRobert Watson uid_t euid; 598eb725b4eSRobert Watson int error; 599df8bae1dSRodney W. Grimes 600df8bae1dSRodney W. Grimes euid = uap->euid; 601835a82eeSMatthew Dillon mtx_lock(&Giant); 602eb725b4eSRobert Watson error = 0; 603b1fc0ec1SRobert Watson oldcred = p->p_ucred; 604b1fc0ec1SRobert Watson if (euid != oldcred->cr_ruid && /* allow seteuid(getuid()) */ 605b1fc0ec1SRobert Watson euid != oldcred->cr_svuid && /* allow seteuid(saved uid) */ 606eb725b4eSRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 607835a82eeSMatthew Dillon goto done2; 608df8bae1dSRodney W. Grimes /* 609df8bae1dSRodney W. Grimes * Everything's okay, do it. Copy credentials so other references do 610df8bae1dSRodney W. Grimes * not see our changes. 611df8bae1dSRodney W. Grimes */ 612b1fc0ec1SRobert Watson newcred = crdup(oldcred); 613b1fc0ec1SRobert Watson if (oldcred->cr_uid != euid) { 614b1fc0ec1SRobert Watson change_euid(newcred, euid); 615d5f81602SSean Eric Fagan setsugid(p); 616229a15f0SPeter Wemm } 617b1fc0ec1SRobert Watson p->p_ucred = newcred; 618b1fc0ec1SRobert Watson crfree(oldcred); 619835a82eeSMatthew Dillon done2: 620835a82eeSMatthew Dillon mtx_unlock(&Giant); 621835a82eeSMatthew Dillon return (error); 622df8bae1dSRodney W. Grimes } 623df8bae1dSRodney W. Grimes 624d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 625df8bae1dSRodney W. Grimes struct setgid_args { 626df8bae1dSRodney W. Grimes gid_t gid; 627df8bae1dSRodney W. Grimes }; 628d2d3e875SBruce Evans #endif 629835a82eeSMatthew Dillon /* 630835a82eeSMatthew Dillon * MPSAFE 631835a82eeSMatthew Dillon */ 632df8bae1dSRodney W. Grimes /* ARGSUSED */ 63326f9a767SRodney W. Grimes int 634b40ce416SJulian Elischer setgid(td, uap) 635b40ce416SJulian Elischer struct thread *td; 636df8bae1dSRodney W. Grimes struct setgid_args *uap; 637df8bae1dSRodney W. Grimes { 638b40ce416SJulian Elischer struct proc *p = td->td_proc; 639b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 640b1fc0ec1SRobert Watson gid_t gid; 641eb725b4eSRobert Watson int error; 642df8bae1dSRodney W. Grimes 643b1fc0ec1SRobert Watson gid = uap->gid; 644835a82eeSMatthew Dillon mtx_lock(&Giant); 645eb725b4eSRobert Watson error = 0; 646b1fc0ec1SRobert Watson oldcred = p->p_ucred; 6475a92ee3cSRobert Watson 648a08f4bf6SPeter Wemm /* 649a08f4bf6SPeter Wemm * See if we have "permission" by POSIX 1003.1 rules. 650a08f4bf6SPeter Wemm * 651a08f4bf6SPeter Wemm * Note that setgid(getegid()) is a special case of 652a08f4bf6SPeter Wemm * "appropriate privileges" in appendix B.4.2.2. We need 6532fa72ea7SJeroen Ruigrok van der Werven * to use this clause to be compatible with traditional BSD 654a08f4bf6SPeter Wemm * semantics. Basically, it means that "setgid(xx)" sets all 655a08f4bf6SPeter Wemm * three id's (assuming you have privs). 656a08f4bf6SPeter Wemm * 657a08f4bf6SPeter Wemm * For notes on the logic here, see setuid() above. 658a08f4bf6SPeter Wemm */ 659b1fc0ec1SRobert Watson if (gid != oldcred->cr_rgid && /* allow setgid(getgid()) */ 6603f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS 661b1fc0ec1SRobert Watson gid != oldcred->cr_svgid && /* allow setgid(saved gid) */ 662a08f4bf6SPeter Wemm #endif 663a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 664b1fc0ec1SRobert Watson gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */ 6653f246666SAndrey A. Chernov #endif 666eb725b4eSRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 667835a82eeSMatthew Dillon goto done2; 668a08f4bf6SPeter Wemm 669b1fc0ec1SRobert Watson newcred = crdup(oldcred); 670a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS 671a08f4bf6SPeter Wemm /* 672a08f4bf6SPeter Wemm * Do we have "appropriate privileges" (are we root or gid == egid) 673a08f4bf6SPeter Wemm * If so, we are changing the real uid and saved gid. 674a08f4bf6SPeter Wemm */ 675a08f4bf6SPeter Wemm if ( 676a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 677b1fc0ec1SRobert Watson gid == oldcred->cr_groups[0] || 678a08f4bf6SPeter Wemm #endif 679b1fc0ec1SRobert Watson suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */ 680a08f4bf6SPeter Wemm #endif 681a08f4bf6SPeter Wemm { 682a08f4bf6SPeter Wemm /* 683a08f4bf6SPeter Wemm * Set real gid 684a08f4bf6SPeter Wemm */ 685b1fc0ec1SRobert Watson if (oldcred->cr_rgid != gid) { 686b1fc0ec1SRobert Watson change_rgid(newcred, gid); 687d5f81602SSean Eric Fagan setsugid(p); 688a08f4bf6SPeter Wemm } 689a08f4bf6SPeter Wemm /* 690a08f4bf6SPeter Wemm * Set saved gid 691a08f4bf6SPeter Wemm * 692a08f4bf6SPeter Wemm * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 693a08f4bf6SPeter Wemm * the security of setegid() depends on it. B.4.2.2 says it 694a08f4bf6SPeter Wemm * is important that we should do this. 695a08f4bf6SPeter Wemm */ 696b1fc0ec1SRobert Watson if (oldcred->cr_svgid != gid) { 697b1fc0ec1SRobert Watson change_svgid(newcred, gid); 698d5f81602SSean Eric Fagan setsugid(p); 699a08f4bf6SPeter Wemm } 700a08f4bf6SPeter Wemm } 701a08f4bf6SPeter Wemm /* 702a08f4bf6SPeter Wemm * In all cases permitted cases, we are changing the egid. 703a08f4bf6SPeter Wemm * Copy credentials so other references do not see our changes. 704a08f4bf6SPeter Wemm */ 705b1fc0ec1SRobert Watson if (oldcred->cr_groups[0] != gid) { 706b1fc0ec1SRobert Watson change_egid(newcred, gid); 707d5f81602SSean Eric Fagan setsugid(p); 708a08f4bf6SPeter Wemm } 709b1fc0ec1SRobert Watson p->p_ucred = newcred; 710b1fc0ec1SRobert Watson crfree(oldcred); 711835a82eeSMatthew Dillon done2: 712835a82eeSMatthew Dillon mtx_unlock(&Giant); 713835a82eeSMatthew Dillon return (error); 714df8bae1dSRodney W. Grimes } 715df8bae1dSRodney W. Grimes 716d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 717df8bae1dSRodney W. Grimes struct setegid_args { 718df8bae1dSRodney W. Grimes gid_t egid; 719df8bae1dSRodney W. Grimes }; 720d2d3e875SBruce Evans #endif 721835a82eeSMatthew Dillon /* 722835a82eeSMatthew Dillon * MPSAFE 723835a82eeSMatthew Dillon */ 724df8bae1dSRodney W. Grimes /* ARGSUSED */ 72526f9a767SRodney W. Grimes int 726b40ce416SJulian Elischer setegid(td, uap) 727b40ce416SJulian Elischer struct thread *td; 728df8bae1dSRodney W. Grimes struct setegid_args *uap; 729df8bae1dSRodney W. Grimes { 730b40ce416SJulian Elischer struct proc *p = td->td_proc; 731b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 732b1fc0ec1SRobert Watson gid_t egid; 733eb725b4eSRobert Watson int error; 734df8bae1dSRodney W. Grimes 735df8bae1dSRodney W. Grimes egid = uap->egid; 736835a82eeSMatthew Dillon mtx_lock(&Giant); 737eb725b4eSRobert Watson error = 0; 738b1fc0ec1SRobert Watson oldcred = p->p_ucred; 739b1fc0ec1SRobert Watson if (egid != oldcred->cr_rgid && /* allow setegid(getgid()) */ 740b1fc0ec1SRobert Watson egid != oldcred->cr_svgid && /* allow setegid(saved gid) */ 741eb725b4eSRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 742835a82eeSMatthew Dillon goto done2; 743b1fc0ec1SRobert Watson newcred = crdup(oldcred); 744b1fc0ec1SRobert Watson if (oldcred->cr_groups[0] != egid) { 745b1fc0ec1SRobert Watson change_egid(newcred, egid); 746d5f81602SSean Eric Fagan setsugid(p); 747229a15f0SPeter Wemm } 748b1fc0ec1SRobert Watson p->p_ucred = newcred; 749b1fc0ec1SRobert Watson crfree(oldcred); 750835a82eeSMatthew Dillon done2: 751835a82eeSMatthew Dillon mtx_unlock(&Giant); 752835a82eeSMatthew Dillon return (error); 753df8bae1dSRodney W. Grimes } 754df8bae1dSRodney W. Grimes 755d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 756df8bae1dSRodney W. Grimes struct setgroups_args { 757df8bae1dSRodney W. Grimes u_int gidsetsize; 758df8bae1dSRodney W. Grimes gid_t *gidset; 759df8bae1dSRodney W. Grimes }; 760d2d3e875SBruce Evans #endif 761835a82eeSMatthew Dillon /* 762835a82eeSMatthew Dillon * MPSAFE 763835a82eeSMatthew Dillon */ 764df8bae1dSRodney W. Grimes /* ARGSUSED */ 76526f9a767SRodney W. Grimes int 766b40ce416SJulian Elischer setgroups(td, uap) 767b40ce416SJulian Elischer struct thread *td; 768df8bae1dSRodney W. Grimes struct setgroups_args *uap; 769df8bae1dSRodney W. Grimes { 770b40ce416SJulian Elischer struct proc *p = td->td_proc; 771b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 772b1fc0ec1SRobert Watson u_int ngrp; 773df8bae1dSRodney W. Grimes int error; 774df8bae1dSRodney W. Grimes 7753956a170SDavid Greenman ngrp = uap->gidsetsize; 7764f5a4612SRobert Watson mtx_lock(&Giant); 777b1fc0ec1SRobert Watson oldcred = p->p_ucred; 778eb725b4eSRobert Watson if ((error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 779835a82eeSMatthew Dillon goto done2; 780835a82eeSMatthew Dillon if (ngrp > NGROUPS) { 781835a82eeSMatthew Dillon error = EINVAL; 782835a82eeSMatthew Dillon goto done2; 783835a82eeSMatthew Dillon } 7848a5d815aSPeter Wemm /* 7858a5d815aSPeter Wemm * XXX A little bit lazy here. We could test if anything has 7868a5d815aSPeter Wemm * changed before crcopy() and setting P_SUGID. 7878a5d815aSPeter Wemm */ 788b1fc0ec1SRobert Watson newcred = crdup(oldcred); 7898a5d815aSPeter Wemm if (ngrp < 1) { 7908a5d815aSPeter Wemm /* 7918a5d815aSPeter Wemm * setgroups(0, NULL) is a legitimate way of clearing the 7928a5d815aSPeter Wemm * groups vector on non-BSD systems (which generally do not 7938a5d815aSPeter Wemm * have the egid in the groups[0]). We risk security holes 7948a5d815aSPeter Wemm * when running non-BSD software if we do not do the same. 7958a5d815aSPeter Wemm */ 796b1fc0ec1SRobert Watson newcred->cr_ngroups = 1; 7978a5d815aSPeter Wemm } else { 798bb56ec4aSPoul-Henning Kamp if ((error = copyin((caddr_t)uap->gidset, 799b1fc0ec1SRobert Watson (caddr_t)newcred->cr_groups, ngrp * sizeof(gid_t)))) { 800b1fc0ec1SRobert Watson crfree(newcred); 801835a82eeSMatthew Dillon goto done2; 802b1fc0ec1SRobert Watson } 803b1fc0ec1SRobert Watson newcred->cr_ngroups = ngrp; 8048a5d815aSPeter Wemm } 805d5f81602SSean Eric Fagan setsugid(p); 806b1fc0ec1SRobert Watson p->p_ucred = newcred; 807b1fc0ec1SRobert Watson crfree(oldcred); 808835a82eeSMatthew Dillon done2: 809835a82eeSMatthew Dillon mtx_unlock(&Giant); 810835a82eeSMatthew Dillon return (error); 811df8bae1dSRodney W. Grimes } 812df8bae1dSRodney W. Grimes 813d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 814df8bae1dSRodney W. Grimes struct setreuid_args { 81500999cd6SAndrey A. Chernov uid_t ruid; 81600999cd6SAndrey A. Chernov uid_t euid; 817df8bae1dSRodney W. Grimes }; 818d2d3e875SBruce Evans #endif 819835a82eeSMatthew Dillon /* 820835a82eeSMatthew Dillon * MPSAFE 821835a82eeSMatthew Dillon */ 822df8bae1dSRodney W. Grimes /* ARGSUSED */ 82326f9a767SRodney W. Grimes int 824b40ce416SJulian Elischer setreuid(td, uap) 825b40ce416SJulian Elischer register struct thread *td; 826df8bae1dSRodney W. Grimes struct setreuid_args *uap; 827df8bae1dSRodney W. Grimes { 828b40ce416SJulian Elischer struct proc *p = td->td_proc; 829b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 830eb725b4eSRobert Watson uid_t euid, ruid; 831eb725b4eSRobert Watson int error; 832df8bae1dSRodney W. Grimes 83300999cd6SAndrey A. Chernov euid = uap->euid; 834eb725b4eSRobert Watson ruid = uap->ruid; 835835a82eeSMatthew Dillon mtx_lock(&Giant); 836eb725b4eSRobert Watson error = 0; 837b1fc0ec1SRobert Watson oldcred = p->p_ucred; 838b1fc0ec1SRobert Watson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 839b1fc0ec1SRobert Watson ruid != oldcred->cr_svuid) || 840b1fc0ec1SRobert Watson (euid != (uid_t)-1 && euid != oldcred->cr_uid && 841b1fc0ec1SRobert Watson euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) && 842eb725b4eSRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 843835a82eeSMatthew Dillon goto done2; 844b1fc0ec1SRobert Watson newcred = crdup(oldcred); 845b1fc0ec1SRobert Watson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 846b1fc0ec1SRobert Watson change_euid(newcred, euid); 847d5f81602SSean Eric Fagan setsugid(p); 848a89a5370SPeter Wemm } 849b1fc0ec1SRobert Watson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 850b1fc0ec1SRobert Watson change_ruid(newcred, ruid); 851d5f81602SSean Eric Fagan setsugid(p); 85200999cd6SAndrey A. Chernov } 853b1fc0ec1SRobert Watson if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) && 854b1fc0ec1SRobert Watson newcred->cr_svuid != newcred->cr_uid) { 855b1fc0ec1SRobert Watson change_svuid(newcred, newcred->cr_uid); 856d5f81602SSean Eric Fagan setsugid(p); 857a89a5370SPeter Wemm } 858b1fc0ec1SRobert Watson p->p_ucred = newcred; 859b1fc0ec1SRobert Watson crfree(oldcred); 860835a82eeSMatthew Dillon done2: 861835a82eeSMatthew Dillon mtx_unlock(&Giant); 862835a82eeSMatthew Dillon return (error); 863df8bae1dSRodney W. Grimes } 864df8bae1dSRodney W. Grimes 865d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 866df8bae1dSRodney W. Grimes struct setregid_args { 86700999cd6SAndrey A. Chernov gid_t rgid; 86800999cd6SAndrey A. Chernov gid_t egid; 869df8bae1dSRodney W. Grimes }; 870d2d3e875SBruce Evans #endif 871835a82eeSMatthew Dillon /* 872835a82eeSMatthew Dillon * MPSAFE 873835a82eeSMatthew Dillon */ 874df8bae1dSRodney W. Grimes /* ARGSUSED */ 87526f9a767SRodney W. Grimes int 876b40ce416SJulian Elischer setregid(td, uap) 877b40ce416SJulian Elischer register struct thread *td; 878df8bae1dSRodney W. Grimes struct setregid_args *uap; 879df8bae1dSRodney W. Grimes { 880b40ce416SJulian Elischer struct proc *p = td->td_proc; 881b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 882eb725b4eSRobert Watson gid_t egid, rgid; 883eb725b4eSRobert Watson int error; 884df8bae1dSRodney W. Grimes 88500999cd6SAndrey A. Chernov egid = uap->egid; 886eb725b4eSRobert Watson rgid = uap->rgid; 887835a82eeSMatthew Dillon mtx_lock(&Giant); 888eb725b4eSRobert Watson error = 0; 889b1fc0ec1SRobert Watson oldcred = p->p_ucred; 890b1fc0ec1SRobert Watson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 891b1fc0ec1SRobert Watson rgid != oldcred->cr_svgid) || 892b1fc0ec1SRobert Watson (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] && 893b1fc0ec1SRobert Watson egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) && 894eb725b4eSRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 895835a82eeSMatthew Dillon goto done2; 896b1fc0ec1SRobert Watson newcred = crdup(oldcred); 897b1fc0ec1SRobert Watson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 898b1fc0ec1SRobert Watson change_egid(newcred, egid); 899d5f81602SSean Eric Fagan setsugid(p); 900a89a5370SPeter Wemm } 901b1fc0ec1SRobert Watson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 902b1fc0ec1SRobert Watson change_rgid(newcred, rgid); 903d5f81602SSean Eric Fagan setsugid(p); 904a89a5370SPeter Wemm } 905b1fc0ec1SRobert Watson if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) && 906b1fc0ec1SRobert Watson newcred->cr_svgid != newcred->cr_groups[0]) { 907b1fc0ec1SRobert Watson change_svgid(newcred, newcred->cr_groups[0]); 908d5f81602SSean Eric Fagan setsugid(p); 909a89a5370SPeter Wemm } 9104589be70SRuslan Ermilov p->p_ucred = newcred; 9114589be70SRuslan Ermilov crfree(oldcred); 912835a82eeSMatthew Dillon done2: 913835a82eeSMatthew Dillon mtx_unlock(&Giant); 914835a82eeSMatthew Dillon return (error); 915df8bae1dSRodney W. Grimes } 916df8bae1dSRodney W. Grimes 9178ccd6334SPeter Wemm /* 9188ccd6334SPeter Wemm * setresuid(ruid, euid, suid) is like setreuid except control over the 9198ccd6334SPeter Wemm * saved uid is explicit. 9208ccd6334SPeter Wemm */ 9218ccd6334SPeter Wemm 9228ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 9238ccd6334SPeter Wemm struct setresuid_args { 9248ccd6334SPeter Wemm uid_t ruid; 9258ccd6334SPeter Wemm uid_t euid; 9268ccd6334SPeter Wemm uid_t suid; 9278ccd6334SPeter Wemm }; 9288ccd6334SPeter Wemm #endif 929835a82eeSMatthew Dillon /* 930835a82eeSMatthew Dillon * MPSAFE 931835a82eeSMatthew Dillon */ 9328ccd6334SPeter Wemm /* ARGSUSED */ 9338ccd6334SPeter Wemm int 934b40ce416SJulian Elischer setresuid(td, uap) 935b40ce416SJulian Elischer register struct thread *td; 9368ccd6334SPeter Wemm struct setresuid_args *uap; 9378ccd6334SPeter Wemm { 938b40ce416SJulian Elischer struct proc *p = td->td_proc; 939b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 940eb725b4eSRobert Watson uid_t euid, ruid, suid; 9418ccd6334SPeter Wemm int error; 9428ccd6334SPeter Wemm 9438ccd6334SPeter Wemm euid = uap->euid; 944eb725b4eSRobert Watson ruid = uap->ruid; 9458ccd6334SPeter Wemm suid = uap->suid; 946835a82eeSMatthew Dillon mtx_lock(&Giant); 947b1fc0ec1SRobert Watson oldcred = p->p_ucred; 948b1fc0ec1SRobert Watson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 949b1fc0ec1SRobert Watson ruid != oldcred->cr_svuid && 950b1fc0ec1SRobert Watson ruid != oldcred->cr_uid) || 951b1fc0ec1SRobert Watson (euid != (uid_t)-1 && euid != oldcred->cr_ruid && 952b1fc0ec1SRobert Watson euid != oldcred->cr_svuid && 953b1fc0ec1SRobert Watson euid != oldcred->cr_uid) || 954b1fc0ec1SRobert Watson (suid != (uid_t)-1 && suid != oldcred->cr_ruid && 955b1fc0ec1SRobert Watson suid != oldcred->cr_svuid && 956b1fc0ec1SRobert Watson suid != oldcred->cr_uid)) && 957eb725b4eSRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 958835a82eeSMatthew Dillon goto done2; 959b1fc0ec1SRobert Watson newcred = crdup(oldcred); 960b1fc0ec1SRobert Watson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 961b1fc0ec1SRobert Watson change_euid(newcred, euid); 9628ccd6334SPeter Wemm setsugid(p); 9638ccd6334SPeter Wemm } 964b1fc0ec1SRobert Watson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 965b1fc0ec1SRobert Watson change_ruid(newcred, ruid); 9668ccd6334SPeter Wemm setsugid(p); 9678ccd6334SPeter Wemm } 968b1fc0ec1SRobert Watson if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) { 969b1fc0ec1SRobert Watson change_svuid(newcred, suid); 9708ccd6334SPeter Wemm setsugid(p); 9718ccd6334SPeter Wemm } 972b1fc0ec1SRobert Watson p->p_ucred = newcred; 973b1fc0ec1SRobert Watson crfree(oldcred); 974835a82eeSMatthew Dillon error = 0; 975835a82eeSMatthew Dillon done2: 976835a82eeSMatthew Dillon mtx_unlock(&Giant); 977835a82eeSMatthew Dillon return (error); 9788ccd6334SPeter Wemm } 9798ccd6334SPeter Wemm 9808ccd6334SPeter Wemm /* 9818ccd6334SPeter Wemm * setresgid(rgid, egid, sgid) is like setregid except control over the 9828ccd6334SPeter Wemm * saved gid is explicit. 9838ccd6334SPeter Wemm */ 9848ccd6334SPeter Wemm 9858ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 9868ccd6334SPeter Wemm struct setresgid_args { 9878ccd6334SPeter Wemm gid_t rgid; 9888ccd6334SPeter Wemm gid_t egid; 9898ccd6334SPeter Wemm gid_t sgid; 9908ccd6334SPeter Wemm }; 9918ccd6334SPeter Wemm #endif 992835a82eeSMatthew Dillon /* 993835a82eeSMatthew Dillon * MPSAFE 994835a82eeSMatthew Dillon */ 9958ccd6334SPeter Wemm /* ARGSUSED */ 9968ccd6334SPeter Wemm int 997b40ce416SJulian Elischer setresgid(td, uap) 998b40ce416SJulian Elischer register struct thread *td; 9998ccd6334SPeter Wemm struct setresgid_args *uap; 10008ccd6334SPeter Wemm { 1001b40ce416SJulian Elischer struct proc *p = td->td_proc; 1002b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 1003eb725b4eSRobert Watson gid_t egid, rgid, sgid; 10048ccd6334SPeter Wemm int error; 10058ccd6334SPeter Wemm 10068ccd6334SPeter Wemm egid = uap->egid; 1007eb725b4eSRobert Watson rgid = uap->rgid; 10088ccd6334SPeter Wemm sgid = uap->sgid; 1009835a82eeSMatthew Dillon mtx_lock(&Giant); 1010b1fc0ec1SRobert Watson oldcred = p->p_ucred; 1011b1fc0ec1SRobert Watson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 1012b1fc0ec1SRobert Watson rgid != oldcred->cr_svgid && 1013b1fc0ec1SRobert Watson rgid != oldcred->cr_groups[0]) || 1014b1fc0ec1SRobert Watson (egid != (gid_t)-1 && egid != oldcred->cr_rgid && 1015b1fc0ec1SRobert Watson egid != oldcred->cr_svgid && 1016b1fc0ec1SRobert Watson egid != oldcred->cr_groups[0]) || 1017b1fc0ec1SRobert Watson (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid && 1018b1fc0ec1SRobert Watson sgid != oldcred->cr_svgid && 1019b1fc0ec1SRobert Watson sgid != oldcred->cr_groups[0])) && 10205a92ee3cSRobert Watson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 1021835a82eeSMatthew Dillon goto done2; 1022b1fc0ec1SRobert Watson newcred = crdup(oldcred); 1023b1fc0ec1SRobert Watson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 1024b1fc0ec1SRobert Watson change_egid(newcred, egid); 10258ccd6334SPeter Wemm setsugid(p); 10268ccd6334SPeter Wemm } 1027b1fc0ec1SRobert Watson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 1028b1fc0ec1SRobert Watson change_rgid(newcred, rgid); 10298ccd6334SPeter Wemm setsugid(p); 10308ccd6334SPeter Wemm } 1031b1fc0ec1SRobert Watson if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) { 1032b1fc0ec1SRobert Watson change_svgid(newcred, sgid); 10338ccd6334SPeter Wemm setsugid(p); 10348ccd6334SPeter Wemm } 1035b1fc0ec1SRobert Watson p->p_ucred = newcred; 1036b1fc0ec1SRobert Watson crfree(oldcred); 1037835a82eeSMatthew Dillon error = 0; 1038835a82eeSMatthew Dillon done2: 1039835a82eeSMatthew Dillon mtx_unlock(&Giant); 1040835a82eeSMatthew Dillon return (error); 10418ccd6334SPeter Wemm } 10428ccd6334SPeter Wemm 10438ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 10448ccd6334SPeter Wemm struct getresuid_args { 10458ccd6334SPeter Wemm uid_t *ruid; 10468ccd6334SPeter Wemm uid_t *euid; 10478ccd6334SPeter Wemm uid_t *suid; 10488ccd6334SPeter Wemm }; 10498ccd6334SPeter Wemm #endif 1050835a82eeSMatthew Dillon /* 1051835a82eeSMatthew Dillon * MPSAFE 1052835a82eeSMatthew Dillon */ 10538ccd6334SPeter Wemm /* ARGSUSED */ 10548ccd6334SPeter Wemm int 1055b40ce416SJulian Elischer getresuid(td, uap) 1056b40ce416SJulian Elischer register struct thread *td; 10578ccd6334SPeter Wemm struct getresuid_args *uap; 10588ccd6334SPeter Wemm { 1059835a82eeSMatthew Dillon struct ucred *cred; 1060b40ce416SJulian Elischer struct proc *p = td->td_proc; 10618ccd6334SPeter Wemm int error1 = 0, error2 = 0, error3 = 0; 10628ccd6334SPeter Wemm 1063835a82eeSMatthew Dillon mtx_lock(&Giant); 1064835a82eeSMatthew Dillon cred = p->p_ucred; 10658ccd6334SPeter Wemm if (uap->ruid) 1066b1fc0ec1SRobert Watson error1 = copyout((caddr_t)&cred->cr_ruid, 1067b1fc0ec1SRobert Watson (caddr_t)uap->ruid, sizeof(cred->cr_ruid)); 10688ccd6334SPeter Wemm if (uap->euid) 1069b1fc0ec1SRobert Watson error2 = copyout((caddr_t)&cred->cr_uid, 1070b1fc0ec1SRobert Watson (caddr_t)uap->euid, sizeof(cred->cr_uid)); 10718ccd6334SPeter Wemm if (uap->suid) 1072b1fc0ec1SRobert Watson error3 = copyout((caddr_t)&cred->cr_svuid, 1073b1fc0ec1SRobert Watson (caddr_t)uap->suid, sizeof(cred->cr_svuid)); 1074835a82eeSMatthew Dillon mtx_unlock(&Giant); 1075eb725b4eSRobert Watson return (error1 ? error1 : error2 ? error2 : error3); 10768ccd6334SPeter Wemm } 10778ccd6334SPeter Wemm 10788ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 10798ccd6334SPeter Wemm struct getresgid_args { 10808ccd6334SPeter Wemm gid_t *rgid; 10818ccd6334SPeter Wemm gid_t *egid; 10828ccd6334SPeter Wemm gid_t *sgid; 10838ccd6334SPeter Wemm }; 10848ccd6334SPeter Wemm #endif 1085835a82eeSMatthew Dillon /* 1086835a82eeSMatthew Dillon * MPSAFE 1087835a82eeSMatthew Dillon */ 10888ccd6334SPeter Wemm /* ARGSUSED */ 10898ccd6334SPeter Wemm int 1090b40ce416SJulian Elischer getresgid(td, uap) 1091b40ce416SJulian Elischer register struct thread *td; 10928ccd6334SPeter Wemm struct getresgid_args *uap; 10938ccd6334SPeter Wemm { 1094835a82eeSMatthew Dillon struct ucred *cred; 1095b40ce416SJulian Elischer struct proc *p = td->td_proc; 10968ccd6334SPeter Wemm int error1 = 0, error2 = 0, error3 = 0; 10978ccd6334SPeter Wemm 1098835a82eeSMatthew Dillon mtx_lock(&Giant); 1099835a82eeSMatthew Dillon cred = p->p_ucred; 11008ccd6334SPeter Wemm if (uap->rgid) 1101b1fc0ec1SRobert Watson error1 = copyout((caddr_t)&cred->cr_rgid, 1102b1fc0ec1SRobert Watson (caddr_t)uap->rgid, sizeof(cred->cr_rgid)); 11038ccd6334SPeter Wemm if (uap->egid) 1104b1fc0ec1SRobert Watson error2 = copyout((caddr_t)&cred->cr_groups[0], 1105b1fc0ec1SRobert Watson (caddr_t)uap->egid, sizeof(cred->cr_groups[0])); 11068ccd6334SPeter Wemm if (uap->sgid) 1107b1fc0ec1SRobert Watson error3 = copyout((caddr_t)&cred->cr_svgid, 1108b1fc0ec1SRobert Watson (caddr_t)uap->sgid, sizeof(cred->cr_svgid)); 1109835a82eeSMatthew Dillon mtx_unlock(&Giant); 1110eb725b4eSRobert Watson return (error1 ? error1 : error2 ? error2 : error3); 11118ccd6334SPeter Wemm } 11128ccd6334SPeter Wemm 1113b67cbc65SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1114b67cbc65SPeter Wemm struct issetugid_args { 1115b67cbc65SPeter Wemm int dummy; 1116b67cbc65SPeter Wemm }; 1117b67cbc65SPeter Wemm #endif 1118eb725b4eSRobert Watson /* 1119eb725b4eSRobert Watson * NOT MPSAFE? 1120eb725b4eSRobert Watson */ 1121b67cbc65SPeter Wemm /* ARGSUSED */ 1122b67cbc65SPeter Wemm int 1123b40ce416SJulian Elischer issetugid(td, uap) 1124b40ce416SJulian Elischer register struct thread *td; 1125b67cbc65SPeter Wemm struct issetugid_args *uap; 1126b67cbc65SPeter Wemm { 1127b40ce416SJulian Elischer struct proc *p = td->td_proc; 1128b40ce416SJulian Elischer 1129b67cbc65SPeter Wemm /* 1130b67cbc65SPeter Wemm * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 1131b67cbc65SPeter Wemm * we use P_SUGID because we consider changing the owners as 1132b67cbc65SPeter Wemm * "tainting" as well. 1133b67cbc65SPeter Wemm * This is significant for procs that start as root and "become" 1134b67cbc65SPeter Wemm * a user without an exec - programs cannot know *everything* 1135b67cbc65SPeter Wemm * that libc *might* have put in their data segment. 1136b67cbc65SPeter Wemm */ 1137b40ce416SJulian Elischer td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 1138b67cbc65SPeter Wemm return (0); 1139b67cbc65SPeter Wemm } 1140b67cbc65SPeter Wemm 1141835a82eeSMatthew Dillon /* 1142835a82eeSMatthew Dillon * MPSAFE 1143835a82eeSMatthew Dillon */ 1144130d0157SRobert Watson int 1145b40ce416SJulian Elischer __setugid(td, uap) 1146b40ce416SJulian Elischer struct thread *td; 1147130d0157SRobert Watson struct __setugid_args *uap; 1148130d0157SRobert Watson { 1149130d0157SRobert Watson #ifdef REGRESSION 1150eb725b4eSRobert Watson int error; 1151835a82eeSMatthew Dillon 1152835a82eeSMatthew Dillon mtx_lock(&Giant); 1153eb725b4eSRobert Watson error = 0; 1154130d0157SRobert Watson switch (uap->flag) { 1155130d0157SRobert Watson case 0: 1156b40ce416SJulian Elischer td->td_proc->p_flag &= ~P_SUGID; 1157835a82eeSMatthew Dillon break; 1158130d0157SRobert Watson case 1: 1159b40ce416SJulian Elischer td->td_proc->p_flag |= P_SUGID; 1160835a82eeSMatthew Dillon break; 1161130d0157SRobert Watson default: 1162835a82eeSMatthew Dillon error = EINVAL; 1163835a82eeSMatthew Dillon break; 1164130d0157SRobert Watson } 1165835a82eeSMatthew Dillon mtx_unlock(&Giant); 1166835a82eeSMatthew Dillon return (error); 1167130d0157SRobert Watson #else /* !REGRESSION */ 1168eb725b4eSRobert Watson 1169130d0157SRobert Watson return (ENOSYS); 1170eb725b4eSRobert Watson #endif /* REGRESSION */ 1171130d0157SRobert Watson } 1172130d0157SRobert Watson 1173df8bae1dSRodney W. Grimes /* 1174df8bae1dSRodney W. Grimes * Check if gid is a member of the group set. 1175df8bae1dSRodney W. Grimes */ 117626f9a767SRodney W. Grimes int 1177df8bae1dSRodney W. Grimes groupmember(gid, cred) 1178df8bae1dSRodney W. Grimes gid_t gid; 1179b1fc0ec1SRobert Watson struct ucred *cred; 1180df8bae1dSRodney W. Grimes { 1181df8bae1dSRodney W. Grimes register gid_t *gp; 1182df8bae1dSRodney W. Grimes gid_t *egp; 1183df8bae1dSRodney W. Grimes 1184df8bae1dSRodney W. Grimes egp = &(cred->cr_groups[cred->cr_ngroups]); 1185df8bae1dSRodney W. Grimes for (gp = cred->cr_groups; gp < egp; gp++) 1186df8bae1dSRodney W. Grimes if (*gp == gid) 1187df8bae1dSRodney W. Grimes return (1); 1188df8bae1dSRodney W. Grimes return (0); 1189df8bae1dSRodney W. Grimes } 1190df8bae1dSRodney W. Grimes 11913b243b72SRobert Watson /* 1192d0615c64SAndrew R. Reiter * `suser_enabled' (which can be set by the security.suser_enabled 11937fd6a959SRobert Watson * sysctl) determines whether the system 'super-user' policy is in effect. 11947fd6a959SRobert Watson * If it is nonzero, an effective uid of 0 connotes special privilege, 11957fd6a959SRobert Watson * overriding many mandatory and discretionary protections. If it is zero, 11967fd6a959SRobert Watson * uid 0 is offered no special privilege in the kernel security policy. 11977fd6a959SRobert Watson * Setting it to zero may seriously impact the functionality of many 11987fd6a959SRobert Watson * existing userland programs, and should not be done without careful 11997fd6a959SRobert Watson * consideration of the consequences. 12003b243b72SRobert Watson */ 120193f4fd1cSRobert Watson int suser_enabled = 1; 1202d0615c64SAndrew R. Reiter SYSCTL_INT(_security_bsd, OID_AUTO, suser_enabled, CTLFLAG_RW, 120393f4fd1cSRobert Watson &suser_enabled, 0, "processes with uid 0 have privilege"); 1204d0615c64SAndrew R. Reiter TUNABLE_INT("security.bsd.suser_enabled", &suser_enabled); 1205579f4eb4SRobert Watson 1206df8bae1dSRodney W. Grimes /* 12077fd6a959SRobert Watson * Test whether the specified credentials imply "super-user" privilege. 12087fd6a959SRobert Watson * Return 0 or EPERM. 1209df8bae1dSRodney W. Grimes */ 121026f9a767SRodney W. Grimes int 1211f711d546SPoul-Henning Kamp suser(p) 121291421ba2SRobert Watson struct proc *p; 1213f711d546SPoul-Henning Kamp { 1214eb725b4eSRobert Watson 1215eb725b4eSRobert Watson return (suser_xxx(0, p, 0)); 1216f711d546SPoul-Henning Kamp } 1217f711d546SPoul-Henning Kamp 1218b40ce416SJulian Elischer /* 1219b40ce416SJulian Elischer * version for when the thread pointer is available and not the proc. 1220b40ce416SJulian Elischer * (saves having to include proc.h into every file that needs to do the change.) 1221b40ce416SJulian Elischer */ 1222b40ce416SJulian Elischer int 1223b40ce416SJulian Elischer suser_td(td) 1224b40ce416SJulian Elischer struct thread *td; 1225b40ce416SJulian Elischer { 12265a92ee3cSRobert Watson return (suser_xxx(0, td->td_proc, 0)); 1227b40ce416SJulian Elischer } 1228b40ce416SJulian Elischer 1229b40ce416SJulian Elischer /* 1230b40ce416SJulian Elischer * wrapper to use if you have the thread on hand but not the proc. 1231b40ce416SJulian Elischer */ 1232b40ce416SJulian Elischer int 1233b40ce416SJulian Elischer suser_xxx_td(cred, td, flag) 1234b40ce416SJulian Elischer struct ucred *cred; 1235b40ce416SJulian Elischer struct thread *td; 1236b40ce416SJulian Elischer int flag; 1237b40ce416SJulian Elischer { 1238b40ce416SJulian Elischer return(suser_xxx(cred, td->td_proc, flag)); 1239b40ce416SJulian Elischer } 1240b40ce416SJulian Elischer 1241f711d546SPoul-Henning Kamp int 124275c13541SPoul-Henning Kamp suser_xxx(cred, proc, flag) 124391421ba2SRobert Watson struct ucred *cred; 124491421ba2SRobert Watson struct proc *proc; 124575c13541SPoul-Henning Kamp int flag; 1246df8bae1dSRodney W. Grimes { 124793f4fd1cSRobert Watson if (!suser_enabled) 124803095547SRobert Watson return (EPERM); 124975c13541SPoul-Henning Kamp if (!cred && !proc) { 125075c13541SPoul-Henning Kamp printf("suser_xxx(): THINK!\n"); 1251df8bae1dSRodney W. Grimes return (EPERM); 1252df8bae1dSRodney W. Grimes } 1253eb725b4eSRobert Watson if (cred == NULL) 125475c13541SPoul-Henning Kamp cred = proc->p_ucred; 125575c13541SPoul-Henning Kamp if (cred->cr_uid != 0) 125675c13541SPoul-Henning Kamp return (EPERM); 125791421ba2SRobert Watson if (jailed(cred) && !(flag & PRISON_ROOT)) 125875c13541SPoul-Henning Kamp return (EPERM); 125975c13541SPoul-Henning Kamp return (0); 126075c13541SPoul-Henning Kamp } 1261df8bae1dSRodney W. Grimes 12623ca719f1SRobert Watson /* 1263eb725b4eSRobert Watson * Test the active securelevel against a given level. securelevel_gt() 1264eb725b4eSRobert Watson * implements (securelevel > level). securelevel_ge() implements 1265eb725b4eSRobert Watson * (securelevel >= level). Note that the logic is inverted -- these 1266eb725b4eSRobert Watson * functions return EPERM on "success" and 0 on "failure". 12673ca719f1SRobert Watson * 12683ca719f1SRobert Watson * cr is permitted to be NULL for the time being, as there were some 12693ca719f1SRobert Watson * existing securelevel checks that occurred without a process/credential 1270eb725b4eSRobert Watson * context. In the future this will be disallowed, so a kernel message 1271eb725b4eSRobert Watson * is displayed. 12723ca719f1SRobert Watson */ 12733ca719f1SRobert Watson int 12743ca719f1SRobert Watson securelevel_gt(struct ucred *cr, int level) 12753ca719f1SRobert Watson { 1276eb725b4eSRobert Watson int active_securelevel; 12773ca719f1SRobert Watson 1278eb725b4eSRobert Watson active_securelevel = securelevel; 1279eb725b4eSRobert Watson if (cr == NULL) 12803ca719f1SRobert Watson printf("securelevel_gt: cr is NULL\n"); 128101137630SRobert Watson if (cr->cr_prison != NULL) { 128201137630SRobert Watson mtx_lock(&cr->cr_prison->pr_mtx); 1283eb725b4eSRobert Watson active_securelevel = imax(cr->cr_prison->pr_securelevel, 1284eb725b4eSRobert Watson active_securelevel); 128501137630SRobert Watson mtx_unlock(&cr->cr_prison->pr_mtx); 128601137630SRobert Watson } 1287eb725b4eSRobert Watson return (active_securelevel > level ? EPERM : 0); 12883ca719f1SRobert Watson } 12893ca719f1SRobert Watson 12903ca719f1SRobert Watson int 12913ca719f1SRobert Watson securelevel_ge(struct ucred *cr, int level) 12923ca719f1SRobert Watson { 1293eb725b4eSRobert Watson int active_securelevel; 12943ca719f1SRobert Watson 1295eb725b4eSRobert Watson active_securelevel = securelevel; 1296eb725b4eSRobert Watson if (cr == NULL) 1297eb725b4eSRobert Watson printf("securelevel_gt: cr is NULL\n"); 129801137630SRobert Watson if (cr->cr_prison != NULL) { 129901137630SRobert Watson mtx_lock(&cr->cr_prison->pr_mtx); 1300eb725b4eSRobert Watson active_securelevel = imax(cr->cr_prison->pr_securelevel, 1301eb725b4eSRobert Watson active_securelevel); 130201137630SRobert Watson mtx_unlock(&cr->cr_prison->pr_mtx); 130301137630SRobert Watson } 1304eb725b4eSRobert Watson return (active_securelevel >= level ? EPERM : 0); 13053ca719f1SRobert Watson } 13063ca719f1SRobert Watson 13078a7d8cc6SRobert Watson /* 1308e409590dSRobert Watson * 'see_other_uids' determines whether or not visibility of processes 1309eb725b4eSRobert Watson * and sockets with credentials holding different real uids is possible 131048713bdcSRobert Watson * using a variety of system MIBs. 1311eb725b4eSRobert Watson * XXX: data declarations should be together near the beginning of the file. 13128a7d8cc6SRobert Watson */ 1313e409590dSRobert Watson static int see_other_uids = 1; 1314d0615c64SAndrew R. Reiter SYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW, 1315eb725b4eSRobert Watson &see_other_uids, 0, 13168a7d8cc6SRobert Watson "Unprivileged processes may see subjects/objects with different real uid"); 13178a7d8cc6SRobert Watson 13187fd6a959SRobert Watson /*- 13197fd6a959SRobert Watson * Determine if u1 "can see" the subject specified by u2. 1320ed639720SRobert Watson * Returns: 0 for permitted, an errno value otherwise 1321ed639720SRobert Watson * Locks: none 1322eb725b4eSRobert Watson * References: *u1 and *u2 must not change during the call 1323ed639720SRobert Watson * u1 may equal u2, in which case only one reference is required 1324ed639720SRobert Watson */ 1325ed639720SRobert Watson int 132694088977SRobert Watson cr_cansee(struct ucred *u1, struct ucred *u2) 1327a9e0361bSPoul-Henning Kamp { 132891421ba2SRobert Watson int error; 1329a9e0361bSPoul-Henning Kamp 1330ed639720SRobert Watson if ((error = prison_check(u1, u2))) 133191421ba2SRobert Watson return (error); 1332e409590dSRobert Watson if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) { 1333f8e6ab29SRobert Watson if (suser_xxx(u1, NULL, PRISON_ROOT) != 0) 1334387d2c03SRobert Watson return (ESRCH); 1335c52396e3SRobert Watson } 1336387d2c03SRobert Watson return (0); 1337387d2c03SRobert Watson } 1338387d2c03SRobert Watson 13397fd6a959SRobert Watson /*- 13407fd6a959SRobert Watson * Determine if p1 "can see" the subject specified by p2. 13413b243b72SRobert Watson * Returns: 0 for permitted, an errno value otherwise 13427fd6a959SRobert Watson * Locks: Sufficient locks to protect p1->p_ucred and p2->p_ucred must 13433b243b72SRobert Watson * be held. Normally, p1 will be curproc, and a lock must be held 13443b243b72SRobert Watson * for p2. 13453b243b72SRobert Watson * References: p1 and p2 must be valid for the lifetime of the call 13463b243b72SRobert Watson */ 1347a0f75161SRobert Watson int 1348a0f75161SRobert Watson p_cansee(struct proc *p1, struct proc *p2) 1349ed639720SRobert Watson { 1350ed639720SRobert Watson 135194088977SRobert Watson /* Wrap cr_cansee() for all functionality. */ 135294088977SRobert Watson return (cr_cansee(p1->p_ucred, p2->p_ucred)); 1353ed639720SRobert Watson } 1354ed639720SRobert Watson 13557fd6a959SRobert Watson /*- 1356c83f8015SRobert Watson * Determine whether cred may deliver the specified signal to proc. 1357c83f8015SRobert Watson * Returns: 0 for permitted, an errno value otherwise. 1358c83f8015SRobert Watson * Locks: A lock must be held for proc. 1359c83f8015SRobert Watson * References: cred and proc must be valid for the lifetime of the call. 13604c5eb9c3SRobert Watson */ 13614c5eb9c3SRobert Watson int 1362c83f8015SRobert Watson cr_cansignal(struct ucred *cred, struct proc *proc, int signum) 1363387d2c03SRobert Watson { 136491421ba2SRobert Watson int error; 1365387d2c03SRobert Watson 13664c5eb9c3SRobert Watson /* 1367c83f8015SRobert Watson * Jail semantics limit the scope of signalling to proc in the 1368c83f8015SRobert Watson * same jail as cred, if cred is in jail. 13694c5eb9c3SRobert Watson */ 1370c83f8015SRobert Watson error = prison_check(cred, proc->p_ucred); 1371c83f8015SRobert Watson if (error) 137291421ba2SRobert Watson return (error); 1373387d2c03SRobert Watson 1374387d2c03SRobert Watson /* 13753b243b72SRobert Watson * UNIX signal semantics depend on the status of the P_SUGID 13763b243b72SRobert Watson * bit on the target process. If the bit is set, then additional 13773b243b72SRobert Watson * restrictions are placed on the set of available signals. 13784c5eb9c3SRobert Watson */ 1379c83f8015SRobert Watson if (proc->p_flag & P_SUGID) { 13804c5eb9c3SRobert Watson switch (signum) { 13814c5eb9c3SRobert Watson case 0: 13824c5eb9c3SRobert Watson case SIGKILL: 13834c5eb9c3SRobert Watson case SIGINT: 13844c5eb9c3SRobert Watson case SIGTERM: 13854c5eb9c3SRobert Watson case SIGSTOP: 13864c5eb9c3SRobert Watson case SIGTTIN: 13874c5eb9c3SRobert Watson case SIGTTOU: 13884c5eb9c3SRobert Watson case SIGTSTP: 13894c5eb9c3SRobert Watson case SIGHUP: 13904c5eb9c3SRobert Watson case SIGUSR1: 13914c5eb9c3SRobert Watson case SIGUSR2: 13927fd6a959SRobert Watson /* 13937fd6a959SRobert Watson * Generally, permit job and terminal control 13947fd6a959SRobert Watson * signals. 13957fd6a959SRobert Watson */ 13964c5eb9c3SRobert Watson break; 13974c5eb9c3SRobert Watson default: 1398c83f8015SRobert Watson /* Not permitted without privilege. */ 1399c83f8015SRobert Watson error = suser_xxx(cred, NULL, PRISON_ROOT); 14004c5eb9c3SRobert Watson if (error) 14014c5eb9c3SRobert Watson return (error); 14024c5eb9c3SRobert Watson } 1403e9e7ff5bSRobert Watson } 1404e9e7ff5bSRobert Watson 14054c5eb9c3SRobert Watson /* 14063b243b72SRobert Watson * Generally, the target credential's ruid or svuid must match the 1407e9e7ff5bSRobert Watson * subject credential's ruid or euid. 14084c5eb9c3SRobert Watson */ 1409c83f8015SRobert Watson if (cred->cr_ruid != proc->p_ucred->cr_ruid && 1410c83f8015SRobert Watson cred->cr_ruid != proc->p_ucred->cr_svuid && 1411c83f8015SRobert Watson cred->cr_uid != proc->p_ucred->cr_ruid && 1412c83f8015SRobert Watson cred->cr_uid != proc->p_ucred->cr_svuid) { 1413c83f8015SRobert Watson /* Not permitted without privilege. */ 1414c83f8015SRobert Watson error = suser_xxx(cred, NULL, PRISON_ROOT); 14154c5eb9c3SRobert Watson if (error) 14164c5eb9c3SRobert Watson return (error); 14174c5eb9c3SRobert Watson } 1418387d2c03SRobert Watson 1419387d2c03SRobert Watson return (0); 1420387d2c03SRobert Watson } 1421a9e0361bSPoul-Henning Kamp 1422c83f8015SRobert Watson 1423c83f8015SRobert Watson /*- 1424c83f8015SRobert Watson * Determine whether p1 may deliver the specified signal to p2. 1425c83f8015SRobert Watson * Returns: 0 for permitted, an errno value otherwise 1426c83f8015SRobert Watson * Locks: Sufficient locks to protect various components of p1 and p2 1427c83f8015SRobert Watson * must be held. Normally, p1 will be curproc, and a lock must 1428c83f8015SRobert Watson * be held for p2. 1429c83f8015SRobert Watson * References: p1 and p2 must be valid for the lifetime of the call 1430c83f8015SRobert Watson */ 1431c83f8015SRobert Watson int 1432c83f8015SRobert Watson p_cansignal(struct proc *p1, struct proc *p2, int signum) 1433c83f8015SRobert Watson { 1434c83f8015SRobert Watson 1435c83f8015SRobert Watson if (p1 == p2) 1436c83f8015SRobert Watson return (0); 1437c83f8015SRobert Watson 1438c83f8015SRobert Watson /* 1439c83f8015SRobert Watson * UNIX signalling semantics require that processes in the same 1440c83f8015SRobert Watson * session always be able to deliver SIGCONT to one another, 1441c83f8015SRobert Watson * overriding the remaining protections. 1442c83f8015SRobert Watson */ 1443c83f8015SRobert Watson if (signum == SIGCONT && p1->p_session == p2->p_session) 1444c83f8015SRobert Watson return (0); 1445c83f8015SRobert Watson 1446c83f8015SRobert Watson return (cr_cansignal(p1->p_ucred, p2, signum)); 1447c83f8015SRobert Watson } 1448c83f8015SRobert Watson 14497fd6a959SRobert Watson /*- 1450eb725b4eSRobert Watson * Determine whether p1 may reschedule p2. 14517fd6a959SRobert Watson * Returns: 0 for permitted, an errno value otherwise 14523b243b72SRobert Watson * Locks: Sufficient locks to protect various components of p1 and p2 14533b243b72SRobert Watson * must be held. Normally, p1 will be curproc, and a lock must 14547fd6a959SRobert Watson * be held for p2. 14553b243b72SRobert Watson * References: p1 and p2 must be valid for the lifetime of the call 14563b243b72SRobert Watson */ 1457a0f75161SRobert Watson int 1458a0f75161SRobert Watson p_cansched(struct proc *p1, struct proc *p2) 1459387d2c03SRobert Watson { 146091421ba2SRobert Watson int error; 1461387d2c03SRobert Watson 1462387d2c03SRobert Watson if (p1 == p2) 1463387d2c03SRobert Watson return (0); 146491421ba2SRobert Watson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 146591421ba2SRobert Watson return (error); 1466b1fc0ec1SRobert Watson if (p1->p_ucred->cr_ruid == p2->p_ucred->cr_ruid) 1467387d2c03SRobert Watson return (0); 1468b1fc0ec1SRobert Watson if (p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid) 1469387d2c03SRobert Watson return (0); 14707fd6a959SRobert Watson if (suser_xxx(0, p1, PRISON_ROOT) == 0) 1471387d2c03SRobert Watson return (0); 1472387d2c03SRobert Watson 1473387d2c03SRobert Watson #ifdef CAPABILITIES 14744df571b1SRobert Watson if (!cap_check(NULL, p1, CAP_SYS_NICE, PRISON_ROOT)) 1475387d2c03SRobert Watson return (0); 1476387d2c03SRobert Watson #endif 1477387d2c03SRobert Watson 1478387d2c03SRobert Watson return (EPERM); 1479387d2c03SRobert Watson } 1480387d2c03SRobert Watson 14813b243b72SRobert Watson /* 14825d476e73SRobert Watson * The 'unprivileged_proc_debug' flag may be used to disable a variety of 14835d476e73SRobert Watson * unprivileged inter-process debugging services, including some procfs 14845d476e73SRobert Watson * functionality, ptrace(), and ktrace(). In the past, inter-process 14855d476e73SRobert Watson * debugging has been involved in a variety of security problems, and sites 14865d476e73SRobert Watson * not requiring the service might choose to disable it when hardening 14875d476e73SRobert Watson * systems. 14883b243b72SRobert Watson * 14893b243b72SRobert Watson * XXX: Should modifying and reading this variable require locking? 1490eb725b4eSRobert Watson * XXX: data declarations should be together near the beginning of the file. 14913b243b72SRobert Watson */ 1492e409590dSRobert Watson static int unprivileged_proc_debug = 1; 1493d0615c64SAndrew R. Reiter SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW, 1494eb725b4eSRobert Watson &unprivileged_proc_debug, 0, 14950ef5652eSRobert Watson "Unprivileged processes may use process debugging facilities"); 14960ef5652eSRobert Watson 14977fd6a959SRobert Watson /*- 14987fd6a959SRobert Watson * Determine whether p1 may debug p2. 14997fd6a959SRobert Watson * Returns: 0 for permitted, an errno value otherwise 15007fd6a959SRobert Watson * Locks: Sufficient locks to protect various components of p1 and p2 15017fd6a959SRobert Watson * must be held. Normally, p1 will be curproc, and a lock must 15027fd6a959SRobert Watson * be held for p2. 15033b243b72SRobert Watson * References: p1 and p2 must be valid for the lifetime of the call 15043b243b72SRobert Watson */ 1505a0f75161SRobert Watson int 1506a0f75161SRobert Watson p_candebug(struct proc *p1, struct proc *p2) 1507387d2c03SRobert Watson { 1508eb725b4eSRobert Watson int credentialchanged, error, grpsubset, i, uidsubset; 1509387d2c03SRobert Watson 1510e409590dSRobert Watson if (!unprivileged_proc_debug) { 151132d18604SRobert Watson error = suser_xxx(NULL, p1, PRISON_ROOT); 151232d18604SRobert Watson if (error) 151332d18604SRobert Watson return (error); 151432d18604SRobert Watson } 151523fad5b6SDag-Erling Smørgrav if (p1 == p2) 151623fad5b6SDag-Erling Smørgrav return (0); 151791421ba2SRobert Watson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 151891421ba2SRobert Watson return (error); 1519387d2c03SRobert Watson 15207fd6a959SRobert Watson /* 1521db42a33dSRobert Watson * Is p2's group set a subset of p1's effective group set? This 1522db42a33dSRobert Watson * includes p2's egid, group access list, rgid, and svgid. 15237fd6a959SRobert Watson */ 1524db42a33dSRobert Watson grpsubset = 1; 1525db42a33dSRobert Watson for (i = 0; i < p2->p_ucred->cr_ngroups; i++) { 1526db42a33dSRobert Watson if (!groupmember(p2->p_ucred->cr_groups[i], p1->p_ucred)) { 1527db42a33dSRobert Watson grpsubset = 0; 1528db42a33dSRobert Watson break; 1529db42a33dSRobert Watson } 1530db42a33dSRobert Watson } 1531db42a33dSRobert Watson grpsubset = grpsubset && 1532db42a33dSRobert Watson groupmember(p2->p_ucred->cr_rgid, p1->p_ucred) && 1533db42a33dSRobert Watson groupmember(p2->p_ucred->cr_svgid, p1->p_ucred); 1534db42a33dSRobert Watson 1535db42a33dSRobert Watson /* 1536db42a33dSRobert Watson * Are the uids present in p2's credential equal to p1's 1537db42a33dSRobert Watson * effective uid? This includes p2's euid, svuid, and ruid. 1538db42a33dSRobert Watson */ 1539db42a33dSRobert Watson uidsubset = (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid && 1540db42a33dSRobert Watson p1->p_ucred->cr_uid == p2->p_ucred->cr_svuid && 1541db42a33dSRobert Watson p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid); 1542db42a33dSRobert Watson 1543db42a33dSRobert Watson /* 1544db42a33dSRobert Watson * Has the credential of the process changed since the last exec()? 1545db42a33dSRobert Watson */ 1546db42a33dSRobert Watson credentialchanged = (p2->p_flag & P_SUGID); 1547db42a33dSRobert Watson 1548db42a33dSRobert Watson /* 1549db42a33dSRobert Watson * If p2's gids aren't a subset, or the uids aren't a subset, 1550db42a33dSRobert Watson * or the credential has changed, require appropriate privilege 1551db42a33dSRobert Watson * for p1 to debug p2. For POSIX.1e capabilities, this will 1552db42a33dSRobert Watson * require CAP_SYS_PTRACE. 1553db42a33dSRobert Watson */ 1554db42a33dSRobert Watson if (!grpsubset || !uidsubset || credentialchanged) { 155532d18604SRobert Watson error = suser_xxx(NULL, p1, PRISON_ROOT); 155632d18604SRobert Watson if (error) 1557387d2c03SRobert Watson return (error); 15587fd6a959SRobert Watson } 1559387d2c03SRobert Watson 1560eb725b4eSRobert Watson /* Can't trace init when securelevel > 0. */ 1561eb725b4eSRobert Watson if (p2 == initproc) { 15623ca719f1SRobert Watson error = securelevel_gt(p1->p_ucred, 0); 15633ca719f1SRobert Watson if (error) 15643ca719f1SRobert Watson return (error); 15653ca719f1SRobert Watson } 1566387d2c03SRobert Watson 15675fab7614SRobert Watson /* 15685fab7614SRobert Watson * Can't trace a process that's currently exec'ing. 15695fab7614SRobert Watson * XXX: Note, this is not a security policy decision, it's a 15705fab7614SRobert Watson * basic correctness/functionality decision. Therefore, this check 15715fab7614SRobert Watson * should be moved to the caller's of p_candebug(). 15725fab7614SRobert Watson */ 15739ca45e81SDag-Erling Smørgrav if ((p2->p_flag & P_INEXEC) != 0) 15749ca45e81SDag-Erling Smørgrav return (EAGAIN); 15759ca45e81SDag-Erling Smørgrav 1576387d2c03SRobert Watson return (0); 1577387d2c03SRobert Watson } 1578387d2c03SRobert Watson 1579a9e0361bSPoul-Henning Kamp /* 1580df8bae1dSRodney W. Grimes * Allocate a zeroed cred structure. 1581df8bae1dSRodney W. Grimes */ 1582df8bae1dSRodney W. Grimes struct ucred * 1583df8bae1dSRodney W. Grimes crget() 1584df8bae1dSRodney W. Grimes { 1585df8bae1dSRodney W. Grimes register struct ucred *cr; 1586df8bae1dSRodney W. Grimes 15871e5d626aSAlfred Perlstein MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK | M_ZERO); 1588df8bae1dSRodney W. Grimes cr->cr_ref = 1; 1589e1bca29fSMatthew Dillon cr->cr_mtxp = mtx_pool_find(cr); 1590df8bae1dSRodney W. Grimes return (cr); 1591df8bae1dSRodney W. Grimes } 1592df8bae1dSRodney W. Grimes 1593df8bae1dSRodney W. Grimes /* 15947fd6a959SRobert Watson * Claim another reference to a ucred structure. 15955c3f70d7SAlfred Perlstein */ 1596bd78ceceSJohn Baldwin struct ucred * 15975c3f70d7SAlfred Perlstein crhold(cr) 15985c3f70d7SAlfred Perlstein struct ucred *cr; 15995c3f70d7SAlfred Perlstein { 16005c3f70d7SAlfred Perlstein 1601e1bca29fSMatthew Dillon mtx_lock(cr->cr_mtxp); 16025c3f70d7SAlfred Perlstein cr->cr_ref++; 1603e1bca29fSMatthew Dillon mtx_unlock(cr->cr_mtxp); 1604bd78ceceSJohn Baldwin return (cr); 16055c3f70d7SAlfred Perlstein } 16065c3f70d7SAlfred Perlstein 16075c3f70d7SAlfred Perlstein /* 1608df8bae1dSRodney W. Grimes * Free a cred structure. 1609df8bae1dSRodney W. Grimes * Throws away space when ref count gets to 0. 1610df8bae1dSRodney W. Grimes */ 161126f9a767SRodney W. Grimes void 1612df8bae1dSRodney W. Grimes crfree(cr) 1613df8bae1dSRodney W. Grimes struct ucred *cr; 1614df8bae1dSRodney W. Grimes { 1615e1bca29fSMatthew Dillon struct mtx *mtxp = cr->cr_mtxp; 16161e5d626aSAlfred Perlstein 1617e1bca29fSMatthew Dillon mtx_lock(mtxp); 1618e04670b7SAlfred Perlstein KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref)); 1619f535380cSDon Lewis if (--cr->cr_ref == 0) { 1620f535380cSDon Lewis /* 1621f535380cSDon Lewis * Some callers of crget(), such as nfs_statfs(), 1622f535380cSDon Lewis * allocate a temporary credential, but don't 1623f535380cSDon Lewis * allocate a uidinfo structure. 1624f535380cSDon Lewis */ 1625e1bca29fSMatthew Dillon mtx_unlock(mtxp); 1626f535380cSDon Lewis if (cr->cr_uidinfo != NULL) 1627f535380cSDon Lewis uifree(cr->cr_uidinfo); 1628823c224eSRobert Watson if (cr->cr_ruidinfo != NULL) 1629823c224eSRobert Watson uifree(cr->cr_ruidinfo); 163091421ba2SRobert Watson /* 163191421ba2SRobert Watson * Free a prison, if any. 163291421ba2SRobert Watson */ 163391421ba2SRobert Watson if (jailed(cr)) 163491421ba2SRobert Watson prison_free(cr->cr_prison); 1635df8bae1dSRodney W. Grimes FREE((caddr_t)cr, M_CRED); 1636e1bca29fSMatthew Dillon } else { 1637e1bca29fSMatthew Dillon mtx_unlock(mtxp); 1638e1bca29fSMatthew Dillon } 1639df8bae1dSRodney W. Grimes } 1640df8bae1dSRodney W. Grimes 1641df8bae1dSRodney W. Grimes /* 1642bd78ceceSJohn Baldwin * Check to see if this ucred is shared. 1643df8bae1dSRodney W. Grimes */ 1644bd78ceceSJohn Baldwin int 1645bd78ceceSJohn Baldwin crshared(cr) 1646df8bae1dSRodney W. Grimes struct ucred *cr; 1647df8bae1dSRodney W. Grimes { 1648bd78ceceSJohn Baldwin int shared; 1649df8bae1dSRodney W. Grimes 1650e1bca29fSMatthew Dillon mtx_lock(cr->cr_mtxp); 1651bd78ceceSJohn Baldwin shared = (cr->cr_ref > 1); 1652e1bca29fSMatthew Dillon mtx_unlock(cr->cr_mtxp); 1653bd78ceceSJohn Baldwin return (shared); 16541e5d626aSAlfred Perlstein } 1655bd78ceceSJohn Baldwin 1656bd78ceceSJohn Baldwin /* 1657bd78ceceSJohn Baldwin * Copy a ucred's contents from a template. Does not block. 1658bd78ceceSJohn Baldwin */ 1659bd78ceceSJohn Baldwin void 1660bd78ceceSJohn Baldwin crcopy(dest, src) 1661bd78ceceSJohn Baldwin struct ucred *dest, *src; 1662bd78ceceSJohn Baldwin { 1663bd78ceceSJohn Baldwin 1664bd78ceceSJohn Baldwin KASSERT(crshared(dest) == 0, ("crcopy of shared ucred")); 1665bd78ceceSJohn Baldwin bcopy(&src->cr_startcopy, &dest->cr_startcopy, 1666bd78ceceSJohn Baldwin (unsigned)((caddr_t)&src->cr_endcopy - 1667bd78ceceSJohn Baldwin (caddr_t)&src->cr_startcopy)); 1668bd78ceceSJohn Baldwin uihold(dest->cr_uidinfo); 1669bd78ceceSJohn Baldwin uihold(dest->cr_ruidinfo); 1670bd78ceceSJohn Baldwin if (jailed(dest)) 1671bd78ceceSJohn Baldwin prison_hold(dest->cr_prison); 1672df8bae1dSRodney W. Grimes } 1673df8bae1dSRodney W. Grimes 1674df8bae1dSRodney W. Grimes /* 1675df8bae1dSRodney W. Grimes * Dup cred struct to a new held one. 1676df8bae1dSRodney W. Grimes */ 1677df8bae1dSRodney W. Grimes struct ucred * 1678df8bae1dSRodney W. Grimes crdup(cr) 1679df8bae1dSRodney W. Grimes struct ucred *cr; 1680df8bae1dSRodney W. Grimes { 1681df8bae1dSRodney W. Grimes struct ucred *newcr; 1682df8bae1dSRodney W. Grimes 1683bd78ceceSJohn Baldwin newcr = crget(); 1684bd78ceceSJohn Baldwin crcopy(newcr, cr); 1685df8bae1dSRodney W. Grimes return (newcr); 1686df8bae1dSRodney W. Grimes } 1687df8bae1dSRodney W. Grimes 1688df8bae1dSRodney W. Grimes /* 16892eb927e2SJulian Elischer * small routine to swap a thread's current ucred for the correct one 16902eb927e2SJulian Elischer * taken from the process. 16912eb927e2SJulian Elischer */ 16922eb927e2SJulian Elischer void 16932eb927e2SJulian Elischer cred_update_thread(struct thread *td) 16942eb927e2SJulian Elischer { 16952eb927e2SJulian Elischer struct proc *p; 16962eb927e2SJulian Elischer 16972eb927e2SJulian Elischer p = td->td_proc; 16982eb927e2SJulian Elischer if (td->td_ucred != NULL) { 16992eb927e2SJulian Elischer mtx_lock(&Giant); 17002eb927e2SJulian Elischer crfree(td->td_ucred); 17012eb927e2SJulian Elischer mtx_unlock(&Giant); 17022eb927e2SJulian Elischer td->td_ucred = NULL; 17032eb927e2SJulian Elischer } 17042eb927e2SJulian Elischer PROC_LOCK(p); 17052eb927e2SJulian Elischer td->td_ucred = crhold(p->p_ucred); 17062eb927e2SJulian Elischer PROC_UNLOCK(p); 17072eb927e2SJulian Elischer } 17082eb927e2SJulian Elischer 17092eb927e2SJulian Elischer /* 1710df8bae1dSRodney W. Grimes * Get login name, if available. 1711df8bae1dSRodney W. Grimes */ 1712d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1713df8bae1dSRodney W. Grimes struct getlogin_args { 1714df8bae1dSRodney W. Grimes char *namebuf; 1715df8bae1dSRodney W. Grimes u_int namelen; 1716df8bae1dSRodney W. Grimes }; 1717d2d3e875SBruce Evans #endif 1718835a82eeSMatthew Dillon /* 1719835a82eeSMatthew Dillon * MPSAFE 1720835a82eeSMatthew Dillon */ 1721df8bae1dSRodney W. Grimes /* ARGSUSED */ 172226f9a767SRodney W. Grimes int 1723b40ce416SJulian Elischer getlogin(td, uap) 1724b40ce416SJulian Elischer struct thread *td; 1725df8bae1dSRodney W. Grimes struct getlogin_args *uap; 1726df8bae1dSRodney W. Grimes { 1727835a82eeSMatthew Dillon int error; 1728b40ce416SJulian Elischer struct proc *p = td->td_proc; 1729df8bae1dSRodney W. Grimes 1730835a82eeSMatthew Dillon mtx_lock(&Giant); 173130cf3ac4SAndrey A. Chernov if (uap->namelen > MAXLOGNAME) 173253490b76SAndrey A. Chernov uap->namelen = MAXLOGNAME; 1733835a82eeSMatthew Dillon error = copyout((caddr_t) p->p_pgrp->pg_session->s_login, 1734835a82eeSMatthew Dillon (caddr_t) uap->namebuf, uap->namelen); 1735835a82eeSMatthew Dillon mtx_unlock(&Giant); 1736835a82eeSMatthew Dillon return(error); 1737df8bae1dSRodney W. Grimes } 1738df8bae1dSRodney W. Grimes 1739df8bae1dSRodney W. Grimes /* 1740df8bae1dSRodney W. Grimes * Set login name. 1741df8bae1dSRodney W. Grimes */ 1742d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1743df8bae1dSRodney W. Grimes struct setlogin_args { 1744df8bae1dSRodney W. Grimes char *namebuf; 1745df8bae1dSRodney W. Grimes }; 1746d2d3e875SBruce Evans #endif 1747835a82eeSMatthew Dillon /* 1748835a82eeSMatthew Dillon * MPSAFE 1749835a82eeSMatthew Dillon */ 1750df8bae1dSRodney W. Grimes /* ARGSUSED */ 175126f9a767SRodney W. Grimes int 1752b40ce416SJulian Elischer setlogin(td, uap) 1753b40ce416SJulian Elischer struct thread *td; 1754df8bae1dSRodney W. Grimes struct setlogin_args *uap; 1755df8bae1dSRodney W. Grimes { 1756b40ce416SJulian Elischer struct proc *p = td->td_proc; 1757df8bae1dSRodney W. Grimes int error; 1758964ca0caSAndrey A. Chernov char logintmp[MAXLOGNAME]; 1759df8bae1dSRodney W. Grimes 1760835a82eeSMatthew Dillon mtx_lock(&Giant); 1761eb725b4eSRobert Watson if ((error = suser_xxx(0, p, PRISON_ROOT)) != 0) 1762835a82eeSMatthew Dillon goto done2; 1763184989c2SDavid Nugent error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 176410d4743fSDoug Rabson sizeof(logintmp), (size_t *)0); 1765eb725b4eSRobert Watson if (error == ENAMETOOLONG) 1766df8bae1dSRodney W. Grimes error = EINVAL; 1767eb725b4eSRobert Watson else if (!error) 1768184989c2SDavid Nugent (void)memcpy(p->p_pgrp->pg_session->s_login, logintmp, 1769964ca0caSAndrey A. Chernov sizeof(logintmp)); 1770835a82eeSMatthew Dillon done2: 1771835a82eeSMatthew Dillon mtx_unlock(&Giant); 1772df8bae1dSRodney W. Grimes return (error); 1773df8bae1dSRodney W. Grimes } 1774d5f81602SSean Eric Fagan 1775d5f81602SSean Eric Fagan void 1776d5f81602SSean Eric Fagan setsugid(p) 1777d5f81602SSean Eric Fagan struct proc *p; 1778d5f81602SSean Eric Fagan { 1779d5f81602SSean Eric Fagan p->p_flag |= P_SUGID; 178089361835SSean Eric Fagan if (!(p->p_pfsflags & PF_ISUGID)) 1781d5f81602SSean Eric Fagan p->p_stops = 0; 1782d5f81602SSean Eric Fagan } 1783f535380cSDon Lewis 17847fd6a959SRobert Watson /*- 17857fd6a959SRobert Watson * Change a process's effective uid. 1786b1fc0ec1SRobert Watson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified. 1787b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1788b1fc0ec1SRobert Watson * duration of the call. 1789f535380cSDon Lewis */ 1790f535380cSDon Lewis void 1791b1fc0ec1SRobert Watson change_euid(newcred, euid) 1792b1fc0ec1SRobert Watson struct ucred *newcred; 1793f535380cSDon Lewis uid_t euid; 1794f535380cSDon Lewis { 1795f535380cSDon Lewis 1796b1fc0ec1SRobert Watson newcred->cr_uid = euid; 1797b1fc0ec1SRobert Watson uifree(newcred->cr_uidinfo); 1798b1fc0ec1SRobert Watson newcred->cr_uidinfo = uifind(euid); 1799f535380cSDon Lewis } 1800f535380cSDon Lewis 18017fd6a959SRobert Watson /*- 18027fd6a959SRobert Watson * Change a process's effective gid. 1803b1fc0ec1SRobert Watson * Side effects: newcred->cr_gid will be modified. 1804b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1805b1fc0ec1SRobert Watson * duration of the call. 1806f535380cSDon Lewis */ 1807810bfc8eSAndrew Gallatin void 1808b1fc0ec1SRobert Watson change_egid(newcred, egid) 1809b1fc0ec1SRobert Watson struct ucred *newcred; 1810b1fc0ec1SRobert Watson gid_t egid; 1811b1fc0ec1SRobert Watson { 1812b1fc0ec1SRobert Watson 1813b1fc0ec1SRobert Watson newcred->cr_groups[0] = egid; 1814b1fc0ec1SRobert Watson } 1815b1fc0ec1SRobert Watson 18167fd6a959SRobert Watson /*- 18177fd6a959SRobert Watson * Change a process's real uid. 1818b1fc0ec1SRobert Watson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo 1819b1fc0ec1SRobert Watson * will be updated, and the old and new cr_ruidinfo proc 1820b1fc0ec1SRobert Watson * counts will be updated. 1821b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1822b1fc0ec1SRobert Watson * duration of the call. 1823b1fc0ec1SRobert Watson */ 1824b1fc0ec1SRobert Watson void 1825b1fc0ec1SRobert Watson change_ruid(newcred, ruid) 1826b1fc0ec1SRobert Watson struct ucred *newcred; 1827f535380cSDon Lewis uid_t ruid; 1828f535380cSDon Lewis { 1829f535380cSDon Lewis 1830b1fc0ec1SRobert Watson (void)chgproccnt(newcred->cr_ruidinfo, -1, 0); 1831b1fc0ec1SRobert Watson newcred->cr_ruid = ruid; 1832b1fc0ec1SRobert Watson uifree(newcred->cr_ruidinfo); 1833b1fc0ec1SRobert Watson newcred->cr_ruidinfo = uifind(ruid); 1834b1fc0ec1SRobert Watson (void)chgproccnt(newcred->cr_ruidinfo, 1, 0); 1835b1fc0ec1SRobert Watson } 1836b1fc0ec1SRobert Watson 18377fd6a959SRobert Watson /*- 18387fd6a959SRobert Watson * Change a process's real gid. 1839b1fc0ec1SRobert Watson * Side effects: newcred->cr_rgid will be updated. 1840b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1841b1fc0ec1SRobert Watson * duration of the call. 1842b1fc0ec1SRobert Watson */ 1843b1fc0ec1SRobert Watson void 1844b1fc0ec1SRobert Watson change_rgid(newcred, rgid) 1845b1fc0ec1SRobert Watson struct ucred *newcred; 1846b1fc0ec1SRobert Watson gid_t rgid; 1847b1fc0ec1SRobert Watson { 1848b1fc0ec1SRobert Watson 1849b1fc0ec1SRobert Watson newcred->cr_rgid = rgid; 1850b1fc0ec1SRobert Watson } 1851b1fc0ec1SRobert Watson 18527fd6a959SRobert Watson /*- 18537fd6a959SRobert Watson * Change a process's saved uid. 1854b1fc0ec1SRobert Watson * Side effects: newcred->cr_svuid will be updated. 1855b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1856b1fc0ec1SRobert Watson * duration of the call. 1857b1fc0ec1SRobert Watson */ 1858b1fc0ec1SRobert Watson void 1859b1fc0ec1SRobert Watson change_svuid(newcred, svuid) 1860b1fc0ec1SRobert Watson struct ucred *newcred; 1861b1fc0ec1SRobert Watson uid_t svuid; 1862b1fc0ec1SRobert Watson { 1863b1fc0ec1SRobert Watson 1864b1fc0ec1SRobert Watson newcred->cr_svuid = svuid; 1865b1fc0ec1SRobert Watson } 1866b1fc0ec1SRobert Watson 18677fd6a959SRobert Watson /*- 18687fd6a959SRobert Watson * Change a process's saved gid. 1869b1fc0ec1SRobert Watson * Side effects: newcred->cr_svgid will be updated. 1870b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 1871b1fc0ec1SRobert Watson * duration of the call. 1872b1fc0ec1SRobert Watson */ 1873b1fc0ec1SRobert Watson void 1874b1fc0ec1SRobert Watson change_svgid(newcred, svgid) 1875b1fc0ec1SRobert Watson struct ucred *newcred; 1876b1fc0ec1SRobert Watson gid_t svgid; 1877b1fc0ec1SRobert Watson { 1878b1fc0ec1SRobert Watson 1879b1fc0ec1SRobert Watson newcred->cr_svgid = svgid; 1880f535380cSDon Lewis } 1881