LCOV - code coverage report
Current view: top level - kern - kern_prot.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 543 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 41 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: kern_prot.c,v 1.75 2018/06/22 13:33:30 visa Exp $     */
       2             : /*      $NetBSD: kern_prot.c,v 1.33 1996/02/09 18:59:42 christos Exp $  */
       3             : 
       4             : /*
       5             :  * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
       6             :  *      The Regents of the University of California.  All rights reserved.
       7             :  * (c) UNIX System Laboratories, Inc.
       8             :  * All or some portions of this file are derived from material licensed
       9             :  * to the University of California by American Telephone and Telegraph
      10             :  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
      11             :  * the permission of UNIX System Laboratories, Inc.
      12             :  *
      13             :  * Redistribution and use in source and binary forms, with or without
      14             :  * modification, are permitted provided that the following conditions
      15             :  * are met:
      16             :  * 1. Redistributions of source code must retain the above copyright
      17             :  *    notice, this list of conditions and the following disclaimer.
      18             :  * 2. Redistributions in binary form must reproduce the above copyright
      19             :  *    notice, this list of conditions and the following disclaimer in the
      20             :  *    documentation and/or other materials provided with the distribution.
      21             :  * 3. Neither the name of the University nor the names of its contributors
      22             :  *    may be used to endorse or promote products derived from this software
      23             :  *    without specific prior written permission.
      24             :  *
      25             :  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      26             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      27             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      28             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      29             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      30             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      31             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      32             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      33             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      34             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      35             :  * SUCH DAMAGE.
      36             :  *
      37             :  *      @(#)kern_prot.c 8.6 (Berkeley) 1/21/94
      38             :  */
      39             : 
      40             : /*
      41             :  * System calls related to processes and protection
      42             :  */
      43             : 
      44             : #include <sys/param.h>
      45             : #include <sys/acct.h>
      46             : #include <sys/atomic.h>
      47             : #include <sys/systm.h>
      48             : #include <sys/ucred.h>
      49             : #include <sys/proc.h>
      50             : #include <sys/filedesc.h>
      51             : #include <sys/pool.h>
      52             : 
      53             : #include <sys/mount.h>
      54             : #include <sys/syscallargs.h>
      55             : #include <machine/tcb.h>
      56             : 
      57             : inline void
      58           0 : crset(struct ucred *newcr, const struct ucred *cr)
      59             : {
      60           0 :         KASSERT(cr->cr_ref > 0);
      61           0 :         memcpy(
      62             :             (char *)newcr    + offsetof(struct ucred, cr_startcopy),
      63             :             (const char *)cr + offsetof(struct ucred, cr_startcopy),
      64             :             sizeof(*cr)      - offsetof(struct ucred, cr_startcopy));
      65           0 : }
      66             : 
      67             : int
      68           0 : sys_getpid(struct proc *p, void *v, register_t *retval)
      69             : {
      70             : 
      71           0 :         *retval = p->p_p->ps_pid;
      72           0 :         return (0);
      73             : }
      74             : 
      75             : int
      76           0 : sys_getthrid(struct proc *p, void *v, register_t *retval)
      77             : {
      78             : 
      79           0 :         *retval = p->p_tid + THREAD_PID_OFFSET;
      80           0 :         return (0);
      81             : }
      82             : 
      83             : int
      84           0 : sys_getppid(struct proc *p, void *v, register_t *retval)
      85             : {
      86             : 
      87           0 :         *retval = p->p_p->ps_pptr->ps_pid;
      88           0 :         return (0);
      89             : }
      90             : 
      91             : /* Get process group ID; note that POSIX getpgrp takes no parameter */
      92             : int
      93           0 : sys_getpgrp(struct proc *p, void *v, register_t *retval)
      94             : {
      95             : 
      96           0 :         *retval = p->p_p->ps_pgrp->pg_id;
      97           0 :         return (0);
      98             : }
      99             : 
     100             : /*
     101             :  * SysVR.4 compatible getpgid()
     102             :  */
     103             : int
     104           0 : sys_getpgid(struct proc *curp, void *v, register_t *retval)
     105             : {
     106             :         struct sys_getpgid_args /* {
     107             :                 syscallarg(pid_t) pid;
     108           0 :         } */ *uap = v;
     109           0 :         struct process *targpr = curp->p_p;
     110             : 
     111           0 :         if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == targpr->ps_pid)
     112             :                 goto found;
     113           0 :         if ((targpr = prfind(SCARG(uap, pid))) == NULL)
     114           0 :                 return (ESRCH);
     115           0 :         if (targpr->ps_session != curp->p_p->ps_session)
     116           0 :                 return (EPERM);
     117             : found:
     118           0 :         *retval = targpr->ps_pgid;
     119           0 :         return (0);
     120           0 : }
     121             : 
     122             : int
     123           0 : sys_getsid(struct proc *curp, void *v, register_t *retval)
     124             : {
     125             :         struct sys_getsid_args /* {
     126             :                 syscallarg(pid_t) pid;
     127           0 :         } */ *uap = v;
     128           0 :         struct process *targpr = curp->p_p;
     129             : 
     130           0 :         if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == targpr->ps_pid)
     131             :                 goto found;
     132           0 :         if ((targpr = prfind(SCARG(uap, pid))) == NULL)
     133           0 :                 return (ESRCH);
     134           0 :         if (targpr->ps_session != curp->p_p->ps_session)
     135           0 :                 return (EPERM);
     136             : found:
     137             :         /* Skip exiting processes */
     138           0 :         if (targpr->ps_pgrp->pg_session->s_leader == NULL)
     139           0 :                 return (ESRCH);
     140           0 :         *retval = targpr->ps_pgrp->pg_session->s_leader->ps_pid;
     141           0 :         return (0);
     142           0 : }
     143             : 
     144             : int
     145           0 : sys_getuid(struct proc *p, void *v, register_t *retval)
     146             : {
     147             : 
     148           0 :         *retval = p->p_ucred->cr_ruid;
     149           0 :         return (0);
     150             : }
     151             : 
     152             : int
     153           0 : sys_geteuid(struct proc *p, void *v, register_t *retval)
     154             : {
     155             : 
     156           0 :         *retval = p->p_ucred->cr_uid;
     157           0 :         return (0);
     158             : }
     159             : 
     160             : int
     161           0 : sys_issetugid(struct proc *p, void *v, register_t *retval)
     162             : {
     163           0 :         if (p->p_p->ps_flags & PS_SUGIDEXEC)
     164           0 :                 *retval = 1;
     165             :         else
     166           0 :                 *retval = 0;
     167           0 :         return (0);
     168             : }
     169             : 
     170             : int
     171           0 : sys_getgid(struct proc *p, void *v, register_t *retval)
     172             : {
     173             : 
     174           0 :         *retval = p->p_ucred->cr_rgid;
     175           0 :         return (0);
     176             : }
     177             : 
     178             : /*
     179             :  * Get effective group ID.  The "egid" is groups[0], and could be obtained
     180             :  * via getgroups.  This syscall exists because it is somewhat painful to do
     181             :  * correctly in a library function.
     182             :  */
     183             : int
     184           0 : sys_getegid(struct proc *p, void *v, register_t *retval)
     185             : {
     186             : 
     187           0 :         *retval = p->p_ucred->cr_gid;
     188           0 :         return (0);
     189             : }
     190             : 
     191             : int
     192           0 : sys_getgroups(struct proc *p, void *v, register_t *retval)
     193             : {
     194             :         struct sys_getgroups_args /* {
     195             :                 syscallarg(int) gidsetsize;
     196             :                 syscallarg(gid_t *) gidset;
     197           0 :         } */ *uap = v;
     198           0 :         struct ucred *uc = p->p_ucred;
     199             :         u_int ngrp;
     200             :         int error;
     201             : 
     202           0 :         if ((ngrp = SCARG(uap, gidsetsize)) == 0) {
     203           0 :                 *retval = uc->cr_ngroups;
     204           0 :                 return (0);
     205             :         }
     206           0 :         if (ngrp < uc->cr_ngroups)
     207           0 :                 return (EINVAL);
     208             :         ngrp = uc->cr_ngroups;
     209           0 :         error = copyout(uc->cr_groups, SCARG(uap, gidset),
     210           0 :             ngrp * sizeof(gid_t));
     211           0 :         if (error)
     212           0 :                 return (error);
     213           0 :         *retval = ngrp;
     214           0 :         return (0);
     215           0 : }
     216             : 
     217             : int
     218           0 : sys_setsid(struct proc *p, void *v, register_t *retval)
     219             : {
     220             :         struct session *newsess;
     221             :         struct pgrp *newpgrp;
     222           0 :         struct process *pr = p->p_p;
     223           0 :         pid_t pid = pr->ps_pid;
     224             : 
     225           0 :         newsess = pool_get(&session_pool, PR_WAITOK);
     226           0 :         newpgrp = pool_get(&pgrp_pool, PR_WAITOK);
     227             : 
     228           0 :         if (pr->ps_pgid == pid || pgfind(pid) != NULL) {
     229           0 :                 pool_put(&pgrp_pool, newpgrp);
     230           0 :                 pool_put(&session_pool, newsess);
     231           0 :                 return (EPERM);
     232             :         } else {
     233           0 :                 enternewpgrp(pr, newpgrp, newsess);
     234           0 :                 *retval = pid;
     235           0 :                 return (0);
     236             :         }
     237           0 : }
     238             : 
     239             : /*
     240             :  * set process group (setpgid/old setpgrp)
     241             :  *
     242             :  * caller does setpgid(targpid, targpgid)
     243             :  *
     244             :  * pid must be caller or child of caller (ESRCH)
     245             :  * if a child
     246             :  *      pid must be in same session (EPERM)
     247             :  *      pid can't have done an exec (EACCES)
     248             :  * if pgid != pid
     249             :  *      there must exist some pid in same session having pgid (EPERM)
     250             :  * pid must not be session leader (EPERM)
     251             :  */
     252             : int
     253           0 : sys_setpgid(struct proc *curp, void *v, register_t *retval)
     254             : {
     255             :         struct sys_setpgid_args /* {
     256             :                 syscallarg(pid_t) pid;
     257             :                 syscallarg(pid_t) pgid;
     258           0 :         } */ *uap = v;
     259           0 :         struct process *curpr = curp->p_p;
     260             :         struct process *targpr;         /* target process */
     261             :         struct pgrp *pgrp, *newpgrp;    /* target pgrp */
     262             :         pid_t pid, pgid;
     263             :         int error;
     264             : 
     265           0 :         pid = SCARG(uap, pid);
     266           0 :         pgid = SCARG(uap, pgid);
     267             : 
     268           0 :         if (pgid < 0)
     269           0 :                 return (EINVAL);
     270             : 
     271           0 :         newpgrp = pool_get(&pgrp_pool, PR_WAITOK);
     272             : 
     273           0 :         if (pid != 0 && pid != curpr->ps_pid) {
     274           0 :                 if ((targpr = prfind(pid)) == 0 || !inferior(targpr, curpr)) {
     275             :                         error = ESRCH;
     276           0 :                         goto out;
     277             :                 }
     278           0 :                 if (targpr->ps_session != curpr->ps_session) {
     279             :                         error = EPERM;
     280           0 :                         goto out;
     281             :                 }
     282           0 :                 if (targpr->ps_flags & PS_EXEC) {
     283             :                         error = EACCES;
     284           0 :                         goto out;
     285             :                 }
     286             :         } else
     287             :                 targpr = curpr;
     288           0 :         if (SESS_LEADER(targpr)) {
     289             :                 error = EPERM;
     290           0 :                 goto out;
     291             :         }
     292           0 :         if (pgid == 0)
     293           0 :                 pgid = targpr->ps_pid;
     294             : 
     295             :         error = 0;
     296           0 :         if ((pgrp = pgfind(pgid)) == NULL) {
     297             :                 /* can only create a new process group with pgid == pid */
     298           0 :                 if (pgid != targpr->ps_pid)
     299           0 :                         error = EPERM;
     300             :                 else {
     301           0 :                         enternewpgrp(targpr, newpgrp, NULL);
     302             :                         newpgrp = NULL;
     303             :                 }
     304           0 :         } else if (pgrp != targpr->ps_pgrp) {                /* anything to do? */
     305           0 :                 if (pgid != targpr->ps_pid &&
     306           0 :                     pgrp->pg_session != curpr->ps_session)
     307           0 :                         error = EPERM;
     308             :                 else
     309           0 :                         enterthispgrp(targpr, pgrp);
     310             :         }
     311             :  out:
     312           0 :         if (newpgrp != NULL)
     313           0 :                 pool_put(&pgrp_pool, newpgrp);
     314           0 :         return (error);
     315           0 : }
     316             : 
     317             : int
     318           0 : sys_getresuid(struct proc *p, void *v, register_t *retval)
     319             : {
     320             :         struct sys_getresuid_args /* {
     321             :                 syscallarg(uid_t *) ruid;
     322             :                 syscallarg(uid_t *) euid;
     323             :                 syscallarg(uid_t *) suid;
     324           0 :         } */ *uap = v;
     325           0 :         struct ucred *uc = p->p_ucred;
     326             :         uid_t *ruid, *euid, *suid;
     327             :         int error1 = 0, error2 = 0, error3 = 0;
     328             : 
     329           0 :         ruid = SCARG(uap, ruid);
     330           0 :         euid = SCARG(uap, euid);
     331           0 :         suid = SCARG(uap, suid);
     332             : 
     333           0 :         if (ruid != NULL)
     334           0 :                 error1 = copyout(&uc->cr_ruid, ruid, sizeof(*ruid));
     335           0 :         if (euid != NULL)
     336           0 :                 error2 = copyout(&uc->cr_uid, euid, sizeof(*euid));
     337           0 :         if (suid != NULL)
     338           0 :                 error3 = copyout(&uc->cr_svuid, suid, sizeof(*suid));
     339             : 
     340           0 :         return (error1 ? error1 : error2 ? error2 : error3);
     341             : }
     342             : 
     343             : int
     344           0 : sys_setresuid(struct proc *p, void *v, register_t *retval)
     345             : {
     346             :         struct sys_setresuid_args /* {
     347             :                 syscallarg(uid_t) ruid;
     348             :                 syscallarg(uid_t) euid;
     349             :                 syscallarg(uid_t) suid;
     350           0 :         } */ *uap = v;
     351           0 :         struct process *pr = p->p_p;
     352           0 :         struct ucred *pruc, *newcred, *uc = p->p_ucred;
     353             :         uid_t ruid, euid, suid;
     354             :         int error;
     355             : 
     356           0 :         ruid = SCARG(uap, ruid);
     357           0 :         euid = SCARG(uap, euid);
     358           0 :         suid = SCARG(uap, suid);
     359             : 
     360             :         /*
     361             :          * make permission checks against the thread's ucred,
     362             :          * but the actual changes will be to the process's ucred
     363             :          */
     364           0 :         pruc = pr->ps_ucred;
     365           0 :         if ((ruid == (uid_t)-1 || ruid == pruc->cr_ruid) &&
     366           0 :             (euid == (uid_t)-1 || euid == pruc->cr_uid) &&
     367           0 :             (suid == (uid_t)-1 || suid == pruc->cr_svuid))
     368           0 :                 return (0);                     /* no change */
     369             : 
     370             :         /*
     371             :          * Any of the real, effective, and saved uids may be changed
     372             :          * to the current value of one of the three (root is not limited).
     373             :          */
     374           0 :         if (ruid != (uid_t)-1 &&
     375           0 :             ruid != uc->cr_ruid &&
     376           0 :             ruid != uc->cr_uid &&
     377           0 :             ruid != uc->cr_svuid &&
     378           0 :             (error = suser(p)))
     379           0 :                 return (error);
     380             : 
     381           0 :         if (euid != (uid_t)-1 &&
     382           0 :             euid != uc->cr_ruid &&
     383           0 :             euid != uc->cr_uid &&
     384           0 :             euid != uc->cr_svuid &&
     385           0 :             (error = suser(p)))
     386           0 :                 return (error);
     387             : 
     388           0 :         if (suid != (uid_t)-1 &&
     389           0 :             suid != uc->cr_ruid &&
     390           0 :             suid != uc->cr_uid &&
     391           0 :             suid != uc->cr_svuid &&
     392           0 :             (error = suser(p)))
     393           0 :                 return (error);
     394             : 
     395             :         /*
     396             :          * Copy credentials so other references do not see our changes.
     397             :          * ps_ucred may change during the crget().
     398             :          */
     399           0 :         newcred = crget();
     400           0 :         pruc = pr->ps_ucred;
     401           0 :         crset(newcred, pruc);
     402             : 
     403             :         /*
     404             :          * Note that unlike the other set*uid() calls, each
     405             :          * uid type is set independently of the others.
     406             :          */
     407           0 :         if (ruid != (uid_t)-1)
     408           0 :                 newcred->cr_ruid = ruid;
     409           0 :         if (euid != (uid_t)-1)
     410           0 :                 newcred->cr_uid = euid;
     411           0 :         if (suid != (uid_t)-1)
     412           0 :                 newcred->cr_svuid = suid;
     413           0 :         pr->ps_ucred = newcred;
     414           0 :         atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
     415             : 
     416             :         /* now that we can sleep, transfer proc count to new user */
     417           0 :         if (ruid != (uid_t)-1 && ruid != pruc->cr_ruid) {
     418           0 :                 chgproccnt(pruc->cr_ruid, -1);
     419           0 :                 chgproccnt(ruid, 1);
     420           0 :         }
     421           0 :         crfree(pruc);
     422             : 
     423           0 :         return (0);
     424           0 : }
     425             : 
     426             : int
     427           0 : sys_getresgid(struct proc *p, void *v, register_t *retval)
     428             : {
     429             :         struct sys_getresgid_args /* {
     430             :                 syscallarg(gid_t *) rgid;
     431             :                 syscallarg(gid_t *) egid;
     432             :                 syscallarg(gid_t *) sgid;
     433           0 :         } */ *uap = v;
     434           0 :         struct ucred *uc = p->p_ucred;
     435             :         gid_t *rgid, *egid, *sgid;
     436             :         int error1 = 0, error2 = 0, error3 = 0;
     437             : 
     438           0 :         rgid = SCARG(uap, rgid);
     439           0 :         egid = SCARG(uap, egid);
     440           0 :         sgid = SCARG(uap, sgid);
     441             : 
     442           0 :         if (rgid != NULL)
     443           0 :                 error1 = copyout(&uc->cr_rgid, rgid, sizeof(*rgid));
     444           0 :         if (egid != NULL)
     445           0 :                 error2 = copyout(&uc->cr_gid, egid, sizeof(*egid));
     446           0 :         if (sgid != NULL)
     447           0 :                 error3 = copyout(&uc->cr_svgid, sgid, sizeof(*sgid));
     448             : 
     449           0 :         return (error1 ? error1 : error2 ? error2 : error3);
     450             : }
     451             : 
     452             : int
     453           0 : sys_setresgid(struct proc *p, void *v, register_t *retval)
     454             : {
     455             :         struct sys_setresgid_args /* {
     456             :                 syscallarg(gid_t) rgid;
     457             :                 syscallarg(gid_t) egid;
     458             :                 syscallarg(gid_t) sgid;
     459           0 :         } */ *uap = v;
     460           0 :         struct process *pr = p->p_p;
     461           0 :         struct ucred *pruc, *newcred, *uc = p->p_ucred;
     462             :         gid_t rgid, egid, sgid;
     463             :         int error;
     464             : 
     465           0 :         rgid = SCARG(uap, rgid);
     466           0 :         egid = SCARG(uap, egid);
     467           0 :         sgid = SCARG(uap, sgid);
     468             : 
     469             :         /*
     470             :          * make permission checks against the thread's ucred,
     471             :          * but the actual changes will be to the process's ucred
     472             :          */
     473           0 :         pruc = pr->ps_ucred;
     474           0 :         if ((rgid == (gid_t)-1 || rgid == pruc->cr_rgid) &&
     475           0 :             (egid == (gid_t)-1 || egid == pruc->cr_gid) &&
     476           0 :             (sgid == (gid_t)-1 || sgid == pruc->cr_svgid))
     477           0 :                 return (0);                     /* no change */
     478             : 
     479             :         /*
     480             :          * Any of the real, effective, and saved gids may be changed
     481             :          * to the current value of one of the three (root is not limited).
     482             :          */
     483           0 :         if (rgid != (gid_t)-1 &&
     484           0 :             rgid != uc->cr_rgid &&
     485           0 :             rgid != uc->cr_gid &&
     486           0 :             rgid != uc->cr_svgid &&
     487           0 :             (error = suser(p)))
     488           0 :                 return (error);
     489             : 
     490           0 :         if (egid != (gid_t)-1 &&
     491           0 :             egid != uc->cr_rgid &&
     492           0 :             egid != uc->cr_gid &&
     493           0 :             egid != uc->cr_svgid &&
     494           0 :             (error = suser(p)))
     495           0 :                 return (error);
     496             : 
     497           0 :         if (sgid != (gid_t)-1 &&
     498           0 :             sgid != uc->cr_rgid &&
     499           0 :             sgid != uc->cr_gid &&
     500           0 :             sgid != uc->cr_svgid &&
     501           0 :             (error = suser(p)))
     502           0 :                 return (error);
     503             : 
     504             :         /*
     505             :          * Copy credentials so other references do not see our changes.
     506             :          * ps_ucred may change during the crget().
     507             :          */
     508           0 :         newcred = crget();
     509           0 :         pruc = pr->ps_ucred;
     510           0 :         crset(newcred, pruc);
     511             : 
     512             :         /*
     513             :          * Note that unlike the other set*gid() calls, each
     514             :          * gid type is set independently of the others.
     515             :          */
     516           0 :         if (rgid != (gid_t)-1)
     517           0 :                 newcred->cr_rgid = rgid;
     518           0 :         if (egid != (gid_t)-1)
     519           0 :                 newcred->cr_gid = egid;
     520           0 :         if (sgid != (gid_t)-1)
     521           0 :                 newcred->cr_svgid = sgid;
     522           0 :         pr->ps_ucred = newcred;
     523           0 :         atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
     524           0 :         crfree(pruc);
     525           0 :         return (0);
     526           0 : }
     527             : 
     528             : int
     529           0 : sys_setregid(struct proc *p, void *v, register_t *retval)
     530             : {
     531             :         struct sys_setregid_args /* {
     532             :                 syscallarg(gid_t) rgid;
     533             :                 syscallarg(gid_t) egid;
     534           0 :         } */ *uap = v;
     535           0 :         struct process *pr = p->p_p;
     536           0 :         struct ucred *pruc, *newcred, *uc = p->p_ucred;
     537             :         gid_t rgid, egid;
     538             :         int error;
     539             : 
     540           0 :         rgid = SCARG(uap, rgid);
     541           0 :         egid = SCARG(uap, egid);
     542             : 
     543             :         /*
     544             :          * make permission checks against the thread's ucred,
     545             :          * but the actual changes will be to the process's ucred
     546             :          *
     547             :          * The saved gid check here is complicated: we reset the
     548             :          * saved gid to the real gid if the real gid is specified
     549             :          * *and* either it's changing _or_ the saved gid won't equal
     550             :          * the effective gid.  So, the svgid *won't* change when
     551             :          * the rgid isn't specified or when the rgid isn't changing
     552             :          * and the svgid equals the requested egid.
     553             :          */
     554           0 :         pruc = pr->ps_ucred;
     555           0 :         if ((rgid == (gid_t)-1 || rgid == pruc->cr_rgid) &&
     556           0 :             (egid == (gid_t)-1 || egid == pruc->cr_gid) &&
     557           0 :             (rgid == (gid_t)-1 || (rgid == pruc->cr_rgid &&
     558           0 :             pruc->cr_svgid == (egid != (gid_t)-1 ? egid : pruc->cr_gid))))
     559           0 :                 return (0);                     /* no change */
     560             : 
     561             :         /*
     562             :          * Any of the real, effective, and saved gids may be changed
     563             :          * to the current value of one of the three (root is not limited).
     564             :          */
     565           0 :         if (rgid != (gid_t)-1 &&
     566           0 :             rgid != uc->cr_rgid &&
     567           0 :             rgid != uc->cr_gid &&
     568           0 :             rgid != uc->cr_svgid &&
     569           0 :             (error = suser(p)))
     570           0 :                 return (error);
     571             : 
     572           0 :         if (egid != (gid_t)-1 &&
     573           0 :             egid != uc->cr_rgid &&
     574           0 :             egid != uc->cr_gid &&
     575           0 :             egid != uc->cr_svgid &&
     576           0 :             (error = suser(p)))
     577           0 :                 return (error);
     578             : 
     579             :         /*
     580             :          * Copy credentials so other references do not see our changes.
     581             :          * ps_ucred may change during the crget().
     582             :          */
     583           0 :         newcred = crget();
     584           0 :         pruc = pr->ps_ucred;
     585           0 :         crset(newcred, pruc);
     586             : 
     587           0 :         if (rgid != (gid_t)-1)
     588           0 :                 newcred->cr_rgid = rgid;
     589           0 :         if (egid != (gid_t)-1)
     590           0 :                 newcred->cr_gid = egid;
     591             : 
     592             :         /*
     593             :          * The saved gid presents a bit of a dilemma, as it did not
     594             :          * exist when setregid(2) was conceived.  We only set the saved
     595             :          * gid when the real gid is specified and either its value would
     596             :          * change, or where the saved and effective gids are different.
     597             :          */
     598           0 :         if (rgid != (gid_t)-1 && (rgid != pruc->cr_rgid ||
     599           0 :             pruc->cr_svgid != (egid != (gid_t)-1 ? egid : pruc->cr_gid)))
     600           0 :                 newcred->cr_svgid = rgid;
     601           0 :         pr->ps_ucred = newcred;
     602           0 :         atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
     603           0 :         crfree(pruc);
     604           0 :         return (0);
     605           0 : }
     606             : 
     607             : int
     608           0 : sys_setreuid(struct proc *p, void *v, register_t *retval)
     609             : {
     610             :         struct sys_setreuid_args /* {
     611             :                 syscallarg(uid_t) ruid;
     612             :                 syscallarg(uid_t) euid;
     613           0 :         } */ *uap = v;
     614           0 :         struct process *pr = p->p_p;
     615           0 :         struct ucred *pruc, *newcred, *uc = p->p_ucred;
     616             :         uid_t ruid, euid;
     617             :         int error;
     618             : 
     619           0 :         ruid = SCARG(uap, ruid);
     620           0 :         euid = SCARG(uap, euid);
     621             : 
     622             :         /*
     623             :          * make permission checks against the thread's ucred,
     624             :          * but the actual changes will be to the process's ucred
     625             :          *
     626             :          * The saved uid check here is complicated: we reset the
     627             :          * saved uid to the real uid if the real uid is specified
     628             :          * *and* either it's changing _or_ the saved uid won't equal
     629             :          * the effective uid.  So, the svuid *won't* change when
     630             :          * the ruid isn't specified or when the ruid isn't changing
     631             :          * and the svuid equals the requested euid.
     632             :          */
     633           0 :         pruc = pr->ps_ucred;
     634           0 :         if ((ruid == (uid_t)-1 || ruid == pruc->cr_ruid) &&
     635           0 :             (euid == (uid_t)-1 || euid == pruc->cr_uid) &&
     636           0 :             (ruid == (uid_t)-1 || (ruid == pruc->cr_ruid &&
     637           0 :             pruc->cr_svuid == (euid != (uid_t)-1 ? euid : pruc->cr_uid))))
     638           0 :                 return (0);                     /* no change */
     639             : 
     640             :         /*
     641             :          * Any of the real, effective, and saved uids may be changed
     642             :          * to the current value of one of the three (root is not limited).
     643             :          */
     644           0 :         if (ruid != (uid_t)-1 &&
     645           0 :             ruid != uc->cr_ruid &&
     646           0 :             ruid != uc->cr_uid &&
     647           0 :             ruid != uc->cr_svuid &&
     648           0 :             (error = suser(p)))
     649           0 :                 return (error);
     650             : 
     651           0 :         if (euid != (uid_t)-1 &&
     652           0 :             euid != uc->cr_ruid &&
     653           0 :             euid != uc->cr_uid &&
     654           0 :             euid != uc->cr_svuid &&
     655           0 :             (error = suser(p)))
     656           0 :                 return (error);
     657             : 
     658             :         /*
     659             :          * Copy credentials so other references do not see our changes.
     660             :          * ps_ucred may change during the crget().
     661             :          */
     662           0 :         newcred = crget();
     663           0 :         pruc = pr->ps_ucred;
     664           0 :         crset(newcred, pruc);
     665             : 
     666           0 :         if (ruid != (uid_t)-1)
     667           0 :                 newcred->cr_ruid = ruid;
     668           0 :         if (euid != (uid_t)-1)
     669           0 :                 newcred->cr_uid = euid;
     670             : 
     671             :         /*
     672             :          * The saved uid presents a bit of a dilemma, as it did not
     673             :          * exist when setreuid(2) was conceived.  We only set the saved
     674             :          * uid when the real uid is specified and either its value would
     675             :          * change, or where the saved and effective uids are different.
     676             :          */
     677           0 :         if (ruid != (uid_t)-1 && (ruid != pruc->cr_ruid ||
     678           0 :             pruc->cr_svuid != (euid != (uid_t)-1 ? euid : pruc->cr_uid)))
     679           0 :                 newcred->cr_svuid = ruid;
     680           0 :         pr->ps_ucred = newcred;
     681           0 :         atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
     682             : 
     683             :         /* now that we can sleep, transfer proc count to new user */
     684           0 :         if (ruid != (uid_t)-1 && ruid != pruc->cr_ruid) {
     685           0 :                 chgproccnt(pruc->cr_ruid, -1);
     686           0 :                 chgproccnt(ruid, 1);
     687           0 :         }
     688           0 :         crfree(pruc);
     689             : 
     690           0 :         return (0);
     691           0 : }
     692             : 
     693             : int
     694           0 : sys_setuid(struct proc *p, void *v, register_t *retval)
     695             : {
     696             :         struct sys_setuid_args /* {
     697             :                 syscallarg(uid_t) uid;
     698           0 :         } */ *uap = v;
     699           0 :         struct process *pr = p->p_p;
     700           0 :         struct ucred *pruc, *newcred, *uc = p->p_ucred;
     701             :         uid_t uid;
     702             :         int did_real, error;
     703             : 
     704           0 :         uid = SCARG(uap, uid);
     705             : 
     706           0 :         pruc = pr->ps_ucred;
     707           0 :         if (pruc->cr_uid == uid &&
     708           0 :             pruc->cr_ruid == uid &&
     709           0 :             pruc->cr_svuid == uid)
     710           0 :                 return (0);
     711             : 
     712           0 :         if (uid != uc->cr_ruid &&
     713           0 :             uid != uc->cr_svuid &&
     714           0 :             uid != uc->cr_uid &&
     715           0 :             (error = suser(p)))
     716           0 :                 return (error);
     717             : 
     718             :         /*
     719             :          * Copy credentials so other references do not see our changes.
     720             :          * ps_ucred may change during the crget().
     721             :          */
     722           0 :         newcred = crget();
     723           0 :         pruc = pr->ps_ucred;
     724           0 :         crset(newcred, pruc);
     725             : 
     726             :         /*
     727             :          * Everything's okay, do it.
     728             :          */
     729           0 :         if (uid == pruc->cr_uid || suser(p) == 0) {
     730             :                 did_real = 1;
     731           0 :                 newcred->cr_ruid = uid;
     732           0 :                 newcred->cr_svuid = uid;
     733           0 :         } else
     734             :                 did_real = 0;
     735           0 :         newcred->cr_uid = uid;
     736           0 :         pr->ps_ucred = newcred;
     737           0 :         atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
     738             : 
     739             :         /*
     740             :          * Transfer proc count to new user.
     741             :          */
     742           0 :         if (did_real && uid != pruc->cr_ruid) {
     743           0 :                 chgproccnt(pruc->cr_ruid, -1);
     744           0 :                 chgproccnt(uid, 1);
     745           0 :         }
     746           0 :         crfree(pruc);
     747             : 
     748           0 :         return (0);
     749           0 : }
     750             : 
     751             : int
     752           0 : sys_seteuid(struct proc *p, void *v, register_t *retval)
     753             : {
     754             :         struct sys_seteuid_args /* {
     755             :                 syscallarg(uid_t) euid;
     756           0 :         } */ *uap = v;
     757           0 :         struct process *pr = p->p_p;
     758           0 :         struct ucred *pruc, *newcred, *uc = p->p_ucred;
     759             :         uid_t euid;
     760             :         int error;
     761             : 
     762           0 :         euid = SCARG(uap, euid);
     763             : 
     764           0 :         if (pr->ps_ucred->cr_uid == euid)
     765           0 :                 return (0);
     766             : 
     767           0 :         if (euid != uc->cr_ruid && euid != uc->cr_svuid &&
     768           0 :             (error = suser(p)))
     769           0 :                 return (error);
     770             : 
     771             :         /*
     772             :          * Copy credentials so other references do not see our changes.
     773             :          * ps_ucred may change during the crget().
     774             :          */
     775           0 :         newcred = crget();
     776           0 :         pruc = pr->ps_ucred;
     777           0 :         crset(newcred, pruc);
     778           0 :         newcred->cr_uid = euid;
     779           0 :         pr->ps_ucred = newcred;
     780           0 :         atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
     781           0 :         crfree(pruc);
     782           0 :         return (0);
     783           0 : }
     784             : 
     785             : int
     786           0 : sys_setgid(struct proc *p, void *v, register_t *retval)
     787             : {
     788             :         struct sys_setgid_args /* {
     789             :                 syscallarg(gid_t) gid;
     790           0 :         } */ *uap = v;
     791           0 :         struct process *pr = p->p_p;
     792           0 :         struct ucred *pruc, *newcred, *uc = p->p_ucred;
     793             :         gid_t gid;
     794             :         int error;
     795             : 
     796           0 :         gid = SCARG(uap, gid);
     797             : 
     798           0 :         pruc = pr->ps_ucred;
     799           0 :         if (pruc->cr_gid == gid &&
     800           0 :             pruc->cr_rgid == gid &&
     801           0 :             pruc->cr_svgid == gid)
     802           0 :                 return (0);
     803             : 
     804           0 :         if (gid != uc->cr_rgid &&
     805           0 :             gid != uc->cr_svgid &&
     806           0 :             gid != uc->cr_gid &&
     807           0 :             (error = suser(p)))
     808           0 :                 return (error);
     809             : 
     810             :         /*
     811             :          * Copy credentials so other references do not see our changes.
     812             :          * ps_ucred may change during the crget().
     813             :          */
     814           0 :         newcred = crget();
     815           0 :         pruc = pr->ps_ucred;
     816           0 :         crset(newcred, pruc);
     817             : 
     818           0 :         if (gid == pruc->cr_gid || suser(p) == 0) {
     819           0 :                 newcred->cr_rgid = gid;
     820           0 :                 newcred->cr_svgid = gid;
     821           0 :         }
     822           0 :         newcred->cr_gid = gid;
     823           0 :         pr->ps_ucred = newcred;
     824           0 :         atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
     825           0 :         crfree(pruc);
     826           0 :         return (0);
     827           0 : }
     828             : 
     829             : int
     830           0 : sys_setegid(struct proc *p, void *v, register_t *retval)
     831             : {
     832             :         struct sys_setegid_args /* {
     833             :                 syscallarg(gid_t) egid;
     834           0 :         } */ *uap = v;
     835           0 :         struct process *pr = p->p_p;
     836           0 :         struct ucred *pruc, *newcred, *uc = p->p_ucred;
     837             :         gid_t egid;
     838             :         int error;
     839             : 
     840           0 :         egid = SCARG(uap, egid);
     841             : 
     842           0 :         if (pr->ps_ucred->cr_gid == egid)
     843           0 :                 return (0);
     844             : 
     845           0 :         if (egid != uc->cr_rgid && egid != uc->cr_svgid &&
     846           0 :             (error = suser(p)))
     847           0 :                 return (error);
     848             : 
     849             :         /*
     850             :          * Copy credentials so other references do not see our changes.
     851             :          * ps_ucred may change during the crget().
     852             :          */
     853           0 :         newcred = crget();
     854           0 :         pruc = pr->ps_ucred;
     855           0 :         crset(newcred, pruc);
     856           0 :         newcred->cr_gid = egid;
     857           0 :         pr->ps_ucred = newcred;
     858           0 :         atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
     859           0 :         crfree(pruc);
     860           0 :         return (0);
     861           0 : }
     862             : 
     863             : int
     864           0 : sys_setgroups(struct proc *p, void *v, register_t *retval)
     865             : {
     866             :         struct sys_setgroups_args /* {
     867             :                 syscallarg(int) gidsetsize;
     868             :                 syscallarg(const gid_t *) gidset;
     869           0 :         } */ *uap = v;
     870           0 :         struct process *pr = p->p_p;
     871             :         struct ucred *pruc, *newcred;
     872           0 :         gid_t groups[NGROUPS_MAX];
     873             :         u_int ngrp;
     874             :         int error;
     875             : 
     876           0 :         if ((error = suser(p)) != 0)
     877           0 :                 return (error);
     878           0 :         ngrp = SCARG(uap, gidsetsize);
     879           0 :         if (ngrp > NGROUPS_MAX)
     880           0 :                 return (EINVAL);
     881           0 :         error = copyin(SCARG(uap, gidset), groups, ngrp * sizeof(gid_t));
     882           0 :         if (error == 0) {
     883           0 :                 newcred = crget();
     884           0 :                 pruc = pr->ps_ucred;
     885           0 :                 crset(newcred, pruc);
     886           0 :                 memcpy(newcred->cr_groups, groups, ngrp * sizeof(gid_t));
     887           0 :                 newcred->cr_ngroups = ngrp;
     888           0 :                 pr->ps_ucred = newcred;
     889           0 :                 atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
     890           0 :                 crfree(pruc);
     891           0 :         }
     892           0 :         return (error);
     893           0 : }
     894             : 
     895             : /*
     896             :  * Check if gid is a member of the group set.
     897             :  */
     898             : int
     899           0 : groupmember(gid_t gid, struct ucred *cred)
     900             : {
     901             :         gid_t *gp;
     902             :         gid_t *egp;
     903             : 
     904           0 :         if (cred->cr_gid == gid)
     905           0 :                 return (1);
     906           0 :         egp = &(cred->cr_groups[cred->cr_ngroups]);
     907           0 :         for (gp = cred->cr_groups; gp < egp; gp++)
     908           0 :                 if (*gp == gid)
     909           0 :                         return (1);
     910           0 :         return (0);
     911           0 : }
     912             : 
     913             : /*
     914             :  * Test whether this process has special user powers.
     915             :  * Returns 0 or error.
     916             :  */
     917             : int
     918           0 : suser(struct proc *p)
     919             : {
     920           0 :         struct ucred *cred = p->p_ucred;
     921             : 
     922           0 :         if (cred->cr_uid == 0)
     923           0 :                 return (0);
     924           0 :         return (EPERM);
     925           0 : }
     926             : 
     927             : /*
     928             :  * replacement for old suser, for callers who don't have a process
     929             :  */
     930             : int
     931           0 : suser_ucred(struct ucred *cred)
     932             : {
     933           0 :         if (cred->cr_uid == 0)
     934           0 :                 return (0);
     935           0 :         return (EPERM);
     936           0 : }
     937             : 
     938             : /*
     939             :  * Allocate a zeroed cred structure.
     940             :  */
     941             : struct ucred *
     942           0 : crget(void)
     943             : {
     944             :         struct ucred *cr;
     945             : 
     946           0 :         cr = pool_get(&ucred_pool, PR_WAITOK|PR_ZERO);
     947           0 :         cr->cr_ref = 1;
     948           0 :         return (cr);
     949             : }
     950             : 
     951             : /*
     952             :  * Increment the reference count of a cred structure.
     953             :  * Returns the passed structure.
     954             :  */
     955             : struct ucred *
     956           0 : crhold(struct ucred *cr)
     957             : {
     958           0 :         atomic_inc_int(&cr->cr_ref);
     959           0 :         return (cr);
     960             : }
     961             : 
     962             : /*
     963             :  * Free a cred structure.
     964             :  * Throws away space when ref count gets to 0.
     965             :  */
     966             : void
     967           0 : crfree(struct ucred *cr)
     968             : {
     969             : 
     970           0 :         if (atomic_dec_int_nv(&cr->cr_ref) == 0)
     971           0 :                 pool_put(&ucred_pool, cr);
     972           0 : }
     973             : 
     974             : /*
     975             :  * Copy cred structure to a new one and free the old one.
     976             :  */
     977             : struct ucred *
     978           0 : crcopy(struct ucred *cr)
     979             : {
     980             :         struct ucred *newcr;
     981             : 
     982           0 :         if (cr->cr_ref == 1)
     983           0 :                 return (cr);
     984           0 :         newcr = crget();
     985           0 :         *newcr = *cr;
     986           0 :         crfree(cr);
     987           0 :         newcr->cr_ref = 1;
     988           0 :         return (newcr);
     989           0 : }
     990             : 
     991             : /*
     992             :  * Dup cred struct to a new held one.
     993             :  */
     994             : struct ucred *
     995           0 : crdup(struct ucred *cr)
     996             : {
     997             :         struct ucred *newcr;
     998             : 
     999           0 :         newcr = crget();
    1000           0 :         *newcr = *cr;
    1001           0 :         newcr->cr_ref = 1;
    1002           0 :         return (newcr);
    1003             : }
    1004             : 
    1005             : /*
    1006             :  * Convert the userspace xucred to a kernel ucred
    1007             :  */
    1008             : int
    1009           0 : crfromxucred(struct ucred *cr, const struct xucred *xcr)
    1010             : {
    1011           0 :         if (xcr->cr_ngroups < 0 || xcr->cr_ngroups > NGROUPS_MAX)
    1012           0 :                 return (EINVAL);
    1013           0 :         cr->cr_ref = 1;
    1014           0 :         cr->cr_uid = xcr->cr_uid;
    1015           0 :         cr->cr_gid = xcr->cr_gid;
    1016           0 :         cr->cr_ngroups = xcr->cr_ngroups;
    1017           0 :         memcpy(cr->cr_groups, xcr->cr_groups,
    1018             :             sizeof(cr->cr_groups[0]) * xcr->cr_ngroups);
    1019           0 :         return (0);
    1020           0 : }
    1021             : 
    1022             : /*
    1023             :  * Get login name, if available.
    1024             :  */
    1025             : int
    1026           0 : sys_getlogin_r(struct proc *p, void *v, register_t *retval)
    1027             : {
    1028             :         struct sys_getlogin_r_args /* {
    1029             :                 syscallarg(char *) namebuf;
    1030             :                 syscallarg(size_t) namelen;
    1031           0 :         } */ *uap = v;
    1032           0 :         size_t namelen = SCARG(uap, namelen);
    1033           0 :         struct session *s = p->p_p->ps_pgrp->pg_session;
    1034             :         int error;
    1035             : 
    1036           0 :         if (namelen > sizeof(s->s_login))
    1037           0 :                 namelen = sizeof(s->s_login);
    1038           0 :         error = copyoutstr(s->s_login, SCARG(uap, namebuf), namelen, NULL);
    1039           0 :         if (error == ENAMETOOLONG)
    1040             :                 error = ERANGE;
    1041           0 :         *retval = error;
    1042           0 :         return (0);
    1043             : }
    1044             : 
    1045             : /*
    1046             :  * Set login name.
    1047             :  */
    1048             : int
    1049           0 : sys_setlogin(struct proc *p, void *v, register_t *retval)
    1050             : {
    1051             :         struct sys_setlogin_args /* {
    1052             :                 syscallarg(const char *) namebuf;
    1053           0 :         } */ *uap = v;
    1054           0 :         struct session *s = p->p_p->ps_pgrp->pg_session;
    1055           0 :         char buf[sizeof(s->s_login)];
    1056             :         int error;
    1057             : 
    1058           0 :         if ((error = suser(p)) != 0)
    1059           0 :                 return (error);
    1060           0 :         error = copyinstr(SCARG(uap, namebuf), buf, sizeof(buf), NULL);
    1061           0 :         if (error == 0)
    1062           0 :                 strlcpy(s->s_login, buf, sizeof(s->s_login));
    1063           0 :         else if (error == ENAMETOOLONG)
    1064           0 :                 error = EINVAL;
    1065           0 :         return (error);
    1066           0 : }
    1067             : 
    1068             : /*
    1069             :  * Check if a process is allowed to raise its privileges.
    1070             :  */
    1071             : int
    1072           0 : proc_cansugid(struct proc *p)
    1073             : {
    1074             :         /* ptrace(2)d processes shouldn't. */
    1075           0 :         if ((p->p_p->ps_flags & PS_TRACED) != 0)
    1076           0 :                 return (0);
    1077             : 
    1078             :         /* processes with shared filedescriptors shouldn't. */
    1079           0 :         if (p->p_fd->fd_refcnt > 1)
    1080           0 :                 return (0);
    1081             : 
    1082             :         /* Allow. */
    1083           0 :         return (1);
    1084           0 : }
    1085             : 
    1086             : /*
    1087             :  * Set address of the proc's thread-control-block
    1088             :  */
    1089             : int
    1090           0 : sys___set_tcb(struct proc *p, void *v, register_t *retval)
    1091             : {
    1092             :         struct sys___set_tcb_args /* {
    1093             :                 syscallarg(void *) tcb;
    1094           0 :         } */ *uap = v;
    1095           0 :         void *tcb = SCARG(uap, tcb);
    1096             : 
    1097             : #ifdef TCB_INVALID
    1098           0 :         if (TCB_INVALID(tcb))
    1099           0 :                 return EINVAL;
    1100             : #endif /* TCB_INVALID */
    1101           0 :         TCB_SET(p, tcb);
    1102           0 :         return (0);
    1103           0 : }
    1104             : 
    1105             : /*
    1106             :  * Get address of the proc's thread-control-block
    1107             :  */
    1108             : int
    1109           0 : sys___get_tcb(struct proc *p, void *v, register_t *retval)
    1110             : {
    1111           0 :         *retval = (register_t)TCB_GET(p);
    1112           0 :         return (0);
    1113             : }
    1114             : 
    1115             : /*
    1116             :  * Refresh the thread's reference to the process's credentials
    1117             :  */
    1118             : void
    1119           0 : dorefreshcreds(struct process *pr, struct proc *p)
    1120             : {
    1121           0 :         struct ucred *uc = p->p_ucred;
    1122             : 
    1123           0 :         KERNEL_LOCK();          /* XXX should be PROCESS_RLOCK(pr) */
    1124           0 :         if (uc != pr->ps_ucred) {
    1125           0 :                 p->p_ucred = pr->ps_ucred;
    1126           0 :                 crhold(p->p_ucred);
    1127           0 :                 crfree(uc);
    1128           0 :         }
    1129           0 :         KERNEL_UNLOCK();
    1130           0 : }

Generated by: LCOV version 1.13