19454b2d8SWarner Losh /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 4df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 5ef08c420SRobert Watson * The Regents of the University of California. 6df8bae1dSRodney W. Grimes * (c) UNIX System Laboratories, Inc. 7ef08c420SRobert Watson * Copyright (c) 2000-2001 Robert N. M. Watson. 8ef08c420SRobert Watson * All rights reserved. 9ef08c420SRobert Watson * 10df8bae1dSRodney W. Grimes * All or some portions of this file are derived from material licensed 11df8bae1dSRodney W. Grimes * to the University of California by American Telephone and Telegraph 12df8bae1dSRodney W. Grimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 13df8bae1dSRodney W. Grimes * the permission of UNIX System Laboratories, Inc. 14df8bae1dSRodney W. Grimes * 15df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 16df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 17df8bae1dSRodney W. Grimes * are met: 18df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 19df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 20df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 21df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 22df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 2369a28758SEd Maste * 3. Neither the name of the University nor the names of its contributors 24df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 25df8bae1dSRodney W. Grimes * without specific prior written permission. 26df8bae1dSRodney W. Grimes * 27df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37df8bae1dSRodney W. Grimes * SUCH DAMAGE. 38df8bae1dSRodney W. Grimes * 39df8bae1dSRodney W. Grimes * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 40df8bae1dSRodney W. Grimes */ 41df8bae1dSRodney W. Grimes 42df8bae1dSRodney W. Grimes /* 43df8bae1dSRodney W. Grimes * System calls related to processes and protection 44df8bae1dSRodney W. Grimes */ 45df8bae1dSRodney W. Grimes 46677b542eSDavid E. O'Brien #include <sys/cdefs.h> 47677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 48677b542eSDavid E. O'Brien 49f08ef6c5SBjoern A. Zeeb #include "opt_inet.h" 50f08ef6c5SBjoern A. Zeeb #include "opt_inet6.h" 515591b823SEivind Eklund 52df8bae1dSRodney W. Grimes #include <sys/param.h> 53df8bae1dSRodney W. Grimes #include <sys/systm.h> 54fb919e4dSMark Murray #include <sys/acct.h> 55df04411aSRobert Watson #include <sys/kdb.h> 561c5bb3eaSPeter Wemm #include <sys/kernel.h> 5798f03f90SJake Burkholder #include <sys/lock.h> 582bfc50bcSEdward Tomasz Napierala #include <sys/loginclass.h> 59f9d0d524SRobert Watson #include <sys/malloc.h> 60fb919e4dSMark Murray #include <sys/mutex.h> 617e9e371fSJohn Baldwin #include <sys/refcount.h> 625b29d6e9SJohn Baldwin #include <sys/sx.h> 63800c9408SRobert Watson #include <sys/priv.h> 64f591779bSSeigo Tanimura #include <sys/proc.h> 657e097daaSKonstantin Belousov #include <sys/sysent.h> 66fb919e4dSMark Murray #include <sys/sysproto.h> 67eb725b4eSRobert Watson #include <sys/jail.h> 68e4dcb704SEdward Tomasz Napierala #include <sys/racct.h> 69f87beb93SAndriy Gapon #include <sys/rctl.h> 70f535380cSDon Lewis #include <sys/resourcevar.h> 7129dc1288SRobert Watson #include <sys/socket.h> 7229dc1288SRobert Watson #include <sys/socketvar.h> 733cb83e71SJohn Baldwin #include <sys/syscallsubr.h> 74579f4eb4SRobert Watson #include <sys/sysctl.h> 75df8bae1dSRodney W. Grimes 76de5b1952SAlexander Leidinger #ifdef REGRESSION 77de5b1952SAlexander Leidinger FEATURE(regression, 78ca54e1aeSHiroki Sato "Kernel support for interfaces necessary for regression testing (SECURITY RISK!)"); 79de5b1952SAlexander Leidinger #endif 80de5b1952SAlexander Leidinger 812f8a46d5SWayne Salamon #include <security/audit/audit.h> 82aed55708SRobert Watson #include <security/mac/mac_framework.h> 832f8a46d5SWayne Salamon 84a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_CRED, "cred", "credentials"); 85a1c995b6SPoul-Henning Kamp 867029da5cSPawel Biernacki SYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 877029da5cSPawel Biernacki "BSD security policy"); 8848713bdcSRobert Watson 89838d9858SBrooks Davis static void crsetgroups_locked(struct ucred *cr, int ngrp, 90838d9858SBrooks Davis gid_t *groups); 91838d9858SBrooks Davis 92d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 93ad7507e2SSteven Wallace struct getpid_args { 94df8bae1dSRodney W. Grimes int dummy; 95df8bae1dSRodney W. Grimes }; 96d2d3e875SBruce Evans #endif 97df8bae1dSRodney W. Grimes /* ARGSUSED */ 9826f9a767SRodney W. Grimes int 998451d0ddSKip Macy sys_getpid(struct thread *td, struct getpid_args *uap) 100df8bae1dSRodney W. Grimes { 101b40ce416SJulian Elischer struct proc *p = td->td_proc; 102df8bae1dSRodney W. Grimes 103b40ce416SJulian Elischer td->td_retval[0] = p->p_pid; 1041930e303SPoul-Henning Kamp #if defined(COMPAT_43) 1057e097daaSKonstantin Belousov if (SV_PROC_FLAG(p, SV_AOUT)) 106abd386baSMateusz Guzik td->td_retval[1] = kern_getppid(td); 107df8bae1dSRodney W. Grimes #endif 108df8bae1dSRodney W. Grimes return (0); 109df8bae1dSRodney W. Grimes } 110df8bae1dSRodney W. Grimes 111d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 112ad7507e2SSteven Wallace struct getppid_args { 113ad7507e2SSteven Wallace int dummy; 114ad7507e2SSteven Wallace }; 115d2d3e875SBruce Evans #endif 116df8bae1dSRodney W. Grimes /* ARGSUSED */ 11726f9a767SRodney W. Grimes int 1188451d0ddSKip Macy sys_getppid(struct thread *td, struct getppid_args *uap) 119df8bae1dSRodney W. Grimes { 120abd386baSMateusz Guzik 121abd386baSMateusz Guzik td->td_retval[0] = kern_getppid(td); 122abd386baSMateusz Guzik return (0); 123abd386baSMateusz Guzik } 124abd386baSMateusz Guzik 125abd386baSMateusz Guzik int 126abd386baSMateusz Guzik kern_getppid(struct thread *td) 127abd386baSMateusz Guzik { 128b40ce416SJulian Elischer struct proc *p = td->td_proc; 129df8bae1dSRodney W. Grimes 1302c054ce9SMateusz Guzik return (p->p_oppid); 131df8bae1dSRodney W. Grimes } 132df8bae1dSRodney W. Grimes 13336e9f877SMatthew Dillon /* 134eb725b4eSRobert Watson * Get process group ID; note that POSIX getpgrp takes no parameter. 13536e9f877SMatthew Dillon */ 136d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 137ad7507e2SSteven Wallace struct getpgrp_args { 138ad7507e2SSteven Wallace int dummy; 139ad7507e2SSteven Wallace }; 140d2d3e875SBruce Evans #endif 14126f9a767SRodney W. Grimes int 1428451d0ddSKip Macy sys_getpgrp(struct thread *td, struct getpgrp_args *uap) 143df8bae1dSRodney W. Grimes { 144b40ce416SJulian Elischer struct proc *p = td->td_proc; 145df8bae1dSRodney W. Grimes 146f591779bSSeigo Tanimura PROC_LOCK(p); 147b40ce416SJulian Elischer td->td_retval[0] = p->p_pgrp->pg_id; 148f591779bSSeigo Tanimura PROC_UNLOCK(p); 149df8bae1dSRodney W. Grimes return (0); 150df8bae1dSRodney W. Grimes } 151df8bae1dSRodney W. Grimes 152e3043798SPedro F. Giffuni /* Get an arbitrary pid's process group id */ 1531a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1541a5018a0SPeter Wemm struct getpgid_args { 1551a5018a0SPeter Wemm pid_t pid; 1561a5018a0SPeter Wemm }; 1571a5018a0SPeter Wemm #endif 1581a5018a0SPeter Wemm int 1598451d0ddSKip Macy sys_getpgid(struct thread *td, struct getpgid_args *uap) 1601a5018a0SPeter Wemm { 161a70a2b74SJohn Baldwin struct proc *p; 162f2ae7368SJohn Baldwin int error; 16365de0c7aSDon Lewis 164f591779bSSeigo Tanimura if (uap->pid == 0) { 165a70a2b74SJohn Baldwin p = td->td_proc; 166f591779bSSeigo Tanimura PROC_LOCK(p); 167a70a2b74SJohn Baldwin } else { 168a70a2b74SJohn Baldwin p = pfind(uap->pid); 169a70a2b74SJohn Baldwin if (p == NULL) 170a70a2b74SJohn Baldwin return (ESRCH); 171a70a2b74SJohn Baldwin error = p_cansee(td, p); 172a70a2b74SJohn Baldwin if (error) { 173a70a2b74SJohn Baldwin PROC_UNLOCK(p); 174a70a2b74SJohn Baldwin return (error); 175a70a2b74SJohn Baldwin } 176a70a2b74SJohn Baldwin } 177b40ce416SJulian Elischer td->td_retval[0] = p->p_pgrp->pg_id; 178f591779bSSeigo Tanimura PROC_UNLOCK(p); 179a70a2b74SJohn Baldwin return (0); 1801a5018a0SPeter Wemm } 1811a5018a0SPeter Wemm 1821a5018a0SPeter Wemm /* 183e3043798SPedro F. Giffuni * Get an arbitrary pid's session id. 1841a5018a0SPeter Wemm */ 1851a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1861a5018a0SPeter Wemm struct getsid_args { 1871a5018a0SPeter Wemm pid_t pid; 1881a5018a0SPeter Wemm }; 1891a5018a0SPeter Wemm #endif 1901a5018a0SPeter Wemm int 1918451d0ddSKip Macy sys_getsid(struct thread *td, struct getsid_args *uap) 1921a5018a0SPeter Wemm { 193be2cfdbcSEdward Tomasz Napierala 194be2cfdbcSEdward Tomasz Napierala return (kern_getsid(td, uap->pid)); 195be2cfdbcSEdward Tomasz Napierala } 196be2cfdbcSEdward Tomasz Napierala 197be2cfdbcSEdward Tomasz Napierala int 198be2cfdbcSEdward Tomasz Napierala kern_getsid(struct thread *td, pid_t pid) 199be2cfdbcSEdward Tomasz Napierala { 200a70a2b74SJohn Baldwin struct proc *p; 201eb725b4eSRobert Watson int error; 20265de0c7aSDon Lewis 203be2cfdbcSEdward Tomasz Napierala if (pid == 0) { 204a70a2b74SJohn Baldwin p = td->td_proc; 205f591779bSSeigo Tanimura PROC_LOCK(p); 206a70a2b74SJohn Baldwin } else { 207be2cfdbcSEdward Tomasz Napierala p = pfind(pid); 208a70a2b74SJohn Baldwin if (p == NULL) 209a70a2b74SJohn Baldwin return (ESRCH); 210a70a2b74SJohn Baldwin error = p_cansee(td, p); 211a70a2b74SJohn Baldwin if (error) { 212a70a2b74SJohn Baldwin PROC_UNLOCK(p); 213a70a2b74SJohn Baldwin return (error); 214a70a2b74SJohn Baldwin } 215a70a2b74SJohn Baldwin } 216b40ce416SJulian Elischer td->td_retval[0] = p->p_session->s_sid; 217f591779bSSeigo Tanimura PROC_UNLOCK(p); 218a70a2b74SJohn Baldwin return (0); 2191a5018a0SPeter Wemm } 2201a5018a0SPeter Wemm 221d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 222ad7507e2SSteven Wallace struct getuid_args { 223ad7507e2SSteven Wallace int dummy; 224ad7507e2SSteven Wallace }; 225d2d3e875SBruce Evans #endif 226df8bae1dSRodney W. Grimes /* ARGSUSED */ 22726f9a767SRodney W. Grimes int 2288451d0ddSKip Macy sys_getuid(struct thread *td, struct getuid_args *uap) 229df8bae1dSRodney W. Grimes { 230df8bae1dSRodney W. Grimes 231d846883bSJohn Baldwin td->td_retval[0] = td->td_ucred->cr_ruid; 2321930e303SPoul-Henning Kamp #if defined(COMPAT_43) 233d846883bSJohn Baldwin td->td_retval[1] = td->td_ucred->cr_uid; 234df8bae1dSRodney W. Grimes #endif 235df8bae1dSRodney W. Grimes return (0); 236df8bae1dSRodney W. Grimes } 237df8bae1dSRodney W. Grimes 238d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 239ad7507e2SSteven Wallace struct geteuid_args { 240ad7507e2SSteven Wallace int dummy; 241ad7507e2SSteven Wallace }; 242d2d3e875SBruce Evans #endif 243df8bae1dSRodney W. Grimes /* ARGSUSED */ 24426f9a767SRodney W. Grimes int 2458451d0ddSKip Macy sys_geteuid(struct thread *td, struct geteuid_args *uap) 246df8bae1dSRodney W. Grimes { 247d846883bSJohn Baldwin 248d846883bSJohn Baldwin td->td_retval[0] = td->td_ucred->cr_uid; 249df8bae1dSRodney W. Grimes return (0); 250df8bae1dSRodney W. Grimes } 251df8bae1dSRodney W. Grimes 252d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 253ad7507e2SSteven Wallace struct getgid_args { 254ad7507e2SSteven Wallace int dummy; 255ad7507e2SSteven Wallace }; 256d2d3e875SBruce Evans #endif 257df8bae1dSRodney W. Grimes /* ARGSUSED */ 25826f9a767SRodney W. Grimes int 2598451d0ddSKip Macy sys_getgid(struct thread *td, struct getgid_args *uap) 260df8bae1dSRodney W. Grimes { 261df8bae1dSRodney W. Grimes 262d846883bSJohn Baldwin td->td_retval[0] = td->td_ucred->cr_rgid; 2631930e303SPoul-Henning Kamp #if defined(COMPAT_43) 264d846883bSJohn Baldwin td->td_retval[1] = td->td_ucred->cr_groups[0]; 265df8bae1dSRodney W. Grimes #endif 266df8bae1dSRodney W. Grimes return (0); 267df8bae1dSRodney W. Grimes } 268df8bae1dSRodney W. Grimes 269df8bae1dSRodney W. Grimes /* 270df8bae1dSRodney W. Grimes * Get effective group ID. The "egid" is groups[0], and could be obtained 271df8bae1dSRodney W. Grimes * via getgroups. This syscall exists because it is somewhat painful to do 272df8bae1dSRodney W. Grimes * correctly in a library function. 273df8bae1dSRodney W. Grimes */ 274d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 275ad7507e2SSteven Wallace struct getegid_args { 276ad7507e2SSteven Wallace int dummy; 277ad7507e2SSteven Wallace }; 278d2d3e875SBruce Evans #endif 279df8bae1dSRodney W. Grimes /* ARGSUSED */ 28026f9a767SRodney W. Grimes int 2818451d0ddSKip Macy sys_getegid(struct thread *td, struct getegid_args *uap) 282df8bae1dSRodney W. Grimes { 283df8bae1dSRodney W. Grimes 284d846883bSJohn Baldwin td->td_retval[0] = td->td_ucred->cr_groups[0]; 285df8bae1dSRodney W. Grimes return (0); 286df8bae1dSRodney W. Grimes } 287df8bae1dSRodney W. Grimes 288d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 289df8bae1dSRodney W. Grimes struct getgroups_args { 290df8bae1dSRodney W. Grimes u_int gidsetsize; 291df8bae1dSRodney W. Grimes gid_t *gidset; 292df8bae1dSRodney W. Grimes }; 293d2d3e875SBruce Evans #endif 29426f9a767SRodney W. Grimes int 2953e85b721SEd Maste sys_getgroups(struct thread *td, struct getgroups_args *uap) 296df8bae1dSRodney W. Grimes { 29707b384cbSMateusz Guzik struct ucred *cred; 298b1fc0ec1SRobert Watson u_int ngrp; 299eb725b4eSRobert Watson int error; 300df8bae1dSRodney W. Grimes 3013cb83e71SJohn Baldwin cred = td->td_ucred; 30207b384cbSMateusz Guzik ngrp = cred->cr_ngroups; 30307b384cbSMateusz Guzik 30407b384cbSMateusz Guzik if (uap->gidsetsize == 0) { 30507b384cbSMateusz Guzik error = 0; 30607b384cbSMateusz Guzik goto out; 3073cb83e71SJohn Baldwin } 30807b384cbSMateusz Guzik if (uap->gidsetsize < ngrp) 3093cb83e71SJohn Baldwin return (EINVAL); 31007b384cbSMateusz Guzik 31107b384cbSMateusz Guzik error = copyout(cred->cr_groups, uap->gidset, ngrp * sizeof(gid_t)); 31207b384cbSMateusz Guzik out: 31307b384cbSMateusz Guzik td->td_retval[0] = ngrp; 31407b384cbSMateusz Guzik return (error); 3153cb83e71SJohn Baldwin } 3163cb83e71SJohn Baldwin 317d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 31882970b81SBruce Evans struct setsid_args { 319ad7507e2SSteven Wallace int dummy; 320ad7507e2SSteven Wallace }; 321d2d3e875SBruce Evans #endif 322df8bae1dSRodney W. Grimes /* ARGSUSED */ 32326f9a767SRodney W. Grimes int 3243e85b721SEd Maste sys_setsid(struct thread *td, struct setsid_args *uap) 325df8bae1dSRodney W. Grimes { 326f591779bSSeigo Tanimura struct pgrp *pgrp; 327835a82eeSMatthew Dillon int error; 328b40ce416SJulian Elischer struct proc *p = td->td_proc; 329f591779bSSeigo Tanimura struct pgrp *newpgrp; 330f591779bSSeigo Tanimura struct session *newsess; 331f591779bSSeigo Tanimura 332f591779bSSeigo Tanimura error = 0; 333f591779bSSeigo Tanimura pgrp = NULL; 334df8bae1dSRodney W. Grimes 3351ede983cSDag-Erling Smørgrav newpgrp = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); 3361ede983cSDag-Erling Smørgrav newsess = malloc(sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO); 337f591779bSSeigo Tanimura 338c8b1829dSJohn Baldwin sx_xlock(&proctree_lock); 339f591779bSSeigo Tanimura 340f591779bSSeigo Tanimura if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) { 341f591779bSSeigo Tanimura if (pgrp != NULL) 342f591779bSSeigo Tanimura PGRP_UNLOCK(pgrp); 343835a82eeSMatthew Dillon error = EPERM; 344f591779bSSeigo Tanimura } else { 345f591779bSSeigo Tanimura (void)enterpgrp(p, p->p_pid, newpgrp, newsess); 346b40ce416SJulian Elischer td->td_retval[0] = p->p_pid; 347c8b1829dSJohn Baldwin newpgrp = NULL; 348c8b1829dSJohn Baldwin newsess = NULL; 349df8bae1dSRodney W. Grimes } 350f591779bSSeigo Tanimura 351c8b1829dSJohn Baldwin sx_xunlock(&proctree_lock); 352f591779bSSeigo Tanimura 353c8b1829dSJohn Baldwin if (newpgrp != NULL) 3541ede983cSDag-Erling Smørgrav free(newpgrp, M_PGRP); 355c8b1829dSJohn Baldwin if (newsess != NULL) 3561ede983cSDag-Erling Smørgrav free(newsess, M_SESSION); 3571c2451c2SSeigo Tanimura 358c8b1829dSJohn Baldwin return (error); 359df8bae1dSRodney W. Grimes } 360df8bae1dSRodney W. Grimes 361df8bae1dSRodney W. Grimes /* 362df8bae1dSRodney W. Grimes * set process group (setpgid/old setpgrp) 363df8bae1dSRodney W. Grimes * 364df8bae1dSRodney W. Grimes * caller does setpgid(targpid, targpgid) 365df8bae1dSRodney W. Grimes * 366df8bae1dSRodney W. Grimes * pid must be caller or child of caller (ESRCH) 367df8bae1dSRodney W. Grimes * if a child 368df8bae1dSRodney W. Grimes * pid must be in same session (EPERM) 369df8bae1dSRodney W. Grimes * pid can't have done an exec (EACCES) 370df8bae1dSRodney W. Grimes * if pgid != pid 371df8bae1dSRodney W. Grimes * there must exist some pid in same session having pgid (EPERM) 372df8bae1dSRodney W. Grimes * pid must not be session leader (EPERM) 373df8bae1dSRodney W. Grimes */ 374d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 375df8bae1dSRodney W. Grimes struct setpgid_args { 376df8bae1dSRodney W. Grimes int pid; /* target process id */ 377df8bae1dSRodney W. Grimes int pgid; /* target pgrp id */ 378df8bae1dSRodney W. Grimes }; 379d2d3e875SBruce Evans #endif 380df8bae1dSRodney W. Grimes /* ARGSUSED */ 38126f9a767SRodney W. Grimes int 3823e85b721SEd Maste sys_setpgid(struct thread *td, struct setpgid_args *uap) 383df8bae1dSRodney W. Grimes { 384b40ce416SJulian Elischer struct proc *curp = td->td_proc; 3853e85b721SEd Maste struct proc *targp; /* target process */ 3863e85b721SEd Maste struct pgrp *pgrp; /* target pgrp */ 387eb9e5c1dSRobert Watson int error; 388f591779bSSeigo Tanimura struct pgrp *newpgrp; 389df8bae1dSRodney W. Grimes 39078f64bccSBruce Evans if (uap->pgid < 0) 39178f64bccSBruce Evans return (EINVAL); 392f591779bSSeigo Tanimura 393f591779bSSeigo Tanimura error = 0; 394f591779bSSeigo Tanimura 3951ede983cSDag-Erling Smørgrav newpgrp = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); 396f591779bSSeigo Tanimura 397c8b1829dSJohn Baldwin sx_xlock(&proctree_lock); 398df8bae1dSRodney W. Grimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 399f591779bSSeigo Tanimura if ((targp = pfind(uap->pid)) == NULL) { 400835a82eeSMatthew Dillon error = ESRCH; 401c8b1829dSJohn Baldwin goto done; 40233a9ed9dSJohn Baldwin } 403f591779bSSeigo Tanimura if (!inferior(targp)) { 404f591779bSSeigo Tanimura PROC_UNLOCK(targp); 4052f932587SSeigo Tanimura error = ESRCH; 406c8b1829dSJohn Baldwin goto done; 407f591779bSSeigo Tanimura } 40871a057bcSRobert Watson if ((error = p_cansee(td, targp))) { 40933a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 410c8b1829dSJohn Baldwin goto done; 41133a9ed9dSJohn Baldwin } 41233a9ed9dSJohn Baldwin if (targp->p_pgrp == NULL || 41333a9ed9dSJohn Baldwin targp->p_session != curp->p_session) { 41433a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 415835a82eeSMatthew Dillon error = EPERM; 416c8b1829dSJohn Baldwin goto done; 41733a9ed9dSJohn Baldwin } 41833a9ed9dSJohn Baldwin if (targp->p_flag & P_EXEC) { 41933a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 420835a82eeSMatthew Dillon error = EACCES; 421c8b1829dSJohn Baldwin goto done; 42233a9ed9dSJohn Baldwin } 42333a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 424f591779bSSeigo Tanimura } else 425f591779bSSeigo Tanimura targp = curp; 426f591779bSSeigo Tanimura if (SESS_LEADER(targp)) { 427835a82eeSMatthew Dillon error = EPERM; 428c8b1829dSJohn Baldwin goto done; 42933a9ed9dSJohn Baldwin } 430eb725b4eSRobert Watson if (uap->pgid == 0) 431df8bae1dSRodney W. Grimes uap->pgid = targp->p_pid; 432a10d5f02SOlivier Houchard if ((pgrp = pgfind(uap->pgid)) == NULL) { 433f591779bSSeigo Tanimura if (uap->pgid == targp->p_pid) { 434a10d5f02SOlivier Houchard error = enterpgrp(targp, uap->pgid, newpgrp, 435a10d5f02SOlivier Houchard NULL); 436f591779bSSeigo Tanimura if (error == 0) 437f591779bSSeigo Tanimura newpgrp = NULL; 438a10d5f02SOlivier Houchard } else 439835a82eeSMatthew Dillon error = EPERM; 440a10d5f02SOlivier Houchard } else { 441f591779bSSeigo Tanimura if (pgrp == targp->p_pgrp) { 442f591779bSSeigo Tanimura PGRP_UNLOCK(pgrp); 443f591779bSSeigo Tanimura goto done; 44433a9ed9dSJohn Baldwin } 445a10d5f02SOlivier Houchard if (pgrp->pg_id != targp->p_pid && 446a10d5f02SOlivier Houchard pgrp->pg_session != curp->p_session) { 447a10d5f02SOlivier Houchard PGRP_UNLOCK(pgrp); 448a10d5f02SOlivier Houchard error = EPERM; 449a10d5f02SOlivier Houchard goto done; 450a10d5f02SOlivier Houchard } 451f591779bSSeigo Tanimura PGRP_UNLOCK(pgrp); 452f591779bSSeigo Tanimura error = enterthispgrp(targp, pgrp); 453f591779bSSeigo Tanimura } 454f591779bSSeigo Tanimura done: 455c8b1829dSJohn Baldwin sx_xunlock(&proctree_lock); 456c8b1829dSJohn Baldwin KASSERT((error == 0) || (newpgrp != NULL), 457c8b1829dSJohn Baldwin ("setpgid failed and newpgrp is NULL")); 4586041fa0aSSeigo Tanimura if (newpgrp != NULL) 4591ede983cSDag-Erling Smørgrav free(newpgrp, M_PGRP); 460835a82eeSMatthew Dillon return (error); 461df8bae1dSRodney W. Grimes } 462df8bae1dSRodney W. Grimes 463a08f4bf6SPeter Wemm /* 464a08f4bf6SPeter Wemm * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 4652fa72ea7SJeroen Ruigrok van der Werven * compatible. It says that setting the uid/gid to euid/egid is a special 466a08f4bf6SPeter Wemm * case of "appropriate privilege". Once the rules are expanded out, this 467a08f4bf6SPeter Wemm * basically means that setuid(nnn) sets all three id's, in all permitted 468a08f4bf6SPeter Wemm * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 469a08f4bf6SPeter Wemm * does not set the saved id - this is dangerous for traditional BSD 470a08f4bf6SPeter Wemm * programs. For this reason, we *really* do not want to set 471a08f4bf6SPeter Wemm * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 472a08f4bf6SPeter Wemm */ 473a08f4bf6SPeter Wemm #define POSIX_APPENDIX_B_4_2_2 474a08f4bf6SPeter Wemm 475d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 476df8bae1dSRodney W. Grimes struct setuid_args { 477df8bae1dSRodney W. Grimes uid_t uid; 478df8bae1dSRodney W. Grimes }; 479d2d3e875SBruce Evans #endif 480df8bae1dSRodney W. Grimes /* ARGSUSED */ 48126f9a767SRodney W. Grimes int 4828451d0ddSKip Macy sys_setuid(struct thread *td, struct setuid_args *uap) 483df8bae1dSRodney W. Grimes { 484b40ce416SJulian Elischer struct proc *p = td->td_proc; 485b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 486b1fc0ec1SRobert Watson uid_t uid; 4871419eacbSAlfred Perlstein struct uidinfo *uip; 488eb725b4eSRobert Watson int error; 489df8bae1dSRodney W. Grimes 49007f3485dSJohn Baldwin uid = uap->uid; 49114961ba7SRobert Watson AUDIT_ARG_UID(uid); 49207f3485dSJohn Baldwin newcred = crget(); 4931419eacbSAlfred Perlstein uip = uifind(uid); 49407f3485dSJohn Baldwin PROC_LOCK(p); 495838d9858SBrooks Davis /* 496838d9858SBrooks Davis * Copy credentials so other references do not see our changes. 497838d9858SBrooks Davis */ 498838d9858SBrooks Davis oldcred = crcopysafe(p, newcred); 4995a92ee3cSRobert Watson 500030a28b3SRobert Watson #ifdef MAC 5016f6174a7SRobert Watson error = mac_cred_check_setuid(oldcred, uid); 502030a28b3SRobert Watson if (error) 503030a28b3SRobert Watson goto fail; 504030a28b3SRobert Watson #endif 505030a28b3SRobert Watson 506a08f4bf6SPeter Wemm /* 507a08f4bf6SPeter Wemm * See if we have "permission" by POSIX 1003.1 rules. 508a08f4bf6SPeter Wemm * 509a08f4bf6SPeter Wemm * Note that setuid(geteuid()) is a special case of 510a08f4bf6SPeter Wemm * "appropriate privileges" in appendix B.4.2.2. We need 5112fa72ea7SJeroen Ruigrok van der Werven * to use this clause to be compatible with traditional BSD 512a08f4bf6SPeter Wemm * semantics. Basically, it means that "setuid(xx)" sets all 513a08f4bf6SPeter Wemm * three id's (assuming you have privs). 514a08f4bf6SPeter Wemm * 515a08f4bf6SPeter Wemm * Notes on the logic. We do things in three steps. 516a08f4bf6SPeter Wemm * 1: We determine if the euid is going to change, and do EPERM 517a08f4bf6SPeter Wemm * right away. We unconditionally change the euid later if this 518a08f4bf6SPeter Wemm * test is satisfied, simplifying that part of the logic. 519eb725b4eSRobert Watson * 2: We determine if the real and/or saved uids are going to 520a08f4bf6SPeter Wemm * change. Determined by compile options. 521a08f4bf6SPeter Wemm * 3: Change euid last. (after tests in #2 for "appropriate privs") 522a08f4bf6SPeter Wemm */ 523b1fc0ec1SRobert Watson if (uid != oldcred->cr_ruid && /* allow setuid(getuid()) */ 5243f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS 525b1fc0ec1SRobert Watson uid != oldcred->cr_svuid && /* allow setuid(saved gid) */ 526a08f4bf6SPeter Wemm #endif 527a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 528b1fc0ec1SRobert Watson uid != oldcred->cr_uid && /* allow setuid(geteuid()) */ 5293f246666SAndrey A. Chernov #endif 530cc426dd3SMateusz Guzik (error = priv_check_cred(oldcred, PRIV_CRED_SETUID)) != 0) 531030a28b3SRobert Watson goto fail; 532a08f4bf6SPeter Wemm 533a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS 534df8bae1dSRodney W. Grimes /* 535a08f4bf6SPeter Wemm * Do we have "appropriate privileges" (are we root or uid == euid) 536a08f4bf6SPeter Wemm * If so, we are changing the real uid and/or saved uid. 537df8bae1dSRodney W. Grimes */ 5383f246666SAndrey A. Chernov if ( 539a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 540b1fc0ec1SRobert Watson uid == oldcred->cr_uid || 5413f246666SAndrey A. Chernov #endif 542800c9408SRobert Watson /* We are using privs. */ 543cc426dd3SMateusz Guzik priv_check_cred(oldcred, PRIV_CRED_SETUID) == 0) 544a08f4bf6SPeter Wemm #endif 545a08f4bf6SPeter Wemm { 546a08f4bf6SPeter Wemm /* 547f535380cSDon Lewis * Set the real uid and transfer proc count to new user. 548a08f4bf6SPeter Wemm */ 549b1fc0ec1SRobert Watson if (uid != oldcred->cr_ruid) { 5501419eacbSAlfred Perlstein change_ruid(newcred, uip); 551f535380cSDon Lewis setsugid(p); 552d3cdb93dSAndrey A. Chernov } 553a08f4bf6SPeter Wemm /* 554a08f4bf6SPeter Wemm * Set saved uid 555a08f4bf6SPeter Wemm * 556a08f4bf6SPeter Wemm * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 557a08f4bf6SPeter Wemm * the security of seteuid() depends on it. B.4.2.2 says it 558a08f4bf6SPeter Wemm * is important that we should do this. 559a08f4bf6SPeter Wemm */ 560b1fc0ec1SRobert Watson if (uid != oldcred->cr_svuid) { 561b1fc0ec1SRobert Watson change_svuid(newcred, uid); 562d5f81602SSean Eric Fagan setsugid(p); 563a08f4bf6SPeter Wemm } 564a08f4bf6SPeter Wemm } 565a08f4bf6SPeter Wemm 566a08f4bf6SPeter Wemm /* 567a08f4bf6SPeter Wemm * In all permitted cases, we are changing the euid. 568a08f4bf6SPeter Wemm */ 569b1fc0ec1SRobert Watson if (uid != oldcred->cr_uid) { 5701419eacbSAlfred Perlstein change_euid(newcred, uip); 571d5f81602SSean Eric Fagan setsugid(p); 572a08f4bf6SPeter Wemm } 573daf63fd2SMateusz Guzik proc_set_cred(p, newcred); 574e4dcb704SEdward Tomasz Napierala #ifdef RACCT 575e4dcb704SEdward Tomasz Napierala racct_proc_ucred_changed(p, oldcred, newcred); 576f87beb93SAndriy Gapon crhold(newcred); 577f87beb93SAndriy Gapon #endif 578f87beb93SAndriy Gapon PROC_UNLOCK(p); 579f87beb93SAndriy Gapon #ifdef RCTL 580f87beb93SAndriy Gapon rctl_proc_ucred_changed(p, newcred); 581f87beb93SAndriy Gapon crfree(newcred); 582e4dcb704SEdward Tomasz Napierala #endif 5831419eacbSAlfred Perlstein uifree(uip); 584b1fc0ec1SRobert Watson crfree(oldcred); 58507f3485dSJohn Baldwin return (0); 586030a28b3SRobert Watson 587030a28b3SRobert Watson fail: 588030a28b3SRobert Watson PROC_UNLOCK(p); 589030a28b3SRobert Watson uifree(uip); 590030a28b3SRobert Watson crfree(newcred); 591030a28b3SRobert Watson return (error); 592df8bae1dSRodney W. Grimes } 593df8bae1dSRodney W. Grimes 594d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 595df8bae1dSRodney W. Grimes struct seteuid_args { 596df8bae1dSRodney W. Grimes uid_t euid; 597df8bae1dSRodney W. Grimes }; 598d2d3e875SBruce Evans #endif 599df8bae1dSRodney W. Grimes /* ARGSUSED */ 60026f9a767SRodney W. Grimes int 6018451d0ddSKip Macy sys_seteuid(struct thread *td, struct seteuid_args *uap) 602df8bae1dSRodney W. Grimes { 603b40ce416SJulian Elischer struct proc *p = td->td_proc; 604b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 605b1fc0ec1SRobert Watson uid_t euid; 6061419eacbSAlfred Perlstein struct uidinfo *euip; 607eb725b4eSRobert Watson int error; 608df8bae1dSRodney W. Grimes 609df8bae1dSRodney W. Grimes euid = uap->euid; 61014961ba7SRobert Watson AUDIT_ARG_EUID(euid); 61107f3485dSJohn Baldwin newcred = crget(); 6121419eacbSAlfred Perlstein euip = uifind(euid); 61307f3485dSJohn Baldwin PROC_LOCK(p); 614838d9858SBrooks Davis /* 615838d9858SBrooks Davis * Copy credentials so other references do not see our changes. 616838d9858SBrooks Davis */ 617838d9858SBrooks Davis oldcred = crcopysafe(p, newcred); 618030a28b3SRobert Watson 619030a28b3SRobert Watson #ifdef MAC 6206f6174a7SRobert Watson error = mac_cred_check_seteuid(oldcred, euid); 621030a28b3SRobert Watson if (error) 622030a28b3SRobert Watson goto fail; 623030a28b3SRobert Watson #endif 624030a28b3SRobert Watson 625b1fc0ec1SRobert Watson if (euid != oldcred->cr_ruid && /* allow seteuid(getuid()) */ 626b1fc0ec1SRobert Watson euid != oldcred->cr_svuid && /* allow seteuid(saved uid) */ 627cc426dd3SMateusz Guzik (error = priv_check_cred(oldcred, PRIV_CRED_SETEUID)) != 0) 628030a28b3SRobert Watson goto fail; 629030a28b3SRobert Watson 630df8bae1dSRodney W. Grimes /* 631838d9858SBrooks Davis * Everything's okay, do it. 632df8bae1dSRodney W. Grimes */ 633b1fc0ec1SRobert Watson if (oldcred->cr_uid != euid) { 6341419eacbSAlfred Perlstein change_euid(newcred, euip); 635d5f81602SSean Eric Fagan setsugid(p); 636229a15f0SPeter Wemm } 637daf63fd2SMateusz Guzik proc_set_cred(p, newcred); 63807f3485dSJohn Baldwin PROC_UNLOCK(p); 6391419eacbSAlfred Perlstein uifree(euip); 640b1fc0ec1SRobert Watson crfree(oldcred); 64107f3485dSJohn Baldwin return (0); 642030a28b3SRobert Watson 643030a28b3SRobert Watson fail: 644030a28b3SRobert Watson PROC_UNLOCK(p); 645030a28b3SRobert Watson uifree(euip); 646030a28b3SRobert Watson crfree(newcred); 647030a28b3SRobert Watson return (error); 648df8bae1dSRodney W. Grimes } 649df8bae1dSRodney W. Grimes 650d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 651df8bae1dSRodney W. Grimes struct setgid_args { 652df8bae1dSRodney W. Grimes gid_t gid; 653df8bae1dSRodney W. Grimes }; 654d2d3e875SBruce Evans #endif 655df8bae1dSRodney W. Grimes /* ARGSUSED */ 65626f9a767SRodney W. Grimes int 6578451d0ddSKip Macy sys_setgid(struct thread *td, struct setgid_args *uap) 658df8bae1dSRodney W. Grimes { 659b40ce416SJulian Elischer struct proc *p = td->td_proc; 660b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 661b1fc0ec1SRobert Watson gid_t gid; 662eb725b4eSRobert Watson int error; 663df8bae1dSRodney W. Grimes 664b1fc0ec1SRobert Watson gid = uap->gid; 66514961ba7SRobert Watson AUDIT_ARG_GID(gid); 66607f3485dSJohn Baldwin newcred = crget(); 66707f3485dSJohn Baldwin PROC_LOCK(p); 668838d9858SBrooks Davis oldcred = crcopysafe(p, newcred); 6695a92ee3cSRobert Watson 670030a28b3SRobert Watson #ifdef MAC 6716f6174a7SRobert Watson error = mac_cred_check_setgid(oldcred, gid); 672030a28b3SRobert Watson if (error) 673030a28b3SRobert Watson goto fail; 674030a28b3SRobert Watson #endif 675030a28b3SRobert Watson 676a08f4bf6SPeter Wemm /* 677a08f4bf6SPeter Wemm * See if we have "permission" by POSIX 1003.1 rules. 678a08f4bf6SPeter Wemm * 679a08f4bf6SPeter Wemm * Note that setgid(getegid()) is a special case of 680a08f4bf6SPeter Wemm * "appropriate privileges" in appendix B.4.2.2. We need 6812fa72ea7SJeroen Ruigrok van der Werven * to use this clause to be compatible with traditional BSD 682a08f4bf6SPeter Wemm * semantics. Basically, it means that "setgid(xx)" sets all 683a08f4bf6SPeter Wemm * three id's (assuming you have privs). 684a08f4bf6SPeter Wemm * 685a08f4bf6SPeter Wemm * For notes on the logic here, see setuid() above. 686a08f4bf6SPeter Wemm */ 687b1fc0ec1SRobert Watson if (gid != oldcred->cr_rgid && /* allow setgid(getgid()) */ 6883f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS 689b1fc0ec1SRobert Watson gid != oldcred->cr_svgid && /* allow setgid(saved gid) */ 690a08f4bf6SPeter Wemm #endif 691a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 692b1fc0ec1SRobert Watson gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */ 6933f246666SAndrey A. Chernov #endif 694cc426dd3SMateusz Guzik (error = priv_check_cred(oldcred, PRIV_CRED_SETGID)) != 0) 695030a28b3SRobert Watson goto fail; 696a08f4bf6SPeter Wemm 697a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS 698a08f4bf6SPeter Wemm /* 699a08f4bf6SPeter Wemm * Do we have "appropriate privileges" (are we root or gid == egid) 700a08f4bf6SPeter Wemm * If so, we are changing the real uid and saved gid. 701a08f4bf6SPeter Wemm */ 702a08f4bf6SPeter Wemm if ( 703a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 704b1fc0ec1SRobert Watson gid == oldcred->cr_groups[0] || 705a08f4bf6SPeter Wemm #endif 706800c9408SRobert Watson /* We are using privs. */ 707cc426dd3SMateusz Guzik priv_check_cred(oldcred, PRIV_CRED_SETGID) == 0) 708a08f4bf6SPeter Wemm #endif 709a08f4bf6SPeter Wemm { 710a08f4bf6SPeter Wemm /* 711a08f4bf6SPeter Wemm * Set real gid 712a08f4bf6SPeter Wemm */ 713b1fc0ec1SRobert Watson if (oldcred->cr_rgid != gid) { 714b1fc0ec1SRobert Watson change_rgid(newcred, gid); 715d5f81602SSean Eric Fagan setsugid(p); 716a08f4bf6SPeter Wemm } 717a08f4bf6SPeter Wemm /* 718a08f4bf6SPeter Wemm * Set saved gid 719a08f4bf6SPeter Wemm * 720a08f4bf6SPeter Wemm * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 721a08f4bf6SPeter Wemm * the security of setegid() depends on it. B.4.2.2 says it 722a08f4bf6SPeter Wemm * is important that we should do this. 723a08f4bf6SPeter Wemm */ 724b1fc0ec1SRobert Watson if (oldcred->cr_svgid != gid) { 725b1fc0ec1SRobert Watson change_svgid(newcred, gid); 726d5f81602SSean Eric Fagan setsugid(p); 727a08f4bf6SPeter Wemm } 728a08f4bf6SPeter Wemm } 729a08f4bf6SPeter Wemm /* 730a08f4bf6SPeter Wemm * In all cases permitted cases, we are changing the egid. 731a08f4bf6SPeter Wemm * Copy credentials so other references do not see our changes. 732a08f4bf6SPeter Wemm */ 733b1fc0ec1SRobert Watson if (oldcred->cr_groups[0] != gid) { 734b1fc0ec1SRobert Watson change_egid(newcred, gid); 735d5f81602SSean Eric Fagan setsugid(p); 736a08f4bf6SPeter Wemm } 737daf63fd2SMateusz Guzik proc_set_cred(p, newcred); 73807f3485dSJohn Baldwin PROC_UNLOCK(p); 739b1fc0ec1SRobert Watson crfree(oldcred); 74007f3485dSJohn Baldwin return (0); 741030a28b3SRobert Watson 742030a28b3SRobert Watson fail: 743030a28b3SRobert Watson PROC_UNLOCK(p); 744030a28b3SRobert Watson crfree(newcred); 745030a28b3SRobert Watson return (error); 746df8bae1dSRodney W. Grimes } 747df8bae1dSRodney W. Grimes 748d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 749df8bae1dSRodney W. Grimes struct setegid_args { 750df8bae1dSRodney W. Grimes gid_t egid; 751df8bae1dSRodney W. Grimes }; 752d2d3e875SBruce Evans #endif 753df8bae1dSRodney W. Grimes /* ARGSUSED */ 75426f9a767SRodney W. Grimes int 7558451d0ddSKip Macy sys_setegid(struct thread *td, struct setegid_args *uap) 756df8bae1dSRodney W. Grimes { 757b40ce416SJulian Elischer struct proc *p = td->td_proc; 758b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 759b1fc0ec1SRobert Watson gid_t egid; 760eb725b4eSRobert Watson int error; 761df8bae1dSRodney W. Grimes 762df8bae1dSRodney W. Grimes egid = uap->egid; 76314961ba7SRobert Watson AUDIT_ARG_EGID(egid); 76407f3485dSJohn Baldwin newcred = crget(); 76507f3485dSJohn Baldwin PROC_LOCK(p); 766838d9858SBrooks Davis oldcred = crcopysafe(p, newcred); 767030a28b3SRobert Watson 768030a28b3SRobert Watson #ifdef MAC 7696f6174a7SRobert Watson error = mac_cred_check_setegid(oldcred, egid); 770030a28b3SRobert Watson if (error) 771030a28b3SRobert Watson goto fail; 772030a28b3SRobert Watson #endif 773030a28b3SRobert Watson 774b1fc0ec1SRobert Watson if (egid != oldcred->cr_rgid && /* allow setegid(getgid()) */ 775b1fc0ec1SRobert Watson egid != oldcred->cr_svgid && /* allow setegid(saved gid) */ 776cc426dd3SMateusz Guzik (error = priv_check_cred(oldcred, PRIV_CRED_SETEGID)) != 0) 777030a28b3SRobert Watson goto fail; 778030a28b3SRobert Watson 779b1fc0ec1SRobert Watson if (oldcred->cr_groups[0] != egid) { 780b1fc0ec1SRobert Watson change_egid(newcred, egid); 781d5f81602SSean Eric Fagan setsugid(p); 782229a15f0SPeter Wemm } 783daf63fd2SMateusz Guzik proc_set_cred(p, newcred); 78407f3485dSJohn Baldwin PROC_UNLOCK(p); 785b1fc0ec1SRobert Watson crfree(oldcred); 78607f3485dSJohn Baldwin return (0); 787030a28b3SRobert Watson 788030a28b3SRobert Watson fail: 789030a28b3SRobert Watson PROC_UNLOCK(p); 790030a28b3SRobert Watson crfree(newcred); 791030a28b3SRobert Watson return (error); 792df8bae1dSRodney W. Grimes } 793df8bae1dSRodney W. Grimes 794d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 795df8bae1dSRodney W. Grimes struct setgroups_args { 796df8bae1dSRodney W. Grimes u_int gidsetsize; 797df8bae1dSRodney W. Grimes gid_t *gidset; 798df8bae1dSRodney W. Grimes }; 799d2d3e875SBruce Evans #endif 800df8bae1dSRodney W. Grimes /* ARGSUSED */ 80126f9a767SRodney W. Grimes int 8028451d0ddSKip Macy sys_setgroups(struct thread *td, struct setgroups_args *uap) 803df8bae1dSRodney W. Grimes { 80492b064f4SMateusz Guzik gid_t smallgroups[XU_NGROUPS]; 8057e9a456aSMateusz Guzik gid_t *groups; 80692b064f4SMateusz Guzik u_int gidsetsize; 807df8bae1dSRodney W. Grimes int error; 808df8bae1dSRodney W. Grimes 80992b064f4SMateusz Guzik gidsetsize = uap->gidsetsize; 81092b064f4SMateusz Guzik if (gidsetsize > ngroups_max + 1) 8113cb83e71SJohn Baldwin return (EINVAL); 8127e9a456aSMateusz Guzik 81392b064f4SMateusz Guzik if (gidsetsize > XU_NGROUPS) 81492b064f4SMateusz Guzik groups = malloc(gidsetsize * sizeof(gid_t), M_TEMP, M_WAITOK); 81592b064f4SMateusz Guzik else 81692b064f4SMateusz Guzik groups = smallgroups; 8177e9a456aSMateusz Guzik 81892b064f4SMateusz Guzik error = copyin(uap->gidset, groups, gidsetsize * sizeof(gid_t)); 8197e9a456aSMateusz Guzik if (error == 0) 82092b064f4SMateusz Guzik error = kern_setgroups(td, gidsetsize, groups); 8217e9a456aSMateusz Guzik 82292b064f4SMateusz Guzik if (gidsetsize > XU_NGROUPS) 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 834b9063886SMateusz Guzik MPASS(ngrp <= ngroups_max + 1); 83514961ba7SRobert Watson AUDIT_ARG_GROUPSET(groups, ngrp); 83607f3485dSJohn Baldwin newcred = crget(); 837838d9858SBrooks Davis crextend(newcred, ngrp); 83807f3485dSJohn Baldwin PROC_LOCK(p); 839838d9858SBrooks Davis oldcred = crcopysafe(p, newcred); 840030a28b3SRobert Watson 841030a28b3SRobert Watson #ifdef MAC 8426f6174a7SRobert Watson error = mac_cred_check_setgroups(oldcred, ngrp, groups); 843030a28b3SRobert Watson if (error) 844030a28b3SRobert Watson goto fail; 845030a28b3SRobert Watson #endif 846030a28b3SRobert Watson 847cc426dd3SMateusz Guzik error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS); 848030a28b3SRobert Watson if (error) 849030a28b3SRobert Watson goto fail; 85007f3485dSJohn Baldwin 8517e9a456aSMateusz Guzik if (ngrp == 0) { 8528a5d815aSPeter Wemm /* 8538a5d815aSPeter Wemm * setgroups(0, NULL) is a legitimate way of clearing the 8548a5d815aSPeter Wemm * groups vector on non-BSD systems (which generally do not 8558a5d815aSPeter Wemm * have the egid in the groups[0]). We risk security holes 8568a5d815aSPeter Wemm * when running non-BSD software if we do not do the same. 8578a5d815aSPeter Wemm */ 858b1fc0ec1SRobert Watson newcred->cr_ngroups = 1; 8598a5d815aSPeter Wemm } else { 860838d9858SBrooks Davis crsetgroups_locked(newcred, ngrp, groups); 8618a5d815aSPeter Wemm } 862d5f81602SSean Eric Fagan setsugid(p); 863daf63fd2SMateusz Guzik proc_set_cred(p, newcred); 86407f3485dSJohn Baldwin PROC_UNLOCK(p); 865b1fc0ec1SRobert Watson crfree(oldcred); 86607f3485dSJohn Baldwin return (0); 867030a28b3SRobert Watson 868030a28b3SRobert Watson fail: 869030a28b3SRobert Watson PROC_UNLOCK(p); 870030a28b3SRobert Watson crfree(newcred); 871030a28b3SRobert Watson return (error); 872df8bae1dSRodney W. Grimes } 873df8bae1dSRodney W. Grimes 874d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 875df8bae1dSRodney W. Grimes struct setreuid_args { 87600999cd6SAndrey A. Chernov uid_t ruid; 87700999cd6SAndrey A. Chernov uid_t euid; 878df8bae1dSRodney W. Grimes }; 879d2d3e875SBruce Evans #endif 880df8bae1dSRodney W. Grimes /* ARGSUSED */ 88126f9a767SRodney W. Grimes int 8823e85b721SEd Maste sys_setreuid(struct thread *td, struct setreuid_args *uap) 883df8bae1dSRodney W. Grimes { 884b40ce416SJulian Elischer struct proc *p = td->td_proc; 885b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 886eb725b4eSRobert Watson uid_t euid, ruid; 8871419eacbSAlfred Perlstein struct uidinfo *euip, *ruip; 888eb725b4eSRobert Watson int error; 889df8bae1dSRodney W. Grimes 89000999cd6SAndrey A. Chernov euid = uap->euid; 891eb725b4eSRobert Watson ruid = uap->ruid; 89214961ba7SRobert Watson AUDIT_ARG_EUID(euid); 89314961ba7SRobert Watson AUDIT_ARG_RUID(ruid); 89407f3485dSJohn Baldwin newcred = crget(); 8951419eacbSAlfred Perlstein euip = uifind(euid); 8961419eacbSAlfred Perlstein ruip = uifind(ruid); 89707f3485dSJohn Baldwin PROC_LOCK(p); 898838d9858SBrooks Davis oldcred = crcopysafe(p, newcred); 899030a28b3SRobert Watson 900030a28b3SRobert Watson #ifdef MAC 9016f6174a7SRobert Watson error = mac_cred_check_setreuid(oldcred, ruid, euid); 902030a28b3SRobert Watson if (error) 903030a28b3SRobert Watson goto fail; 904030a28b3SRobert Watson #endif 905030a28b3SRobert Watson 906b1fc0ec1SRobert Watson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 907b1fc0ec1SRobert Watson ruid != oldcred->cr_svuid) || 908b1fc0ec1SRobert Watson (euid != (uid_t)-1 && euid != oldcred->cr_uid && 909b1fc0ec1SRobert Watson euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) && 910cc426dd3SMateusz Guzik (error = priv_check_cred(oldcred, PRIV_CRED_SETREUID)) != 0) 911030a28b3SRobert Watson goto fail; 912030a28b3SRobert Watson 913b1fc0ec1SRobert Watson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 9141419eacbSAlfred Perlstein change_euid(newcred, euip); 915d5f81602SSean Eric Fagan setsugid(p); 916a89a5370SPeter Wemm } 917b1fc0ec1SRobert Watson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 9181419eacbSAlfred Perlstein change_ruid(newcred, ruip); 919d5f81602SSean Eric Fagan setsugid(p); 92000999cd6SAndrey A. Chernov } 921b1fc0ec1SRobert Watson if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) && 922b1fc0ec1SRobert Watson newcred->cr_svuid != newcred->cr_uid) { 923b1fc0ec1SRobert Watson change_svuid(newcred, newcred->cr_uid); 924d5f81602SSean Eric Fagan setsugid(p); 925a89a5370SPeter Wemm } 926daf63fd2SMateusz Guzik proc_set_cred(p, newcred); 927e4dcb704SEdward Tomasz Napierala #ifdef RACCT 928e4dcb704SEdward Tomasz Napierala racct_proc_ucred_changed(p, oldcred, newcred); 929f87beb93SAndriy Gapon crhold(newcred); 930f87beb93SAndriy Gapon #endif 931f87beb93SAndriy Gapon PROC_UNLOCK(p); 932f87beb93SAndriy Gapon #ifdef RCTL 933f87beb93SAndriy Gapon rctl_proc_ucred_changed(p, newcred); 934f87beb93SAndriy Gapon crfree(newcred); 935e4dcb704SEdward Tomasz Napierala #endif 9361419eacbSAlfred Perlstein uifree(ruip); 9371419eacbSAlfred Perlstein uifree(euip); 938b1fc0ec1SRobert Watson crfree(oldcred); 93907f3485dSJohn Baldwin return (0); 940030a28b3SRobert Watson 941030a28b3SRobert Watson fail: 942030a28b3SRobert Watson PROC_UNLOCK(p); 943030a28b3SRobert Watson uifree(ruip); 944030a28b3SRobert Watson uifree(euip); 945030a28b3SRobert Watson crfree(newcred); 946030a28b3SRobert Watson return (error); 947df8bae1dSRodney W. Grimes } 948df8bae1dSRodney W. Grimes 949d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 950df8bae1dSRodney W. Grimes struct setregid_args { 95100999cd6SAndrey A. Chernov gid_t rgid; 95200999cd6SAndrey A. Chernov gid_t egid; 953df8bae1dSRodney W. Grimes }; 954d2d3e875SBruce Evans #endif 955df8bae1dSRodney W. Grimes /* ARGSUSED */ 95626f9a767SRodney W. Grimes int 9573e85b721SEd Maste sys_setregid(struct thread *td, struct setregid_args *uap) 958df8bae1dSRodney W. Grimes { 959b40ce416SJulian Elischer struct proc *p = td->td_proc; 960b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 961eb725b4eSRobert Watson gid_t egid, rgid; 962eb725b4eSRobert Watson int error; 963df8bae1dSRodney W. Grimes 96400999cd6SAndrey A. Chernov egid = uap->egid; 965eb725b4eSRobert Watson rgid = uap->rgid; 96614961ba7SRobert Watson AUDIT_ARG_EGID(egid); 96714961ba7SRobert Watson AUDIT_ARG_RGID(rgid); 96807f3485dSJohn Baldwin newcred = crget(); 96907f3485dSJohn Baldwin PROC_LOCK(p); 970838d9858SBrooks Davis oldcred = crcopysafe(p, newcred); 971030a28b3SRobert Watson 972030a28b3SRobert Watson #ifdef MAC 9736f6174a7SRobert Watson error = mac_cred_check_setregid(oldcred, rgid, egid); 974030a28b3SRobert Watson if (error) 975030a28b3SRobert Watson goto fail; 976030a28b3SRobert Watson #endif 977030a28b3SRobert Watson 978b1fc0ec1SRobert Watson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 979b1fc0ec1SRobert Watson rgid != oldcred->cr_svgid) || 980b1fc0ec1SRobert Watson (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] && 981b1fc0ec1SRobert Watson egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) && 982cc426dd3SMateusz Guzik (error = priv_check_cred(oldcred, PRIV_CRED_SETREGID)) != 0) 983030a28b3SRobert Watson goto fail; 98407f3485dSJohn Baldwin 985b1fc0ec1SRobert Watson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 986b1fc0ec1SRobert Watson change_egid(newcred, egid); 987d5f81602SSean Eric Fagan setsugid(p); 988a89a5370SPeter Wemm } 989b1fc0ec1SRobert Watson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 990b1fc0ec1SRobert Watson change_rgid(newcred, rgid); 991d5f81602SSean Eric Fagan setsugid(p); 992a89a5370SPeter Wemm } 993b1fc0ec1SRobert Watson if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) && 994b1fc0ec1SRobert Watson newcred->cr_svgid != newcred->cr_groups[0]) { 995b1fc0ec1SRobert Watson change_svgid(newcred, newcred->cr_groups[0]); 996d5f81602SSean Eric Fagan setsugid(p); 997a89a5370SPeter Wemm } 998daf63fd2SMateusz Guzik proc_set_cred(p, newcred); 99907f3485dSJohn Baldwin PROC_UNLOCK(p); 10004589be70SRuslan Ermilov crfree(oldcred); 100107f3485dSJohn Baldwin return (0); 1002030a28b3SRobert Watson 1003030a28b3SRobert Watson fail: 1004030a28b3SRobert Watson PROC_UNLOCK(p); 1005030a28b3SRobert Watson crfree(newcred); 1006030a28b3SRobert Watson return (error); 1007df8bae1dSRodney W. Grimes } 1008df8bae1dSRodney W. Grimes 10098ccd6334SPeter Wemm /* 1010873fbcd7SRobert Watson * setresuid(ruid, euid, suid) is like setreuid except control over the saved 1011873fbcd7SRobert Watson * uid is explicit. 10128ccd6334SPeter Wemm */ 10138ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 10148ccd6334SPeter Wemm struct setresuid_args { 10158ccd6334SPeter Wemm uid_t ruid; 10168ccd6334SPeter Wemm uid_t euid; 10178ccd6334SPeter Wemm uid_t suid; 10188ccd6334SPeter Wemm }; 10198ccd6334SPeter Wemm #endif 10208ccd6334SPeter Wemm /* ARGSUSED */ 10218ccd6334SPeter Wemm int 10223e85b721SEd Maste sys_setresuid(struct thread *td, struct setresuid_args *uap) 10238ccd6334SPeter Wemm { 1024b40ce416SJulian Elischer struct proc *p = td->td_proc; 1025b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 1026eb725b4eSRobert Watson uid_t euid, ruid, suid; 10271419eacbSAlfred Perlstein struct uidinfo *euip, *ruip; 10288ccd6334SPeter Wemm int error; 10298ccd6334SPeter Wemm 10308ccd6334SPeter Wemm euid = uap->euid; 1031eb725b4eSRobert Watson ruid = uap->ruid; 10328ccd6334SPeter Wemm suid = uap->suid; 103314961ba7SRobert Watson AUDIT_ARG_EUID(euid); 103414961ba7SRobert Watson AUDIT_ARG_RUID(ruid); 103514961ba7SRobert Watson AUDIT_ARG_SUID(suid); 103607f3485dSJohn Baldwin newcred = crget(); 10371419eacbSAlfred Perlstein euip = uifind(euid); 10381419eacbSAlfred Perlstein ruip = uifind(ruid); 103907f3485dSJohn Baldwin PROC_LOCK(p); 1040838d9858SBrooks Davis oldcred = crcopysafe(p, newcred); 1041030a28b3SRobert Watson 1042030a28b3SRobert Watson #ifdef MAC 10436f6174a7SRobert Watson error = mac_cred_check_setresuid(oldcred, ruid, euid, suid); 1044030a28b3SRobert Watson if (error) 1045030a28b3SRobert Watson goto fail; 1046030a28b3SRobert Watson #endif 1047030a28b3SRobert Watson 1048b1fc0ec1SRobert Watson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 1049b1fc0ec1SRobert Watson ruid != oldcred->cr_svuid && 1050b1fc0ec1SRobert Watson ruid != oldcred->cr_uid) || 1051b1fc0ec1SRobert Watson (euid != (uid_t)-1 && euid != oldcred->cr_ruid && 1052b1fc0ec1SRobert Watson euid != oldcred->cr_svuid && 1053b1fc0ec1SRobert Watson euid != oldcred->cr_uid) || 1054b1fc0ec1SRobert Watson (suid != (uid_t)-1 && suid != oldcred->cr_ruid && 1055b1fc0ec1SRobert Watson suid != oldcred->cr_svuid && 1056b1fc0ec1SRobert Watson suid != oldcred->cr_uid)) && 1057cc426dd3SMateusz Guzik (error = priv_check_cred(oldcred, PRIV_CRED_SETRESUID)) != 0) 1058030a28b3SRobert Watson goto fail; 105907f3485dSJohn Baldwin 1060b1fc0ec1SRobert Watson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 10611419eacbSAlfred Perlstein change_euid(newcred, euip); 10628ccd6334SPeter Wemm setsugid(p); 10638ccd6334SPeter Wemm } 1064b1fc0ec1SRobert Watson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 10651419eacbSAlfred Perlstein change_ruid(newcred, ruip); 10668ccd6334SPeter Wemm setsugid(p); 10678ccd6334SPeter Wemm } 1068b1fc0ec1SRobert Watson if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) { 1069b1fc0ec1SRobert Watson change_svuid(newcred, suid); 10708ccd6334SPeter Wemm setsugid(p); 10718ccd6334SPeter Wemm } 1072daf63fd2SMateusz Guzik proc_set_cred(p, newcred); 1073e4dcb704SEdward Tomasz Napierala #ifdef RACCT 1074e4dcb704SEdward Tomasz Napierala racct_proc_ucred_changed(p, oldcred, newcred); 1075f87beb93SAndriy Gapon crhold(newcred); 1076f87beb93SAndriy Gapon #endif 1077f87beb93SAndriy Gapon PROC_UNLOCK(p); 1078f87beb93SAndriy Gapon #ifdef RCTL 1079f87beb93SAndriy Gapon rctl_proc_ucred_changed(p, newcred); 1080f87beb93SAndriy Gapon crfree(newcred); 1081e4dcb704SEdward Tomasz Napierala #endif 10821419eacbSAlfred Perlstein uifree(ruip); 10831419eacbSAlfred Perlstein uifree(euip); 1084b1fc0ec1SRobert Watson crfree(oldcred); 108507f3485dSJohn Baldwin return (0); 1086030a28b3SRobert Watson 1087030a28b3SRobert Watson fail: 1088030a28b3SRobert Watson PROC_UNLOCK(p); 1089030a28b3SRobert Watson uifree(ruip); 1090030a28b3SRobert Watson uifree(euip); 1091030a28b3SRobert Watson crfree(newcred); 1092030a28b3SRobert Watson return (error); 1093030a28b3SRobert Watson 10948ccd6334SPeter Wemm } 10958ccd6334SPeter Wemm 10968ccd6334SPeter Wemm /* 1097873fbcd7SRobert Watson * setresgid(rgid, egid, sgid) is like setregid except control over the saved 1098873fbcd7SRobert Watson * gid is explicit. 10998ccd6334SPeter Wemm */ 11008ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 11018ccd6334SPeter Wemm struct setresgid_args { 11028ccd6334SPeter Wemm gid_t rgid; 11038ccd6334SPeter Wemm gid_t egid; 11048ccd6334SPeter Wemm gid_t sgid; 11058ccd6334SPeter Wemm }; 11068ccd6334SPeter Wemm #endif 11078ccd6334SPeter Wemm /* ARGSUSED */ 11088ccd6334SPeter Wemm int 11093e85b721SEd Maste sys_setresgid(struct thread *td, struct setresgid_args *uap) 11108ccd6334SPeter Wemm { 1111b40ce416SJulian Elischer struct proc *p = td->td_proc; 1112b1fc0ec1SRobert Watson struct ucred *newcred, *oldcred; 1113eb725b4eSRobert Watson gid_t egid, rgid, sgid; 11148ccd6334SPeter Wemm int error; 11158ccd6334SPeter Wemm 11168ccd6334SPeter Wemm egid = uap->egid; 1117eb725b4eSRobert Watson rgid = uap->rgid; 11188ccd6334SPeter Wemm sgid = uap->sgid; 111914961ba7SRobert Watson AUDIT_ARG_EGID(egid); 112014961ba7SRobert Watson AUDIT_ARG_RGID(rgid); 112114961ba7SRobert Watson AUDIT_ARG_SGID(sgid); 112207f3485dSJohn Baldwin newcred = crget(); 112307f3485dSJohn Baldwin PROC_LOCK(p); 1124838d9858SBrooks Davis oldcred = crcopysafe(p, newcred); 1125030a28b3SRobert Watson 1126030a28b3SRobert Watson #ifdef MAC 11276f6174a7SRobert Watson error = mac_cred_check_setresgid(oldcred, rgid, egid, sgid); 1128030a28b3SRobert Watson if (error) 1129030a28b3SRobert Watson goto fail; 1130030a28b3SRobert Watson #endif 1131030a28b3SRobert Watson 1132b1fc0ec1SRobert Watson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 1133b1fc0ec1SRobert Watson rgid != oldcred->cr_svgid && 1134b1fc0ec1SRobert Watson rgid != oldcred->cr_groups[0]) || 1135b1fc0ec1SRobert Watson (egid != (gid_t)-1 && egid != oldcred->cr_rgid && 1136b1fc0ec1SRobert Watson egid != oldcred->cr_svgid && 1137b1fc0ec1SRobert Watson egid != oldcred->cr_groups[0]) || 1138b1fc0ec1SRobert Watson (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid && 1139b1fc0ec1SRobert Watson sgid != oldcred->cr_svgid && 1140b1fc0ec1SRobert Watson sgid != oldcred->cr_groups[0])) && 1141cc426dd3SMateusz Guzik (error = priv_check_cred(oldcred, PRIV_CRED_SETRESGID)) != 0) 1142030a28b3SRobert Watson goto fail; 114307f3485dSJohn Baldwin 1144b1fc0ec1SRobert Watson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 1145b1fc0ec1SRobert Watson change_egid(newcred, egid); 11468ccd6334SPeter Wemm setsugid(p); 11478ccd6334SPeter Wemm } 1148b1fc0ec1SRobert Watson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 1149b1fc0ec1SRobert Watson change_rgid(newcred, rgid); 11508ccd6334SPeter Wemm setsugid(p); 11518ccd6334SPeter Wemm } 1152b1fc0ec1SRobert Watson if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) { 1153b1fc0ec1SRobert Watson change_svgid(newcred, sgid); 11548ccd6334SPeter Wemm setsugid(p); 11558ccd6334SPeter Wemm } 1156daf63fd2SMateusz Guzik proc_set_cred(p, newcred); 115707f3485dSJohn Baldwin PROC_UNLOCK(p); 1158b1fc0ec1SRobert Watson crfree(oldcred); 115907f3485dSJohn Baldwin return (0); 1160030a28b3SRobert Watson 1161030a28b3SRobert Watson fail: 1162030a28b3SRobert Watson PROC_UNLOCK(p); 1163030a28b3SRobert Watson crfree(newcred); 1164030a28b3SRobert Watson return (error); 11658ccd6334SPeter Wemm } 11668ccd6334SPeter Wemm 11678ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 11688ccd6334SPeter Wemm struct getresuid_args { 11698ccd6334SPeter Wemm uid_t *ruid; 11708ccd6334SPeter Wemm uid_t *euid; 11718ccd6334SPeter Wemm uid_t *suid; 11728ccd6334SPeter Wemm }; 11738ccd6334SPeter Wemm #endif 11748ccd6334SPeter Wemm /* ARGSUSED */ 11758ccd6334SPeter Wemm int 11763e85b721SEd Maste sys_getresuid(struct thread *td, struct getresuid_args *uap) 11778ccd6334SPeter Wemm { 1178835a82eeSMatthew Dillon struct ucred *cred; 11798ccd6334SPeter Wemm int error1 = 0, error2 = 0, error3 = 0; 11808ccd6334SPeter Wemm 1181d74ac681SMatthew Dillon cred = td->td_ucred; 11828ccd6334SPeter Wemm if (uap->ruid) 11837f05b035SAlfred Perlstein error1 = copyout(&cred->cr_ruid, 11847f05b035SAlfred Perlstein uap->ruid, sizeof(cred->cr_ruid)); 11858ccd6334SPeter Wemm if (uap->euid) 11867f05b035SAlfred Perlstein error2 = copyout(&cred->cr_uid, 11877f05b035SAlfred Perlstein uap->euid, sizeof(cred->cr_uid)); 11888ccd6334SPeter Wemm if (uap->suid) 11897f05b035SAlfred Perlstein error3 = copyout(&cred->cr_svuid, 11907f05b035SAlfred Perlstein uap->suid, sizeof(cred->cr_svuid)); 1191eb725b4eSRobert Watson return (error1 ? error1 : error2 ? error2 : error3); 11928ccd6334SPeter Wemm } 11938ccd6334SPeter Wemm 11948ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 11958ccd6334SPeter Wemm struct getresgid_args { 11968ccd6334SPeter Wemm gid_t *rgid; 11978ccd6334SPeter Wemm gid_t *egid; 11988ccd6334SPeter Wemm gid_t *sgid; 11998ccd6334SPeter Wemm }; 12008ccd6334SPeter Wemm #endif 12018ccd6334SPeter Wemm /* ARGSUSED */ 12028ccd6334SPeter Wemm int 12033e85b721SEd Maste sys_getresgid(struct thread *td, struct getresgid_args *uap) 12048ccd6334SPeter Wemm { 1205835a82eeSMatthew Dillon struct ucred *cred; 12068ccd6334SPeter Wemm int error1 = 0, error2 = 0, error3 = 0; 12078ccd6334SPeter Wemm 1208d74ac681SMatthew Dillon cred = td->td_ucred; 12098ccd6334SPeter Wemm if (uap->rgid) 12107f05b035SAlfred Perlstein error1 = copyout(&cred->cr_rgid, 12117f05b035SAlfred Perlstein uap->rgid, sizeof(cred->cr_rgid)); 12128ccd6334SPeter Wemm if (uap->egid) 12137f05b035SAlfred Perlstein error2 = copyout(&cred->cr_groups[0], 12147f05b035SAlfred Perlstein uap->egid, sizeof(cred->cr_groups[0])); 12158ccd6334SPeter Wemm if (uap->sgid) 12167f05b035SAlfred Perlstein error3 = copyout(&cred->cr_svgid, 12177f05b035SAlfred Perlstein uap->sgid, sizeof(cred->cr_svgid)); 1218eb725b4eSRobert Watson return (error1 ? error1 : error2 ? error2 : error3); 12198ccd6334SPeter Wemm } 12208ccd6334SPeter Wemm 1221b67cbc65SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1222b67cbc65SPeter Wemm struct issetugid_args { 1223b67cbc65SPeter Wemm int dummy; 1224b67cbc65SPeter Wemm }; 1225b67cbc65SPeter Wemm #endif 1226b67cbc65SPeter Wemm /* ARGSUSED */ 1227b67cbc65SPeter Wemm int 12283e85b721SEd Maste sys_issetugid(struct thread *td, struct issetugid_args *uap) 1229b67cbc65SPeter Wemm { 1230b40ce416SJulian Elischer struct proc *p = td->td_proc; 1231b40ce416SJulian Elischer 1232b67cbc65SPeter Wemm /* 1233b67cbc65SPeter Wemm * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 1234b67cbc65SPeter Wemm * we use P_SUGID because we consider changing the owners as 1235b67cbc65SPeter Wemm * "tainting" as well. 1236b67cbc65SPeter Wemm * This is significant for procs that start as root and "become" 1237b67cbc65SPeter Wemm * a user without an exec - programs cannot know *everything* 1238b67cbc65SPeter Wemm * that libc *might* have put in their data segment. 1239b67cbc65SPeter Wemm */ 1240b40ce416SJulian Elischer td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 1241b67cbc65SPeter Wemm return (0); 1242b67cbc65SPeter Wemm } 1243b67cbc65SPeter Wemm 1244130d0157SRobert Watson int 12458451d0ddSKip Macy sys___setugid(struct thread *td, struct __setugid_args *uap) 1246130d0157SRobert Watson { 1247130d0157SRobert Watson #ifdef REGRESSION 124807f3485dSJohn Baldwin struct proc *p; 1249835a82eeSMatthew Dillon 125007f3485dSJohn Baldwin p = td->td_proc; 1251130d0157SRobert Watson switch (uap->flag) { 1252130d0157SRobert Watson case 0: 125307f3485dSJohn Baldwin PROC_LOCK(p); 125407f3485dSJohn Baldwin p->p_flag &= ~P_SUGID; 125507f3485dSJohn Baldwin PROC_UNLOCK(p); 125607f3485dSJohn Baldwin return (0); 125707f3485dSJohn Baldwin case 1: 125807f3485dSJohn Baldwin PROC_LOCK(p); 125907f3485dSJohn Baldwin p->p_flag |= P_SUGID; 126007f3485dSJohn Baldwin PROC_UNLOCK(p); 126107f3485dSJohn Baldwin return (0); 126207f3485dSJohn Baldwin default: 126307f3485dSJohn Baldwin return (EINVAL); 126407f3485dSJohn Baldwin } 1265130d0157SRobert Watson #else /* !REGRESSION */ 1266eb725b4eSRobert Watson 1267130d0157SRobert Watson return (ENOSYS); 1268eb725b4eSRobert Watson #endif /* REGRESSION */ 1269130d0157SRobert Watson } 1270130d0157SRobert Watson 1271df8bae1dSRodney W. Grimes /* 1272df8bae1dSRodney W. Grimes * Check if gid is a member of the group set. 1273df8bae1dSRodney W. Grimes */ 127426f9a767SRodney W. Grimes int 12754c44ad8eSJohn Baldwin groupmember(gid_t gid, struct ucred *cred) 1276df8bae1dSRodney W. Grimes { 12777f92e578SBrooks Davis int l; 12787f92e578SBrooks Davis int h; 12797f92e578SBrooks Davis int m; 1280df8bae1dSRodney W. Grimes 12817f92e578SBrooks Davis if (cred->cr_groups[0] == gid) 1282df8bae1dSRodney W. Grimes return(1); 12837f92e578SBrooks Davis 12847f92e578SBrooks Davis /* 12857f92e578SBrooks Davis * If gid was not our primary group, perform a binary search 12867f92e578SBrooks Davis * of the supplemental groups. This is possible because we 12877f92e578SBrooks Davis * sort the groups in crsetgroups(). 12887f92e578SBrooks Davis */ 12897f92e578SBrooks Davis l = 1; 12907f92e578SBrooks Davis h = cred->cr_ngroups; 12917f92e578SBrooks Davis while (l < h) { 12927f92e578SBrooks Davis m = l + ((h - l) / 2); 12937f92e578SBrooks Davis if (cred->cr_groups[m] < gid) 12947f92e578SBrooks Davis l = m + 1; 12957f92e578SBrooks Davis else 12967f92e578SBrooks Davis h = m; 12977f92e578SBrooks Davis } 12987f92e578SBrooks Davis if ((l < cred->cr_ngroups) && (cred->cr_groups[l] == gid)) 12997f92e578SBrooks Davis return (1); 13007f92e578SBrooks Davis 1301df8bae1dSRodney W. Grimes return (0); 1302df8bae1dSRodney W. Grimes } 1303df8bae1dSRodney W. Grimes 13043b243b72SRobert Watson /* 1305eb725b4eSRobert Watson * Test the active securelevel against a given level. securelevel_gt() 1306eb725b4eSRobert Watson * implements (securelevel > level). securelevel_ge() implements 1307eb725b4eSRobert Watson * (securelevel >= level). Note that the logic is inverted -- these 1308eb725b4eSRobert Watson * functions return EPERM on "success" and 0 on "failure". 13093ca719f1SRobert Watson * 13100304c731SJamie Gritton * Due to care taken when setting the securelevel, we know that no jail will 13110304c731SJamie Gritton * be less secure that its parent (or the physical system), so it is sufficient 13120304c731SJamie Gritton * to test the current jail only. 13130304c731SJamie Gritton * 1314800c9408SRobert Watson * XXXRW: Possibly since this has to do with privilege, it should move to 1315800c9408SRobert Watson * kern_priv.c. 13163ca719f1SRobert Watson */ 13173ca719f1SRobert Watson int 13183ca719f1SRobert Watson securelevel_gt(struct ucred *cr, int level) 13193ca719f1SRobert Watson { 13203ca719f1SRobert Watson 13210304c731SJamie Gritton return (cr->cr_prison->pr_securelevel > level ? EPERM : 0); 13223ca719f1SRobert Watson } 13233ca719f1SRobert Watson 13243ca719f1SRobert Watson int 13253ca719f1SRobert Watson securelevel_ge(struct ucred *cr, int level) 13263ca719f1SRobert Watson { 13273ca719f1SRobert Watson 13280304c731SJamie Gritton return (cr->cr_prison->pr_securelevel >= level ? EPERM : 0); 13293ca719f1SRobert Watson } 13303ca719f1SRobert Watson 13318a7d8cc6SRobert Watson /* 1332e409590dSRobert Watson * 'see_other_uids' determines whether or not visibility of processes 1333eb725b4eSRobert Watson * and sockets with credentials holding different real uids is possible 133448713bdcSRobert Watson * using a variety of system MIBs. 1335eb725b4eSRobert Watson * XXX: data declarations should be together near the beginning of the file. 13368a7d8cc6SRobert Watson */ 1337e409590dSRobert Watson static int see_other_uids = 1; 1338d0615c64SAndrew R. Reiter SYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW, 1339eb725b4eSRobert Watson &see_other_uids, 0, 13408a7d8cc6SRobert Watson "Unprivileged processes may see subjects/objects with different real uid"); 13418a7d8cc6SRobert Watson 13421a996ed1SEdward Tomasz Napierala /*- 13431b350b45SRobert Watson * Determine if u1 "can see" the subject specified by u2, according to the 13441b350b45SRobert Watson * 'see_other_uids' policy. 13451b350b45SRobert Watson * Returns: 0 for permitted, ESRCH otherwise 13461b350b45SRobert Watson * Locks: none 13471b350b45SRobert Watson * References: *u1 and *u2 must not change during the call 13481b350b45SRobert Watson * u1 may equal u2, in which case only one reference is required 13491b350b45SRobert Watson */ 13504ac21b4fSStephen J. Kiernan int 13514ac21b4fSStephen J. Kiernan cr_canseeotheruids(struct ucred *u1, struct ucred *u2) 13521b350b45SRobert Watson { 13531b350b45SRobert Watson 13541b350b45SRobert Watson if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) { 1355cc426dd3SMateusz Guzik if (priv_check_cred(u1, PRIV_SEEOTHERUIDS) != 0) 13561b350b45SRobert Watson return (ESRCH); 13571b350b45SRobert Watson } 13581b350b45SRobert Watson return (0); 13591b350b45SRobert Watson } 13601b350b45SRobert Watson 136164d19c2eSRobert Watson /* 136264d19c2eSRobert Watson * 'see_other_gids' determines whether or not visibility of processes 136364d19c2eSRobert Watson * and sockets with credentials holding different real gids is possible 136464d19c2eSRobert Watson * using a variety of system MIBs. 136564d19c2eSRobert Watson * XXX: data declarations should be together near the beginning of the file. 136664d19c2eSRobert Watson */ 136764d19c2eSRobert Watson static int see_other_gids = 1; 136864d19c2eSRobert Watson SYSCTL_INT(_security_bsd, OID_AUTO, see_other_gids, CTLFLAG_RW, 136964d19c2eSRobert Watson &see_other_gids, 0, 137064d19c2eSRobert Watson "Unprivileged processes may see subjects/objects with different real gid"); 137164d19c2eSRobert Watson 137264d19c2eSRobert Watson /* 137364d19c2eSRobert Watson * Determine if u1 can "see" the subject specified by u2, according to the 137464d19c2eSRobert Watson * 'see_other_gids' policy. 137564d19c2eSRobert Watson * Returns: 0 for permitted, ESRCH otherwise 137664d19c2eSRobert Watson * Locks: none 137764d19c2eSRobert Watson * References: *u1 and *u2 must not change during the call 137864d19c2eSRobert Watson * u1 may equal u2, in which case only one reference is required 137964d19c2eSRobert Watson */ 13804ac21b4fSStephen J. Kiernan int 13814ac21b4fSStephen J. Kiernan cr_canseeothergids(struct ucred *u1, struct ucred *u2) 138264d19c2eSRobert Watson { 138364d19c2eSRobert Watson int i, match; 138464d19c2eSRobert Watson 138564d19c2eSRobert Watson if (!see_other_gids) { 138664d19c2eSRobert Watson match = 0; 138764d19c2eSRobert Watson for (i = 0; i < u1->cr_ngroups; i++) { 138864d19c2eSRobert Watson if (groupmember(u1->cr_groups[i], u2)) 138964d19c2eSRobert Watson match = 1; 139064d19c2eSRobert Watson if (match) 139164d19c2eSRobert Watson break; 139264d19c2eSRobert Watson } 139364d19c2eSRobert Watson if (!match) { 1394cc426dd3SMateusz Guzik if (priv_check_cred(u1, PRIV_SEEOTHERGIDS) != 0) 139564d19c2eSRobert Watson return (ESRCH); 139664d19c2eSRobert Watson } 139764d19c2eSRobert Watson } 139864d19c2eSRobert Watson return (0); 139964d19c2eSRobert Watson } 140064d19c2eSRobert Watson 1401a4aaba3bSSteve Wills /* 1402a4aaba3bSSteve Wills * 'see_jail_proc' determines whether or not visibility of processes and 1403a4aaba3bSSteve Wills * sockets with credentials holding different jail ids is possible using a 1404a4aaba3bSSteve Wills * variety of system MIBs. 1405a4aaba3bSSteve Wills * 1406a4aaba3bSSteve Wills * XXX: data declarations should be together near the beginning of the file. 1407a4aaba3bSSteve Wills */ 1408a4aaba3bSSteve Wills 1409a4aaba3bSSteve Wills static int see_jail_proc = 1; 1410a4aaba3bSSteve Wills SYSCTL_INT(_security_bsd, OID_AUTO, see_jail_proc, CTLFLAG_RW, 1411a4aaba3bSSteve Wills &see_jail_proc, 0, 1412a4aaba3bSSteve Wills "Unprivileged processes may see subjects/objects with different jail ids"); 1413a4aaba3bSSteve Wills 1414a4aaba3bSSteve Wills /*- 1415a4aaba3bSSteve Wills * Determine if u1 "can see" the subject specified by u2, according to the 1416a4aaba3bSSteve Wills * 'see_jail_proc' policy. 1417a4aaba3bSSteve Wills * Returns: 0 for permitted, ESRCH otherwise 1418a4aaba3bSSteve Wills * Locks: none 1419a4aaba3bSSteve Wills * References: *u1 and *u2 must not change during the call 1420a4aaba3bSSteve Wills * u1 may equal u2, in which case only one reference is required 1421a4aaba3bSSteve Wills */ 1422a4aaba3bSSteve Wills int 1423a4aaba3bSSteve Wills cr_canseejailproc(struct ucred *u1, struct ucred *u2) 1424a4aaba3bSSteve Wills { 1425a4aaba3bSSteve Wills if (u1->cr_uid == 0) 1426a4aaba3bSSteve Wills return (0); 1427a4aaba3bSSteve Wills return (!see_jail_proc && u1->cr_prison != u2->cr_prison ? ESRCH : 0); 1428a4aaba3bSSteve Wills } 1429a4aaba3bSSteve Wills 14301a996ed1SEdward Tomasz Napierala /*- 14317fd6a959SRobert Watson * Determine if u1 "can see" the subject specified by u2. 1432ed639720SRobert Watson * Returns: 0 for permitted, an errno value otherwise 1433ed639720SRobert Watson * Locks: none 1434eb725b4eSRobert Watson * References: *u1 and *u2 must not change during the call 1435ed639720SRobert Watson * u1 may equal u2, in which case only one reference is required 1436ed639720SRobert Watson */ 1437ed639720SRobert Watson int 143894088977SRobert Watson cr_cansee(struct ucred *u1, struct ucred *u2) 1439a9e0361bSPoul-Henning Kamp { 144091421ba2SRobert Watson int error; 1441a9e0361bSPoul-Henning Kamp 1442ed639720SRobert Watson if ((error = prison_check(u1, u2))) 144391421ba2SRobert Watson return (error); 14448a1d977dSRobert Watson #ifdef MAC 144530d239bcSRobert Watson if ((error = mac_cred_check_visible(u1, u2))) 14468a1d977dSRobert Watson return (error); 14478a1d977dSRobert Watson #endif 14484ac21b4fSStephen J. Kiernan if ((error = cr_canseeotheruids(u1, u2))) 14491b350b45SRobert Watson return (error); 14504ac21b4fSStephen J. Kiernan if ((error = cr_canseeothergids(u1, u2))) 145164d19c2eSRobert Watson return (error); 1452a4aaba3bSSteve Wills if ((error = cr_canseejailproc(u1, u2))) 1453a4aaba3bSSteve Wills return (error); 1454387d2c03SRobert Watson return (0); 1455387d2c03SRobert Watson } 1456387d2c03SRobert Watson 14571a996ed1SEdward Tomasz Napierala /*- 1458f44d9e24SJohn Baldwin * Determine if td "can see" the subject specified by p. 14593b243b72SRobert Watson * Returns: 0 for permitted, an errno value otherwise 1460f44d9e24SJohn Baldwin * Locks: Sufficient locks to protect p->p_ucred must be held. td really 1461f44d9e24SJohn Baldwin * should be curthread. 1462f44d9e24SJohn Baldwin * References: td and p must be valid for the lifetime of the call 14633b243b72SRobert Watson */ 1464a0f75161SRobert Watson int 1465f44d9e24SJohn Baldwin p_cansee(struct thread *td, struct proc *p) 1466ed639720SRobert Watson { 1467ed639720SRobert Watson 146894088977SRobert Watson /* Wrap cr_cansee() for all functionality. */ 1469f44d9e24SJohn Baldwin KASSERT(td == curthread, ("%s: td not curthread", __func__)); 1470f44d9e24SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 1471f44d9e24SJohn Baldwin return (cr_cansee(td->td_ucred, p->p_ucred)); 1472ed639720SRobert Watson } 1473ed639720SRobert Watson 147462c45ef4SRobert Watson /* 147562c45ef4SRobert Watson * 'conservative_signals' prevents the delivery of a broad class of 147662c45ef4SRobert Watson * signals by unprivileged processes to processes that have changed their 147762c45ef4SRobert Watson * credentials since the last invocation of execve(). This can prevent 147862c45ef4SRobert Watson * the leakage of cached information or retained privileges as a result 147962c45ef4SRobert Watson * of a common class of signal-related vulnerabilities. However, this 148062c45ef4SRobert Watson * may interfere with some applications that expect to be able to 148162c45ef4SRobert Watson * deliver these signals to peer processes after having given up 148262c45ef4SRobert Watson * privilege. 148362c45ef4SRobert Watson */ 148462c45ef4SRobert Watson static int conservative_signals = 1; 148562c45ef4SRobert Watson SYSCTL_INT(_security_bsd, OID_AUTO, conservative_signals, CTLFLAG_RW, 148662c45ef4SRobert Watson &conservative_signals, 0, "Unprivileged processes prevented from " 148762c45ef4SRobert Watson "sending certain signals to processes whose credentials have changed"); 14881a996ed1SEdward Tomasz Napierala /*- 1489c83f8015SRobert Watson * Determine whether cred may deliver the specified signal to proc. 1490c83f8015SRobert Watson * Returns: 0 for permitted, an errno value otherwise. 1491c83f8015SRobert Watson * Locks: A lock must be held for proc. 1492c83f8015SRobert Watson * References: cred and proc must be valid for the lifetime of the call. 14934c5eb9c3SRobert Watson */ 14944c5eb9c3SRobert Watson int 14951a88a252SMaxim Sobolev cr_cansignal(struct ucred *cred, struct proc *proc, int signum) 1496387d2c03SRobert Watson { 149791421ba2SRobert Watson int error; 1498387d2c03SRobert Watson 1499f44d9e24SJohn Baldwin PROC_LOCK_ASSERT(proc, MA_OWNED); 15004c5eb9c3SRobert Watson /* 1501c83f8015SRobert Watson * Jail semantics limit the scope of signalling to proc in the 1502c83f8015SRobert Watson * same jail as cred, if cred is in jail. 15034c5eb9c3SRobert Watson */ 1504c83f8015SRobert Watson error = prison_check(cred, proc->p_ucred); 1505c83f8015SRobert Watson if (error) 150691421ba2SRobert Watson return (error); 15078a1d977dSRobert Watson #ifdef MAC 150830d239bcSRobert Watson if ((error = mac_proc_check_signal(cred, proc, signum))) 15098a1d977dSRobert Watson return (error); 15108a1d977dSRobert Watson #endif 15114ac21b4fSStephen J. Kiernan if ((error = cr_canseeotheruids(cred, proc->p_ucred))) 151264d19c2eSRobert Watson return (error); 15134ac21b4fSStephen J. Kiernan if ((error = cr_canseeothergids(cred, proc->p_ucred))) 15141b350b45SRobert Watson return (error); 1515387d2c03SRobert Watson 1516387d2c03SRobert Watson /* 15173b243b72SRobert Watson * UNIX signal semantics depend on the status of the P_SUGID 15183b243b72SRobert Watson * bit on the target process. If the bit is set, then additional 15193b243b72SRobert Watson * restrictions are placed on the set of available signals. 15204c5eb9c3SRobert Watson */ 15211a88a252SMaxim Sobolev if (conservative_signals && (proc->p_flag & P_SUGID)) { 15224c5eb9c3SRobert Watson switch (signum) { 15234c5eb9c3SRobert Watson case 0: 15244c5eb9c3SRobert Watson case SIGKILL: 15254c5eb9c3SRobert Watson case SIGINT: 15264c5eb9c3SRobert Watson case SIGTERM: 152762c45ef4SRobert Watson case SIGALRM: 15284c5eb9c3SRobert Watson case SIGSTOP: 15294c5eb9c3SRobert Watson case SIGTTIN: 15304c5eb9c3SRobert Watson case SIGTTOU: 15314c5eb9c3SRobert Watson case SIGTSTP: 15324c5eb9c3SRobert Watson case SIGHUP: 15334c5eb9c3SRobert Watson case SIGUSR1: 15344c5eb9c3SRobert Watson case SIGUSR2: 15357fd6a959SRobert Watson /* 15367fd6a959SRobert Watson * Generally, permit job and terminal control 15377fd6a959SRobert Watson * signals. 15387fd6a959SRobert Watson */ 15394c5eb9c3SRobert Watson break; 15404c5eb9c3SRobert Watson default: 1541c83f8015SRobert Watson /* Not permitted without privilege. */ 1542cc426dd3SMateusz Guzik error = priv_check_cred(cred, PRIV_SIGNAL_SUGID); 15434c5eb9c3SRobert Watson if (error) 15444c5eb9c3SRobert Watson return (error); 15454c5eb9c3SRobert Watson } 1546e9e7ff5bSRobert Watson } 1547e9e7ff5bSRobert Watson 15484c5eb9c3SRobert Watson /* 15493b243b72SRobert Watson * Generally, the target credential's ruid or svuid must match the 1550e9e7ff5bSRobert Watson * subject credential's ruid or euid. 15514c5eb9c3SRobert Watson */ 1552c83f8015SRobert Watson if (cred->cr_ruid != proc->p_ucred->cr_ruid && 1553c83f8015SRobert Watson cred->cr_ruid != proc->p_ucred->cr_svuid && 1554c83f8015SRobert Watson cred->cr_uid != proc->p_ucred->cr_ruid && 1555c83f8015SRobert Watson cred->cr_uid != proc->p_ucred->cr_svuid) { 1556cc426dd3SMateusz Guzik error = priv_check_cred(cred, PRIV_SIGNAL_DIFFCRED); 15574c5eb9c3SRobert Watson if (error) 15584c5eb9c3SRobert Watson return (error); 15594c5eb9c3SRobert Watson } 1560387d2c03SRobert Watson 1561387d2c03SRobert Watson return (0); 1562387d2c03SRobert Watson } 1563a9e0361bSPoul-Henning Kamp 15641a996ed1SEdward Tomasz Napierala /*- 1565f44d9e24SJohn Baldwin * Determine whether td may deliver the specified signal to p. 1566c83f8015SRobert Watson * Returns: 0 for permitted, an errno value otherwise 1567f44d9e24SJohn Baldwin * Locks: Sufficient locks to protect various components of td and p 1568f44d9e24SJohn Baldwin * must be held. td must be curthread, and a lock must be 1569f44d9e24SJohn Baldwin * held for p. 1570f44d9e24SJohn Baldwin * References: td and p must be valid for the lifetime of the call 1571c83f8015SRobert Watson */ 1572c83f8015SRobert Watson int 15731a88a252SMaxim Sobolev p_cansignal(struct thread *td, struct proc *p, int signum) 1574c83f8015SRobert Watson { 1575c83f8015SRobert Watson 1576f44d9e24SJohn Baldwin KASSERT(td == curthread, ("%s: td not curthread", __func__)); 1577f44d9e24SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 1578f44d9e24SJohn Baldwin if (td->td_proc == p) 1579c83f8015SRobert Watson return (0); 1580c83f8015SRobert Watson 1581c83f8015SRobert Watson /* 1582c83f8015SRobert Watson * UNIX signalling semantics require that processes in the same 1583c83f8015SRobert Watson * session always be able to deliver SIGCONT to one another, 1584c83f8015SRobert Watson * overriding the remaining protections. 1585c83f8015SRobert Watson */ 1586f44d9e24SJohn Baldwin /* XXX: This will require an additional lock of some sort. */ 1587f44d9e24SJohn Baldwin if (signum == SIGCONT && td->td_proc->p_session == p->p_session) 1588c83f8015SRobert Watson return (0); 15894b178336SMaxim Sobolev /* 1590f9cd63d4SMaxim Sobolev * Some compat layers use SIGTHR and higher signals for 1591f9cd63d4SMaxim Sobolev * communication between different kernel threads of the same 1592f9cd63d4SMaxim Sobolev * process, so that they expect that it's always possible to 1593f9cd63d4SMaxim Sobolev * deliver them, even for suid applications where cr_cansignal() can 15944b178336SMaxim Sobolev * deny such ability for security consideration. It should be 15954b178336SMaxim Sobolev * pretty safe to do since the only way to create two processes 15964b178336SMaxim Sobolev * with the same p_leader is via rfork(2). 15974b178336SMaxim Sobolev */ 15982322a0a7SMaxim Sobolev if (td->td_proc->p_leader != NULL && signum >= SIGTHR && 15992322a0a7SMaxim Sobolev signum < SIGTHR + 4 && td->td_proc->p_leader == p->p_leader) 16004b178336SMaxim Sobolev return (0); 1601c83f8015SRobert Watson 16021a88a252SMaxim Sobolev return (cr_cansignal(td->td_ucred, p, signum)); 1603c83f8015SRobert Watson } 1604c83f8015SRobert Watson 16051a996ed1SEdward Tomasz Napierala /*- 1606f44d9e24SJohn Baldwin * Determine whether td may reschedule p. 16077fd6a959SRobert Watson * Returns: 0 for permitted, an errno value otherwise 1608f44d9e24SJohn Baldwin * Locks: Sufficient locks to protect various components of td and p 1609f44d9e24SJohn Baldwin * must be held. td must be curthread, and a lock must 1610f44d9e24SJohn Baldwin * be held for p. 1611f44d9e24SJohn Baldwin * References: td and p must be valid for the lifetime of the call 16123b243b72SRobert Watson */ 1613a0f75161SRobert Watson int 1614f44d9e24SJohn Baldwin p_cansched(struct thread *td, struct proc *p) 1615387d2c03SRobert Watson { 161691421ba2SRobert Watson int error; 1617387d2c03SRobert Watson 1618f44d9e24SJohn Baldwin KASSERT(td == curthread, ("%s: td not curthread", __func__)); 1619f44d9e24SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 1620f44d9e24SJohn Baldwin if (td->td_proc == p) 1621387d2c03SRobert Watson return (0); 1622f44d9e24SJohn Baldwin if ((error = prison_check(td->td_ucred, p->p_ucred))) 162391421ba2SRobert Watson return (error); 16248a1d977dSRobert Watson #ifdef MAC 162530d239bcSRobert Watson if ((error = mac_proc_check_sched(td->td_ucred, p))) 16268a1d977dSRobert Watson return (error); 16278a1d977dSRobert Watson #endif 16284ac21b4fSStephen J. Kiernan if ((error = cr_canseeotheruids(td->td_ucred, p->p_ucred))) 16291b350b45SRobert Watson return (error); 16304ac21b4fSStephen J. Kiernan if ((error = cr_canseeothergids(td->td_ucred, p->p_ucred))) 163164d19c2eSRobert Watson return (error); 1632800c9408SRobert Watson if (td->td_ucred->cr_ruid != p->p_ucred->cr_ruid && 1633800c9408SRobert Watson td->td_ucred->cr_uid != p->p_ucred->cr_ruid) { 163432f9753cSRobert Watson error = priv_check(td, PRIV_SCHED_DIFFCRED); 1635800c9408SRobert Watson if (error) 1636800c9408SRobert Watson return (error); 1637800c9408SRobert Watson } 1638387d2c03SRobert Watson return (0); 1639387d2c03SRobert Watson } 1640387d2c03SRobert Watson 16413b243b72SRobert Watson /* 1642b3079544SJamie Gritton * Handle getting or setting the prison's unprivileged_proc_debug 1643b3079544SJamie Gritton * value. 1644b3079544SJamie Gritton */ 1645b3079544SJamie Gritton static int 1646b3079544SJamie Gritton sysctl_unprivileged_proc_debug(SYSCTL_HANDLER_ARGS) 1647b3079544SJamie Gritton { 1648b3079544SJamie Gritton struct prison *pr; 1649b3079544SJamie Gritton int error, val; 1650b3079544SJamie Gritton 1651b3079544SJamie Gritton val = prison_allow(req->td->td_ucred, PR_ALLOW_UNPRIV_DEBUG) != 0; 1652b3079544SJamie Gritton error = sysctl_handle_int(oidp, &val, 0, req); 1653b3079544SJamie Gritton if (error != 0 || req->newptr == NULL) 1654b3079544SJamie Gritton return (error); 1655b3079544SJamie Gritton pr = req->td->td_ucred->cr_prison; 1656b3079544SJamie Gritton mtx_lock(&pr->pr_mtx); 1657b3079544SJamie Gritton switch (val) { 1658b3079544SJamie Gritton case 0: 1659b3079544SJamie Gritton pr->pr_allow &= ~(PR_ALLOW_UNPRIV_DEBUG); 1660b3079544SJamie Gritton break; 1661b3079544SJamie Gritton case 1: 1662b3079544SJamie Gritton pr->pr_allow |= PR_ALLOW_UNPRIV_DEBUG; 1663b3079544SJamie Gritton break; 1664b3079544SJamie Gritton default: 1665b3079544SJamie Gritton error = EINVAL; 1666b3079544SJamie Gritton } 1667b3079544SJamie Gritton mtx_unlock(&pr->pr_mtx); 1668b3079544SJamie Gritton 1669b3079544SJamie Gritton return (error); 1670b3079544SJamie Gritton } 1671b3079544SJamie Gritton 1672b3079544SJamie Gritton /* 16735d476e73SRobert Watson * The 'unprivileged_proc_debug' flag may be used to disable a variety of 16745d476e73SRobert Watson * unprivileged inter-process debugging services, including some procfs 16755d476e73SRobert Watson * functionality, ptrace(), and ktrace(). In the past, inter-process 16765d476e73SRobert Watson * debugging has been involved in a variety of security problems, and sites 16775d476e73SRobert Watson * not requiring the service might choose to disable it when hardening 16785d476e73SRobert Watson * systems. 16793b243b72SRobert Watson */ 1680b3079544SJamie Gritton SYSCTL_PROC(_security_bsd, OID_AUTO, unprivileged_proc_debug, 16817029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_SECURE | 16827029da5cSPawel Biernacki CTLFLAG_MPSAFE, 0, 0, sysctl_unprivileged_proc_debug, "I", 16830ef5652eSRobert Watson "Unprivileged processes may use process debugging facilities"); 16840ef5652eSRobert Watson 16851a996ed1SEdward Tomasz Napierala /*- 1686f44d9e24SJohn Baldwin * Determine whether td may debug p. 16877fd6a959SRobert Watson * Returns: 0 for permitted, an errno value otherwise 1688f44d9e24SJohn Baldwin * Locks: Sufficient locks to protect various components of td and p 1689f44d9e24SJohn Baldwin * must be held. td must be curthread, and a lock must 1690f44d9e24SJohn Baldwin * be held for p. 1691f44d9e24SJohn Baldwin * References: td and p must be valid for the lifetime of the call 16923b243b72SRobert Watson */ 1693a0f75161SRobert Watson int 1694f44d9e24SJohn Baldwin p_candebug(struct thread *td, struct proc *p) 1695387d2c03SRobert Watson { 1696eb725b4eSRobert Watson int credentialchanged, error, grpsubset, i, uidsubset; 1697387d2c03SRobert Watson 1698f44d9e24SJohn Baldwin KASSERT(td == curthread, ("%s: td not curthread", __func__)); 1699f44d9e24SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 1700b3079544SJamie Gritton if ((error = priv_check(td, PRIV_DEBUG_UNPRIV))) 170132d18604SRobert Watson return (error); 1702f44d9e24SJohn Baldwin if (td->td_proc == p) 170323fad5b6SDag-Erling Smørgrav return (0); 1704f44d9e24SJohn Baldwin if ((error = prison_check(td->td_ucred, p->p_ucred))) 170591421ba2SRobert Watson return (error); 17068a1d977dSRobert Watson #ifdef MAC 170730d239bcSRobert Watson if ((error = mac_proc_check_debug(td->td_ucred, p))) 17088a1d977dSRobert Watson return (error); 17098a1d977dSRobert Watson #endif 17104ac21b4fSStephen J. Kiernan if ((error = cr_canseeotheruids(td->td_ucred, p->p_ucred))) 17111b350b45SRobert Watson return (error); 17124ac21b4fSStephen J. Kiernan if ((error = cr_canseeothergids(td->td_ucred, p->p_ucred))) 171364d19c2eSRobert Watson return (error); 1714387d2c03SRobert Watson 17157fd6a959SRobert Watson /* 1716f44d9e24SJohn Baldwin * Is p's group set a subset of td's effective group set? This 1717f44d9e24SJohn Baldwin * includes p's egid, group access list, rgid, and svgid. 17187fd6a959SRobert Watson */ 1719db42a33dSRobert Watson grpsubset = 1; 1720f44d9e24SJohn Baldwin for (i = 0; i < p->p_ucred->cr_ngroups; i++) { 1721f44d9e24SJohn Baldwin if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) { 1722db42a33dSRobert Watson grpsubset = 0; 1723db42a33dSRobert Watson break; 1724db42a33dSRobert Watson } 1725db42a33dSRobert Watson } 1726db42a33dSRobert Watson grpsubset = grpsubset && 1727f44d9e24SJohn Baldwin groupmember(p->p_ucred->cr_rgid, td->td_ucred) && 1728f44d9e24SJohn Baldwin groupmember(p->p_ucred->cr_svgid, td->td_ucred); 1729db42a33dSRobert Watson 1730db42a33dSRobert Watson /* 1731f44d9e24SJohn Baldwin * Are the uids present in p's credential equal to td's 1732f44d9e24SJohn Baldwin * effective uid? This includes p's euid, svuid, and ruid. 1733db42a33dSRobert Watson */ 1734f44d9e24SJohn Baldwin uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid && 1735f44d9e24SJohn Baldwin td->td_ucred->cr_uid == p->p_ucred->cr_svuid && 1736f44d9e24SJohn Baldwin td->td_ucred->cr_uid == p->p_ucred->cr_ruid); 1737db42a33dSRobert Watson 1738db42a33dSRobert Watson /* 1739db42a33dSRobert Watson * Has the credential of the process changed since the last exec()? 1740db42a33dSRobert Watson */ 1741f44d9e24SJohn Baldwin credentialchanged = (p->p_flag & P_SUGID); 1742db42a33dSRobert Watson 1743db42a33dSRobert Watson /* 1744f44d9e24SJohn Baldwin * If p's gids aren't a subset, or the uids aren't a subset, 1745db42a33dSRobert Watson * or the credential has changed, require appropriate privilege 1746800c9408SRobert Watson * for td to debug p. 1747db42a33dSRobert Watson */ 1748800c9408SRobert Watson if (!grpsubset || !uidsubset) { 174932f9753cSRobert Watson error = priv_check(td, PRIV_DEBUG_DIFFCRED); 1750800c9408SRobert Watson if (error) 1751800c9408SRobert Watson return (error); 1752800c9408SRobert Watson } 1753800c9408SRobert Watson 1754800c9408SRobert Watson if (credentialchanged) { 175532f9753cSRobert Watson error = priv_check(td, PRIV_DEBUG_SUGID); 175632d18604SRobert Watson if (error) 1757387d2c03SRobert Watson return (error); 17587fd6a959SRobert Watson } 1759387d2c03SRobert Watson 1760eb725b4eSRobert Watson /* Can't trace init when securelevel > 0. */ 1761f44d9e24SJohn Baldwin if (p == initproc) { 1762f44d9e24SJohn Baldwin error = securelevel_gt(td->td_ucred, 0); 17633ca719f1SRobert Watson if (error) 17643ca719f1SRobert Watson return (error); 17653ca719f1SRobert Watson } 1766387d2c03SRobert Watson 17675fab7614SRobert Watson /* 17685fab7614SRobert Watson * Can't trace a process that's currently exec'ing. 1769800c9408SRobert Watson * 17705fab7614SRobert Watson * XXX: Note, this is not a security policy decision, it's a 17715fab7614SRobert Watson * basic correctness/functionality decision. Therefore, this check 17725fab7614SRobert Watson * should be moved to the caller's of p_candebug(). 17735fab7614SRobert Watson */ 1774f44d9e24SJohn Baldwin if ((p->p_flag & P_INEXEC) != 0) 1775af80b2c9SKonstantin Belousov return (EBUSY); 17769ca45e81SDag-Erling Smørgrav 1777677258f7SKonstantin Belousov /* Denied explicitely */ 1778677258f7SKonstantin Belousov if ((p->p_flag2 & P2_NOTRACE) != 0) { 1779677258f7SKonstantin Belousov error = priv_check(td, PRIV_DEBUG_DENIED); 1780677258f7SKonstantin Belousov if (error != 0) 1781677258f7SKonstantin Belousov return (error); 1782677258f7SKonstantin Belousov } 1783677258f7SKonstantin Belousov 1784387d2c03SRobert Watson return (0); 1785387d2c03SRobert Watson } 1786387d2c03SRobert Watson 17871a996ed1SEdward Tomasz Napierala /*- 178829dc1288SRobert Watson * Determine whether the subject represented by cred can "see" a socket. 178929dc1288SRobert Watson * Returns: 0 for permitted, ENOENT otherwise. 179029dc1288SRobert Watson */ 179129dc1288SRobert Watson int 179229dc1288SRobert Watson cr_canseesocket(struct ucred *cred, struct socket *so) 179329dc1288SRobert Watson { 179429dc1288SRobert Watson int error; 179529dc1288SRobert Watson 179629dc1288SRobert Watson error = prison_check(cred, so->so_cred); 179729dc1288SRobert Watson if (error) 179829dc1288SRobert Watson return (ENOENT); 17998a1d977dSRobert Watson #ifdef MAC 180030d239bcSRobert Watson error = mac_socket_check_visible(cred, so); 18018a1d977dSRobert Watson if (error) 18028a1d977dSRobert Watson return (error); 18038a1d977dSRobert Watson #endif 18044ac21b4fSStephen J. Kiernan if (cr_canseeotheruids(cred, so->so_cred)) 180529dc1288SRobert Watson return (ENOENT); 18064ac21b4fSStephen J. Kiernan if (cr_canseeothergids(cred, so->so_cred)) 180764d19c2eSRobert Watson return (ENOENT); 180829dc1288SRobert Watson 180929dc1288SRobert Watson return (0); 181029dc1288SRobert Watson } 181129dc1288SRobert Watson 18121a996ed1SEdward Tomasz Napierala /*- 1813babe9a2bSRobert Watson * Determine whether td can wait for the exit of p. 1814babe9a2bSRobert Watson * Returns: 0 for permitted, an errno value otherwise 1815babe9a2bSRobert Watson * Locks: Sufficient locks to protect various components of td and p 1816babe9a2bSRobert Watson * must be held. td must be curthread, and a lock must 1817babe9a2bSRobert Watson * be held for p. 1818babe9a2bSRobert Watson * References: td and p must be valid for the lifetime of the call 1819babe9a2bSRobert Watson 1820babe9a2bSRobert Watson */ 1821babe9a2bSRobert Watson int 1822babe9a2bSRobert Watson p_canwait(struct thread *td, struct proc *p) 1823babe9a2bSRobert Watson { 1824babe9a2bSRobert Watson int error; 1825babe9a2bSRobert Watson 1826babe9a2bSRobert Watson KASSERT(td == curthread, ("%s: td not curthread", __func__)); 1827babe9a2bSRobert Watson PROC_LOCK_ASSERT(p, MA_OWNED); 18287afcbc18SJamie Gritton if ((error = prison_check(td->td_ucred, p->p_ucred))) 1829babe9a2bSRobert Watson return (error); 1830babe9a2bSRobert Watson #ifdef MAC 183130d239bcSRobert Watson if ((error = mac_proc_check_wait(td->td_ucred, p))) 1832babe9a2bSRobert Watson return (error); 1833babe9a2bSRobert Watson #endif 1834babe9a2bSRobert Watson #if 0 1835babe9a2bSRobert Watson /* XXXMAC: This could have odd effects on some shells. */ 18364ac21b4fSStephen J. Kiernan if ((error = cr_canseeotheruids(td->td_ucred, p->p_ucred))) 1837babe9a2bSRobert Watson return (error); 1838babe9a2bSRobert Watson #endif 1839babe9a2bSRobert Watson 1840babe9a2bSRobert Watson return (0); 1841babe9a2bSRobert Watson } 1842babe9a2bSRobert Watson 1843a9e0361bSPoul-Henning Kamp /* 18441724c563SMateusz Guzik * Credential management. 18451724c563SMateusz Guzik * 18461724c563SMateusz Guzik * struct ucred objects are rarely allocated but gain and lose references all 18471724c563SMateusz Guzik * the time (e.g., on struct file alloc/dealloc) turning refcount updates into 18481724c563SMateusz Guzik * a significant source of cache-line ping ponging. Common cases are worked 18491724c563SMateusz Guzik * around by modifying thread-local counter instead if the cred to operate on 18501724c563SMateusz Guzik * matches td_realucred. 18511724c563SMateusz Guzik * 18521724c563SMateusz Guzik * The counter is split into 2 parts: 18531724c563SMateusz Guzik * - cr_users -- total count of all struct proc and struct thread objects 18541724c563SMateusz Guzik * which have given cred in p_ucred and td_ucred respectively 18551724c563SMateusz Guzik * - cr_ref -- the actual ref count, only valid if cr_users == 0 18561724c563SMateusz Guzik * 18571724c563SMateusz Guzik * If users == 0 then cr_ref behaves similarly to refcount(9), in particular if 18581724c563SMateusz Guzik * the count reaches 0 the object is freeable. 18591724c563SMateusz Guzik * If users > 0 and curthread->td_realucred == cred, then updates are performed 18601724c563SMateusz Guzik * against td_ucredref. 18611724c563SMateusz Guzik * In other cases updates are performed against cr_ref. 18621724c563SMateusz Guzik * 18631724c563SMateusz Guzik * Changing td_realucred into something else decrements cr_users and transfers 18641724c563SMateusz Guzik * accumulated updates. 18651724c563SMateusz Guzik */ 18661724c563SMateusz Guzik struct ucred * 18671724c563SMateusz Guzik crcowget(struct ucred *cr) 18681724c563SMateusz Guzik { 18691724c563SMateusz Guzik 18701724c563SMateusz Guzik mtx_lock(&cr->cr_mtx); 18711724c563SMateusz Guzik KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p", 18721724c563SMateusz Guzik __func__, cr->cr_users, cr)); 18731724c563SMateusz Guzik cr->cr_users++; 18741724c563SMateusz Guzik cr->cr_ref++; 18751724c563SMateusz Guzik mtx_unlock(&cr->cr_mtx); 18761724c563SMateusz Guzik return (cr); 18771724c563SMateusz Guzik } 18781724c563SMateusz Guzik 18791724c563SMateusz Guzik static struct ucred * 18801724c563SMateusz Guzik crunuse(struct thread *td) 18811724c563SMateusz Guzik { 18821724c563SMateusz Guzik struct ucred *cr, *crold; 18831724c563SMateusz Guzik 18841724c563SMateusz Guzik cr = td->td_ucred; 18851724c563SMateusz Guzik mtx_lock(&cr->cr_mtx); 18861724c563SMateusz Guzik cr->cr_ref += td->td_ucredref; 18871724c563SMateusz Guzik td->td_ucredref = 0; 18881724c563SMateusz Guzik KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p", 18891724c563SMateusz Guzik __func__, cr->cr_users, cr)); 18901724c563SMateusz Guzik cr->cr_users--; 18911724c563SMateusz Guzik if (cr->cr_users == 0) { 18921724c563SMateusz Guzik KASSERT(cr->cr_ref > 0, ("%s: ref %d not > 0 on cred %p", 18931724c563SMateusz Guzik __func__, cr->cr_ref, cr)); 18941724c563SMateusz Guzik crold = cr; 18951724c563SMateusz Guzik } else { 18961724c563SMateusz Guzik cr->cr_ref--; 18971724c563SMateusz Guzik crold = NULL; 18981724c563SMateusz Guzik } 18991724c563SMateusz Guzik mtx_unlock(&cr->cr_mtx); 19001724c563SMateusz Guzik return (crold); 19011724c563SMateusz Guzik } 19021724c563SMateusz Guzik 19031724c563SMateusz Guzik void 19041724c563SMateusz Guzik crcowfree(struct thread *td) 19051724c563SMateusz Guzik { 19061724c563SMateusz Guzik struct ucred *cr; 19071724c563SMateusz Guzik 19081724c563SMateusz Guzik cr = crunuse(td); 19091724c563SMateusz Guzik if (cr != NULL) 19101724c563SMateusz Guzik crfree(cr); 19111724c563SMateusz Guzik } 19121724c563SMateusz Guzik 19131724c563SMateusz Guzik struct ucred * 19141724c563SMateusz Guzik crcowsync(void) 19151724c563SMateusz Guzik { 19161724c563SMateusz Guzik struct thread *td; 19171724c563SMateusz Guzik struct proc *p; 19181724c563SMateusz Guzik struct ucred *crnew, *crold; 19191724c563SMateusz Guzik 19201724c563SMateusz Guzik td = curthread; 19211724c563SMateusz Guzik p = td->td_proc; 19221724c563SMateusz Guzik PROC_LOCK_ASSERT(p, MA_OWNED); 19231724c563SMateusz Guzik 19241724c563SMateusz Guzik MPASS(td->td_realucred == td->td_ucred); 19251724c563SMateusz Guzik if (td->td_realucred == p->p_ucred) 19261724c563SMateusz Guzik return (NULL); 19271724c563SMateusz Guzik 19281724c563SMateusz Guzik crnew = crcowget(p->p_ucred); 19291724c563SMateusz Guzik crold = crunuse(td); 19301724c563SMateusz Guzik td->td_realucred = crnew; 19311724c563SMateusz Guzik td->td_ucred = td->td_realucred; 19321724c563SMateusz Guzik return (crold); 19331724c563SMateusz Guzik } 19341724c563SMateusz Guzik 19351724c563SMateusz Guzik /* 1936df8bae1dSRodney W. Grimes * Allocate a zeroed cred structure. 1937df8bae1dSRodney W. Grimes */ 1938df8bae1dSRodney W. Grimes struct ucred * 19394c44ad8eSJohn Baldwin crget(void) 1940df8bae1dSRodney W. Grimes { 19413e85b721SEd Maste struct ucred *cr; 1942df8bae1dSRodney W. Grimes 19431ede983cSDag-Erling Smørgrav cr = malloc(sizeof(*cr), M_CRED, M_WAITOK | M_ZERO); 19441724c563SMateusz Guzik mtx_init(&cr->cr_mtx, "cred", NULL, MTX_DEF); 19451724c563SMateusz Guzik cr->cr_ref = 1; 1946faef5371SRobert Watson #ifdef AUDIT 1947faef5371SRobert Watson audit_cred_init(cr); 1948faef5371SRobert Watson #endif 194940244964SRobert Watson #ifdef MAC 195030d239bcSRobert Watson mac_cred_init(cr); 195140244964SRobert Watson #endif 1952a99500a9SMateusz Guzik cr->cr_groups = cr->cr_smallgroups; 1953a99500a9SMateusz Guzik cr->cr_agroups = 1954a99500a9SMateusz Guzik sizeof(cr->cr_smallgroups) / sizeof(cr->cr_smallgroups[0]); 1955df8bae1dSRodney W. Grimes return (cr); 1956df8bae1dSRodney W. Grimes } 1957df8bae1dSRodney W. Grimes 1958df8bae1dSRodney W. Grimes /* 19597fd6a959SRobert Watson * Claim another reference to a ucred structure. 19605c3f70d7SAlfred Perlstein */ 1961bd78ceceSJohn Baldwin struct ucred * 19624c44ad8eSJohn Baldwin crhold(struct ucred *cr) 19635c3f70d7SAlfred Perlstein { 19641724c563SMateusz Guzik struct thread *td; 19655c3f70d7SAlfred Perlstein 19661724c563SMateusz Guzik td = curthread; 19671724c563SMateusz Guzik if (__predict_true(td->td_realucred == cr)) { 19681724c563SMateusz Guzik KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p", 19691724c563SMateusz Guzik __func__, cr->cr_users, cr)); 19701724c563SMateusz Guzik td->td_ucredref++; 19711724c563SMateusz Guzik return (cr); 19721724c563SMateusz Guzik } 19731724c563SMateusz Guzik mtx_lock(&cr->cr_mtx); 19741724c563SMateusz Guzik cr->cr_ref++; 19751724c563SMateusz Guzik mtx_unlock(&cr->cr_mtx); 1976bd78ceceSJohn Baldwin return (cr); 19775c3f70d7SAlfred Perlstein } 19785c3f70d7SAlfred Perlstein 19795c3f70d7SAlfred Perlstein /* 19800c14ff0eSRobert Watson * Free a cred structure. Throws away space when ref count gets to 0. 1981df8bae1dSRodney W. Grimes */ 198226f9a767SRodney W. Grimes void 19834c44ad8eSJohn Baldwin crfree(struct ucred *cr) 1984df8bae1dSRodney W. Grimes { 19851724c563SMateusz Guzik struct thread *td; 19861e5d626aSAlfred Perlstein 19871724c563SMateusz Guzik td = curthread; 1988*a2de789eSMateusz Guzik if (__predict_true(td->td_realucred == cr)) { 19891724c563SMateusz Guzik KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p", 19901724c563SMateusz Guzik __func__, cr->cr_users, cr)); 19911724c563SMateusz Guzik td->td_ucredref--; 19921724c563SMateusz Guzik return; 19931724c563SMateusz Guzik } 19941724c563SMateusz Guzik mtx_lock(&cr->cr_mtx); 19951724c563SMateusz Guzik KASSERT(cr->cr_users >= 0, ("%s: users %d not >= 0 on cred %p", 19961724c563SMateusz Guzik __func__, cr->cr_users, cr)); 19971724c563SMateusz Guzik cr->cr_ref--; 19981724c563SMateusz Guzik if (cr->cr_users > 0) { 19991724c563SMateusz Guzik mtx_unlock(&cr->cr_mtx); 20001724c563SMateusz Guzik return; 20011724c563SMateusz Guzik } 20021724c563SMateusz Guzik KASSERT(cr->cr_ref >= 0, ("%s: ref %d not >= 0 on cred %p", 20031724c563SMateusz Guzik __func__, cr->cr_ref, cr)); 20041724c563SMateusz Guzik if (cr->cr_ref > 0) { 20051724c563SMateusz Guzik mtx_unlock(&cr->cr_mtx); 20061724c563SMateusz Guzik return; 20071724c563SMateusz Guzik } 2008f535380cSDon Lewis /* 20091724c563SMateusz Guzik * Some callers of crget(), such as nfs_statfs(), allocate a temporary 20101724c563SMateusz Guzik * credential, but don't allocate a uidinfo structure. 2011f535380cSDon Lewis */ 2012f535380cSDon Lewis if (cr->cr_uidinfo != NULL) 2013f535380cSDon Lewis uifree(cr->cr_uidinfo); 2014823c224eSRobert Watson if (cr->cr_ruidinfo != NULL) 2015823c224eSRobert Watson uifree(cr->cr_ruidinfo); 20160304c731SJamie Gritton if (cr->cr_prison != NULL) 201791421ba2SRobert Watson prison_free(cr->cr_prison); 20182bfc50bcSEdward Tomasz Napierala if (cr->cr_loginclass != NULL) 20192bfc50bcSEdward Tomasz Napierala loginclass_free(cr->cr_loginclass); 2020faef5371SRobert Watson #ifdef AUDIT 2021faef5371SRobert Watson audit_cred_destroy(cr); 2022faef5371SRobert Watson #endif 202340244964SRobert Watson #ifdef MAC 202430d239bcSRobert Watson mac_cred_destroy(cr); 202540244964SRobert Watson #endif 20261724c563SMateusz Guzik mtx_destroy(&cr->cr_mtx); 2027a99500a9SMateusz Guzik if (cr->cr_groups != cr->cr_smallgroups) 2028838d9858SBrooks Davis free(cr->cr_groups, M_CRED); 20291ede983cSDag-Erling Smørgrav free(cr, M_CRED); 2030e1bca29fSMatthew Dillon } 2031df8bae1dSRodney W. Grimes 2032df8bae1dSRodney W. Grimes /* 2033bd78ceceSJohn Baldwin * Copy a ucred's contents from a template. Does not block. 2034bd78ceceSJohn Baldwin */ 2035bd78ceceSJohn Baldwin void 20364c44ad8eSJohn Baldwin crcopy(struct ucred *dest, struct ucred *src) 2037bd78ceceSJohn Baldwin { 2038bd78ceceSJohn Baldwin 203925108069SMateusz Guzik KASSERT(dest->cr_ref == 1, ("crcopy of shared ucred")); 2040bd78ceceSJohn Baldwin bcopy(&src->cr_startcopy, &dest->cr_startcopy, 2041bd78ceceSJohn Baldwin (unsigned)((caddr_t)&src->cr_endcopy - 2042bd78ceceSJohn Baldwin (caddr_t)&src->cr_startcopy)); 2043838d9858SBrooks Davis crsetgroups(dest, src->cr_ngroups, src->cr_groups); 2044bd78ceceSJohn Baldwin uihold(dest->cr_uidinfo); 2045bd78ceceSJohn Baldwin uihold(dest->cr_ruidinfo); 2046bd78ceceSJohn Baldwin prison_hold(dest->cr_prison); 20472bfc50bcSEdward Tomasz Napierala loginclass_hold(dest->cr_loginclass); 2048faef5371SRobert Watson #ifdef AUDIT 2049faef5371SRobert Watson audit_cred_copy(src, dest); 2050faef5371SRobert Watson #endif 205140244964SRobert Watson #ifdef MAC 205230d239bcSRobert Watson mac_cred_copy(src, dest); 205340244964SRobert Watson #endif 2054df8bae1dSRodney W. Grimes } 2055df8bae1dSRodney W. Grimes 2056df8bae1dSRodney W. Grimes /* 2057df8bae1dSRodney W. Grimes * Dup cred struct to a new held one. 2058df8bae1dSRodney W. Grimes */ 2059df8bae1dSRodney W. Grimes struct ucred * 20604c44ad8eSJohn Baldwin crdup(struct ucred *cr) 2061df8bae1dSRodney W. Grimes { 2062df8bae1dSRodney W. Grimes struct ucred *newcr; 2063df8bae1dSRodney W. Grimes 2064bd78ceceSJohn Baldwin newcr = crget(); 2065bd78ceceSJohn Baldwin crcopy(newcr, cr); 2066df8bae1dSRodney W. Grimes return (newcr); 2067df8bae1dSRodney W. Grimes } 2068df8bae1dSRodney W. Grimes 2069df8bae1dSRodney W. Grimes /* 207076183f34SDima Dorfman * Fill in a struct xucred based on a struct ucred. 207176183f34SDima Dorfman */ 207276183f34SDima Dorfman void 20734c44ad8eSJohn Baldwin cru2x(struct ucred *cr, struct xucred *xcr) 207476183f34SDima Dorfman { 2075838d9858SBrooks Davis int ngroups; 207676183f34SDima Dorfman 207776183f34SDima Dorfman bzero(xcr, sizeof(*xcr)); 207876183f34SDima Dorfman xcr->cr_version = XUCRED_VERSION; 207976183f34SDima Dorfman xcr->cr_uid = cr->cr_uid; 2080838d9858SBrooks Davis 2081838d9858SBrooks Davis ngroups = MIN(cr->cr_ngroups, XU_NGROUPS); 2082838d9858SBrooks Davis xcr->cr_ngroups = ngroups; 2083838d9858SBrooks Davis bcopy(cr->cr_groups, xcr->cr_groups, 2084838d9858SBrooks Davis ngroups * sizeof(*cr->cr_groups)); 208576183f34SDima Dorfman } 208676183f34SDima Dorfman 2087c8124e20SDmitry Chagin void 2088c5afec6eSDmitry Chagin cru2xt(struct thread *td, struct xucred *xcr) 2089c5afec6eSDmitry Chagin { 2090c5afec6eSDmitry Chagin 2091c5afec6eSDmitry Chagin cru2x(td->td_ucred, xcr); 2092c5afec6eSDmitry Chagin xcr->cr_pid = td->td_proc->p_pid; 2093c5afec6eSDmitry Chagin } 2094c5afec6eSDmitry Chagin 209576183f34SDima Dorfman /* 2096ffb34484SMateusz Guzik * Set initial process credentials. 2097ffb34484SMateusz Guzik * Callers are responsible for providing the reference for provided credentials. 2098ffb34484SMateusz Guzik */ 2099ffb34484SMateusz Guzik void 2100ffb34484SMateusz Guzik proc_set_cred_init(struct proc *p, struct ucred *newcred) 2101ffb34484SMateusz Guzik { 2102ffb34484SMateusz Guzik 21031724c563SMateusz Guzik p->p_ucred = crcowget(newcred); 2104ffb34484SMateusz Guzik } 2105ffb34484SMateusz Guzik 2106ffb34484SMateusz Guzik /* 2107daf63fd2SMateusz Guzik * Change process credentials. 2108ffb34484SMateusz Guzik * Callers are responsible for providing the reference for passed credentials 2109daf63fd2SMateusz Guzik * and for freeing old ones. 2110daf63fd2SMateusz Guzik * 2111daf63fd2SMateusz Guzik * Process has to be locked except when it does not have credentials (as it 2112daf63fd2SMateusz Guzik * should not be visible just yet) or when newcred is NULL (as this can be 2113daf63fd2SMateusz Guzik * only used when the process is about to be freed, at which point it should 2114daf63fd2SMateusz Guzik * not be visible anymore). 2115daf63fd2SMateusz Guzik */ 21166f836483SMateusz Guzik void 2117daf63fd2SMateusz Guzik proc_set_cred(struct proc *p, struct ucred *newcred) 2118daf63fd2SMateusz Guzik { 21191724c563SMateusz Guzik struct ucred *cr; 2120daf63fd2SMateusz Guzik 21211724c563SMateusz Guzik cr = p->p_ucred; 21221724c563SMateusz Guzik MPASS(cr != NULL); 2123daf63fd2SMateusz Guzik PROC_LOCK_ASSERT(p, MA_OWNED); 21241724c563SMateusz Guzik KASSERT(newcred->cr_users == 0, ("%s: users %d not 0 on cred %p", 21251724c563SMateusz Guzik __func__, newcred->cr_users, newcred)); 21261724c563SMateusz Guzik mtx_lock(&cr->cr_mtx); 21271724c563SMateusz Guzik KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p", 21281724c563SMateusz Guzik __func__, cr->cr_users, cr)); 21291724c563SMateusz Guzik cr->cr_users--; 21301724c563SMateusz Guzik mtx_unlock(&cr->cr_mtx); 2131daf63fd2SMateusz Guzik p->p_ucred = newcred; 21321724c563SMateusz Guzik newcred->cr_users = 1; 21334ea6a9a2SMateusz Guzik PROC_UPDATE_COW(p); 2134daf63fd2SMateusz Guzik } 2135daf63fd2SMateusz Guzik 21365a90435cSMateusz Guzik void 21375a90435cSMateusz Guzik proc_unset_cred(struct proc *p) 21385a90435cSMateusz Guzik { 21395a90435cSMateusz Guzik struct ucred *cr; 21405a90435cSMateusz Guzik 21411724c563SMateusz Guzik MPASS(p->p_state == PRS_ZOMBIE || p->p_state == PRS_NEW); 21425a90435cSMateusz Guzik cr = p->p_ucred; 21435a90435cSMateusz Guzik p->p_ucred = NULL; 21441724c563SMateusz Guzik KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p", 21451724c563SMateusz Guzik __func__, cr->cr_users, cr)); 21461724c563SMateusz Guzik mtx_lock(&cr->cr_mtx); 21471724c563SMateusz Guzik cr->cr_users--; 21481724c563SMateusz Guzik if (cr->cr_users == 0) 21491724c563SMateusz Guzik KASSERT(cr->cr_ref > 0, ("%s: ref %d not > 0 on cred %p", 21501724c563SMateusz Guzik __func__, cr->cr_ref, cr)); 21511724c563SMateusz Guzik mtx_unlock(&cr->cr_mtx); 21525a90435cSMateusz Guzik crfree(cr); 21535a90435cSMateusz Guzik } 21545a90435cSMateusz Guzik 2155838d9858SBrooks Davis struct ucred * 2156838d9858SBrooks Davis crcopysafe(struct proc *p, struct ucred *cr) 2157838d9858SBrooks Davis { 2158838d9858SBrooks Davis struct ucred *oldcred; 2159838d9858SBrooks Davis int groups; 2160838d9858SBrooks Davis 2161838d9858SBrooks Davis PROC_LOCK_ASSERT(p, MA_OWNED); 2162838d9858SBrooks Davis 2163838d9858SBrooks Davis oldcred = p->p_ucred; 2164838d9858SBrooks Davis while (cr->cr_agroups < oldcred->cr_agroups) { 2165838d9858SBrooks Davis groups = oldcred->cr_agroups; 2166838d9858SBrooks Davis PROC_UNLOCK(p); 2167838d9858SBrooks Davis crextend(cr, groups); 2168838d9858SBrooks Davis PROC_LOCK(p); 2169838d9858SBrooks Davis oldcred = p->p_ucred; 2170838d9858SBrooks Davis } 2171838d9858SBrooks Davis crcopy(cr, oldcred); 2172838d9858SBrooks Davis 2173838d9858SBrooks Davis return (oldcred); 2174838d9858SBrooks Davis } 2175838d9858SBrooks Davis 2176838d9858SBrooks Davis /* 2177838d9858SBrooks Davis * Extend the passed in credential to hold n items. 2178838d9858SBrooks Davis */ 2179c8358c6eSGleb Smirnoff void 2180838d9858SBrooks Davis crextend(struct ucred *cr, int n) 2181838d9858SBrooks Davis { 2182838d9858SBrooks Davis int cnt; 2183838d9858SBrooks Davis 2184838d9858SBrooks Davis /* Truncate? */ 2185838d9858SBrooks Davis if (n <= cr->cr_agroups) 2186838d9858SBrooks Davis return; 2187838d9858SBrooks Davis 2188838d9858SBrooks Davis /* 2189838d9858SBrooks Davis * We extend by 2 each time since we're using a power of two 2190838d9858SBrooks Davis * allocator until we need enough groups to fill a page. 2191838d9858SBrooks Davis * Once we're allocating multiple pages, only allocate as many 2192838d9858SBrooks Davis * as we actually need. The case of processes needing a 2193838d9858SBrooks Davis * non-power of two number of pages seems more likely than 2194838d9858SBrooks Davis * a real world process that adds thousands of groups one at a 2195838d9858SBrooks Davis * time. 2196838d9858SBrooks Davis */ 2197838d9858SBrooks Davis if ( n < PAGE_SIZE / sizeof(gid_t) ) { 2198838d9858SBrooks Davis if (cr->cr_agroups == 0) 219951871224SRyan Libby cnt = MAX(1, MINALLOCSIZE / sizeof(gid_t)); 2200838d9858SBrooks Davis else 2201838d9858SBrooks Davis cnt = cr->cr_agroups * 2; 2202838d9858SBrooks Davis 2203838d9858SBrooks Davis while (cnt < n) 2204838d9858SBrooks Davis cnt *= 2; 2205838d9858SBrooks Davis } else 2206838d9858SBrooks Davis cnt = roundup2(n, PAGE_SIZE / sizeof(gid_t)); 2207838d9858SBrooks Davis 2208838d9858SBrooks Davis /* Free the old array. */ 2209a99500a9SMateusz Guzik if (cr->cr_groups != cr->cr_smallgroups) 2210838d9858SBrooks Davis free(cr->cr_groups, M_CRED); 2211838d9858SBrooks Davis 2212838d9858SBrooks Davis cr->cr_groups = malloc(cnt * sizeof(gid_t), M_CRED, M_WAITOK | M_ZERO); 2213838d9858SBrooks Davis cr->cr_agroups = cnt; 2214838d9858SBrooks Davis } 2215838d9858SBrooks Davis 2216838d9858SBrooks Davis /* 22177f92e578SBrooks Davis * Copy groups in to a credential, preserving any necessary invariants. 22187f92e578SBrooks Davis * Currently this includes the sorting of all supplemental gids. 22197f92e578SBrooks Davis * crextend() must have been called before hand to ensure sufficient 22207f92e578SBrooks Davis * space is available. 2221838d9858SBrooks Davis */ 2222838d9858SBrooks Davis static void 2223838d9858SBrooks Davis crsetgroups_locked(struct ucred *cr, int ngrp, gid_t *groups) 2224838d9858SBrooks Davis { 22257f92e578SBrooks Davis int i; 22267f92e578SBrooks Davis int j; 22277f92e578SBrooks Davis gid_t g; 2228838d9858SBrooks Davis 2229838d9858SBrooks Davis KASSERT(cr->cr_agroups >= ngrp, ("cr_ngroups is too small")); 2230838d9858SBrooks Davis 2231838d9858SBrooks Davis bcopy(groups, cr->cr_groups, ngrp * sizeof(gid_t)); 2232838d9858SBrooks Davis cr->cr_ngroups = ngrp; 22337f92e578SBrooks Davis 22347f92e578SBrooks Davis /* 22357f92e578SBrooks Davis * Sort all groups except cr_groups[0] to allow groupmember to 22367f92e578SBrooks Davis * perform a binary search. 22377f92e578SBrooks Davis * 22387f92e578SBrooks Davis * XXX: If large numbers of groups become common this should 22397f92e578SBrooks Davis * be replaced with shell sort like linux uses or possibly 22407f92e578SBrooks Davis * heap sort. 22417f92e578SBrooks Davis */ 22427f92e578SBrooks Davis for (i = 2; i < ngrp; i++) { 22437f92e578SBrooks Davis g = cr->cr_groups[i]; 22447f92e578SBrooks Davis for (j = i-1; j >= 1 && g < cr->cr_groups[j]; j--) 22457f92e578SBrooks Davis cr->cr_groups[j + 1] = cr->cr_groups[j]; 22467f92e578SBrooks Davis cr->cr_groups[j + 1] = g; 22477f92e578SBrooks Davis } 2248838d9858SBrooks Davis } 2249838d9858SBrooks Davis 2250838d9858SBrooks Davis /* 2251838d9858SBrooks Davis * Copy groups in to a credential after expanding it if required. 2252412f9500SBrooks Davis * Truncate the list to (ngroups_max + 1) if it is too large. 2253838d9858SBrooks Davis */ 2254838d9858SBrooks Davis void 2255838d9858SBrooks Davis crsetgroups(struct ucred *cr, int ngrp, gid_t *groups) 2256838d9858SBrooks Davis { 2257838d9858SBrooks Davis 2258412f9500SBrooks Davis if (ngrp > ngroups_max + 1) 2259412f9500SBrooks Davis ngrp = ngroups_max + 1; 2260838d9858SBrooks Davis 2261838d9858SBrooks Davis crextend(cr, ngrp); 2262838d9858SBrooks Davis crsetgroups_locked(cr, ngrp, groups); 2263838d9858SBrooks Davis } 2264838d9858SBrooks Davis 22652eb927e2SJulian Elischer /* 2266df8bae1dSRodney W. Grimes * Get login name, if available. 2267df8bae1dSRodney W. Grimes */ 2268d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 2269df8bae1dSRodney W. Grimes struct getlogin_args { 2270df8bae1dSRodney W. Grimes char *namebuf; 2271df8bae1dSRodney W. Grimes u_int namelen; 2272df8bae1dSRodney W. Grimes }; 2273d2d3e875SBruce Evans #endif 2274df8bae1dSRodney W. Grimes /* ARGSUSED */ 227526f9a767SRodney W. Grimes int 22768451d0ddSKip Macy sys_getlogin(struct thread *td, struct getlogin_args *uap) 2277df8bae1dSRodney W. Grimes { 2278f591779bSSeigo Tanimura char login[MAXLOGNAME]; 2279b40ce416SJulian Elischer struct proc *p = td->td_proc; 2280bccb6d5aSDag-Erling Smørgrav size_t len; 2281df8bae1dSRodney W. Grimes 228230cf3ac4SAndrey A. Chernov if (uap->namelen > MAXLOGNAME) 228353490b76SAndrey A. Chernov uap->namelen = MAXLOGNAME; 2284f591779bSSeigo Tanimura PROC_LOCK(p); 2285f591779bSSeigo Tanimura SESS_LOCK(p->p_session); 2286bccb6d5aSDag-Erling Smørgrav len = strlcpy(login, p->p_session->s_login, uap->namelen) + 1; 2287f591779bSSeigo Tanimura SESS_UNLOCK(p->p_session); 2288f591779bSSeigo Tanimura PROC_UNLOCK(p); 2289bccb6d5aSDag-Erling Smørgrav if (len > uap->namelen) 22906f68699fSBaptiste Daroussin return (ERANGE); 2291bccb6d5aSDag-Erling Smørgrav return (copyout(login, uap->namebuf, len)); 2292df8bae1dSRodney W. Grimes } 2293df8bae1dSRodney W. Grimes 2294df8bae1dSRodney W. Grimes /* 2295df8bae1dSRodney W. Grimes * Set login name. 2296df8bae1dSRodney W. Grimes */ 2297d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 2298df8bae1dSRodney W. Grimes struct setlogin_args { 2299df8bae1dSRodney W. Grimes char *namebuf; 2300df8bae1dSRodney W. Grimes }; 2301d2d3e875SBruce Evans #endif 2302df8bae1dSRodney W. Grimes /* ARGSUSED */ 230326f9a767SRodney W. Grimes int 23048451d0ddSKip Macy sys_setlogin(struct thread *td, struct setlogin_args *uap) 2305df8bae1dSRodney W. Grimes { 2306b40ce416SJulian Elischer struct proc *p = td->td_proc; 2307df8bae1dSRodney W. Grimes int error; 2308964ca0caSAndrey A. Chernov char logintmp[MAXLOGNAME]; 2309df8bae1dSRodney W. Grimes 2310bccb6d5aSDag-Erling Smørgrav CTASSERT(sizeof(p->p_session->s_login) >= sizeof(logintmp)); 2311bccb6d5aSDag-Erling Smørgrav 231232f9753cSRobert Watson error = priv_check(td, PRIV_PROC_SETLOGIN); 231307f3485dSJohn Baldwin if (error) 231407f3485dSJohn Baldwin return (error); 23157f05b035SAlfred Perlstein error = copyinstr(uap->namebuf, logintmp, sizeof(logintmp), NULL); 2316bccb6d5aSDag-Erling Smørgrav if (error != 0) { 2317eb725b4eSRobert Watson if (error == ENAMETOOLONG) 2318df8bae1dSRodney W. Grimes error = EINVAL; 2319bccb6d5aSDag-Erling Smørgrav return (error); 2320bccb6d5aSDag-Erling Smørgrav } 232170a98c11SRobert Watson AUDIT_ARG_LOGIN(logintmp); 2322f591779bSSeigo Tanimura PROC_LOCK(p); 2323f591779bSSeigo Tanimura SESS_LOCK(p->p_session); 2324bccb6d5aSDag-Erling Smørgrav strcpy(p->p_session->s_login, logintmp); 2325f591779bSSeigo Tanimura SESS_UNLOCK(p->p_session); 2326f591779bSSeigo Tanimura PROC_UNLOCK(p); 2327bccb6d5aSDag-Erling Smørgrav return (0); 2328df8bae1dSRodney W. Grimes } 2329d5f81602SSean Eric Fagan 2330d5f81602SSean Eric Fagan void 23314c44ad8eSJohn Baldwin setsugid(struct proc *p) 2332d5f81602SSean Eric Fagan { 2333f2102dadSAlfred Perlstein 2334f2102dadSAlfred Perlstein PROC_LOCK_ASSERT(p, MA_OWNED); 2335d5f81602SSean Eric Fagan p->p_flag |= P_SUGID; 2336d5f81602SSean Eric Fagan } 2337f535380cSDon Lewis 23381a996ed1SEdward Tomasz Napierala /*- 23397fd6a959SRobert Watson * Change a process's effective uid. 2340b1fc0ec1SRobert Watson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified. 2341b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 2342b1fc0ec1SRobert Watson * duration of the call. 2343f535380cSDon Lewis */ 2344f535380cSDon Lewis void 23451419eacbSAlfred Perlstein change_euid(struct ucred *newcred, struct uidinfo *euip) 2346f535380cSDon Lewis { 2347f535380cSDon Lewis 23481419eacbSAlfred Perlstein newcred->cr_uid = euip->ui_uid; 23491419eacbSAlfred Perlstein uihold(euip); 2350b1fc0ec1SRobert Watson uifree(newcred->cr_uidinfo); 23511419eacbSAlfred Perlstein newcred->cr_uidinfo = euip; 2352f535380cSDon Lewis } 2353f535380cSDon Lewis 23541a996ed1SEdward Tomasz Napierala /*- 23557fd6a959SRobert Watson * Change a process's effective gid. 2356b1fc0ec1SRobert Watson * Side effects: newcred->cr_gid will be modified. 2357b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 2358b1fc0ec1SRobert Watson * duration of the call. 2359f535380cSDon Lewis */ 2360810bfc8eSAndrew Gallatin void 23614c44ad8eSJohn Baldwin change_egid(struct ucred *newcred, gid_t egid) 2362b1fc0ec1SRobert Watson { 2363b1fc0ec1SRobert Watson 2364b1fc0ec1SRobert Watson newcred->cr_groups[0] = egid; 2365b1fc0ec1SRobert Watson } 2366b1fc0ec1SRobert Watson 23671a996ed1SEdward Tomasz Napierala /*- 23687fd6a959SRobert Watson * Change a process's real uid. 2369b1fc0ec1SRobert Watson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo 2370b1fc0ec1SRobert Watson * will be updated, and the old and new cr_ruidinfo proc 2371b1fc0ec1SRobert Watson * counts will be updated. 2372b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 2373b1fc0ec1SRobert Watson * duration of the call. 2374b1fc0ec1SRobert Watson */ 2375b1fc0ec1SRobert Watson void 23761419eacbSAlfred Perlstein change_ruid(struct ucred *newcred, struct uidinfo *ruip) 2377f535380cSDon Lewis { 2378f535380cSDon Lewis 2379b1fc0ec1SRobert Watson (void)chgproccnt(newcred->cr_ruidinfo, -1, 0); 23801419eacbSAlfred Perlstein newcred->cr_ruid = ruip->ui_uid; 23811419eacbSAlfred Perlstein uihold(ruip); 2382b1fc0ec1SRobert Watson uifree(newcred->cr_ruidinfo); 23831419eacbSAlfred Perlstein newcred->cr_ruidinfo = ruip; 2384b1fc0ec1SRobert Watson (void)chgproccnt(newcred->cr_ruidinfo, 1, 0); 2385b1fc0ec1SRobert Watson } 2386b1fc0ec1SRobert Watson 23871a996ed1SEdward Tomasz Napierala /*- 23887fd6a959SRobert Watson * Change a process's real gid. 2389b1fc0ec1SRobert Watson * Side effects: newcred->cr_rgid will be updated. 2390b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 2391b1fc0ec1SRobert Watson * duration of the call. 2392b1fc0ec1SRobert Watson */ 2393b1fc0ec1SRobert Watson void 23944c44ad8eSJohn Baldwin change_rgid(struct ucred *newcred, gid_t rgid) 2395b1fc0ec1SRobert Watson { 2396b1fc0ec1SRobert Watson 2397b1fc0ec1SRobert Watson newcred->cr_rgid = rgid; 2398b1fc0ec1SRobert Watson } 2399b1fc0ec1SRobert Watson 24001a996ed1SEdward Tomasz Napierala /*- 24017fd6a959SRobert Watson * Change a process's saved uid. 2402b1fc0ec1SRobert Watson * Side effects: newcred->cr_svuid will be updated. 2403b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 2404b1fc0ec1SRobert Watson * duration of the call. 2405b1fc0ec1SRobert Watson */ 2406b1fc0ec1SRobert Watson void 24074c44ad8eSJohn Baldwin change_svuid(struct ucred *newcred, uid_t svuid) 2408b1fc0ec1SRobert Watson { 2409b1fc0ec1SRobert Watson 2410b1fc0ec1SRobert Watson newcred->cr_svuid = svuid; 2411b1fc0ec1SRobert Watson } 2412b1fc0ec1SRobert Watson 24131a996ed1SEdward Tomasz Napierala /*- 24147fd6a959SRobert Watson * Change a process's saved gid. 2415b1fc0ec1SRobert Watson * Side effects: newcred->cr_svgid will be updated. 2416b1fc0ec1SRobert Watson * References: newcred must be an exclusive credential reference for the 2417b1fc0ec1SRobert Watson * duration of the call. 2418b1fc0ec1SRobert Watson */ 2419b1fc0ec1SRobert Watson void 24204c44ad8eSJohn Baldwin change_svgid(struct ucred *newcred, gid_t svgid) 2421b1fc0ec1SRobert Watson { 2422b1fc0ec1SRobert Watson 2423b1fc0ec1SRobert Watson newcred->cr_svgid = svgid; 2424f535380cSDon Lewis } 2425