19454b2d8SWarner Losh /*- 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 3ef08c420SRobert Watson * The Regents of the University of California. 4df8bae1dSRodney W. Grimes * (c) UNIX System Laboratories, Inc. 5ef08c420SRobert Watson * Copyright (c) 2000-2001 Robert N. M. Watson. 6ef08c420SRobert Watson * All rights reserved. 7ef08c420SRobert Watson * 8df8bae1dSRodney W. Grimes * All or some portions of this file are derived from material licensed 9df8bae1dSRodney W. Grimes * to the University of California by American Telephone and Telegraph 10df8bae1dSRodney W. Grimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 11df8bae1dSRodney W. Grimes * the permission of UNIX System Laboratories, Inc. 12df8bae1dSRodney W. Grimes * 13df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 14df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 15df8bae1dSRodney W. Grimes * are met: 16df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 17df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 18df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 19df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 20df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 21df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 22df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 23df8bae1dSRodney W. Grimes * without specific prior written permission. 24df8bae1dSRodney W. Grimes * 25df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35df8bae1dSRodney W. Grimes * SUCH DAMAGE. 36df8bae1dSRodney W. Grimes * 37df8bae1dSRodney W. Grimes * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 38df8bae1dSRodney W. Grimes */ 39df8bae1dSRodney W. Grimes 40df8bae1dSRodney W. Grimes /* 41df8bae1dSRodney W. Grimes * System calls related to processes and protection 42df8bae1dSRodney W. Grimes */ 43df8bae1dSRodney W. Grimes 44677b542eSDavid E. O'Brien #include <sys/cdefs.h> 45677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 46677b542eSDavid E. O'Brien 475591b823SEivind Eklund #include "opt_compat.h" 48f08ef6c5SBjoern A. Zeeb #include "opt_inet.h" 49f08ef6c5SBjoern A. Zeeb #include "opt_inet6.h" 505591b823SEivind Eklund 51df8bae1dSRodney W. Grimes #include <sys/param.h> 52df8bae1dSRodney W. Grimes #include <sys/systm.h> 53fb919e4dSMark Murray #include <sys/acct.h> 54df04411aSRobert Watson #include <sys/kdb.h> 551c5bb3eaSPeter Wemm #include <sys/kernel.h> 5698f03f90SJake Burkholder #include <sys/lock.h> 572bfc50bcSEdward Tomasz Napierala #include <sys/loginclass.h> 58f9d0d524SRobert Watson #include <sys/malloc.h> 59fb919e4dSMark Murray #include <sys/mutex.h> 607e9e371fSJohn Baldwin #include <sys/refcount.h> 615b29d6e9SJohn Baldwin #include <sys/sx.h> 62800c9408SRobert Watson #include <sys/priv.h> 63f591779bSSeigo Tanimura #include <sys/proc.h> 64fb919e4dSMark Murray #include <sys/sysproto.h> 65eb725b4eSRobert Watson #include <sys/jail.h> 66d5f81602SSean Eric Fagan #include <sys/pioctl.h> 67e4dcb704SEdward Tomasz Napierala #include <sys/racct.h> 68f535380cSDon Lewis #include <sys/resourcevar.h> 6929dc1288SRobert Watson #include <sys/socket.h> 7029dc1288SRobert Watson #include <sys/socketvar.h> 713cb83e71SJohn Baldwin #include <sys/syscallsubr.h> 72579f4eb4SRobert Watson #include <sys/sysctl.h> 73df8bae1dSRodney W. Grimes 74de5b1952SAlexander Leidinger #ifdef REGRESSION 75de5b1952SAlexander Leidinger FEATURE(regression, 76de5b1952SAlexander Leidinger "Kernel support for interfaces nessesary for regression testing (SECURITY RISK!)"); 77de5b1952SAlexander Leidinger #endif 78de5b1952SAlexander Leidinger 79f08ef6c5SBjoern A. Zeeb #if defined(INET) || defined(INET6) 80f08ef6c5SBjoern A. Zeeb #include <netinet/in.h> 81f08ef6c5SBjoern A. Zeeb #include <netinet/in_pcb.h> 82f08ef6c5SBjoern A. Zeeb #endif 83f08ef6c5SBjoern A. Zeeb 842f8a46d5SWayne Salamon #include <security/audit/audit.h> 85aed55708SRobert Watson #include <security/mac/mac_framework.h> 862f8a46d5SWayne Salamon 87a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_CRED, "cred", "credentials"); 88a1c995b6SPoul-Henning Kamp 895702e096SRobert Watson SYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0, "BSD security policy"); 9048713bdcSRobert Watson 91838d9858SBrooks Davis static void crextend(struct ucred *cr, int n); 92838d9858SBrooks Davis static void crsetgroups_locked(struct ucred *cr, int ngrp, 93838d9858SBrooks Davis gid_t *groups); 94838d9858SBrooks Davis 95d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 96ad7507e2SSteven Wallace struct getpid_args { 97df8bae1dSRodney W. Grimes int dummy; 98df8bae1dSRodney W. Grimes }; 99d2d3e875SBruce Evans #endif 100df8bae1dSRodney W. Grimes /* ARGSUSED */ 10126f9a767SRodney W. Grimes int 102*8451d0ddSKip Macy sys_getpid(struct thread *td, struct getpid_args *uap) 103df8bae1dSRodney W. Grimes { 104b40ce416SJulian Elischer struct proc *p = td->td_proc; 105df8bae1dSRodney W. Grimes 106b40ce416SJulian Elischer td->td_retval[0] = p->p_pid; 1071930e303SPoul-Henning Kamp #if defined(COMPAT_43) 108bae3a80bSJohn Baldwin PROC_LOCK(p); 109b40ce416SJulian Elischer td->td_retval[1] = p->p_pptr->p_pid; 110bae3a80bSJohn Baldwin PROC_UNLOCK(p); 111df8bae1dSRodney W. Grimes #endif 112df8bae1dSRodney W. Grimes return (0); 113df8bae1dSRodney W. Grimes } 114df8bae1dSRodney W. Grimes 115d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 116ad7507e2SSteven Wallace struct getppid_args { 117ad7507e2SSteven Wallace int dummy; 118ad7507e2SSteven Wallace }; 119d2d3e875SBruce Evans #endif 120df8bae1dSRodney W. Grimes /* ARGSUSED */ 12126f9a767SRodney W. Grimes int 122*8451d0ddSKip Macy sys_getppid(struct thread *td, struct getppid_args *uap) 123df8bae1dSRodney W. Grimes { 124b40ce416SJulian Elischer struct proc *p = td->td_proc; 125df8bae1dSRodney W. Grimes 126bae3a80bSJohn Baldwin PROC_LOCK(p); 127b40ce416SJulian Elischer td->td_retval[0] = p->p_pptr->p_pid; 128bae3a80bSJohn Baldwin PROC_UNLOCK(p); 129df8bae1dSRodney W. Grimes return (0); 130df8bae1dSRodney W. Grimes } 131df8bae1dSRodney W. Grimes 13236e9f877SMatthew Dillon /* 133eb725b4eSRobert Watson * Get process group ID; note that POSIX getpgrp takes no parameter. 13436e9f877SMatthew Dillon */ 135d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 136ad7507e2SSteven Wallace struct getpgrp_args { 137ad7507e2SSteven Wallace int dummy; 138ad7507e2SSteven Wallace }; 139d2d3e875SBruce Evans #endif 14026f9a767SRodney W. Grimes int 141*8451d0ddSKip Macy sys_getpgrp(struct thread *td, struct getpgrp_args *uap) 142df8bae1dSRodney W. Grimes { 143b40ce416SJulian Elischer struct proc *p = td->td_proc; 144df8bae1dSRodney W. Grimes 145f591779bSSeigo Tanimura PROC_LOCK(p); 146b40ce416SJulian Elischer td->td_retval[0] = p->p_pgrp->pg_id; 147f591779bSSeigo Tanimura PROC_UNLOCK(p); 148df8bae1dSRodney W. Grimes return (0); 149df8bae1dSRodney W. Grimes } 150df8bae1dSRodney W. Grimes 1511a5018a0SPeter Wemm /* Get an arbitary pid's process group id */ 1521a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1531a5018a0SPeter Wemm struct getpgid_args { 1541a5018a0SPeter Wemm pid_t pid; 1551a5018a0SPeter Wemm }; 1561a5018a0SPeter Wemm #endif 1571a5018a0SPeter Wemm int 158*8451d0ddSKip Macy sys_getpgid(struct thread *td, struct getpgid_args *uap) 1591a5018a0SPeter Wemm { 160a70a2b74SJohn Baldwin struct proc *p; 161f2ae7368SJohn Baldwin int error; 16265de0c7aSDon Lewis 163f591779bSSeigo Tanimura if (uap->pid == 0) { 164a70a2b74SJohn Baldwin p = td->td_proc; 165f591779bSSeigo Tanimura PROC_LOCK(p); 166a70a2b74SJohn Baldwin } else { 167a70a2b74SJohn Baldwin p = pfind(uap->pid); 168a70a2b74SJohn Baldwin if (p == NULL) 169a70a2b74SJohn Baldwin return (ESRCH); 170a70a2b74SJohn Baldwin error = p_cansee(td, p); 171a70a2b74SJohn Baldwin if (error) { 172a70a2b74SJohn Baldwin PROC_UNLOCK(p); 173a70a2b74SJohn Baldwin return (error); 174a70a2b74SJohn Baldwin } 175a70a2b74SJohn Baldwin } 176b40ce416SJulian Elischer td->td_retval[0] = p->p_pgrp->pg_id; 177f591779bSSeigo Tanimura PROC_UNLOCK(p); 178a70a2b74SJohn Baldwin return (0); 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 1891a5018a0SPeter Wemm int 190*8451d0ddSKip Macy sys_getsid(struct thread *td, struct getsid_args *uap) 1911a5018a0SPeter Wemm { 192a70a2b74SJohn Baldwin struct proc *p; 193eb725b4eSRobert Watson int error; 19465de0c7aSDon Lewis 195f591779bSSeigo Tanimura if (uap->pid == 0) { 196a70a2b74SJohn Baldwin p = td->td_proc; 197f591779bSSeigo Tanimura PROC_LOCK(p); 198a70a2b74SJohn Baldwin } else { 199a70a2b74SJohn Baldwin p = pfind(uap->pid); 200a70a2b74SJohn Baldwin if (p == NULL) 201a70a2b74SJohn Baldwin return (ESRCH); 202a70a2b74SJohn Baldwin error = p_cansee(td, p); 203a70a2b74SJohn Baldwin if (error) { 204a70a2b74SJohn Baldwin PROC_UNLOCK(p); 205a70a2b74SJohn Baldwin return (error); 206a70a2b74SJohn Baldwin } 207a70a2b74SJohn Baldwin } 208b40ce416SJulian Elischer td->td_retval[0] = p->p_session->s_sid; 209f591779bSSeigo Tanimura PROC_UNLOCK(p); 210a70a2b74SJohn Baldwin return (0); 2111a5018a0SPeter Wemm } 2121a5018a0SPeter Wemm 213d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 214ad7507e2SSteven Wallace struct getuid_args { 215ad7507e2SSteven Wallace int dummy; 216ad7507e2SSteven Wallace }; 217d2d3e875SBruce Evans #endif 218df8bae1dSRodney W. Grimes /* ARGSUSED */ 21926f9a767SRodney W. Grimes int 220*8451d0ddSKip Macy sys_getuid(struct thread *td, struct getuid_args *uap) 221df8bae1dSRodney W. Grimes { 222df8bae1dSRodney W. Grimes 223d846883bSJohn Baldwin td->td_retval[0] = td->td_ucred->cr_ruid; 2241930e303SPoul-Henning Kamp #if defined(COMPAT_43) 225d846883bSJohn Baldwin td->td_retval[1] = td->td_ucred->cr_uid; 226df8bae1dSRodney W. Grimes #endif 227df8bae1dSRodney W. Grimes return (0); 228df8bae1dSRodney W. Grimes } 229df8bae1dSRodney W. Grimes 230d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 231ad7507e2SSteven Wallace struct geteuid_args { 232ad7507e2SSteven Wallace int dummy; 233ad7507e2SSteven Wallace }; 234d2d3e875SBruce Evans #endif 235df8bae1dSRodney W. Grimes /* ARGSUSED */ 23626f9a767SRodney W. Grimes int 237*8451d0ddSKip Macy sys_geteuid(struct thread *td, struct geteuid_args *uap) 238df8bae1dSRodney W. Grimes { 239d846883bSJohn Baldwin 240d846883bSJohn Baldwin td->td_retval[0] = td->td_ucred->cr_uid; 241df8bae1dSRodney W. Grimes return (0); 242df8bae1dSRodney W. Grimes } 243df8bae1dSRodney W. Grimes 244d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 245ad7507e2SSteven Wallace struct getgid_args { 246ad7507e2SSteven Wallace int dummy; 247ad7507e2SSteven Wallace }; 248d2d3e875SBruce Evans #endif 249df8bae1dSRodney W. Grimes /* ARGSUSED */ 25026f9a767SRodney W. Grimes int 251*8451d0ddSKip Macy sys_getgid(struct thread *td, struct getgid_args *uap) 252df8bae1dSRodney W. Grimes { 253df8bae1dSRodney W. Grimes 254d846883bSJohn Baldwin td->td_retval[0] = td->td_ucred->cr_rgid; 2551930e303SPoul-Henning Kamp #if defined(COMPAT_43) 256d846883bSJohn Baldwin td->td_retval[1] = td->td_ucred->cr_groups[0]; 257df8bae1dSRodney W. Grimes #endif 258df8bae1dSRodney W. Grimes return (0); 259df8bae1dSRodney W. Grimes } 260df8bae1dSRodney W. Grimes 261df8bae1dSRodney W. Grimes /* 262df8bae1dSRodney W. Grimes * Get effective group ID. The "egid" is groups[0], and could be obtained 263df8bae1dSRodney W. Grimes * via getgroups. This syscall exists because it is somewhat painful to do 264df8bae1dSRodney W. Grimes * correctly in a library function. 265df8bae1dSRodney W. Grimes */ 266d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 267ad7507e2SSteven Wallace struct getegid_args { 268ad7507e2SSteven Wallace int dummy; 269ad7507e2SSteven Wallace }; 270d2d3e875SBruce Evans #endif 271df8bae1dSRodney W. Grimes /* ARGSUSED */ 27226f9a767SRodney W. Grimes int 273*8451d0ddSKip Macy sys_getegid(struct thread *td, struct getegid_args *uap) 274df8bae1dSRodney W. Grimes { 275df8bae1dSRodney W. Grimes 276d846883bSJohn Baldwin td->td_retval[0] = td->td_ucred->cr_groups[0]; 277df8bae1dSRodney W. Grimes return (0); 278df8bae1dSRodney W. Grimes } 279df8bae1dSRodney W. Grimes 280d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 281df8bae1dSRodney W. Grimes struct getgroups_args { 282df8bae1dSRodney W. Grimes u_int gidsetsize; 283df8bae1dSRodney W. Grimes gid_t *gidset; 284df8bae1dSRodney W. Grimes }; 285d2d3e875SBruce Evans #endif 28626f9a767SRodney W. Grimes int 287*8451d0ddSKip Macy sys_getgroups(struct thread *td, register struct getgroups_args *uap) 288df8bae1dSRodney W. Grimes { 289838d9858SBrooks Davis gid_t *groups; 290b1fc0ec1SRobert Watson u_int ngrp; 291eb725b4eSRobert Watson int error; 292df8bae1dSRodney W. Grimes 2939126964cSBrooks Davis if (uap->gidsetsize < td->td_ucred->cr_ngroups) { 2949126964cSBrooks Davis if (uap->gidsetsize == 0) 2959126964cSBrooks Davis ngrp = 0; 2969126964cSBrooks Davis else 2979126964cSBrooks Davis return (EINVAL); 2989126964cSBrooks Davis } else 2999126964cSBrooks Davis ngrp = td->td_ucred->cr_ngroups; 300838d9858SBrooks Davis groups = malloc(ngrp * sizeof(*groups), M_TEMP, M_WAITOK); 3013cb83e71SJohn Baldwin error = kern_getgroups(td, &ngrp, groups); 3023cb83e71SJohn Baldwin if (error) 303838d9858SBrooks Davis goto out; 3043cb83e71SJohn Baldwin if (uap->gidsetsize > 0) 3053cb83e71SJohn Baldwin error = copyout(groups, uap->gidset, ngrp * sizeof(gid_t)); 306d74ac681SMatthew Dillon if (error == 0) 307d846883bSJohn Baldwin td->td_retval[0] = ngrp; 308838d9858SBrooks Davis out: 309838d9858SBrooks Davis free(groups, M_TEMP); 310d74ac681SMatthew Dillon return (error); 311df8bae1dSRodney W. Grimes } 312df8bae1dSRodney W. Grimes 3133cb83e71SJohn Baldwin int 3143cb83e71SJohn Baldwin kern_getgroups(struct thread *td, u_int *ngrp, gid_t *groups) 3153cb83e71SJohn Baldwin { 3163cb83e71SJohn Baldwin struct ucred *cred; 3173cb83e71SJohn Baldwin 3183cb83e71SJohn Baldwin cred = td->td_ucred; 3193cb83e71SJohn Baldwin if (*ngrp == 0) { 3203cb83e71SJohn Baldwin *ngrp = cred->cr_ngroups; 3213cb83e71SJohn Baldwin return (0); 3223cb83e71SJohn Baldwin } 3233cb83e71SJohn Baldwin if (*ngrp < cred->cr_ngroups) 3243cb83e71SJohn Baldwin return (EINVAL); 3253cb83e71SJohn Baldwin *ngrp = cred->cr_ngroups; 3263cb83e71SJohn Baldwin bcopy(cred->cr_groups, groups, *ngrp * sizeof(gid_t)); 3273cb83e71SJohn Baldwin return (0); 3283cb83e71SJohn Baldwin } 3293cb83e71SJohn Baldwin 330d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 33182970b81SBruce Evans struct setsid_args { 332ad7507e2SSteven Wallace int dummy; 333ad7507e2SSteven Wallace }; 334d2d3e875SBruce Evans #endif 335df8bae1dSRodney W. Grimes /* ARGSUSED */ 33626f9a767SRodney W. Grimes int 337*8451d0ddSKip Macy sys_setsid(register struct thread *td, struct setsid_args *uap) 338df8bae1dSRodney W. Grimes { 339f591779bSSeigo Tanimura struct pgrp *pgrp; 340835a82eeSMatthew Dillon int error; 341b40ce416SJulian Elischer struct proc *p = td->td_proc; 342f591779bSSeigo Tanimura struct pgrp *newpgrp; 343f591779bSSeigo Tanimura struct session *newsess; 344f591779bSSeigo Tanimura 345f591779bSSeigo Tanimura error = 0; 346f591779bSSeigo Tanimura pgrp = NULL; 347df8bae1dSRodney W. Grimes 3481ede983cSDag-Erling Smørgrav newpgrp = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); 3491ede983cSDag-Erling Smørgrav newsess = malloc(sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO); 350f591779bSSeigo Tanimura 351c8b1829dSJohn Baldwin sx_xlock(&proctree_lock); 352f591779bSSeigo Tanimura 353f591779bSSeigo Tanimura if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) { 354f591779bSSeigo Tanimura if (pgrp != NULL) 355f591779bSSeigo Tanimura PGRP_UNLOCK(pgrp); 356835a82eeSMatthew Dillon error = EPERM; 357f591779bSSeigo Tanimura } else { 358f591779bSSeigo Tanimura (void)enterpgrp(p, p->p_pid, newpgrp, newsess); 359b40ce416SJulian Elischer td->td_retval[0] = p->p_pid; 360c8b1829dSJohn Baldwin newpgrp = NULL; 361c8b1829dSJohn Baldwin newsess = NULL; 362df8bae1dSRodney W. Grimes } 363f591779bSSeigo Tanimura 364c8b1829dSJohn Baldwin sx_xunlock(&proctree_lock); 365f591779bSSeigo Tanimura 366c8b1829dSJohn Baldwin if (newpgrp != NULL) 3671ede983cSDag-Erling Smørgrav free(newpgrp, M_PGRP); 368c8b1829dSJohn Baldwin if (newsess != NULL) 3691ede983cSDag-Erling Smørgrav free(newsess, M_SESSION); 3701c2451c2SSeigo Tanimura 371c8b1829dSJohn Baldwin return (error); 372df8bae1dSRodney W. Grimes } 373df8bae1dSRodney W. Grimes 374df8bae1dSRodney W. Grimes /* 375df8bae1dSRodney W. Grimes * set process group (setpgid/old setpgrp) 376df8bae1dSRodney W. Grimes * 377df8bae1dSRodney W. Grimes * caller does setpgid(targpid, targpgid) 378df8bae1dSRodney W. Grimes * 379df8bae1dSRodney W. Grimes * pid must be caller or child of caller (ESRCH) 380df8bae1dSRodney W. Grimes * if a child 381df8bae1dSRodney W. Grimes * pid must be in same session (EPERM) 382df8bae1dSRodney W. Grimes * pid can't have done an exec (EACCES) 383df8bae1dSRodney W. Grimes * if pgid != pid 384df8bae1dSRodney W. Grimes * there must exist some pid in same session having pgid (EPERM) 385df8bae1dSRodney W. Grimes * pid must not be session leader (EPERM) 386df8bae1dSRodney W. Grimes */ 387d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 388df8bae1dSRodney W. Grimes struct setpgid_args { 389df8bae1dSRodney W. Grimes int pid; /* target process id */ 390df8bae1dSRodney W. Grimes int pgid; /* target pgrp id */ 391df8bae1dSRodney W. Grimes }; 392d2d3e875SBruce Evans #endif 393df8bae1dSRodney W. Grimes /* ARGSUSED */ 39426f9a767SRodney W. Grimes int 395*8451d0ddSKip Macy sys_setpgid(struct thread *td, register struct setpgid_args *uap) 396df8bae1dSRodney W. Grimes { 397b40ce416SJulian Elischer struct proc *curp = td->td_proc; 398df8bae1dSRodney W. Grimes register struct proc *targp; /* target process */ 399df8bae1dSRodney W. Grimes register struct pgrp *pgrp; /* target pgrp */ 400eb9e5c1dSRobert Watson int error; 401f591779bSSeigo Tanimura struct pgrp *newpgrp; 402df8bae1dSRodney W. Grimes 40378f64bccSBruce Evans if (uap->pgid < 0) 40478f64bccSBruce Evans return (EINVAL); 405f591779bSSeigo Tanimura 406f591779bSSeigo Tanimura error = 0; 407f591779bSSeigo Tanimura 4081ede983cSDag-Erling Smørgrav newpgrp = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); 409f591779bSSeigo Tanimura 410c8b1829dSJohn Baldwin sx_xlock(&proctree_lock); 411df8bae1dSRodney W. Grimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 412f591779bSSeigo Tanimura if ((targp = pfind(uap->pid)) == NULL) { 413835a82eeSMatthew Dillon error = ESRCH; 414c8b1829dSJohn Baldwin goto done; 41533a9ed9dSJohn Baldwin } 416f591779bSSeigo Tanimura if (!inferior(targp)) { 417f591779bSSeigo Tanimura PROC_UNLOCK(targp); 4182f932587SSeigo Tanimura error = ESRCH; 419c8b1829dSJohn Baldwin goto done; 420f591779bSSeigo Tanimura } 42171a057bcSRobert Watson if ((error = p_cansee(td, targp))) { 42233a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 423c8b1829dSJohn Baldwin goto done; 42433a9ed9dSJohn Baldwin } 42533a9ed9dSJohn Baldwin if (targp->p_pgrp == NULL || 42633a9ed9dSJohn Baldwin targp->p_session != curp->p_session) { 42733a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 428835a82eeSMatthew Dillon error = EPERM; 429c8b1829dSJohn Baldwin goto done; 43033a9ed9dSJohn Baldwin } 43133a9ed9dSJohn Baldwin if (targp->p_flag & P_EXEC) { 43233a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 433835a82eeSMatthew Dillon error = EACCES; 434c8b1829dSJohn Baldwin goto done; 43533a9ed9dSJohn Baldwin } 43633a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 437f591779bSSeigo Tanimura } else 438f591779bSSeigo Tanimura targp = curp; 439f591779bSSeigo Tanimura if (SESS_LEADER(targp)) { 440835a82eeSMatthew Dillon error = EPERM; 441c8b1829dSJohn Baldwin goto done; 44233a9ed9dSJohn Baldwin } 443eb725b4eSRobert Watson if (uap->pgid == 0) 444df8bae1dSRodney W. Grimes uap->pgid = targp->p_pid; 445a10d5f02SOlivier Houchard if ((pgrp = pgfind(uap->pgid)) == NULL) { 446f591779bSSeigo Tanimura if (uap->pgid == targp->p_pid) { 447a10d5f02SOlivier Houchard error = enterpgrp(targp, uap->pgid, newpgrp, 448a10d5f02SOlivier Houchard NULL); 449f591779bSSeigo Tanimura if (error == 0) 450f591779bSSeigo Tanimura newpgrp = NULL; 451a10d5f02SOlivier Houchard } else 452835a82eeSMatthew Dillon error = EPERM; 453a10d5f02SOlivier Houchard } else { 454f591779bSSeigo Tanimura if (pgrp == targp->p_pgrp) { 455f591779bSSeigo Tanimura PGRP_UNLOCK(pgrp); 456f591779bSSeigo Tanimura goto done; 45733a9ed9dSJohn Baldwin } 458a10d5f02SOlivier Houchard if (pgrp->pg_id != targp->p_pid && 459a10d5f02SOlivier Houchard pgrp->pg_session != curp->p_session) { 460a10d5f02SOlivier Houchard PGRP_UNLOCK(pgrp); 461a10d5f02SOlivier Houchard error = EPERM; 462a10d5f02SOlivier Houchard goto done; 463a10d5f02SOlivier Houchard } 464f591779bSSeigo Tanimura PGRP_UNLOCK(pgrp); 465f591779bSSeigo Tanimura error = enterthispgrp(targp, pgrp); 466f591779bSSeigo Tanimura } 467f591779bSSeigo Tanimura done: 468c8b1829dSJohn Baldwin sx_xunlock(&proctree_lock); 469c8b1829dSJohn Baldwin KASSERT((error == 0) || (newpgrp != NULL), 470c8b1829dSJohn Baldwin ("setpgid failed and newpgrp is NULL")); 4716041fa0aSSeigo Tanimura if (newpgrp != NULL) 4721ede983cSDag-Erling Smørgrav free(newpgrp, M_PGRP); 473835a82eeSMatthew Dillon return (error); 474df8bae1dSRodney W. Grimes } 475df8bae1dSRodney W. Grimes 476a08f4bf6SPeter Wemm /* 477a08f4bf6SPeter Wemm * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 4782fa72ea7SJeroen Ruigrok van der Werven * compatible. It says that setting the uid/gid to euid/egid is a special 479a08f4bf6SPeter Wemm * case of "appropriate privilege". Once the rules are expanded out, this 480a08f4bf6SPeter Wemm * basically means that setuid(nnn) sets all three id's, in all permitted 481a08f4bf6SPeter Wemm * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 482a08f4bf6SPeter Wemm * does not set the saved id - this is dangerous for traditional BSD 483a08f4bf6SPeter Wemm * programs. For this reason, we *really* do not want to set 484a08f4bf6SPeter Wemm * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 485a08f4bf6SPeter Wemm */ 486a08f4bf6SPeter Wemm #define POSIX_APPENDIX_B_4_2_2 487a08f4bf6SPeter Wemm 488d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 489df8bae1dSRodney W. Grimes struct setuid_args { 490df8bae1dSRodney W. Grimes uid_t uid; 491df8bae1dSRodney W. Grimes }; 492d2d3e875SBruce Evans #endif 493df8bae1dSRodney W. Grimes /* ARGSUSED */ 49426f9a767SRodney W. Grimes int 495*8451d0ddSKip Macy sys_setuid(struct thread *td, struct setuid_args *uap) 496df8bae1dSRodney W. Grimes { 497b40ce416SJulian Elischer struct proc *p = td->td_proc; 498b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 499b1fc0ec1SRobert Watson uid_t uid; 5001419eacbSAlfred Perlstein struct uidinfo *uip; 501eb725b4eSRobert Watson int error; 502df8bae1dSRodney W. Grimes 50307f3485dSJohn Baldwin uid = uap->uid; 50414961ba7SRobert Watson AUDIT_ARG_UID(uid); 50507f3485dSJohn Baldwin newcred = crget(); 5061419eacbSAlfred Perlstein uip = uifind(uid); 50707f3485dSJohn Baldwin PROC_LOCK(p); 508838d9858SBrooks Davis /* 509838d9858SBrooks Davis * Copy credentials so other references do not see our changes. 510838d9858SBrooks Davis */ 511838d9858SBrooks Davis oldcred = crcopysafe(p, newcred); 5125a92ee3cSRobert Watson 513030a28b3SRobert Watson #ifdef MAC 5146f6174a7SRobert Watson error = mac_cred_check_setuid(oldcred, uid); 515030a28b3SRobert Watson if (error) 516030a28b3SRobert Watson goto fail; 517030a28b3SRobert Watson #endif 518030a28b3SRobert Watson 519a08f4bf6SPeter Wemm /* 520a08f4bf6SPeter Wemm * See if we have "permission" by POSIX 1003.1 rules. 521a08f4bf6SPeter Wemm * 522a08f4bf6SPeter Wemm * Note that setuid(geteuid()) is a special case of 523a08f4bf6SPeter Wemm * "appropriate privileges" in appendix B.4.2.2. We need 5242fa72ea7SJeroen Ruigrok van der Werven * to use this clause to be compatible with traditional BSD 525a08f4bf6SPeter Wemm * semantics. Basically, it means that "setuid(xx)" sets all 526a08f4bf6SPeter Wemm * three id's (assuming you have privs). 527a08f4bf6SPeter Wemm * 528a08f4bf6SPeter Wemm * Notes on the logic. We do things in three steps. 529a08f4bf6SPeter Wemm * 1: We determine if the euid is going to change, and do EPERM 530a08f4bf6SPeter Wemm * right away. We unconditionally change the euid later if this 531a08f4bf6SPeter Wemm * test is satisfied, simplifying that part of the logic. 532eb725b4eSRobert Watson * 2: We determine if the real and/or saved uids are going to 533a08f4bf6SPeter Wemm * change. Determined by compile options. 534a08f4bf6SPeter Wemm * 3: Change euid last. (after tests in #2 for "appropriate privs") 535a08f4bf6SPeter Wemm */ 536b1fc0ec1SRobert Watson if (uid != oldcred->cr_ruid && /* allow setuid(getuid()) */ 5373f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS 538b1fc0ec1SRobert Watson uid != oldcred->cr_svuid && /* allow setuid(saved gid) */ 539a08f4bf6SPeter Wemm #endif 540a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 541b1fc0ec1SRobert Watson uid != oldcred->cr_uid && /* allow setuid(geteuid()) */ 5423f246666SAndrey A. Chernov #endif 54332f9753cSRobert Watson (error = priv_check_cred(oldcred, PRIV_CRED_SETUID, 0)) != 0) 544030a28b3SRobert Watson goto fail; 545a08f4bf6SPeter Wemm 546a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS 547df8bae1dSRodney W. Grimes /* 548a08f4bf6SPeter Wemm * Do we have "appropriate privileges" (are we root or uid == euid) 549a08f4bf6SPeter Wemm * If so, we are changing the real uid and/or saved uid. 550df8bae1dSRodney W. Grimes */ 5513f246666SAndrey A. Chernov if ( 552a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 553b1fc0ec1SRobert Watson uid == oldcred->cr_uid || 5543f246666SAndrey A. Chernov #endif 555800c9408SRobert Watson /* We are using privs. */ 55632f9753cSRobert Watson priv_check_cred(oldcred, PRIV_CRED_SETUID, 0) == 0) 557a08f4bf6SPeter Wemm #endif 558a08f4bf6SPeter Wemm { 559a08f4bf6SPeter Wemm /* 560f535380cSDon Lewis * Set the real uid and transfer proc count to new user. 561a08f4bf6SPeter Wemm */ 562b1fc0ec1SRobert Watson if (uid != oldcred->cr_ruid) { 5631419eacbSAlfred Perlstein change_ruid(newcred, uip); 564f535380cSDon Lewis setsugid(p); 565d3cdb93dSAndrey A. Chernov } 566a08f4bf6SPeter Wemm /* 567a08f4bf6SPeter Wemm * Set saved uid 568a08f4bf6SPeter Wemm * 569a08f4bf6SPeter Wemm * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 570a08f4bf6SPeter Wemm * the security of seteuid() depends on it. B.4.2.2 says it 571a08f4bf6SPeter Wemm * is important that we should do this. 572a08f4bf6SPeter Wemm */ 573b1fc0ec1SRobert Watson if (uid != oldcred->cr_svuid) { 574b1fc0ec1SRobert Watson change_svuid(newcred, uid); 575d5f81602SSean Eric Fagan setsugid(p); 576a08f4bf6SPeter Wemm } 577a08f4bf6SPeter Wemm } 578a08f4bf6SPeter Wemm 579a08f4bf6SPeter Wemm /* 580a08f4bf6SPeter Wemm * In all permitted cases, we are changing the euid. 581a08f4bf6SPeter Wemm */ 582b1fc0ec1SRobert Watson if (uid != oldcred->cr_uid) { 5831419eacbSAlfred Perlstein change_euid(newcred, uip); 584d5f81602SSean Eric Fagan setsugid(p); 585a08f4bf6SPeter Wemm } 586b1fc0ec1SRobert Watson p->p_ucred = newcred; 58707f3485dSJohn Baldwin PROC_UNLOCK(p); 588e4dcb704SEdward Tomasz Napierala #ifdef RACCT 589e4dcb704SEdward Tomasz Napierala racct_proc_ucred_changed(p, oldcred, newcred); 590e4dcb704SEdward Tomasz Napierala #endif 5911419eacbSAlfred Perlstein uifree(uip); 592b1fc0ec1SRobert Watson crfree(oldcred); 59307f3485dSJohn Baldwin return (0); 594030a28b3SRobert Watson 595030a28b3SRobert Watson fail: 596030a28b3SRobert Watson PROC_UNLOCK(p); 597030a28b3SRobert Watson uifree(uip); 598030a28b3SRobert Watson crfree(newcred); 599030a28b3SRobert Watson return (error); 600df8bae1dSRodney W. Grimes } 601df8bae1dSRodney W. Grimes 602d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 603df8bae1dSRodney W. Grimes struct seteuid_args { 604df8bae1dSRodney W. Grimes uid_t euid; 605df8bae1dSRodney W. Grimes }; 606d2d3e875SBruce Evans #endif 607df8bae1dSRodney W. Grimes /* ARGSUSED */ 60826f9a767SRodney W. Grimes int 609*8451d0ddSKip Macy sys_seteuid(struct thread *td, struct seteuid_args *uap) 610df8bae1dSRodney W. Grimes { 611b40ce416SJulian Elischer struct proc *p = td->td_proc; 612b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 613b1fc0ec1SRobert Watson uid_t euid; 6141419eacbSAlfred Perlstein struct uidinfo *euip; 615eb725b4eSRobert Watson int error; 616df8bae1dSRodney W. Grimes 617df8bae1dSRodney W. Grimes euid = uap->euid; 61814961ba7SRobert Watson AUDIT_ARG_EUID(euid); 61907f3485dSJohn Baldwin newcred = crget(); 6201419eacbSAlfred Perlstein euip = uifind(euid); 62107f3485dSJohn Baldwin PROC_LOCK(p); 622838d9858SBrooks Davis /* 623838d9858SBrooks Davis * Copy credentials so other references do not see our changes. 624838d9858SBrooks Davis */ 625838d9858SBrooks Davis oldcred = crcopysafe(p, newcred); 626030a28b3SRobert Watson 627030a28b3SRobert Watson #ifdef MAC 6286f6174a7SRobert Watson error = mac_cred_check_seteuid(oldcred, euid); 629030a28b3SRobert Watson if (error) 630030a28b3SRobert Watson goto fail; 631030a28b3SRobert Watson #endif 632030a28b3SRobert Watson 633b1fc0ec1SRobert Watson if (euid != oldcred->cr_ruid && /* allow seteuid(getuid()) */ 634b1fc0ec1SRobert Watson euid != oldcred->cr_svuid && /* allow seteuid(saved uid) */ 63532f9753cSRobert Watson (error = priv_check_cred(oldcred, PRIV_CRED_SETEUID, 0)) != 0) 636030a28b3SRobert Watson goto fail; 637030a28b3SRobert Watson 638df8bae1dSRodney W. Grimes /* 639838d9858SBrooks Davis * Everything's okay, do it. 640df8bae1dSRodney W. Grimes */ 641b1fc0ec1SRobert Watson if (oldcred->cr_uid != euid) { 6421419eacbSAlfred Perlstein change_euid(newcred, euip); 643d5f81602SSean Eric Fagan setsugid(p); 644229a15f0SPeter Wemm } 645b1fc0ec1SRobert Watson p->p_ucred = newcred; 64607f3485dSJohn Baldwin PROC_UNLOCK(p); 6471419eacbSAlfred Perlstein uifree(euip); 648b1fc0ec1SRobert Watson crfree(oldcred); 64907f3485dSJohn Baldwin return (0); 650030a28b3SRobert Watson 651030a28b3SRobert Watson fail: 652030a28b3SRobert Watson PROC_UNLOCK(p); 653030a28b3SRobert Watson uifree(euip); 654030a28b3SRobert Watson crfree(newcred); 655030a28b3SRobert Watson return (error); 656df8bae1dSRodney W. Grimes } 657df8bae1dSRodney W. Grimes 658d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 659df8bae1dSRodney W. Grimes struct setgid_args { 660df8bae1dSRodney W. Grimes gid_t gid; 661df8bae1dSRodney W. Grimes }; 662d2d3e875SBruce Evans #endif 663df8bae1dSRodney W. Grimes /* ARGSUSED */ 66426f9a767SRodney W. Grimes int 665*8451d0ddSKip Macy sys_setgid(struct thread *td, struct setgid_args *uap) 666df8bae1dSRodney W. Grimes { 667b40ce416SJulian Elischer struct proc *p = td->td_proc; 668b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 669b1fc0ec1SRobert Watson gid_t gid; 670eb725b4eSRobert Watson int error; 671df8bae1dSRodney W. Grimes 672b1fc0ec1SRobert Watson gid = uap->gid; 67314961ba7SRobert Watson AUDIT_ARG_GID(gid); 67407f3485dSJohn Baldwin newcred = crget(); 67507f3485dSJohn Baldwin PROC_LOCK(p); 676838d9858SBrooks Davis oldcred = crcopysafe(p, newcred); 6775a92ee3cSRobert Watson 678030a28b3SRobert Watson #ifdef MAC 6796f6174a7SRobert Watson error = mac_cred_check_setgid(oldcred, gid); 680030a28b3SRobert Watson if (error) 681030a28b3SRobert Watson goto fail; 682030a28b3SRobert Watson #endif 683030a28b3SRobert Watson 684a08f4bf6SPeter Wemm /* 685a08f4bf6SPeter Wemm * See if we have "permission" by POSIX 1003.1 rules. 686a08f4bf6SPeter Wemm * 687a08f4bf6SPeter Wemm * Note that setgid(getegid()) is a special case of 688a08f4bf6SPeter Wemm * "appropriate privileges" in appendix B.4.2.2. We need 6892fa72ea7SJeroen Ruigrok van der Werven * to use this clause to be compatible with traditional BSD 690a08f4bf6SPeter Wemm * semantics. Basically, it means that "setgid(xx)" sets all 691a08f4bf6SPeter Wemm * three id's (assuming you have privs). 692a08f4bf6SPeter Wemm * 693a08f4bf6SPeter Wemm * For notes on the logic here, see setuid() above. 694a08f4bf6SPeter Wemm */ 695b1fc0ec1SRobert Watson if (gid != oldcred->cr_rgid && /* allow setgid(getgid()) */ 6963f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS 697b1fc0ec1SRobert Watson gid != oldcred->cr_svgid && /* allow setgid(saved gid) */ 698a08f4bf6SPeter Wemm #endif 699a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 700b1fc0ec1SRobert Watson gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */ 7013f246666SAndrey A. Chernov #endif 70232f9753cSRobert Watson (error = priv_check_cred(oldcred, PRIV_CRED_SETGID, 0)) != 0) 703030a28b3SRobert Watson goto fail; 704a08f4bf6SPeter Wemm 705a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS 706a08f4bf6SPeter Wemm /* 707a08f4bf6SPeter Wemm * Do we have "appropriate privileges" (are we root or gid == egid) 708a08f4bf6SPeter Wemm * If so, we are changing the real uid and saved gid. 709a08f4bf6SPeter Wemm */ 710a08f4bf6SPeter Wemm if ( 711a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 712b1fc0ec1SRobert Watson gid == oldcred->cr_groups[0] || 713a08f4bf6SPeter Wemm #endif 714800c9408SRobert Watson /* We are using privs. */ 71532f9753cSRobert Watson priv_check_cred(oldcred, PRIV_CRED_SETGID, 0) == 0) 716a08f4bf6SPeter Wemm #endif 717a08f4bf6SPeter Wemm { 718a08f4bf6SPeter Wemm /* 719a08f4bf6SPeter Wemm * Set real gid 720a08f4bf6SPeter Wemm */ 721b1fc0ec1SRobert Watson if (oldcred->cr_rgid != gid) { 722b1fc0ec1SRobert Watson change_rgid(newcred, gid); 723d5f81602SSean Eric Fagan setsugid(p); 724a08f4bf6SPeter Wemm } 725a08f4bf6SPeter Wemm /* 726a08f4bf6SPeter Wemm * Set saved gid 727a08f4bf6SPeter Wemm * 728a08f4bf6SPeter Wemm * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 729a08f4bf6SPeter Wemm * the security of setegid() depends on it. B.4.2.2 says it 730a08f4bf6SPeter Wemm * is important that we should do this. 731a08f4bf6SPeter Wemm */ 732b1fc0ec1SRobert Watson if (oldcred->cr_svgid != gid) { 733b1fc0ec1SRobert Watson change_svgid(newcred, gid); 734d5f81602SSean Eric Fagan setsugid(p); 735a08f4bf6SPeter Wemm } 736a08f4bf6SPeter Wemm } 737a08f4bf6SPeter Wemm /* 738a08f4bf6SPeter Wemm * In all cases permitted cases, we are changing the egid. 739a08f4bf6SPeter Wemm * Copy credentials so other references do not see our changes. 740a08f4bf6SPeter Wemm */ 741b1fc0ec1SRobert Watson if (oldcred->cr_groups[0] != gid) { 742b1fc0ec1SRobert Watson change_egid(newcred, gid); 743d5f81602SSean Eric Fagan setsugid(p); 744a08f4bf6SPeter Wemm } 745b1fc0ec1SRobert Watson p->p_ucred = newcred; 74607f3485dSJohn Baldwin PROC_UNLOCK(p); 747b1fc0ec1SRobert Watson crfree(oldcred); 74807f3485dSJohn Baldwin return (0); 749030a28b3SRobert Watson 750030a28b3SRobert Watson fail: 751030a28b3SRobert Watson PROC_UNLOCK(p); 752030a28b3SRobert Watson crfree(newcred); 753030a28b3SRobert Watson return (error); 754df8bae1dSRodney W. Grimes } 755df8bae1dSRodney W. Grimes 756d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 757df8bae1dSRodney W. Grimes struct setegid_args { 758df8bae1dSRodney W. Grimes gid_t egid; 759df8bae1dSRodney W. Grimes }; 760d2d3e875SBruce Evans #endif 761df8bae1dSRodney W. Grimes /* ARGSUSED */ 76226f9a767SRodney W. Grimes int 763*8451d0ddSKip Macy sys_setegid(struct thread *td, struct setegid_args *uap) 764df8bae1dSRodney W. Grimes { 765b40ce416SJulian Elischer struct proc *p = td->td_proc; 766b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 767b1fc0ec1SRobert Watson gid_t egid; 768eb725b4eSRobert Watson int error; 769df8bae1dSRodney W. Grimes 770df8bae1dSRodney W. Grimes egid = uap->egid; 77114961ba7SRobert Watson AUDIT_ARG_EGID(egid); 77207f3485dSJohn Baldwin newcred = crget(); 77307f3485dSJohn Baldwin PROC_LOCK(p); 774838d9858SBrooks Davis oldcred = crcopysafe(p, newcred); 775030a28b3SRobert Watson 776030a28b3SRobert Watson #ifdef MAC 7776f6174a7SRobert Watson error = mac_cred_check_setegid(oldcred, egid); 778030a28b3SRobert Watson if (error) 779030a28b3SRobert Watson goto fail; 780030a28b3SRobert Watson #endif 781030a28b3SRobert Watson 782b1fc0ec1SRobert Watson if (egid != oldcred->cr_rgid && /* allow setegid(getgid()) */ 783b1fc0ec1SRobert Watson egid != oldcred->cr_svgid && /* allow setegid(saved gid) */ 78432f9753cSRobert Watson (error = priv_check_cred(oldcred, PRIV_CRED_SETEGID, 0)) != 0) 785030a28b3SRobert Watson goto fail; 786030a28b3SRobert Watson 787b1fc0ec1SRobert Watson if (oldcred->cr_groups[0] != egid) { 788b1fc0ec1SRobert Watson change_egid(newcred, egid); 789d5f81602SSean Eric Fagan setsugid(p); 790229a15f0SPeter Wemm } 791b1fc0ec1SRobert Watson p->p_ucred = newcred; 79207f3485dSJohn Baldwin PROC_UNLOCK(p); 793b1fc0ec1SRobert Watson crfree(oldcred); 79407f3485dSJohn Baldwin return (0); 795030a28b3SRobert Watson 796030a28b3SRobert Watson fail: 797030a28b3SRobert Watson PROC_UNLOCK(p); 798030a28b3SRobert Watson crfree(newcred); 799030a28b3SRobert Watson return (error); 800df8bae1dSRodney W. Grimes } 801df8bae1dSRodney W. Grimes 802d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 803df8bae1dSRodney W. Grimes struct setgroups_args { 804df8bae1dSRodney W. Grimes u_int gidsetsize; 805df8bae1dSRodney W. Grimes gid_t *gidset; 806df8bae1dSRodney W. Grimes }; 807d2d3e875SBruce Evans #endif 808df8bae1dSRodney W. Grimes /* ARGSUSED */ 80926f9a767SRodney W. Grimes int 810*8451d0ddSKip Macy sys_setgroups(struct thread *td, struct setgroups_args *uap) 811df8bae1dSRodney W. Grimes { 812838d9858SBrooks Davis gid_t *groups = NULL; 813df8bae1dSRodney W. Grimes int error; 814df8bae1dSRodney W. Grimes 815412f9500SBrooks Davis if (uap->gidsetsize > ngroups_max + 1) 8163cb83e71SJohn Baldwin return (EINVAL); 817838d9858SBrooks Davis groups = malloc(uap->gidsetsize * sizeof(gid_t), M_TEMP, M_WAITOK); 8183cb83e71SJohn Baldwin error = copyin(uap->gidset, groups, uap->gidsetsize * sizeof(gid_t)); 8193cb83e71SJohn Baldwin if (error) 820838d9858SBrooks Davis goto out; 821838d9858SBrooks Davis error = kern_setgroups(td, uap->gidsetsize, groups); 822838d9858SBrooks Davis out: 823838d9858SBrooks Davis free(groups, M_TEMP); 8243cb83e71SJohn Baldwin return (error); 8253cb83e71SJohn Baldwin } 8263cb83e71SJohn Baldwin 8273cb83e71SJohn Baldwin int 8283cb83e71SJohn Baldwin kern_setgroups(struct thread *td, u_int ngrp, gid_t *groups) 8293cb83e71SJohn Baldwin { 8303cb83e71SJohn Baldwin struct proc *p = td->td_proc; 8313cb83e71SJohn Baldwin struct ucred *newcred, *oldcred; 8323cb83e71SJohn Baldwin int error; 8333cb83e71SJohn Baldwin 834412f9500SBrooks Davis if (ngrp > ngroups_max + 1) 83507f3485dSJohn Baldwin return (EINVAL); 83614961ba7SRobert Watson AUDIT_ARG_GROUPSET(groups, ngrp); 83707f3485dSJohn Baldwin newcred = crget(); 838838d9858SBrooks Davis crextend(newcred, ngrp); 83907f3485dSJohn Baldwin PROC_LOCK(p); 840838d9858SBrooks Davis oldcred = crcopysafe(p, newcred); 841030a28b3SRobert Watson 842030a28b3SRobert Watson #ifdef MAC 8436f6174a7SRobert Watson error = mac_cred_check_setgroups(oldcred, ngrp, groups); 844030a28b3SRobert Watson if (error) 845030a28b3SRobert Watson goto fail; 846030a28b3SRobert Watson #endif 847030a28b3SRobert Watson 84832f9753cSRobert Watson error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0); 849030a28b3SRobert Watson if (error) 850030a28b3SRobert Watson goto fail; 85107f3485dSJohn Baldwin 8528a5d815aSPeter Wemm if (ngrp < 1) { 8538a5d815aSPeter Wemm /* 8548a5d815aSPeter Wemm * setgroups(0, NULL) is a legitimate way of clearing the 8558a5d815aSPeter Wemm * groups vector on non-BSD systems (which generally do not 8568a5d815aSPeter Wemm * have the egid in the groups[0]). We risk security holes 8578a5d815aSPeter Wemm * when running non-BSD software if we do not do the same. 8588a5d815aSPeter Wemm */ 859b1fc0ec1SRobert Watson newcred->cr_ngroups = 1; 8608a5d815aSPeter Wemm } else { 861838d9858SBrooks Davis crsetgroups_locked(newcred, ngrp, groups); 8628a5d815aSPeter Wemm } 863d5f81602SSean Eric Fagan setsugid(p); 864b1fc0ec1SRobert Watson p->p_ucred = newcred; 86507f3485dSJohn Baldwin PROC_UNLOCK(p); 866b1fc0ec1SRobert Watson crfree(oldcred); 86707f3485dSJohn Baldwin return (0); 868030a28b3SRobert Watson 869030a28b3SRobert Watson fail: 870030a28b3SRobert Watson PROC_UNLOCK(p); 871030a28b3SRobert Watson crfree(newcred); 872030a28b3SRobert Watson return (error); 873df8bae1dSRodney W. Grimes } 874df8bae1dSRodney W. Grimes 875d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 876df8bae1dSRodney W. Grimes struct setreuid_args { 87700999cd6SAndrey A. Chernov uid_t ruid; 87800999cd6SAndrey A. Chernov uid_t euid; 879df8bae1dSRodney W. Grimes }; 880d2d3e875SBruce Evans #endif 881df8bae1dSRodney W. Grimes /* ARGSUSED */ 88226f9a767SRodney W. Grimes int 883*8451d0ddSKip Macy sys_setreuid(register struct thread *td, struct setreuid_args *uap) 884df8bae1dSRodney W. Grimes { 885b40ce416SJulian Elischer struct proc *p = td->td_proc; 886b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 887eb725b4eSRobert Watson uid_t euid, ruid; 8881419eacbSAlfred Perlstein struct uidinfo *euip, *ruip; 889eb725b4eSRobert Watson int error; 890df8bae1dSRodney W. Grimes 89100999cd6SAndrey A. Chernov euid = uap->euid; 892eb725b4eSRobert Watson ruid = uap->ruid; 89314961ba7SRobert Watson AUDIT_ARG_EUID(euid); 89414961ba7SRobert Watson AUDIT_ARG_RUID(ruid); 89507f3485dSJohn Baldwin newcred = crget(); 8961419eacbSAlfred Perlstein euip = uifind(euid); 8971419eacbSAlfred Perlstein ruip = uifind(ruid); 89807f3485dSJohn Baldwin PROC_LOCK(p); 899838d9858SBrooks Davis oldcred = crcopysafe(p, newcred); 900030a28b3SRobert Watson 901030a28b3SRobert Watson #ifdef MAC 9026f6174a7SRobert Watson error = mac_cred_check_setreuid(oldcred, ruid, euid); 903030a28b3SRobert Watson if (error) 904030a28b3SRobert Watson goto fail; 905030a28b3SRobert Watson #endif 906030a28b3SRobert Watson 907b1fc0ec1SRobert Watson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 908b1fc0ec1SRobert Watson ruid != oldcred->cr_svuid) || 909b1fc0ec1SRobert Watson (euid != (uid_t)-1 && euid != oldcred->cr_uid && 910b1fc0ec1SRobert Watson euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) && 91132f9753cSRobert Watson (error = priv_check_cred(oldcred, PRIV_CRED_SETREUID, 0)) != 0) 912030a28b3SRobert Watson goto fail; 913030a28b3SRobert Watson 914b1fc0ec1SRobert Watson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 9151419eacbSAlfred Perlstein change_euid(newcred, euip); 916d5f81602SSean Eric Fagan setsugid(p); 917a89a5370SPeter Wemm } 918b1fc0ec1SRobert Watson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 9191419eacbSAlfred Perlstein change_ruid(newcred, ruip); 920d5f81602SSean Eric Fagan setsugid(p); 92100999cd6SAndrey A. Chernov } 922b1fc0ec1SRobert Watson if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) && 923b1fc0ec1SRobert Watson newcred->cr_svuid != newcred->cr_uid) { 924b1fc0ec1SRobert Watson change_svuid(newcred, newcred->cr_uid); 925d5f81602SSean Eric Fagan setsugid(p); 926a89a5370SPeter Wemm } 927b1fc0ec1SRobert Watson p->p_ucred = newcred; 92807f3485dSJohn Baldwin PROC_UNLOCK(p); 929e4dcb704SEdward Tomasz Napierala #ifdef RACCT 930e4dcb704SEdward Tomasz Napierala racct_proc_ucred_changed(p, oldcred, newcred); 931e4dcb704SEdward Tomasz Napierala #endif 9321419eacbSAlfred Perlstein uifree(ruip); 9331419eacbSAlfred Perlstein uifree(euip); 934b1fc0ec1SRobert Watson crfree(oldcred); 93507f3485dSJohn Baldwin return (0); 936030a28b3SRobert Watson 937030a28b3SRobert Watson fail: 938030a28b3SRobert Watson PROC_UNLOCK(p); 939030a28b3SRobert Watson uifree(ruip); 940030a28b3SRobert Watson uifree(euip); 941030a28b3SRobert Watson crfree(newcred); 942030a28b3SRobert Watson return (error); 943df8bae1dSRodney W. Grimes } 944df8bae1dSRodney W. Grimes 945d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 946df8bae1dSRodney W. Grimes struct setregid_args { 94700999cd6SAndrey A. Chernov gid_t rgid; 94800999cd6SAndrey A. Chernov gid_t egid; 949df8bae1dSRodney W. Grimes }; 950d2d3e875SBruce Evans #endif 951df8bae1dSRodney W. Grimes /* ARGSUSED */ 95226f9a767SRodney W. Grimes int 953*8451d0ddSKip Macy sys_setregid(register struct thread *td, struct setregid_args *uap) 954df8bae1dSRodney W. Grimes { 955b40ce416SJulian Elischer struct proc *p = td->td_proc; 956b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 957eb725b4eSRobert Watson gid_t egid, rgid; 958eb725b4eSRobert Watson int error; 959df8bae1dSRodney W. Grimes 96000999cd6SAndrey A. Chernov egid = uap->egid; 961eb725b4eSRobert Watson rgid = uap->rgid; 96214961ba7SRobert Watson AUDIT_ARG_EGID(egid); 96314961ba7SRobert Watson AUDIT_ARG_RGID(rgid); 96407f3485dSJohn Baldwin newcred = crget(); 96507f3485dSJohn Baldwin PROC_LOCK(p); 966838d9858SBrooks Davis oldcred = crcopysafe(p, newcred); 967030a28b3SRobert Watson 968030a28b3SRobert Watson #ifdef MAC 9696f6174a7SRobert Watson error = mac_cred_check_setregid(oldcred, rgid, egid); 970030a28b3SRobert Watson if (error) 971030a28b3SRobert Watson goto fail; 972030a28b3SRobert Watson #endif 973030a28b3SRobert Watson 974b1fc0ec1SRobert Watson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 975b1fc0ec1SRobert Watson rgid != oldcred->cr_svgid) || 976b1fc0ec1SRobert Watson (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] && 977b1fc0ec1SRobert Watson egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) && 97832f9753cSRobert Watson (error = priv_check_cred(oldcred, PRIV_CRED_SETREGID, 0)) != 0) 979030a28b3SRobert Watson goto fail; 98007f3485dSJohn Baldwin 981b1fc0ec1SRobert Watson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 982b1fc0ec1SRobert Watson change_egid(newcred, egid); 983d5f81602SSean Eric Fagan setsugid(p); 984a89a5370SPeter Wemm } 985b1fc0ec1SRobert Watson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 986b1fc0ec1SRobert Watson change_rgid(newcred, rgid); 987d5f81602SSean Eric Fagan setsugid(p); 988a89a5370SPeter Wemm } 989b1fc0ec1SRobert Watson if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) && 990b1fc0ec1SRobert Watson newcred->cr_svgid != newcred->cr_groups[0]) { 991b1fc0ec1SRobert Watson change_svgid(newcred, newcred->cr_groups[0]); 992d5f81602SSean Eric Fagan setsugid(p); 993a89a5370SPeter Wemm } 9944589be70SRuslan Ermilov p->p_ucred = newcred; 99507f3485dSJohn Baldwin PROC_UNLOCK(p); 9964589be70SRuslan Ermilov crfree(oldcred); 99707f3485dSJohn Baldwin return (0); 998030a28b3SRobert Watson 999030a28b3SRobert Watson fail: 1000030a28b3SRobert Watson PROC_UNLOCK(p); 1001030a28b3SRobert Watson crfree(newcred); 1002030a28b3SRobert Watson return (error); 1003df8bae1dSRodney W. Grimes } 1004df8bae1dSRodney W. Grimes 10058ccd6334SPeter Wemm /* 1006873fbcd7SRobert Watson * setresuid(ruid, euid, suid) is like setreuid except control over the saved 1007873fbcd7SRobert Watson * uid is explicit. 10088ccd6334SPeter Wemm */ 10098ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 10108ccd6334SPeter Wemm struct setresuid_args { 10118ccd6334SPeter Wemm uid_t ruid; 10128ccd6334SPeter Wemm uid_t euid; 10138ccd6334SPeter Wemm uid_t suid; 10148ccd6334SPeter Wemm }; 10158ccd6334SPeter Wemm #endif 10168ccd6334SPeter Wemm /* ARGSUSED */ 10178ccd6334SPeter Wemm int 1018*8451d0ddSKip Macy sys_setresuid(register struct thread *td, struct setresuid_args *uap) 10198ccd6334SPeter Wemm { 1020b40ce416SJulian Elischer struct proc *p = td->td_proc; 1021b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 1022eb725b4eSRobert Watson uid_t euid, ruid, suid; 10231419eacbSAlfred Perlstein struct uidinfo *euip, *ruip; 10248ccd6334SPeter Wemm int error; 10258ccd6334SPeter Wemm 10268ccd6334SPeter Wemm euid = uap->euid; 1027eb725b4eSRobert Watson ruid = uap->ruid; 10288ccd6334SPeter Wemm suid = uap->suid; 102914961ba7SRobert Watson AUDIT_ARG_EUID(euid); 103014961ba7SRobert Watson AUDIT_ARG_RUID(ruid); 103114961ba7SRobert Watson AUDIT_ARG_SUID(suid); 103207f3485dSJohn Baldwin newcred = crget(); 10331419eacbSAlfred Perlstein euip = uifind(euid); 10341419eacbSAlfred Perlstein ruip = uifind(ruid); 103507f3485dSJohn Baldwin PROC_LOCK(p); 1036838d9858SBrooks Davis oldcred = crcopysafe(p, newcred); 1037030a28b3SRobert Watson 1038030a28b3SRobert Watson #ifdef MAC 10396f6174a7SRobert Watson error = mac_cred_check_setresuid(oldcred, ruid, euid, suid); 1040030a28b3SRobert Watson if (error) 1041030a28b3SRobert Watson goto fail; 1042030a28b3SRobert Watson #endif 1043030a28b3SRobert Watson 1044b1fc0ec1SRobert Watson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 1045b1fc0ec1SRobert Watson ruid != oldcred->cr_svuid && 1046b1fc0ec1SRobert Watson ruid != oldcred->cr_uid) || 1047b1fc0ec1SRobert Watson (euid != (uid_t)-1 && euid != oldcred->cr_ruid && 1048b1fc0ec1SRobert Watson euid != oldcred->cr_svuid && 1049b1fc0ec1SRobert Watson euid != oldcred->cr_uid) || 1050b1fc0ec1SRobert Watson (suid != (uid_t)-1 && suid != oldcred->cr_ruid && 1051b1fc0ec1SRobert Watson suid != oldcred->cr_svuid && 1052b1fc0ec1SRobert Watson suid != oldcred->cr_uid)) && 105332f9753cSRobert Watson (error = priv_check_cred(oldcred, PRIV_CRED_SETRESUID, 0)) != 0) 1054030a28b3SRobert Watson goto fail; 105507f3485dSJohn Baldwin 1056b1fc0ec1SRobert Watson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 10571419eacbSAlfred Perlstein change_euid(newcred, euip); 10588ccd6334SPeter Wemm setsugid(p); 10598ccd6334SPeter Wemm } 1060b1fc0ec1SRobert Watson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 10611419eacbSAlfred Perlstein change_ruid(newcred, ruip); 10628ccd6334SPeter Wemm setsugid(p); 10638ccd6334SPeter Wemm } 1064b1fc0ec1SRobert Watson if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) { 1065b1fc0ec1SRobert Watson change_svuid(newcred, suid); 10668ccd6334SPeter Wemm setsugid(p); 10678ccd6334SPeter Wemm } 1068b1fc0ec1SRobert Watson p->p_ucred = newcred; 106907f3485dSJohn Baldwin PROC_UNLOCK(p); 1070e4dcb704SEdward Tomasz Napierala #ifdef RACCT 1071e4dcb704SEdward Tomasz Napierala racct_proc_ucred_changed(p, oldcred, newcred); 1072e4dcb704SEdward Tomasz Napierala #endif 10731419eacbSAlfred Perlstein uifree(ruip); 10741419eacbSAlfred Perlstein uifree(euip); 1075b1fc0ec1SRobert Watson crfree(oldcred); 107607f3485dSJohn Baldwin return (0); 1077030a28b3SRobert Watson 1078030a28b3SRobert Watson fail: 1079030a28b3SRobert Watson PROC_UNLOCK(p); 1080030a28b3SRobert Watson uifree(ruip); 1081030a28b3SRobert Watson uifree(euip); 1082030a28b3SRobert Watson crfree(newcred); 1083030a28b3SRobert Watson return (error); 1084030a28b3SRobert Watson 10858ccd6334SPeter Wemm } 10868ccd6334SPeter Wemm 10878ccd6334SPeter Wemm /* 1088873fbcd7SRobert Watson * setresgid(rgid, egid, sgid) is like setregid except control over the saved 1089873fbcd7SRobert Watson * gid is explicit. 10908ccd6334SPeter Wemm */ 10918ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 10928ccd6334SPeter Wemm struct setresgid_args { 10938ccd6334SPeter Wemm gid_t rgid; 10948ccd6334SPeter Wemm gid_t egid; 10958ccd6334SPeter Wemm gid_t sgid; 10968ccd6334SPeter Wemm }; 10978ccd6334SPeter Wemm #endif 10988ccd6334SPeter Wemm /* ARGSUSED */ 10998ccd6334SPeter Wemm int 1100*8451d0ddSKip Macy sys_setresgid(register struct thread *td, struct setresgid_args *uap) 11018ccd6334SPeter Wemm { 1102b40ce416SJulian Elischer struct proc *p = td->td_proc; 1103b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 1104eb725b4eSRobert Watson gid_t egid, rgid, sgid; 11058ccd6334SPeter Wemm int error; 11068ccd6334SPeter Wemm 11078ccd6334SPeter Wemm egid = uap->egid; 1108eb725b4eSRobert Watson rgid = uap->rgid; 11098ccd6334SPeter Wemm sgid = uap->sgid; 111014961ba7SRobert Watson AUDIT_ARG_EGID(egid); 111114961ba7SRobert Watson AUDIT_ARG_RGID(rgid); 111214961ba7SRobert Watson AUDIT_ARG_SGID(sgid); 111307f3485dSJohn Baldwin newcred = crget(); 111407f3485dSJohn Baldwin PROC_LOCK(p); 1115838d9858SBrooks Davis oldcred = crcopysafe(p, newcred); 1116030a28b3SRobert Watson 1117030a28b3SRobert Watson #ifdef MAC 11186f6174a7SRobert Watson error = mac_cred_check_setresgid(oldcred, rgid, egid, sgid); 1119030a28b3SRobert Watson if (error) 1120030a28b3SRobert Watson goto fail; 1121030a28b3SRobert Watson #endif 1122030a28b3SRobert Watson 1123b1fc0ec1SRobert Watson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 1124b1fc0ec1SRobert Watson rgid != oldcred->cr_svgid && 1125b1fc0ec1SRobert Watson rgid != oldcred->cr_groups[0]) || 1126b1fc0ec1SRobert Watson (egid != (gid_t)-1 && egid != oldcred->cr_rgid && 1127b1fc0ec1SRobert Watson egid != oldcred->cr_svgid && 1128b1fc0ec1SRobert Watson egid != oldcred->cr_groups[0]) || 1129b1fc0ec1SRobert Watson (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid && 1130b1fc0ec1SRobert Watson sgid != oldcred->cr_svgid && 1131b1fc0ec1SRobert Watson sgid != oldcred->cr_groups[0])) && 113232f9753cSRobert Watson (error = priv_check_cred(oldcred, PRIV_CRED_SETRESGID, 0)) != 0) 1133030a28b3SRobert Watson goto fail; 113407f3485dSJohn Baldwin 1135b1fc0ec1SRobert Watson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 1136b1fc0ec1SRobert Watson change_egid(newcred, egid); 11378ccd6334SPeter Wemm setsugid(p); 11388ccd6334SPeter Wemm } 1139b1fc0ec1SRobert Watson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 1140b1fc0ec1SRobert Watson change_rgid(newcred, rgid); 11418ccd6334SPeter Wemm setsugid(p); 11428ccd6334SPeter Wemm } 1143b1fc0ec1SRobert Watson if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) { 1144b1fc0ec1SRobert Watson change_svgid(newcred, sgid); 11458ccd6334SPeter Wemm setsugid(p); 11468ccd6334SPeter Wemm } 1147b1fc0ec1SRobert Watson p->p_ucred = newcred; 114807f3485dSJohn Baldwin PROC_UNLOCK(p); 1149b1fc0ec1SRobert Watson crfree(oldcred); 115007f3485dSJohn Baldwin return (0); 1151030a28b3SRobert Watson 1152030a28b3SRobert Watson fail: 1153030a28b3SRobert Watson PROC_UNLOCK(p); 1154030a28b3SRobert Watson crfree(newcred); 1155030a28b3SRobert Watson return (error); 11568ccd6334SPeter Wemm } 11578ccd6334SPeter Wemm 11588ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 11598ccd6334SPeter Wemm struct getresuid_args { 11608ccd6334SPeter Wemm uid_t *ruid; 11618ccd6334SPeter Wemm uid_t *euid; 11628ccd6334SPeter Wemm uid_t *suid; 11638ccd6334SPeter Wemm }; 11648ccd6334SPeter Wemm #endif 11658ccd6334SPeter Wemm /* ARGSUSED */ 11668ccd6334SPeter Wemm int 1167*8451d0ddSKip Macy sys_getresuid(register struct thread *td, struct getresuid_args *uap) 11688ccd6334SPeter Wemm { 1169835a82eeSMatthew Dillon struct ucred *cred; 11708ccd6334SPeter Wemm int error1 = 0, error2 = 0, error3 = 0; 11718ccd6334SPeter Wemm 1172d74ac681SMatthew Dillon cred = td->td_ucred; 11738ccd6334SPeter Wemm if (uap->ruid) 11747f05b035SAlfred Perlstein error1 = copyout(&cred->cr_ruid, 11757f05b035SAlfred Perlstein uap->ruid, sizeof(cred->cr_ruid)); 11768ccd6334SPeter Wemm if (uap->euid) 11777f05b035SAlfred Perlstein error2 = copyout(&cred->cr_uid, 11787f05b035SAlfred Perlstein uap->euid, sizeof(cred->cr_uid)); 11798ccd6334SPeter Wemm if (uap->suid) 11807f05b035SAlfred Perlstein error3 = copyout(&cred->cr_svuid, 11817f05b035SAlfred Perlstein uap->suid, sizeof(cred->cr_svuid)); 1182eb725b4eSRobert Watson return (error1 ? error1 : error2 ? error2 : error3); 11838ccd6334SPeter Wemm } 11848ccd6334SPeter Wemm 11858ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 11868ccd6334SPeter Wemm struct getresgid_args { 11878ccd6334SPeter Wemm gid_t *rgid; 11888ccd6334SPeter Wemm gid_t *egid; 11898ccd6334SPeter Wemm gid_t *sgid; 11908ccd6334SPeter Wemm }; 11918ccd6334SPeter Wemm #endif 11928ccd6334SPeter Wemm /* ARGSUSED */ 11938ccd6334SPeter Wemm int 1194*8451d0ddSKip Macy sys_getresgid(register struct thread *td, struct getresgid_args *uap) 11958ccd6334SPeter Wemm { 1196835a82eeSMatthew Dillon struct ucred *cred; 11978ccd6334SPeter Wemm int error1 = 0, error2 = 0, error3 = 0; 11988ccd6334SPeter Wemm 1199d74ac681SMatthew Dillon cred = td->td_ucred; 12008ccd6334SPeter Wemm if (uap->rgid) 12017f05b035SAlfred Perlstein error1 = copyout(&cred->cr_rgid, 12027f05b035SAlfred Perlstein uap->rgid, sizeof(cred->cr_rgid)); 12038ccd6334SPeter Wemm if (uap->egid) 12047f05b035SAlfred Perlstein error2 = copyout(&cred->cr_groups[0], 12057f05b035SAlfred Perlstein uap->egid, sizeof(cred->cr_groups[0])); 12068ccd6334SPeter Wemm if (uap->sgid) 12077f05b035SAlfred Perlstein error3 = copyout(&cred->cr_svgid, 12087f05b035SAlfred Perlstein uap->sgid, sizeof(cred->cr_svgid)); 1209eb725b4eSRobert Watson return (error1 ? error1 : error2 ? error2 : error3); 12108ccd6334SPeter Wemm } 12118ccd6334SPeter Wemm 1212b67cbc65SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1213b67cbc65SPeter Wemm struct issetugid_args { 1214b67cbc65SPeter Wemm int dummy; 1215b67cbc65SPeter Wemm }; 1216b67cbc65SPeter Wemm #endif 1217b67cbc65SPeter Wemm /* ARGSUSED */ 1218b67cbc65SPeter Wemm int 1219*8451d0ddSKip Macy sys_issetugid(register struct thread *td, struct issetugid_args *uap) 1220b67cbc65SPeter Wemm { 1221b40ce416SJulian Elischer struct proc *p = td->td_proc; 1222b40ce416SJulian Elischer 1223b67cbc65SPeter Wemm /* 1224b67cbc65SPeter Wemm * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 1225b67cbc65SPeter Wemm * we use P_SUGID because we consider changing the owners as 1226b67cbc65SPeter Wemm * "tainting" as well. 1227b67cbc65SPeter Wemm * This is significant for procs that start as root and "become" 1228b67cbc65SPeter Wemm * a user without an exec - programs cannot know *everything* 1229b67cbc65SPeter Wemm * that libc *might* have put in their data segment. 1230b67cbc65SPeter Wemm */ 1231f591779bSSeigo Tanimura PROC_LOCK(p); 1232b40ce416SJulian Elischer td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 1233f591779bSSeigo Tanimura PROC_UNLOCK(p); 1234b67cbc65SPeter Wemm return (0); 1235b67cbc65SPeter Wemm } 1236b67cbc65SPeter Wemm 1237130d0157SRobert Watson int 1238*8451d0ddSKip Macy sys___setugid(struct thread *td, struct __setugid_args *uap) 1239130d0157SRobert Watson { 1240130d0157SRobert Watson #ifdef REGRESSION 124107f3485dSJohn Baldwin struct proc *p; 1242835a82eeSMatthew Dillon 124307f3485dSJohn Baldwin p = td->td_proc; 1244130d0157SRobert Watson switch (uap->flag) { 1245130d0157SRobert Watson case 0: 124607f3485dSJohn Baldwin PROC_LOCK(p); 124707f3485dSJohn Baldwin p->p_flag &= ~P_SUGID; 124807f3485dSJohn Baldwin PROC_UNLOCK(p); 124907f3485dSJohn Baldwin return (0); 125007f3485dSJohn Baldwin case 1: 125107f3485dSJohn Baldwin PROC_LOCK(p); 125207f3485dSJohn Baldwin p->p_flag |= P_SUGID; 125307f3485dSJohn Baldwin PROC_UNLOCK(p); 125407f3485dSJohn Baldwin return (0); 125507f3485dSJohn Baldwin default: 125607f3485dSJohn Baldwin return (EINVAL); 125707f3485dSJohn Baldwin } 1258130d0157SRobert Watson #else /* !REGRESSION */ 1259eb725b4eSRobert Watson 1260130d0157SRobert Watson return (ENOSYS); 1261eb725b4eSRobert Watson #endif /* REGRESSION */ 1262130d0157SRobert Watson } 1263130d0157SRobert Watson 1264df8bae1dSRodney W. Grimes /* 1265df8bae1dSRodney W. Grimes * Check if gid is a member of the group set. 1266df8bae1dSRodney W. Grimes */ 126726f9a767SRodney W. Grimes int 12684c44ad8eSJohn Baldwin groupmember(gid_t gid, struct ucred *cred) 1269df8bae1dSRodney W. Grimes { 12707f92e578SBrooks Davis int l; 12717f92e578SBrooks Davis int h; 12727f92e578SBrooks Davis int m; 1273df8bae1dSRodney W. Grimes 12747f92e578SBrooks Davis if (cred->cr_groups[0] == gid) 1275df8bae1dSRodney W. Grimes return(1); 12767f92e578SBrooks Davis 12777f92e578SBrooks Davis /* 12787f92e578SBrooks Davis * If gid was not our primary group, perform a binary search 12797f92e578SBrooks Davis * of the supplemental groups. This is possible because we 12807f92e578SBrooks Davis * sort the groups in crsetgroups(). 12817f92e578SBrooks Davis */ 12827f92e578SBrooks Davis l = 1; 12837f92e578SBrooks Davis h = cred->cr_ngroups; 12847f92e578SBrooks Davis while (l < h) { 12857f92e578SBrooks Davis m = l + ((h - l) / 2); 12867f92e578SBrooks Davis if (cred->cr_groups[m] < gid) 12877f92e578SBrooks Davis l = m + 1; 12887f92e578SBrooks Davis else 12897f92e578SBrooks Davis h = m; 12907f92e578SBrooks Davis } 12917f92e578SBrooks Davis if ((l < cred->cr_ngroups) && (cred->cr_groups[l] == gid)) 12927f92e578SBrooks Davis return (1); 12937f92e578SBrooks Davis 1294df8bae1dSRodney W. Grimes return (0); 1295df8bae1dSRodney W. Grimes } 1296df8bae1dSRodney W. Grimes 12973b243b72SRobert Watson /* 1298eb725b4eSRobert Watson * Test the active securelevel against a given level. securelevel_gt() 1299eb725b4eSRobert Watson * implements (securelevel > level). securelevel_ge() implements 1300eb725b4eSRobert Watson * (securelevel >= level). Note that the logic is inverted -- these 1301eb725b4eSRobert Watson * functions return EPERM on "success" and 0 on "failure". 13023ca719f1SRobert Watson * 13030304c731SJamie Gritton * Due to care taken when setting the securelevel, we know that no jail will 13040304c731SJamie Gritton * be less secure that its parent (or the physical system), so it is sufficient 13050304c731SJamie Gritton * to test the current jail only. 13060304c731SJamie Gritton * 1307800c9408SRobert Watson * XXXRW: Possibly since this has to do with privilege, it should move to 1308800c9408SRobert Watson * kern_priv.c. 13093ca719f1SRobert Watson */ 13103ca719f1SRobert Watson int 13113ca719f1SRobert Watson securelevel_gt(struct ucred *cr, int level) 13123ca719f1SRobert Watson { 13133ca719f1SRobert Watson 13140304c731SJamie Gritton return (cr->cr_prison->pr_securelevel > level ? EPERM : 0); 13153ca719f1SRobert Watson } 13163ca719f1SRobert Watson 13173ca719f1SRobert Watson int 13183ca719f1SRobert Watson securelevel_ge(struct ucred *cr, int level) 13193ca719f1SRobert Watson { 13203ca719f1SRobert Watson 13210304c731SJamie Gritton return (cr->cr_prison->pr_securelevel >= level ? EPERM : 0); 13223ca719f1SRobert Watson } 13233ca719f1SRobert Watson 13248a7d8cc6SRobert Watson /* 1325e409590dSRobert Watson * 'see_other_uids' determines whether or not visibility of processes 1326eb725b4eSRobert Watson * and sockets with credentials holding different real uids is possible 132748713bdcSRobert Watson * using a variety of system MIBs. 1328eb725b4eSRobert Watson * XXX: data declarations should be together near the beginning of the file. 13298a7d8cc6SRobert Watson */ 1330e409590dSRobert Watson static int see_other_uids = 1; 1331d0615c64SAndrew R. Reiter SYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW, 1332eb725b4eSRobert Watson &see_other_uids, 0, 13338a7d8cc6SRobert Watson "Unprivileged processes may see subjects/objects with different real uid"); 13348a7d8cc6SRobert Watson 13351a996ed1SEdward Tomasz Napierala /*- 13361b350b45SRobert Watson * Determine if u1 "can see" the subject specified by u2, according to the 13371b350b45SRobert Watson * 'see_other_uids' policy. 13381b350b45SRobert Watson * Returns: 0 for permitted, ESRCH otherwise 13391b350b45SRobert Watson * Locks: none 13401b350b45SRobert Watson * References: *u1 and *u2 must not change during the call 13411b350b45SRobert Watson * u1 may equal u2, in which case only one reference is required 13421b350b45SRobert Watson */ 13431b350b45SRobert Watson static int 13441b350b45SRobert Watson cr_seeotheruids(struct ucred *u1, struct ucred *u2) 13451b350b45SRobert Watson { 13461b350b45SRobert Watson 13471b350b45SRobert Watson if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) { 134832f9753cSRobert Watson if (priv_check_cred(u1, PRIV_SEEOTHERUIDS, 0) != 0) 13491b350b45SRobert Watson return (ESRCH); 13501b350b45SRobert Watson } 13511b350b45SRobert Watson return (0); 13521b350b45SRobert Watson } 13531b350b45SRobert Watson 135464d19c2eSRobert Watson /* 135564d19c2eSRobert Watson * 'see_other_gids' determines whether or not visibility of processes 135664d19c2eSRobert Watson * and sockets with credentials holding different real gids is possible 135764d19c2eSRobert Watson * using a variety of system MIBs. 135864d19c2eSRobert Watson * XXX: data declarations should be together near the beginning of the file. 135964d19c2eSRobert Watson */ 136064d19c2eSRobert Watson static int see_other_gids = 1; 136164d19c2eSRobert Watson SYSCTL_INT(_security_bsd, OID_AUTO, see_other_gids, CTLFLAG_RW, 136264d19c2eSRobert Watson &see_other_gids, 0, 136364d19c2eSRobert Watson "Unprivileged processes may see subjects/objects with different real gid"); 136464d19c2eSRobert Watson 136564d19c2eSRobert Watson /* 136664d19c2eSRobert Watson * Determine if u1 can "see" the subject specified by u2, according to the 136764d19c2eSRobert Watson * 'see_other_gids' policy. 136864d19c2eSRobert Watson * Returns: 0 for permitted, ESRCH otherwise 136964d19c2eSRobert Watson * Locks: none 137064d19c2eSRobert Watson * References: *u1 and *u2 must not change during the call 137164d19c2eSRobert Watson * u1 may equal u2, in which case only one reference is required 137264d19c2eSRobert Watson */ 137364d19c2eSRobert Watson static int 137464d19c2eSRobert Watson cr_seeothergids(struct ucred *u1, struct ucred *u2) 137564d19c2eSRobert Watson { 137664d19c2eSRobert Watson int i, match; 137764d19c2eSRobert Watson 137864d19c2eSRobert Watson if (!see_other_gids) { 137964d19c2eSRobert Watson match = 0; 138064d19c2eSRobert Watson for (i = 0; i < u1->cr_ngroups; i++) { 138164d19c2eSRobert Watson if (groupmember(u1->cr_groups[i], u2)) 138264d19c2eSRobert Watson match = 1; 138364d19c2eSRobert Watson if (match) 138464d19c2eSRobert Watson break; 138564d19c2eSRobert Watson } 138664d19c2eSRobert Watson if (!match) { 138732f9753cSRobert Watson if (priv_check_cred(u1, PRIV_SEEOTHERGIDS, 0) != 0) 138864d19c2eSRobert Watson return (ESRCH); 138964d19c2eSRobert Watson } 139064d19c2eSRobert Watson } 139164d19c2eSRobert Watson return (0); 139264d19c2eSRobert Watson } 139364d19c2eSRobert Watson 13941a996ed1SEdward Tomasz Napierala /*- 13957fd6a959SRobert Watson * Determine if u1 "can see" the subject specified by u2. 1396ed639720SRobert Watson * Returns: 0 for permitted, an errno value otherwise 1397ed639720SRobert Watson * Locks: none 1398eb725b4eSRobert Watson * References: *u1 and *u2 must not change during the call 1399ed639720SRobert Watson * u1 may equal u2, in which case only one reference is required 1400ed639720SRobert Watson */ 1401ed639720SRobert Watson int 140294088977SRobert Watson cr_cansee(struct ucred *u1, struct ucred *u2) 1403a9e0361bSPoul-Henning Kamp { 140491421ba2SRobert Watson int error; 1405a9e0361bSPoul-Henning Kamp 1406ed639720SRobert Watson if ((error = prison_check(u1, u2))) 140791421ba2SRobert Watson return (error); 14088a1d977dSRobert Watson #ifdef MAC 140930d239bcSRobert Watson if ((error = mac_cred_check_visible(u1, u2))) 14108a1d977dSRobert Watson return (error); 14118a1d977dSRobert Watson #endif 14121b350b45SRobert Watson if ((error = cr_seeotheruids(u1, u2))) 14131b350b45SRobert Watson return (error); 141464d19c2eSRobert Watson if ((error = cr_seeothergids(u1, u2))) 141564d19c2eSRobert Watson return (error); 1416387d2c03SRobert Watson return (0); 1417387d2c03SRobert Watson } 1418387d2c03SRobert Watson 14191a996ed1SEdward Tomasz Napierala /*- 1420f44d9e24SJohn Baldwin * Determine if td "can see" the subject specified by p. 14213b243b72SRobert Watson * Returns: 0 for permitted, an errno value otherwise 1422f44d9e24SJohn Baldwin * Locks: Sufficient locks to protect p->p_ucred must be held. td really 1423f44d9e24SJohn Baldwin * should be curthread. 1424f44d9e24SJohn Baldwin * References: td and p must be valid for the lifetime of the call 14253b243b72SRobert Watson */ 1426a0f75161SRobert Watson int 1427f44d9e24SJohn Baldwin p_cansee(struct thread *td, struct proc *p) 1428ed639720SRobert Watson { 1429ed639720SRobert Watson 143094088977SRobert Watson /* Wrap cr_cansee() for all functionality. */ 1431f44d9e24SJohn Baldwin KASSERT(td == curthread, ("%s: td not curthread", __func__)); 1432f44d9e24SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 1433f44d9e24SJohn Baldwin return (cr_cansee(td->td_ucred, p->p_ucred)); 1434ed639720SRobert Watson } 1435ed639720SRobert Watson 143662c45ef4SRobert Watson /* 143762c45ef4SRobert Watson * 'conservative_signals' prevents the delivery of a broad class of 143862c45ef4SRobert Watson * signals by unprivileged processes to processes that have changed their 143962c45ef4SRobert Watson * credentials since the last invocation of execve(). This can prevent 144062c45ef4SRobert Watson * the leakage of cached information or retained privileges as a result 144162c45ef4SRobert Watson * of a common class of signal-related vulnerabilities. However, this 144262c45ef4SRobert Watson * may interfere with some applications that expect to be able to 144362c45ef4SRobert Watson * deliver these signals to peer processes after having given up 144462c45ef4SRobert Watson * privilege. 144562c45ef4SRobert Watson */ 144662c45ef4SRobert Watson static int conservative_signals = 1; 144762c45ef4SRobert Watson SYSCTL_INT(_security_bsd, OID_AUTO, conservative_signals, CTLFLAG_RW, 144862c45ef4SRobert Watson &conservative_signals, 0, "Unprivileged processes prevented from " 144962c45ef4SRobert Watson "sending certain signals to processes whose credentials have changed"); 14501a996ed1SEdward Tomasz Napierala /*- 1451c83f8015SRobert Watson * Determine whether cred may deliver the specified signal to proc. 1452c83f8015SRobert Watson * Returns: 0 for permitted, an errno value otherwise. 1453c83f8015SRobert Watson * Locks: A lock must be held for proc. 1454c83f8015SRobert Watson * References: cred and proc must be valid for the lifetime of the call. 14554c5eb9c3SRobert Watson */ 14564c5eb9c3SRobert Watson int 14571a88a252SMaxim Sobolev cr_cansignal(struct ucred *cred, struct proc *proc, int signum) 1458387d2c03SRobert Watson { 145991421ba2SRobert Watson int error; 1460387d2c03SRobert Watson 1461f44d9e24SJohn Baldwin PROC_LOCK_ASSERT(proc, MA_OWNED); 14624c5eb9c3SRobert Watson /* 1463c83f8015SRobert Watson * Jail semantics limit the scope of signalling to proc in the 1464c83f8015SRobert Watson * same jail as cred, if cred is in jail. 14654c5eb9c3SRobert Watson */ 1466c83f8015SRobert Watson error = prison_check(cred, proc->p_ucred); 1467c83f8015SRobert Watson if (error) 146891421ba2SRobert Watson return (error); 14698a1d977dSRobert Watson #ifdef MAC 147030d239bcSRobert Watson if ((error = mac_proc_check_signal(cred, proc, signum))) 14718a1d977dSRobert Watson return (error); 14728a1d977dSRobert Watson #endif 147364d19c2eSRobert Watson if ((error = cr_seeotheruids(cred, proc->p_ucred))) 147464d19c2eSRobert Watson return (error); 147564d19c2eSRobert Watson if ((error = cr_seeothergids(cred, proc->p_ucred))) 14761b350b45SRobert Watson return (error); 1477387d2c03SRobert Watson 1478387d2c03SRobert Watson /* 14793b243b72SRobert Watson * UNIX signal semantics depend on the status of the P_SUGID 14803b243b72SRobert Watson * bit on the target process. If the bit is set, then additional 14813b243b72SRobert Watson * restrictions are placed on the set of available signals. 14824c5eb9c3SRobert Watson */ 14831a88a252SMaxim Sobolev if (conservative_signals && (proc->p_flag & P_SUGID)) { 14844c5eb9c3SRobert Watson switch (signum) { 14854c5eb9c3SRobert Watson case 0: 14864c5eb9c3SRobert Watson case SIGKILL: 14874c5eb9c3SRobert Watson case SIGINT: 14884c5eb9c3SRobert Watson case SIGTERM: 148962c45ef4SRobert Watson case SIGALRM: 14904c5eb9c3SRobert Watson case SIGSTOP: 14914c5eb9c3SRobert Watson case SIGTTIN: 14924c5eb9c3SRobert Watson case SIGTTOU: 14934c5eb9c3SRobert Watson case SIGTSTP: 14944c5eb9c3SRobert Watson case SIGHUP: 14954c5eb9c3SRobert Watson case SIGUSR1: 14964c5eb9c3SRobert Watson case SIGUSR2: 14977fd6a959SRobert Watson /* 14987fd6a959SRobert Watson * Generally, permit job and terminal control 14997fd6a959SRobert Watson * signals. 15007fd6a959SRobert Watson */ 15014c5eb9c3SRobert Watson break; 15024c5eb9c3SRobert Watson default: 1503c83f8015SRobert Watson /* Not permitted without privilege. */ 150432f9753cSRobert Watson error = priv_check_cred(cred, PRIV_SIGNAL_SUGID, 0); 15054c5eb9c3SRobert Watson if (error) 15064c5eb9c3SRobert Watson return (error); 15074c5eb9c3SRobert Watson } 1508e9e7ff5bSRobert Watson } 1509e9e7ff5bSRobert Watson 15104c5eb9c3SRobert Watson /* 15113b243b72SRobert Watson * Generally, the target credential's ruid or svuid must match the 1512e9e7ff5bSRobert Watson * subject credential's ruid or euid. 15134c5eb9c3SRobert Watson */ 1514c83f8015SRobert Watson if (cred->cr_ruid != proc->p_ucred->cr_ruid && 1515c83f8015SRobert Watson cred->cr_ruid != proc->p_ucred->cr_svuid && 1516c83f8015SRobert Watson cred->cr_uid != proc->p_ucred->cr_ruid && 1517c83f8015SRobert Watson cred->cr_uid != proc->p_ucred->cr_svuid) { 151832f9753cSRobert Watson error = priv_check_cred(cred, PRIV_SIGNAL_DIFFCRED, 0); 15194c5eb9c3SRobert Watson if (error) 15204c5eb9c3SRobert Watson return (error); 15214c5eb9c3SRobert Watson } 1522387d2c03SRobert Watson 1523387d2c03SRobert Watson return (0); 1524387d2c03SRobert Watson } 1525a9e0361bSPoul-Henning Kamp 15261a996ed1SEdward Tomasz Napierala /*- 1527f44d9e24SJohn Baldwin * Determine whether td may deliver the specified signal to p. 1528c83f8015SRobert Watson * Returns: 0 for permitted, an errno value otherwise 1529f44d9e24SJohn Baldwin * Locks: Sufficient locks to protect various components of td and p 1530f44d9e24SJohn Baldwin * must be held. td must be curthread, and a lock must be 1531f44d9e24SJohn Baldwin * held for p. 1532f44d9e24SJohn Baldwin * References: td and p must be valid for the lifetime of the call 1533c83f8015SRobert Watson */ 1534c83f8015SRobert Watson int 15351a88a252SMaxim Sobolev p_cansignal(struct thread *td, struct proc *p, int signum) 1536c83f8015SRobert Watson { 1537c83f8015SRobert Watson 1538f44d9e24SJohn Baldwin KASSERT(td == curthread, ("%s: td not curthread", __func__)); 1539f44d9e24SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 1540f44d9e24SJohn Baldwin if (td->td_proc == p) 1541c83f8015SRobert Watson return (0); 1542c83f8015SRobert Watson 1543c83f8015SRobert Watson /* 1544c83f8015SRobert Watson * UNIX signalling semantics require that processes in the same 1545c83f8015SRobert Watson * session always be able to deliver SIGCONT to one another, 1546c83f8015SRobert Watson * overriding the remaining protections. 1547c83f8015SRobert Watson */ 1548f44d9e24SJohn Baldwin /* XXX: This will require an additional lock of some sort. */ 1549f44d9e24SJohn Baldwin if (signum == SIGCONT && td->td_proc->p_session == p->p_session) 1550c83f8015SRobert Watson return (0); 15514b178336SMaxim Sobolev /* 1552f9cd63d4SMaxim Sobolev * Some compat layers use SIGTHR and higher signals for 1553f9cd63d4SMaxim Sobolev * communication between different kernel threads of the same 1554f9cd63d4SMaxim Sobolev * process, so that they expect that it's always possible to 1555f9cd63d4SMaxim Sobolev * deliver them, even for suid applications where cr_cansignal() can 15564b178336SMaxim Sobolev * deny such ability for security consideration. It should be 15574b178336SMaxim Sobolev * pretty safe to do since the only way to create two processes 15584b178336SMaxim Sobolev * with the same p_leader is via rfork(2). 15594b178336SMaxim Sobolev */ 15602322a0a7SMaxim Sobolev if (td->td_proc->p_leader != NULL && signum >= SIGTHR && 15612322a0a7SMaxim Sobolev signum < SIGTHR + 4 && td->td_proc->p_leader == p->p_leader) 15624b178336SMaxim Sobolev return (0); 1563c83f8015SRobert Watson 15641a88a252SMaxim Sobolev return (cr_cansignal(td->td_ucred, p, signum)); 1565c83f8015SRobert Watson } 1566c83f8015SRobert Watson 15671a996ed1SEdward Tomasz Napierala /*- 1568f44d9e24SJohn Baldwin * Determine whether td may reschedule p. 15697fd6a959SRobert Watson * Returns: 0 for permitted, an errno value otherwise 1570f44d9e24SJohn Baldwin * Locks: Sufficient locks to protect various components of td and p 1571f44d9e24SJohn Baldwin * must be held. td must be curthread, and a lock must 1572f44d9e24SJohn Baldwin * be held for p. 1573f44d9e24SJohn Baldwin * References: td and p must be valid for the lifetime of the call 15743b243b72SRobert Watson */ 1575a0f75161SRobert Watson int 1576f44d9e24SJohn Baldwin p_cansched(struct thread *td, struct proc *p) 1577387d2c03SRobert Watson { 157891421ba2SRobert Watson int error; 1579387d2c03SRobert Watson 1580f44d9e24SJohn Baldwin KASSERT(td == curthread, ("%s: td not curthread", __func__)); 1581f44d9e24SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 1582f44d9e24SJohn Baldwin if (td->td_proc == p) 1583387d2c03SRobert Watson return (0); 1584f44d9e24SJohn Baldwin if ((error = prison_check(td->td_ucred, p->p_ucred))) 158591421ba2SRobert Watson return (error); 15868a1d977dSRobert Watson #ifdef MAC 158730d239bcSRobert Watson if ((error = mac_proc_check_sched(td->td_ucred, p))) 15888a1d977dSRobert Watson return (error); 15898a1d977dSRobert Watson #endif 1590f44d9e24SJohn Baldwin if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) 15911b350b45SRobert Watson return (error); 159264d19c2eSRobert Watson if ((error = cr_seeothergids(td->td_ucred, p->p_ucred))) 159364d19c2eSRobert Watson return (error); 1594800c9408SRobert Watson if (td->td_ucred->cr_ruid != p->p_ucred->cr_ruid && 1595800c9408SRobert Watson td->td_ucred->cr_uid != p->p_ucred->cr_ruid) { 159632f9753cSRobert Watson error = priv_check(td, PRIV_SCHED_DIFFCRED); 1597800c9408SRobert Watson if (error) 1598800c9408SRobert Watson return (error); 1599800c9408SRobert Watson } 1600387d2c03SRobert Watson return (0); 1601387d2c03SRobert Watson } 1602387d2c03SRobert Watson 16033b243b72SRobert Watson /* 16045d476e73SRobert Watson * The 'unprivileged_proc_debug' flag may be used to disable a variety of 16055d476e73SRobert Watson * unprivileged inter-process debugging services, including some procfs 16065d476e73SRobert Watson * functionality, ptrace(), and ktrace(). In the past, inter-process 16075d476e73SRobert Watson * debugging has been involved in a variety of security problems, and sites 16085d476e73SRobert Watson * not requiring the service might choose to disable it when hardening 16095d476e73SRobert Watson * systems. 16103b243b72SRobert Watson * 16113b243b72SRobert Watson * XXX: Should modifying and reading this variable require locking? 1612eb725b4eSRobert Watson * XXX: data declarations should be together near the beginning of the file. 16133b243b72SRobert Watson */ 1614e409590dSRobert Watson static int unprivileged_proc_debug = 1; 1615d0615c64SAndrew R. Reiter SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW, 1616eb725b4eSRobert Watson &unprivileged_proc_debug, 0, 16170ef5652eSRobert Watson "Unprivileged processes may use process debugging facilities"); 16180ef5652eSRobert Watson 16191a996ed1SEdward Tomasz Napierala /*- 1620f44d9e24SJohn Baldwin * Determine whether td may debug p. 16217fd6a959SRobert Watson * Returns: 0 for permitted, an errno value otherwise 1622f44d9e24SJohn Baldwin * Locks: Sufficient locks to protect various components of td and p 1623f44d9e24SJohn Baldwin * must be held. td must be curthread, and a lock must 1624f44d9e24SJohn Baldwin * be held for p. 1625f44d9e24SJohn Baldwin * References: td and p must be valid for the lifetime of the call 16263b243b72SRobert Watson */ 1627a0f75161SRobert Watson int 1628f44d9e24SJohn Baldwin p_candebug(struct thread *td, struct proc *p) 1629387d2c03SRobert Watson { 1630eb725b4eSRobert Watson int credentialchanged, error, grpsubset, i, uidsubset; 1631387d2c03SRobert Watson 1632f44d9e24SJohn Baldwin KASSERT(td == curthread, ("%s: td not curthread", __func__)); 1633f44d9e24SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 1634e409590dSRobert Watson if (!unprivileged_proc_debug) { 163532f9753cSRobert Watson error = priv_check(td, PRIV_DEBUG_UNPRIV); 163632d18604SRobert Watson if (error) 163732d18604SRobert Watson return (error); 163832d18604SRobert Watson } 1639f44d9e24SJohn Baldwin if (td->td_proc == p) 164023fad5b6SDag-Erling Smørgrav return (0); 1641f44d9e24SJohn Baldwin if ((error = prison_check(td->td_ucred, p->p_ucred))) 164291421ba2SRobert Watson return (error); 16438a1d977dSRobert Watson #ifdef MAC 164430d239bcSRobert Watson if ((error = mac_proc_check_debug(td->td_ucred, p))) 16458a1d977dSRobert Watson return (error); 16468a1d977dSRobert Watson #endif 1647f44d9e24SJohn Baldwin if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) 16481b350b45SRobert Watson return (error); 164964d19c2eSRobert Watson if ((error = cr_seeothergids(td->td_ucred, p->p_ucred))) 165064d19c2eSRobert Watson return (error); 1651387d2c03SRobert Watson 16527fd6a959SRobert Watson /* 1653f44d9e24SJohn Baldwin * Is p's group set a subset of td's effective group set? This 1654f44d9e24SJohn Baldwin * includes p's egid, group access list, rgid, and svgid. 16557fd6a959SRobert Watson */ 1656db42a33dSRobert Watson grpsubset = 1; 1657f44d9e24SJohn Baldwin for (i = 0; i < p->p_ucred->cr_ngroups; i++) { 1658f44d9e24SJohn Baldwin if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) { 1659db42a33dSRobert Watson grpsubset = 0; 1660db42a33dSRobert Watson break; 1661db42a33dSRobert Watson } 1662db42a33dSRobert Watson } 1663db42a33dSRobert Watson grpsubset = grpsubset && 1664f44d9e24SJohn Baldwin groupmember(p->p_ucred->cr_rgid, td->td_ucred) && 1665f44d9e24SJohn Baldwin groupmember(p->p_ucred->cr_svgid, td->td_ucred); 1666db42a33dSRobert Watson 1667db42a33dSRobert Watson /* 1668f44d9e24SJohn Baldwin * Are the uids present in p's credential equal to td's 1669f44d9e24SJohn Baldwin * effective uid? This includes p's euid, svuid, and ruid. 1670db42a33dSRobert Watson */ 1671f44d9e24SJohn Baldwin uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid && 1672f44d9e24SJohn Baldwin td->td_ucred->cr_uid == p->p_ucred->cr_svuid && 1673f44d9e24SJohn Baldwin td->td_ucred->cr_uid == p->p_ucred->cr_ruid); 1674db42a33dSRobert Watson 1675db42a33dSRobert Watson /* 1676db42a33dSRobert Watson * Has the credential of the process changed since the last exec()? 1677db42a33dSRobert Watson */ 1678f44d9e24SJohn Baldwin credentialchanged = (p->p_flag & P_SUGID); 1679db42a33dSRobert Watson 1680db42a33dSRobert Watson /* 1681f44d9e24SJohn Baldwin * If p's gids aren't a subset, or the uids aren't a subset, 1682db42a33dSRobert Watson * or the credential has changed, require appropriate privilege 1683800c9408SRobert Watson * for td to debug p. 1684db42a33dSRobert Watson */ 1685800c9408SRobert Watson if (!grpsubset || !uidsubset) { 168632f9753cSRobert Watson error = priv_check(td, PRIV_DEBUG_DIFFCRED); 1687800c9408SRobert Watson if (error) 1688800c9408SRobert Watson return (error); 1689800c9408SRobert Watson } 1690800c9408SRobert Watson 1691800c9408SRobert Watson if (credentialchanged) { 169232f9753cSRobert Watson error = priv_check(td, PRIV_DEBUG_SUGID); 169332d18604SRobert Watson if (error) 1694387d2c03SRobert Watson return (error); 16957fd6a959SRobert Watson } 1696387d2c03SRobert Watson 1697eb725b4eSRobert Watson /* Can't trace init when securelevel > 0. */ 1698f44d9e24SJohn Baldwin if (p == initproc) { 1699f44d9e24SJohn Baldwin error = securelevel_gt(td->td_ucred, 0); 17003ca719f1SRobert Watson if (error) 17013ca719f1SRobert Watson return (error); 17023ca719f1SRobert Watson } 1703387d2c03SRobert Watson 17045fab7614SRobert Watson /* 17055fab7614SRobert Watson * Can't trace a process that's currently exec'ing. 1706800c9408SRobert Watson * 17075fab7614SRobert Watson * XXX: Note, this is not a security policy decision, it's a 17085fab7614SRobert Watson * basic correctness/functionality decision. Therefore, this check 17095fab7614SRobert Watson * should be moved to the caller's of p_candebug(). 17105fab7614SRobert Watson */ 1711f44d9e24SJohn Baldwin if ((p->p_flag & P_INEXEC) != 0) 1712af80b2c9SKonstantin Belousov return (EBUSY); 17139ca45e81SDag-Erling Smørgrav 1714387d2c03SRobert Watson return (0); 1715387d2c03SRobert Watson } 1716387d2c03SRobert Watson 17171a996ed1SEdward Tomasz Napierala /*- 171829dc1288SRobert Watson * Determine whether the subject represented by cred can "see" a socket. 171929dc1288SRobert Watson * Returns: 0 for permitted, ENOENT otherwise. 172029dc1288SRobert Watson */ 172129dc1288SRobert Watson int 172229dc1288SRobert Watson cr_canseesocket(struct ucred *cred, struct socket *so) 172329dc1288SRobert Watson { 172429dc1288SRobert Watson int error; 172529dc1288SRobert Watson 172629dc1288SRobert Watson error = prison_check(cred, so->so_cred); 172729dc1288SRobert Watson if (error) 172829dc1288SRobert Watson return (ENOENT); 17298a1d977dSRobert Watson #ifdef MAC 173030d239bcSRobert Watson error = mac_socket_check_visible(cred, so); 17318a1d977dSRobert Watson if (error) 17328a1d977dSRobert Watson return (error); 17338a1d977dSRobert Watson #endif 173429dc1288SRobert Watson if (cr_seeotheruids(cred, so->so_cred)) 173529dc1288SRobert Watson return (ENOENT); 173664d19c2eSRobert Watson if (cr_seeothergids(cred, so->so_cred)) 173764d19c2eSRobert Watson return (ENOENT); 173829dc1288SRobert Watson 173929dc1288SRobert Watson return (0); 174029dc1288SRobert Watson } 174129dc1288SRobert Watson 1742f08ef6c5SBjoern A. Zeeb #if defined(INET) || defined(INET6) 17431a996ed1SEdward Tomasz Napierala /*- 1744f08ef6c5SBjoern A. Zeeb * Determine whether the subject represented by cred can "see" a socket. 1745f08ef6c5SBjoern A. Zeeb * Returns: 0 for permitted, ENOENT otherwise. 1746f08ef6c5SBjoern A. Zeeb */ 1747f08ef6c5SBjoern A. Zeeb int 1748f08ef6c5SBjoern A. Zeeb cr_canseeinpcb(struct ucred *cred, struct inpcb *inp) 1749f08ef6c5SBjoern A. Zeeb { 1750f08ef6c5SBjoern A. Zeeb int error; 1751f08ef6c5SBjoern A. Zeeb 1752f08ef6c5SBjoern A. Zeeb error = prison_check(cred, inp->inp_cred); 1753f08ef6c5SBjoern A. Zeeb if (error) 1754f08ef6c5SBjoern A. Zeeb return (ENOENT); 1755f08ef6c5SBjoern A. Zeeb #ifdef MAC 1756f08ef6c5SBjoern A. Zeeb INP_LOCK_ASSERT(inp); 1757f08ef6c5SBjoern A. Zeeb error = mac_inpcb_check_visible(cred, inp); 1758f08ef6c5SBjoern A. Zeeb if (error) 1759f08ef6c5SBjoern A. Zeeb return (error); 1760f08ef6c5SBjoern A. Zeeb #endif 1761f08ef6c5SBjoern A. Zeeb if (cr_seeotheruids(cred, inp->inp_cred)) 1762f08ef6c5SBjoern A. Zeeb return (ENOENT); 1763f08ef6c5SBjoern A. Zeeb if (cr_seeothergids(cred, inp->inp_cred)) 1764f08ef6c5SBjoern A. Zeeb return (ENOENT); 1765f08ef6c5SBjoern A. Zeeb 1766f08ef6c5SBjoern A. Zeeb return (0); 1767f08ef6c5SBjoern A. Zeeb } 1768f08ef6c5SBjoern A. Zeeb #endif 1769f08ef6c5SBjoern A. Zeeb 17701a996ed1SEdward Tomasz Napierala /*- 1771babe9a2bSRobert Watson * Determine whether td can wait for the exit of p. 1772babe9a2bSRobert Watson * Returns: 0 for permitted, an errno value otherwise 1773babe9a2bSRobert Watson * Locks: Sufficient locks to protect various components of td and p 1774babe9a2bSRobert Watson * must be held. td must be curthread, and a lock must 1775babe9a2bSRobert Watson * be held for p. 1776babe9a2bSRobert Watson * References: td and p must be valid for the lifetime of the call 1777babe9a2bSRobert Watson 1778babe9a2bSRobert Watson */ 1779babe9a2bSRobert Watson int 1780babe9a2bSRobert Watson p_canwait(struct thread *td, struct proc *p) 1781babe9a2bSRobert Watson { 1782babe9a2bSRobert Watson int error; 1783babe9a2bSRobert Watson 1784babe9a2bSRobert Watson KASSERT(td == curthread, ("%s: td not curthread", __func__)); 1785babe9a2bSRobert Watson PROC_LOCK_ASSERT(p, MA_OWNED); 17867afcbc18SJamie Gritton if ((error = prison_check(td->td_ucred, p->p_ucred))) 1787babe9a2bSRobert Watson return (error); 1788babe9a2bSRobert Watson #ifdef MAC 178930d239bcSRobert Watson if ((error = mac_proc_check_wait(td->td_ucred, p))) 1790babe9a2bSRobert Watson return (error); 1791babe9a2bSRobert Watson #endif 1792babe9a2bSRobert Watson #if 0 1793babe9a2bSRobert Watson /* XXXMAC: This could have odd effects on some shells. */ 1794babe9a2bSRobert Watson if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) 1795babe9a2bSRobert Watson return (error); 1796babe9a2bSRobert Watson #endif 1797babe9a2bSRobert Watson 1798babe9a2bSRobert Watson return (0); 1799babe9a2bSRobert Watson } 1800babe9a2bSRobert Watson 1801a9e0361bSPoul-Henning Kamp /* 1802df8bae1dSRodney W. Grimes * Allocate a zeroed cred structure. 1803df8bae1dSRodney W. Grimes */ 1804df8bae1dSRodney W. Grimes struct ucred * 18054c44ad8eSJohn Baldwin crget(void) 1806df8bae1dSRodney W. Grimes { 1807df8bae1dSRodney W. Grimes register struct ucred *cr; 1808df8bae1dSRodney W. Grimes 18091ede983cSDag-Erling Smørgrav cr = malloc(sizeof(*cr), M_CRED, M_WAITOK | M_ZERO); 18107e9e371fSJohn Baldwin refcount_init(&cr->cr_ref, 1); 1811faef5371SRobert Watson #ifdef AUDIT 1812faef5371SRobert Watson audit_cred_init(cr); 1813faef5371SRobert Watson #endif 181440244964SRobert Watson #ifdef MAC 181530d239bcSRobert Watson mac_cred_init(cr); 181640244964SRobert Watson #endif 1817838d9858SBrooks Davis crextend(cr, XU_NGROUPS); 1818df8bae1dSRodney W. Grimes return (cr); 1819df8bae1dSRodney W. Grimes } 1820df8bae1dSRodney W. Grimes 1821df8bae1dSRodney W. Grimes /* 18227fd6a959SRobert Watson * Claim another reference to a ucred structure. 18235c3f70d7SAlfred Perlstein */ 1824bd78ceceSJohn Baldwin struct ucred * 18254c44ad8eSJohn Baldwin crhold(struct ucred *cr) 18265c3f70d7SAlfred Perlstein { 18275c3f70d7SAlfred Perlstein 18287e9e371fSJohn Baldwin refcount_acquire(&cr->cr_ref); 1829bd78ceceSJohn Baldwin return (cr); 18305c3f70d7SAlfred Perlstein } 18315c3f70d7SAlfred Perlstein 18325c3f70d7SAlfred Perlstein /* 18330c14ff0eSRobert Watson * Free a cred structure. Throws away space when ref count gets to 0. 1834df8bae1dSRodney W. Grimes */ 183526f9a767SRodney W. Grimes void 18364c44ad8eSJohn Baldwin crfree(struct ucred *cr) 1837df8bae1dSRodney W. Grimes { 18381e5d626aSAlfred Perlstein 1839e04670b7SAlfred Perlstein KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref)); 18407e9e371fSJohn Baldwin KASSERT(cr->cr_ref != 0xdeadc0de, ("dangling reference to ucred")); 18417e9e371fSJohn Baldwin if (refcount_release(&cr->cr_ref)) { 1842f535380cSDon Lewis /* 1843f535380cSDon Lewis * Some callers of crget(), such as nfs_statfs(), 1844f535380cSDon Lewis * allocate a temporary credential, but don't 1845f535380cSDon Lewis * allocate a uidinfo structure. 1846f535380cSDon Lewis */ 1847f535380cSDon Lewis if (cr->cr_uidinfo != NULL) 1848f535380cSDon Lewis uifree(cr->cr_uidinfo); 1849823c224eSRobert Watson if (cr->cr_ruidinfo != NULL) 1850823c224eSRobert Watson uifree(cr->cr_ruidinfo); 185191421ba2SRobert Watson /* 185291421ba2SRobert Watson * Free a prison, if any. 185391421ba2SRobert Watson */ 18540304c731SJamie Gritton if (cr->cr_prison != NULL) 185591421ba2SRobert Watson prison_free(cr->cr_prison); 18562bfc50bcSEdward Tomasz Napierala if (cr->cr_loginclass != NULL) 18572bfc50bcSEdward Tomasz Napierala loginclass_free(cr->cr_loginclass); 1858faef5371SRobert Watson #ifdef AUDIT 1859faef5371SRobert Watson audit_cred_destroy(cr); 1860faef5371SRobert Watson #endif 186140244964SRobert Watson #ifdef MAC 186230d239bcSRobert Watson mac_cred_destroy(cr); 186340244964SRobert Watson #endif 1864838d9858SBrooks Davis free(cr->cr_groups, M_CRED); 18651ede983cSDag-Erling Smørgrav free(cr, M_CRED); 1866e1bca29fSMatthew Dillon } 1867df8bae1dSRodney W. Grimes } 1868df8bae1dSRodney W. Grimes 1869df8bae1dSRodney W. Grimes /* 1870bd78ceceSJohn Baldwin * Check to see if this ucred is shared. 1871df8bae1dSRodney W. Grimes */ 1872bd78ceceSJohn Baldwin int 18734c44ad8eSJohn Baldwin crshared(struct ucred *cr) 1874df8bae1dSRodney W. Grimes { 1875df8bae1dSRodney W. Grimes 18767e9e371fSJohn Baldwin return (cr->cr_ref > 1); 18771e5d626aSAlfred Perlstein } 1878bd78ceceSJohn Baldwin 1879bd78ceceSJohn Baldwin /* 1880bd78ceceSJohn Baldwin * Copy a ucred's contents from a template. Does not block. 1881bd78ceceSJohn Baldwin */ 1882bd78ceceSJohn Baldwin void 18834c44ad8eSJohn Baldwin crcopy(struct ucred *dest, struct ucred *src) 1884bd78ceceSJohn Baldwin { 1885bd78ceceSJohn Baldwin 1886bd78ceceSJohn Baldwin KASSERT(crshared(dest) == 0, ("crcopy of shared ucred")); 1887bd78ceceSJohn Baldwin bcopy(&src->cr_startcopy, &dest->cr_startcopy, 1888bd78ceceSJohn Baldwin (unsigned)((caddr_t)&src->cr_endcopy - 1889bd78ceceSJohn Baldwin (caddr_t)&src->cr_startcopy)); 1890838d9858SBrooks Davis crsetgroups(dest, src->cr_ngroups, src->cr_groups); 1891bd78ceceSJohn Baldwin uihold(dest->cr_uidinfo); 1892bd78ceceSJohn Baldwin uihold(dest->cr_ruidinfo); 1893bd78ceceSJohn Baldwin prison_hold(dest->cr_prison); 18942bfc50bcSEdward Tomasz Napierala loginclass_hold(dest->cr_loginclass); 1895faef5371SRobert Watson #ifdef AUDIT 1896faef5371SRobert Watson audit_cred_copy(src, dest); 1897faef5371SRobert Watson #endif 189840244964SRobert Watson #ifdef MAC 189930d239bcSRobert Watson mac_cred_copy(src, dest); 190040244964SRobert Watson #endif 1901df8bae1dSRodney W. Grimes } 1902df8bae1dSRodney W. Grimes 1903df8bae1dSRodney W. Grimes /* 1904df8bae1dSRodney W. Grimes * Dup cred struct to a new held one. 1905df8bae1dSRodney W. Grimes */ 1906df8bae1dSRodney W. Grimes struct ucred * 19074c44ad8eSJohn Baldwin crdup(struct ucred *cr) 1908df8bae1dSRodney W. Grimes { 1909df8bae1dSRodney W. Grimes struct ucred *newcr; 1910df8bae1dSRodney W. Grimes 1911bd78ceceSJohn Baldwin newcr = crget(); 1912bd78ceceSJohn Baldwin crcopy(newcr, cr); 1913df8bae1dSRodney W. Grimes return (newcr); 1914df8bae1dSRodney W. Grimes } 1915df8bae1dSRodney W. Grimes 1916df8bae1dSRodney W. Grimes /* 191776183f34SDima Dorfman * Fill in a struct xucred based on a struct ucred. 191876183f34SDima Dorfman */ 191976183f34SDima Dorfman void 19204c44ad8eSJohn Baldwin cru2x(struct ucred *cr, struct xucred *xcr) 192176183f34SDima Dorfman { 1922838d9858SBrooks Davis int ngroups; 192376183f34SDima Dorfman 192476183f34SDima Dorfman bzero(xcr, sizeof(*xcr)); 192576183f34SDima Dorfman xcr->cr_version = XUCRED_VERSION; 192676183f34SDima Dorfman xcr->cr_uid = cr->cr_uid; 1927838d9858SBrooks Davis 1928838d9858SBrooks Davis ngroups = MIN(cr->cr_ngroups, XU_NGROUPS); 1929838d9858SBrooks Davis xcr->cr_ngroups = ngroups; 1930838d9858SBrooks Davis bcopy(cr->cr_groups, xcr->cr_groups, 1931838d9858SBrooks Davis ngroups * sizeof(*cr->cr_groups)); 193276183f34SDima Dorfman } 193376183f34SDima Dorfman 193476183f34SDima Dorfman /* 19350c14ff0eSRobert Watson * small routine to swap a thread's current ucred for the correct one taken 19360c14ff0eSRobert Watson * from the process. 19372eb927e2SJulian Elischer */ 19382eb927e2SJulian Elischer void 19392eb927e2SJulian Elischer cred_update_thread(struct thread *td) 19402eb927e2SJulian Elischer { 19412eb927e2SJulian Elischer struct proc *p; 194265e3406dSJohn Baldwin struct ucred *cred; 19432eb927e2SJulian Elischer 19442eb927e2SJulian Elischer p = td->td_proc; 194565e3406dSJohn Baldwin cred = td->td_ucred; 19462eb927e2SJulian Elischer PROC_LOCK(p); 19472eb927e2SJulian Elischer td->td_ucred = crhold(p->p_ucred); 19482eb927e2SJulian Elischer PROC_UNLOCK(p); 194965e3406dSJohn Baldwin if (cred != NULL) 195065e3406dSJohn Baldwin crfree(cred); 19512eb927e2SJulian Elischer } 19522eb927e2SJulian Elischer 1953838d9858SBrooks Davis struct ucred * 1954838d9858SBrooks Davis crcopysafe(struct proc *p, struct ucred *cr) 1955838d9858SBrooks Davis { 1956838d9858SBrooks Davis struct ucred *oldcred; 1957838d9858SBrooks Davis int groups; 1958838d9858SBrooks Davis 1959838d9858SBrooks Davis PROC_LOCK_ASSERT(p, MA_OWNED); 1960838d9858SBrooks Davis 1961838d9858SBrooks Davis oldcred = p->p_ucred; 1962838d9858SBrooks Davis while (cr->cr_agroups < oldcred->cr_agroups) { 1963838d9858SBrooks Davis groups = oldcred->cr_agroups; 1964838d9858SBrooks Davis PROC_UNLOCK(p); 1965838d9858SBrooks Davis crextend(cr, groups); 1966838d9858SBrooks Davis PROC_LOCK(p); 1967838d9858SBrooks Davis oldcred = p->p_ucred; 1968838d9858SBrooks Davis } 1969838d9858SBrooks Davis crcopy(cr, oldcred); 1970838d9858SBrooks Davis 1971838d9858SBrooks Davis return (oldcred); 1972838d9858SBrooks Davis } 1973838d9858SBrooks Davis 1974838d9858SBrooks Davis /* 1975838d9858SBrooks Davis * Extend the passed in credential to hold n items. 1976838d9858SBrooks Davis */ 1977838d9858SBrooks Davis static void 1978838d9858SBrooks Davis crextend(struct ucred *cr, int n) 1979838d9858SBrooks Davis { 1980838d9858SBrooks Davis int cnt; 1981838d9858SBrooks Davis 1982838d9858SBrooks Davis /* Truncate? */ 1983838d9858SBrooks Davis if (n <= cr->cr_agroups) 1984838d9858SBrooks Davis return; 1985838d9858SBrooks Davis 1986838d9858SBrooks Davis /* 1987838d9858SBrooks Davis * We extend by 2 each time since we're using a power of two 1988838d9858SBrooks Davis * allocator until we need enough groups to fill a page. 1989838d9858SBrooks Davis * Once we're allocating multiple pages, only allocate as many 1990838d9858SBrooks Davis * as we actually need. The case of processes needing a 1991838d9858SBrooks Davis * non-power of two number of pages seems more likely than 1992838d9858SBrooks Davis * a real world process that adds thousands of groups one at a 1993838d9858SBrooks Davis * time. 1994838d9858SBrooks Davis */ 1995838d9858SBrooks Davis if ( n < PAGE_SIZE / sizeof(gid_t) ) { 1996838d9858SBrooks Davis if (cr->cr_agroups == 0) 1997838d9858SBrooks Davis cnt = MINALLOCSIZE / sizeof(gid_t); 1998838d9858SBrooks Davis else 1999838d9858SBrooks Davis cnt = cr->cr_agroups * 2; 2000838d9858SBrooks Davis 2001838d9858SBrooks Davis while (cnt < n) 2002838d9858SBrooks Davis cnt *= 2; 2003838d9858SBrooks Davis } else 2004838d9858SBrooks Davis cnt = roundup2(n, PAGE_SIZE / sizeof(gid_t)); 2005838d9858SBrooks Davis 2006838d9858SBrooks Davis /* Free the old array. */ 2007838d9858SBrooks Davis if (cr->cr_groups) 2008838d9858SBrooks Davis free(cr->cr_groups, M_CRED); 2009838d9858SBrooks Davis 2010838d9858SBrooks Davis cr->cr_groups = malloc(cnt * sizeof(gid_t), M_CRED, M_WAITOK | M_ZERO); 2011838d9858SBrooks Davis cr->cr_agroups = cnt; 2012838d9858SBrooks Davis } 2013838d9858SBrooks Davis 2014838d9858SBrooks Davis /* 20157f92e578SBrooks Davis * Copy groups in to a credential, preserving any necessary invariants. 20167f92e578SBrooks Davis * Currently this includes the sorting of all supplemental gids. 20177f92e578SBrooks Davis * crextend() must have been called before hand to ensure sufficient 20187f92e578SBrooks Davis * space is available. 2019838d9858SBrooks Davis */ 2020838d9858SBrooks Davis static void 2021838d9858SBrooks Davis crsetgroups_locked(struct ucred *cr, int ngrp, gid_t *groups) 2022838d9858SBrooks Davis { 20237f92e578SBrooks Davis int i; 20247f92e578SBrooks Davis int j; 20257f92e578SBrooks Davis gid_t g; 2026838d9858SBrooks Davis 2027838d9858SBrooks Davis KASSERT(cr->cr_agroups >= ngrp, ("cr_ngroups is too small")); 2028838d9858SBrooks Davis 2029838d9858SBrooks Davis bcopy(groups, cr->cr_groups, ngrp * sizeof(gid_t)); 2030838d9858SBrooks Davis cr->cr_ngroups = ngrp; 20317f92e578SBrooks Davis 20327f92e578SBrooks Davis /* 20337f92e578SBrooks Davis * Sort all groups except cr_groups[0] to allow groupmember to 20347f92e578SBrooks Davis * perform a binary search. 20357f92e578SBrooks Davis * 20367f92e578SBrooks Davis * XXX: If large numbers of groups become common this should 20377f92e578SBrooks Davis * be replaced with shell sort like linux uses or possibly 20387f92e578SBrooks Davis * heap sort. 20397f92e578SBrooks Davis */ 20407f92e578SBrooks Davis for (i = 2; i < ngrp; i++) { 20417f92e578SBrooks Davis g = cr->cr_groups[i]; 20427f92e578SBrooks Davis for (j = i-1; j >= 1 && g < cr->cr_groups[j]; j--) 20437f92e578SBrooks Davis cr->cr_groups[j + 1] = cr->cr_groups[j]; 20447f92e578SBrooks Davis cr->cr_groups[j + 1] = g; 20457f92e578SBrooks Davis } 2046838d9858SBrooks Davis } 2047838d9858SBrooks Davis 2048838d9858SBrooks Davis /* 2049838d9858SBrooks Davis * Copy groups in to a credential after expanding it if required. 2050412f9500SBrooks Davis * Truncate the list to (ngroups_max + 1) if it is too large. 2051838d9858SBrooks Davis */ 2052838d9858SBrooks Davis void 2053838d9858SBrooks Davis crsetgroups(struct ucred *cr, int ngrp, gid_t *groups) 2054838d9858SBrooks Davis { 2055838d9858SBrooks Davis 2056412f9500SBrooks Davis if (ngrp > ngroups_max + 1) 2057412f9500SBrooks Davis ngrp = ngroups_max + 1; 2058838d9858SBrooks Davis 2059838d9858SBrooks Davis crextend(cr, ngrp); 2060838d9858SBrooks Davis crsetgroups_locked(cr, ngrp, groups); 2061838d9858SBrooks Davis } 2062838d9858SBrooks Davis 20632eb927e2SJulian Elischer /* 2064df8bae1dSRodney W. Grimes * Get login name, if available. 2065df8bae1dSRodney W. Grimes */ 2066d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 2067df8bae1dSRodney W. Grimes struct getlogin_args { 2068df8bae1dSRodney W. Grimes char *namebuf; 2069df8bae1dSRodney W. Grimes u_int namelen; 2070df8bae1dSRodney W. Grimes }; 2071d2d3e875SBruce Evans #endif 2072df8bae1dSRodney W. Grimes /* ARGSUSED */ 207326f9a767SRodney W. Grimes int 2074*8451d0ddSKip Macy sys_getlogin(struct thread *td, struct getlogin_args *uap) 2075df8bae1dSRodney W. Grimes { 2076835a82eeSMatthew Dillon int error; 2077f591779bSSeigo Tanimura char login[MAXLOGNAME]; 2078b40ce416SJulian Elischer struct proc *p = td->td_proc; 2079df8bae1dSRodney W. Grimes 208030cf3ac4SAndrey A. Chernov if (uap->namelen > MAXLOGNAME) 208153490b76SAndrey A. Chernov uap->namelen = MAXLOGNAME; 2082f591779bSSeigo Tanimura PROC_LOCK(p); 2083f591779bSSeigo Tanimura SESS_LOCK(p->p_session); 2084f591779bSSeigo Tanimura bcopy(p->p_session->s_login, login, uap->namelen); 2085f591779bSSeigo Tanimura SESS_UNLOCK(p->p_session); 2086f591779bSSeigo Tanimura PROC_UNLOCK(p); 20877f05b035SAlfred Perlstein error = copyout(login, uap->namebuf, uap->namelen); 2088835a82eeSMatthew Dillon return(error); 2089df8bae1dSRodney W. Grimes } 2090df8bae1dSRodney W. Grimes 2091df8bae1dSRodney W. Grimes /* 2092df8bae1dSRodney W. Grimes * Set login name. 2093df8bae1dSRodney W. Grimes */ 2094d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 2095df8bae1dSRodney W. Grimes struct setlogin_args { 2096df8bae1dSRodney W. Grimes char *namebuf; 2097df8bae1dSRodney W. Grimes }; 2098d2d3e875SBruce Evans #endif 2099df8bae1dSRodney W. Grimes /* ARGSUSED */ 210026f9a767SRodney W. Grimes int 2101*8451d0ddSKip Macy sys_setlogin(struct thread *td, struct setlogin_args *uap) 2102df8bae1dSRodney W. Grimes { 2103b40ce416SJulian Elischer struct proc *p = td->td_proc; 2104df8bae1dSRodney W. Grimes int error; 2105964ca0caSAndrey A. Chernov char logintmp[MAXLOGNAME]; 2106df8bae1dSRodney W. Grimes 210732f9753cSRobert Watson error = priv_check(td, PRIV_PROC_SETLOGIN); 210807f3485dSJohn Baldwin if (error) 210907f3485dSJohn Baldwin return (error); 21107f05b035SAlfred Perlstein error = copyinstr(uap->namebuf, logintmp, sizeof(logintmp), NULL); 2111eb725b4eSRobert Watson if (error == ENAMETOOLONG) 2112df8bae1dSRodney W. Grimes error = EINVAL; 2113f591779bSSeigo Tanimura else if (!error) { 2114f591779bSSeigo Tanimura PROC_LOCK(p); 2115f591779bSSeigo Tanimura SESS_LOCK(p->p_session); 2116f591779bSSeigo Tanimura (void) memcpy(p->p_session->s_login, logintmp, 2117964ca0caSAndrey A. Chernov sizeof(logintmp)); 2118f591779bSSeigo Tanimura SESS_UNLOCK(p->p_session); 2119f591779bSSeigo Tanimura PROC_UNLOCK(p); 2120f591779bSSeigo Tanimura } 2121df8bae1dSRodney W. Grimes return (error); 2122df8bae1dSRodney W. Grimes } 2123d5f81602SSean Eric Fagan 2124d5f81602SSean Eric Fagan void 21254c44ad8eSJohn Baldwin setsugid(struct proc *p) 2126d5f81602SSean Eric Fagan { 2127f2102dadSAlfred Perlstein 2128f2102dadSAlfred Perlstein PROC_LOCK_ASSERT(p, MA_OWNED); 2129d5f81602SSean Eric Fagan p->p_flag |= P_SUGID; 213089361835SSean Eric Fagan if (!(p->p_pfsflags & PF_ISUGID)) 2131d5f81602SSean Eric Fagan p->p_stops = 0; 2132d5f81602SSean Eric Fagan } 2133f535380cSDon Lewis 21341a996ed1SEdward Tomasz Napierala /*- 21357fd6a959SRobert Watson * Change a process's effective uid. 2136b1fc0ec1SRobert Watson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified. 2137b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 2138b1fc0ec1SRobert Watson * duration of the call. 2139f535380cSDon Lewis */ 2140f535380cSDon Lewis void 21411419eacbSAlfred Perlstein change_euid(struct ucred *newcred, struct uidinfo *euip) 2142f535380cSDon Lewis { 2143f535380cSDon Lewis 21441419eacbSAlfred Perlstein newcred->cr_uid = euip->ui_uid; 21451419eacbSAlfred Perlstein uihold(euip); 2146b1fc0ec1SRobert Watson uifree(newcred->cr_uidinfo); 21471419eacbSAlfred Perlstein newcred->cr_uidinfo = euip; 2148f535380cSDon Lewis } 2149f535380cSDon Lewis 21501a996ed1SEdward Tomasz Napierala /*- 21517fd6a959SRobert Watson * Change a process's effective gid. 2152b1fc0ec1SRobert Watson * Side effects: newcred->cr_gid will be modified. 2153b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 2154b1fc0ec1SRobert Watson * duration of the call. 2155f535380cSDon Lewis */ 2156810bfc8eSAndrew Gallatin void 21574c44ad8eSJohn Baldwin change_egid(struct ucred *newcred, gid_t egid) 2158b1fc0ec1SRobert Watson { 2159b1fc0ec1SRobert Watson 2160b1fc0ec1SRobert Watson newcred->cr_groups[0] = egid; 2161b1fc0ec1SRobert Watson } 2162b1fc0ec1SRobert Watson 21631a996ed1SEdward Tomasz Napierala /*- 21647fd6a959SRobert Watson * Change a process's real uid. 2165b1fc0ec1SRobert Watson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo 2166b1fc0ec1SRobert Watson * will be updated, and the old and new cr_ruidinfo proc 2167b1fc0ec1SRobert Watson * counts will be updated. 2168b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 2169b1fc0ec1SRobert Watson * duration of the call. 2170b1fc0ec1SRobert Watson */ 2171b1fc0ec1SRobert Watson void 21721419eacbSAlfred Perlstein change_ruid(struct ucred *newcred, struct uidinfo *ruip) 2173f535380cSDon Lewis { 2174f535380cSDon Lewis 2175b1fc0ec1SRobert Watson (void)chgproccnt(newcred->cr_ruidinfo, -1, 0); 21761419eacbSAlfred Perlstein newcred->cr_ruid = ruip->ui_uid; 21771419eacbSAlfred Perlstein uihold(ruip); 2178b1fc0ec1SRobert Watson uifree(newcred->cr_ruidinfo); 21791419eacbSAlfred Perlstein newcred->cr_ruidinfo = ruip; 2180b1fc0ec1SRobert Watson (void)chgproccnt(newcred->cr_ruidinfo, 1, 0); 2181b1fc0ec1SRobert Watson } 2182b1fc0ec1SRobert Watson 21831a996ed1SEdward Tomasz Napierala /*- 21847fd6a959SRobert Watson * Change a process's real gid. 2185b1fc0ec1SRobert Watson * Side effects: newcred->cr_rgid will be updated. 2186b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 2187b1fc0ec1SRobert Watson * duration of the call. 2188b1fc0ec1SRobert Watson */ 2189b1fc0ec1SRobert Watson void 21904c44ad8eSJohn Baldwin change_rgid(struct ucred *newcred, gid_t rgid) 2191b1fc0ec1SRobert Watson { 2192b1fc0ec1SRobert Watson 2193b1fc0ec1SRobert Watson newcred->cr_rgid = rgid; 2194b1fc0ec1SRobert Watson } 2195b1fc0ec1SRobert Watson 21961a996ed1SEdward Tomasz Napierala /*- 21977fd6a959SRobert Watson * Change a process's saved uid. 2198b1fc0ec1SRobert Watson * Side effects: newcred->cr_svuid will be updated. 2199b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 2200b1fc0ec1SRobert Watson * duration of the call. 2201b1fc0ec1SRobert Watson */ 2202b1fc0ec1SRobert Watson void 22034c44ad8eSJohn Baldwin change_svuid(struct ucred *newcred, uid_t svuid) 2204b1fc0ec1SRobert Watson { 2205b1fc0ec1SRobert Watson 2206b1fc0ec1SRobert Watson newcred->cr_svuid = svuid; 2207b1fc0ec1SRobert Watson } 2208b1fc0ec1SRobert Watson 22091a996ed1SEdward Tomasz Napierala /*- 22107fd6a959SRobert Watson * Change a process's saved gid. 2211b1fc0ec1SRobert Watson * Side effects: newcred->cr_svgid will be updated. 2212b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 2213b1fc0ec1SRobert Watson * duration of the call. 2214b1fc0ec1SRobert Watson */ 2215b1fc0ec1SRobert Watson void 22164c44ad8eSJohn Baldwin change_svgid(struct ucred *newcred, gid_t svgid) 2217b1fc0ec1SRobert Watson { 2218b1fc0ec1SRobert Watson 2219b1fc0ec1SRobert Watson newcred->cr_svgid = svgid; 2220f535380cSDon Lewis } 2221