The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_prot.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $OpenBSD: kern_prot.c,v 1.82 2023/01/09 02:12:13 guenther 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/atomic.h>
   46 #include <sys/systm.h>
   47 #include <sys/ucred.h>
   48 #include <sys/proc.h>
   49 #include <sys/filedesc.h>
   50 #include <sys/pool.h>
   51 
   52 #include <sys/mount.h>
   53 #include <sys/syscallargs.h>
   54 #include <machine/tcb.h>
   55 
   56 inline void
   57 crset(struct ucred *newcr, const struct ucred *cr)
   58 {
   59         KASSERT(cr->cr_refcnt.r_refs > 0);
   60         memcpy(
   61             (char *)newcr    + offsetof(struct ucred, cr_startcopy),
   62             (const char *)cr + offsetof(struct ucred, cr_startcopy),
   63             sizeof(*cr)      - offsetof(struct ucred, cr_startcopy));
   64 }
   65 
   66 int
   67 sys_getpid(struct proc *p, void *v, register_t *retval)
   68 {
   69 
   70         *retval = p->p_p->ps_pid;
   71         return (0);
   72 }
   73 
   74 int
   75 sys_getthrid(struct proc *p, void *v, register_t *retval)
   76 {
   77 
   78         *retval = p->p_tid + THREAD_PID_OFFSET;
   79         return (0);
   80 }
   81 
   82 int
   83 sys_getppid(struct proc *p, void *v, register_t *retval)
   84 {
   85 
   86         *retval = p->p_p->ps_ppid;
   87         return (0);
   88 }
   89 
   90 /* Get process group ID; note that POSIX getpgrp takes no parameter */
   91 int
   92 sys_getpgrp(struct proc *p, void *v, register_t *retval)
   93 {
   94 
   95         *retval = p->p_p->ps_pgrp->pg_id;
   96         return (0);
   97 }
   98 
   99 /*
  100  * SysVR.4 compatible getpgid()
  101  */
  102 int
  103 sys_getpgid(struct proc *curp, void *v, register_t *retval)
  104 {
  105         struct sys_getpgid_args /* {
  106                 syscallarg(pid_t) pid;
  107         } */ *uap = v;
  108         struct process *targpr = curp->p_p;
  109 
  110         if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == targpr->ps_pid)
  111                 goto found;
  112         if ((targpr = prfind(SCARG(uap, pid))) == NULL)
  113                 return (ESRCH);
  114         if (targpr->ps_session != curp->p_p->ps_session)
  115                 return (EPERM);
  116 found:
  117         *retval = targpr->ps_pgid;
  118         return (0);
  119 }
  120 
  121 int
  122 sys_getsid(struct proc *curp, void *v, register_t *retval)
  123 {
  124         struct sys_getsid_args /* {
  125                 syscallarg(pid_t) pid;
  126         } */ *uap = v;
  127         struct process *targpr = curp->p_p;
  128 
  129         if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == targpr->ps_pid)
  130                 goto found;
  131         if ((targpr = prfind(SCARG(uap, pid))) == NULL)
  132                 return (ESRCH);
  133         if (targpr->ps_session != curp->p_p->ps_session)
  134                 return (EPERM);
  135 found:
  136         /* Skip exiting processes */
  137         if (targpr->ps_pgrp->pg_session->s_leader == NULL)
  138                 return (ESRCH);
  139         *retval = targpr->ps_pgrp->pg_session->s_leader->ps_pid;
  140         return (0);
  141 }
  142 
  143 int
  144 sys_getuid(struct proc *p, void *v, register_t *retval)
  145 {
  146 
  147         *retval = p->p_ucred->cr_ruid;
  148         return (0);
  149 }
  150 
  151 int
  152 sys_geteuid(struct proc *p, void *v, register_t *retval)
  153 {
  154 
  155         *retval = p->p_ucred->cr_uid;
  156         return (0);
  157 }
  158 
  159 int
  160 sys_issetugid(struct proc *p, void *v, register_t *retval)
  161 {
  162         if (p->p_p->ps_flags & PS_SUGIDEXEC)
  163                 *retval = 1;
  164         else
  165                 *retval = 0;
  166         return (0);
  167 }
  168 
  169 int
  170 sys_getgid(struct proc *p, void *v, register_t *retval)
  171 {
  172 
  173         *retval = p->p_ucred->cr_rgid;
  174         return (0);
  175 }
  176 
  177 /*
  178  * Get effective group ID.  The "egid" is groups[0], and could be obtained
  179  * via getgroups.  This syscall exists because it is somewhat painful to do
  180  * correctly in a library function.
  181  */
  182 int
  183 sys_getegid(struct proc *p, void *v, register_t *retval)
  184 {
  185 
  186         *retval = p->p_ucred->cr_gid;
  187         return (0);
  188 }
  189 
  190 int
  191 sys_getgroups(struct proc *p, void *v, register_t *retval)
  192 {
  193         struct sys_getgroups_args /* {
  194                 syscallarg(int) gidsetsize;
  195                 syscallarg(gid_t *) gidset;
  196         } */ *uap = v;
  197         struct ucred *uc = p->p_ucred;
  198         int ngrp;
  199         int error;
  200 
  201         if ((ngrp = SCARG(uap, gidsetsize)) == 0) {
  202                 *retval = uc->cr_ngroups;
  203                 return (0);
  204         }
  205         if (ngrp < uc->cr_ngroups)
  206                 return (EINVAL);
  207         ngrp = uc->cr_ngroups;
  208         error = copyout(uc->cr_groups, SCARG(uap, gidset),
  209             ngrp * sizeof(gid_t));
  210         if (error)
  211                 return (error);
  212         *retval = ngrp;
  213         return (0);
  214 }
  215 
  216 int
  217 sys_setsid(struct proc *p, void *v, register_t *retval)
  218 {
  219         struct session *newsess;
  220         struct pgrp *newpgrp;
  221         struct process *pr = p->p_p;
  222         pid_t pid = pr->ps_pid;
  223 
  224         newsess = pool_get(&session_pool, PR_WAITOK);
  225         newpgrp = pool_get(&pgrp_pool, PR_WAITOK);
  226 
  227         if (pr->ps_pgid == pid || pgfind(pid) != NULL) {
  228                 pool_put(&pgrp_pool, newpgrp);
  229                 pool_put(&session_pool, newsess);
  230                 return (EPERM);
  231         } else {
  232                 enternewpgrp(pr, newpgrp, newsess);
  233                 *retval = pid;
  234                 return (0);
  235         }
  236 }
  237 
  238 /*
  239  * set process group (setpgid/old setpgrp)
  240  *
  241  * caller does setpgid(targpid, targpgid)
  242  *
  243  * pid must be caller or child of caller (ESRCH)
  244  * if a child
  245  *      pid must be in same session (EPERM)
  246  *      pid can't have done an exec (EACCES)
  247  * if pgid != pid
  248  *      there must exist some pid in same session having pgid (EPERM)
  249  * pid must not be session leader (EPERM)
  250  */
  251 int
  252 sys_setpgid(struct proc *curp, void *v, register_t *retval)
  253 {
  254         struct sys_setpgid_args /* {
  255                 syscallarg(pid_t) pid;
  256                 syscallarg(pid_t) pgid;
  257         } */ *uap = v;
  258         struct process *curpr = curp->p_p;
  259         struct process *targpr;         /* target process */
  260         struct pgrp *pgrp, *newpgrp;    /* target pgrp */
  261         pid_t pid, pgid;
  262         int error;
  263 
  264         pid = SCARG(uap, pid);
  265         pgid = SCARG(uap, pgid);
  266 
  267         if (pgid < 0)
  268                 return (EINVAL);
  269 
  270         newpgrp = pool_get(&pgrp_pool, PR_WAITOK);
  271 
  272         if (pid != 0 && pid != curpr->ps_pid) {
  273                 if ((targpr = prfind(pid)) == NULL ||
  274                     !inferior(targpr, curpr)) {
  275                         error = ESRCH;
  276                         goto out;
  277                 }
  278                 if (targpr->ps_session != curpr->ps_session) {
  279                         error = EPERM;
  280                         goto out;
  281                 }
  282                 if (targpr->ps_flags & PS_EXEC) {
  283                         error = EACCES;
  284                         goto out;
  285                 }
  286         } else
  287                 targpr = curpr;
  288         if (SESS_LEADER(targpr)) {
  289                 error = EPERM;
  290                 goto out;
  291         }
  292         if (pgid == 0)
  293                 pgid = targpr->ps_pid;
  294 
  295         error = 0;
  296         if ((pgrp = pgfind(pgid)) == NULL) {
  297                 /* can only create a new process group with pgid == pid */
  298                 if (pgid != targpr->ps_pid)
  299                         error = EPERM;
  300                 else {
  301                         enternewpgrp(targpr, newpgrp, NULL);
  302                         newpgrp = NULL;
  303                 }
  304         } else if (pgrp != targpr->ps_pgrp) {           /* anything to do? */
  305                 if (pgid != targpr->ps_pid &&
  306                     pgrp->pg_session != curpr->ps_session)
  307                         error = EPERM;
  308                 else
  309                         enterthispgrp(targpr, pgrp);
  310         }
  311  out:
  312         if (newpgrp != NULL)
  313                 pool_put(&pgrp_pool, newpgrp);
  314         return (error);
  315 }
  316 
  317 int
  318 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         } */ *uap = v;
  325         struct ucred *uc = p->p_ucred;
  326         uid_t *ruid, *euid, *suid;
  327         int error1 = 0, error2 = 0, error3 = 0;
  328 
  329         ruid = SCARG(uap, ruid);
  330         euid = SCARG(uap, euid);
  331         suid = SCARG(uap, suid);
  332 
  333         if (ruid != NULL)
  334                 error1 = copyout(&uc->cr_ruid, ruid, sizeof(*ruid));
  335         if (euid != NULL)
  336                 error2 = copyout(&uc->cr_uid, euid, sizeof(*euid));
  337         if (suid != NULL)
  338                 error3 = copyout(&uc->cr_svuid, suid, sizeof(*suid));
  339 
  340         return (error1 ? error1 : error2 ? error2 : error3);
  341 }
  342 
  343 int
  344 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         } */ *uap = v;
  351         struct process *pr = p->p_p;
  352         struct ucred *pruc, *newcred, *uc = p->p_ucred;
  353         uid_t ruid, euid, suid;
  354         int error;
  355 
  356         ruid = SCARG(uap, ruid);
  357         euid = SCARG(uap, euid);
  358         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         pruc = pr->ps_ucred;
  365         if ((ruid == (uid_t)-1 || ruid == pruc->cr_ruid) &&
  366             (euid == (uid_t)-1 || euid == pruc->cr_uid) &&
  367             (suid == (uid_t)-1 || suid == pruc->cr_svuid))
  368                 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         if (ruid != (uid_t)-1 &&
  375             ruid != uc->cr_ruid &&
  376             ruid != uc->cr_uid &&
  377             ruid != uc->cr_svuid &&
  378             (error = suser(p)))
  379                 return (error);
  380 
  381         if (euid != (uid_t)-1 &&
  382             euid != uc->cr_ruid &&
  383             euid != uc->cr_uid &&
  384             euid != uc->cr_svuid &&
  385             (error = suser(p)))
  386                 return (error);
  387 
  388         if (suid != (uid_t)-1 &&
  389             suid != uc->cr_ruid &&
  390             suid != uc->cr_uid &&
  391             suid != uc->cr_svuid &&
  392             (error = suser(p)))
  393                 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         newcred = crget();
  400         pruc = pr->ps_ucred;
  401         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         if (ruid != (uid_t)-1)
  408                 newcred->cr_ruid = ruid;
  409         if (euid != (uid_t)-1)
  410                 newcred->cr_uid = euid;
  411         if (suid != (uid_t)-1)
  412                 newcred->cr_svuid = suid;
  413         pr->ps_ucred = newcred;
  414         atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
  415 
  416         /* now that we can sleep, transfer proc count to new user */
  417         if (ruid != (uid_t)-1 && ruid != pruc->cr_ruid) {
  418                 chgproccnt(pruc->cr_ruid, -1);
  419                 chgproccnt(ruid, 1);
  420         }
  421         crfree(pruc);
  422 
  423         return (0);
  424 }
  425 
  426 int
  427 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         } */ *uap = v;
  434         struct ucred *uc = p->p_ucred;
  435         gid_t *rgid, *egid, *sgid;
  436         int error1 = 0, error2 = 0, error3 = 0;
  437 
  438         rgid = SCARG(uap, rgid);
  439         egid = SCARG(uap, egid);
  440         sgid = SCARG(uap, sgid);
  441 
  442         if (rgid != NULL)
  443                 error1 = copyout(&uc->cr_rgid, rgid, sizeof(*rgid));
  444         if (egid != NULL)
  445                 error2 = copyout(&uc->cr_gid, egid, sizeof(*egid));
  446         if (sgid != NULL)
  447                 error3 = copyout(&uc->cr_svgid, sgid, sizeof(*sgid));
  448 
  449         return (error1 ? error1 : error2 ? error2 : error3);
  450 }
  451 
  452 int
  453 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         } */ *uap = v;
  460         struct process *pr = p->p_p;
  461         struct ucred *pruc, *newcred, *uc = p->p_ucred;
  462         gid_t rgid, egid, sgid;
  463         int error;
  464 
  465         rgid = SCARG(uap, rgid);
  466         egid = SCARG(uap, egid);
  467         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         pruc = pr->ps_ucred;
  474         if ((rgid == (gid_t)-1 || rgid == pruc->cr_rgid) &&
  475             (egid == (gid_t)-1 || egid == pruc->cr_gid) &&
  476             (sgid == (gid_t)-1 || sgid == pruc->cr_svgid))
  477                 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         if (rgid != (gid_t)-1 &&
  484             rgid != uc->cr_rgid &&
  485             rgid != uc->cr_gid &&
  486             rgid != uc->cr_svgid &&
  487             (error = suser(p)))
  488                 return (error);
  489 
  490         if (egid != (gid_t)-1 &&
  491             egid != uc->cr_rgid &&
  492             egid != uc->cr_gid &&
  493             egid != uc->cr_svgid &&
  494             (error = suser(p)))
  495                 return (error);
  496 
  497         if (sgid != (gid_t)-1 &&
  498             sgid != uc->cr_rgid &&
  499             sgid != uc->cr_gid &&
  500             sgid != uc->cr_svgid &&
  501             (error = suser(p)))
  502                 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         newcred = crget();
  509         pruc = pr->ps_ucred;
  510         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         if (rgid != (gid_t)-1)
  517                 newcred->cr_rgid = rgid;
  518         if (egid != (gid_t)-1)
  519                 newcred->cr_gid = egid;
  520         if (sgid != (gid_t)-1)
  521                 newcred->cr_svgid = sgid;
  522         pr->ps_ucred = newcred;
  523         atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
  524         crfree(pruc);
  525         return (0);
  526 }
  527 
  528 int
  529 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         } */ *uap = v;
  535         struct process *pr = p->p_p;
  536         struct ucred *pruc, *newcred, *uc = p->p_ucred;
  537         gid_t rgid, egid;
  538         int error;
  539 
  540         rgid = SCARG(uap, rgid);
  541         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         pruc = pr->ps_ucred;
  555         if ((rgid == (gid_t)-1 || rgid == pruc->cr_rgid) &&
  556             (egid == (gid_t)-1 || egid == pruc->cr_gid) &&
  557             (rgid == (gid_t)-1 || (rgid == pruc->cr_rgid &&
  558             pruc->cr_svgid == (egid != (gid_t)-1 ? egid : pruc->cr_gid))))
  559                 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         if (rgid != (gid_t)-1 &&
  566             rgid != uc->cr_rgid &&
  567             rgid != uc->cr_gid &&
  568             rgid != uc->cr_svgid &&
  569             (error = suser(p)))
  570                 return (error);
  571 
  572         if (egid != (gid_t)-1 &&
  573             egid != uc->cr_rgid &&
  574             egid != uc->cr_gid &&
  575             egid != uc->cr_svgid &&
  576             (error = suser(p)))
  577                 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         newcred = crget();
  584         pruc = pr->ps_ucred;
  585         crset(newcred, pruc);
  586 
  587         if (rgid != (gid_t)-1)
  588                 newcred->cr_rgid = rgid;
  589         if (egid != (gid_t)-1)
  590                 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         if (rgid != (gid_t)-1 && (rgid != pruc->cr_rgid ||
  599             pruc->cr_svgid != (egid != (gid_t)-1 ? egid : pruc->cr_gid)))
  600                 newcred->cr_svgid = rgid;
  601         pr->ps_ucred = newcred;
  602         atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
  603         crfree(pruc);
  604         return (0);
  605 }
  606 
  607 int
  608 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         } */ *uap = v;
  614         struct process *pr = p->p_p;
  615         struct ucred *pruc, *newcred, *uc = p->p_ucred;
  616         uid_t ruid, euid;
  617         int error;
  618 
  619         ruid = SCARG(uap, ruid);
  620         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         pruc = pr->ps_ucred;
  634         if ((ruid == (uid_t)-1 || ruid == pruc->cr_ruid) &&
  635             (euid == (uid_t)-1 || euid == pruc->cr_uid) &&
  636             (ruid == (uid_t)-1 || (ruid == pruc->cr_ruid &&
  637             pruc->cr_svuid == (euid != (uid_t)-1 ? euid : pruc->cr_uid))))
  638                 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         if (ruid != (uid_t)-1 &&
  645             ruid != uc->cr_ruid &&
  646             ruid != uc->cr_uid &&
  647             ruid != uc->cr_svuid &&
  648             (error = suser(p)))
  649                 return (error);
  650 
  651         if (euid != (uid_t)-1 &&
  652             euid != uc->cr_ruid &&
  653             euid != uc->cr_uid &&
  654             euid != uc->cr_svuid &&
  655             (error = suser(p)))
  656                 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         newcred = crget();
  663         pruc = pr->ps_ucred;
  664         crset(newcred, pruc);
  665 
  666         if (ruid != (uid_t)-1)
  667                 newcred->cr_ruid = ruid;
  668         if (euid != (uid_t)-1)
  669                 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         if (ruid != (uid_t)-1 && (ruid != pruc->cr_ruid ||
  678             pruc->cr_svuid != (euid != (uid_t)-1 ? euid : pruc->cr_uid)))
  679                 newcred->cr_svuid = ruid;
  680         pr->ps_ucred = newcred;
  681         atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
  682 
  683         /* now that we can sleep, transfer proc count to new user */
  684         if (ruid != (uid_t)-1 && ruid != pruc->cr_ruid) {
  685                 chgproccnt(pruc->cr_ruid, -1);
  686                 chgproccnt(ruid, 1);
  687         }
  688         crfree(pruc);
  689 
  690         return (0);
  691 }
  692 
  693 int
  694 sys_setuid(struct proc *p, void *v, register_t *retval)
  695 {
  696         struct sys_setuid_args /* {
  697                 syscallarg(uid_t) uid;
  698         } */ *uap = v;
  699         struct process *pr = p->p_p;
  700         struct ucred *pruc, *newcred, *uc = p->p_ucred;
  701         uid_t uid;
  702         int did_real, error;
  703 
  704         uid = SCARG(uap, uid);
  705 
  706         pruc = pr->ps_ucred;
  707         if (pruc->cr_uid == uid &&
  708             pruc->cr_ruid == uid &&
  709             pruc->cr_svuid == uid)
  710                 return (0);
  711 
  712         if (uid != uc->cr_ruid &&
  713             uid != uc->cr_svuid &&
  714             uid != uc->cr_uid &&
  715             (error = suser(p)))
  716                 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         newcred = crget();
  723         pruc = pr->ps_ucred;
  724         crset(newcred, pruc);
  725 
  726         /*
  727          * Everything's okay, do it.
  728          */
  729         if (uid == pruc->cr_uid || suser(p) == 0) {
  730                 did_real = 1;
  731                 newcred->cr_ruid = uid;
  732                 newcred->cr_svuid = uid;
  733         } else
  734                 did_real = 0;
  735         newcred->cr_uid = uid;
  736         pr->ps_ucred = newcred;
  737         atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
  738 
  739         /*
  740          * Transfer proc count to new user.
  741          */
  742         if (did_real && uid != pruc->cr_ruid) {
  743                 chgproccnt(pruc->cr_ruid, -1);
  744                 chgproccnt(uid, 1);
  745         }
  746         crfree(pruc);
  747 
  748         return (0);
  749 }
  750 
  751 int
  752 sys_seteuid(struct proc *p, void *v, register_t *retval)
  753 {
  754         struct sys_seteuid_args /* {
  755                 syscallarg(uid_t) euid;
  756         } */ *uap = v;
  757         struct process *pr = p->p_p;
  758         struct ucred *pruc, *newcred, *uc = p->p_ucred;
  759         uid_t euid;
  760         int error;
  761 
  762         euid = SCARG(uap, euid);
  763 
  764         if (pr->ps_ucred->cr_uid == euid)
  765                 return (0);
  766 
  767         if (euid != uc->cr_ruid && euid != uc->cr_svuid &&
  768             (error = suser(p)))
  769                 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         newcred = crget();
  776         pruc = pr->ps_ucred;
  777         crset(newcred, pruc);
  778         newcred->cr_uid = euid;
  779         pr->ps_ucred = newcred;
  780         atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
  781         crfree(pruc);
  782         return (0);
  783 }
  784 
  785 int
  786 sys_setgid(struct proc *p, void *v, register_t *retval)
  787 {
  788         struct sys_setgid_args /* {
  789                 syscallarg(gid_t) gid;
  790         } */ *uap = v;
  791         struct process *pr = p->p_p;
  792         struct ucred *pruc, *newcred, *uc = p->p_ucred;
  793         gid_t gid;
  794         int error;
  795 
  796         gid = SCARG(uap, gid);
  797 
  798         pruc = pr->ps_ucred;
  799         if (pruc->cr_gid == gid &&
  800             pruc->cr_rgid == gid &&
  801             pruc->cr_svgid == gid)
  802                 return (0);
  803 
  804         if (gid != uc->cr_rgid &&
  805             gid != uc->cr_svgid &&
  806             gid != uc->cr_gid &&
  807             (error = suser(p)))
  808                 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         newcred = crget();
  815         pruc = pr->ps_ucred;
  816         crset(newcred, pruc);
  817 
  818         if (gid == pruc->cr_gid || suser(p) == 0) {
  819                 newcred->cr_rgid = gid;
  820                 newcred->cr_svgid = gid;
  821         }
  822         newcred->cr_gid = gid;
  823         pr->ps_ucred = newcred;
  824         atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
  825         crfree(pruc);
  826         return (0);
  827 }
  828 
  829 int
  830 sys_setegid(struct proc *p, void *v, register_t *retval)
  831 {
  832         struct sys_setegid_args /* {
  833                 syscallarg(gid_t) egid;
  834         } */ *uap = v;
  835         struct process *pr = p->p_p;
  836         struct ucred *pruc, *newcred, *uc = p->p_ucred;
  837         gid_t egid;
  838         int error;
  839 
  840         egid = SCARG(uap, egid);
  841 
  842         if (pr->ps_ucred->cr_gid == egid)
  843                 return (0);
  844 
  845         if (egid != uc->cr_rgid && egid != uc->cr_svgid &&
  846             (error = suser(p)))
  847                 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         newcred = crget();
  854         pruc = pr->ps_ucred;
  855         crset(newcred, pruc);
  856         newcred->cr_gid = egid;
  857         pr->ps_ucred = newcred;
  858         atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
  859         crfree(pruc);
  860         return (0);
  861 }
  862 
  863 int
  864 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         } */ *uap = v;
  870         struct process *pr = p->p_p;
  871         struct ucred *pruc, *newcred;
  872         gid_t groups[NGROUPS_MAX];
  873         int ngrp;
  874         int error;
  875 
  876         if ((error = suser(p)) != 0)
  877                 return (error);
  878         ngrp = SCARG(uap, gidsetsize);
  879         if (ngrp > NGROUPS_MAX || ngrp < 0)
  880                 return (EINVAL);
  881         error = copyin(SCARG(uap, gidset), groups, ngrp * sizeof(gid_t));
  882         if (error == 0) {
  883                 newcred = crget();
  884                 pruc = pr->ps_ucred;
  885                 crset(newcred, pruc);
  886                 memcpy(newcred->cr_groups, groups, ngrp * sizeof(gid_t));
  887                 newcred->cr_ngroups = ngrp;
  888                 pr->ps_ucred = newcred;
  889                 atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
  890                 crfree(pruc);
  891         }
  892         return (error);
  893 }
  894 
  895 /*
  896  * Check if gid is a member of the group set.
  897  */
  898 int
  899 groupmember(gid_t gid, struct ucred *cred)
  900 {
  901         gid_t *gp;
  902         gid_t *egp;
  903 
  904         if (cred->cr_gid == gid)
  905                 return (1);
  906         egp = &(cred->cr_groups[cred->cr_ngroups]);
  907         for (gp = cred->cr_groups; gp < egp; gp++)
  908                 if (*gp == gid)
  909                         return (1);
  910         return (0);
  911 }
  912 
  913 /*
  914  * Test whether this process has special user powers.
  915  * Returns 0 or error.
  916  */
  917 int
  918 suser(struct proc *p)
  919 {
  920         struct ucred *cred = p->p_ucred;
  921 
  922         if (cred->cr_uid == 0)
  923                 return (0);
  924         return (EPERM);
  925 }
  926 
  927 /*
  928  * replacement for old suser, for callers who don't have a process
  929  */
  930 int
  931 suser_ucred(struct ucred *cred)
  932 {
  933         if (cred->cr_uid == 0)
  934                 return (0);
  935         return (EPERM);
  936 }
  937 
  938 /*
  939  * Allocate a zeroed cred structure.
  940  */
  941 struct ucred *
  942 crget(void)
  943 {
  944         struct ucred *cr;
  945 
  946         cr = pool_get(&ucred_pool, PR_WAITOK|PR_ZERO);
  947         refcnt_init(&cr->cr_refcnt);
  948         return (cr);
  949 }
  950 
  951 /*
  952  * Increment the reference count of a cred structure.
  953  * Returns the passed structure.
  954  */
  955 struct ucred *
  956 crhold(struct ucred *cr)
  957 {
  958         refcnt_take(&cr->cr_refcnt);
  959         return (cr);
  960 }
  961 
  962 /*
  963  * Free a cred structure.
  964  * Throws away space when ref count gets to 0.
  965  */
  966 void
  967 crfree(struct ucred *cr)
  968 {
  969         if (refcnt_rele(&cr->cr_refcnt))
  970                 pool_put(&ucred_pool, cr);
  971 }
  972 
  973 /*
  974  * Copy cred structure to a new one and free the old one.
  975  */
  976 struct ucred *
  977 crcopy(struct ucred *cr)
  978 {
  979         struct ucred *newcr;
  980 
  981         if (!refcnt_shared(&cr->cr_refcnt))
  982                 return (cr);
  983         newcr = crget();
  984         *newcr = *cr;
  985         crfree(cr);
  986         refcnt_init(&newcr->cr_refcnt);
  987         return (newcr);
  988 }
  989 
  990 /*
  991  * Dup cred struct to a new held one.
  992  */
  993 struct ucred *
  994 crdup(struct ucred *cr)
  995 {
  996         struct ucred *newcr;
  997 
  998         newcr = crget();
  999         *newcr = *cr;
 1000         refcnt_init(&newcr->cr_refcnt);
 1001         return (newcr);
 1002 }
 1003 
 1004 /*
 1005  * Convert the userspace xucred to a kernel ucred
 1006  */
 1007 int
 1008 crfromxucred(struct ucred *cr, const struct xucred *xcr)
 1009 {
 1010         if (xcr->cr_ngroups < 0 || xcr->cr_ngroups > NGROUPS_MAX)
 1011                 return (EINVAL);
 1012         refcnt_init(&cr->cr_refcnt);
 1013         cr->cr_uid = xcr->cr_uid;
 1014         cr->cr_gid = xcr->cr_gid;
 1015         cr->cr_ngroups = xcr->cr_ngroups;
 1016         memcpy(cr->cr_groups, xcr->cr_groups,
 1017             sizeof(cr->cr_groups[0]) * xcr->cr_ngroups);
 1018         return (0);
 1019 }
 1020 
 1021 /*
 1022  * Get login name, if available.
 1023  */
 1024 int
 1025 sys_getlogin_r(struct proc *p, void *v, register_t *retval)
 1026 {
 1027         struct sys_getlogin_r_args /* {
 1028                 syscallarg(char *) namebuf;
 1029                 syscallarg(size_t) namelen;
 1030         } */ *uap = v;
 1031         size_t namelen = SCARG(uap, namelen);
 1032         struct session *s = p->p_p->ps_pgrp->pg_session;
 1033         int error;
 1034 
 1035         if (namelen > sizeof(s->s_login))
 1036                 namelen = sizeof(s->s_login);
 1037         error = copyoutstr(s->s_login, SCARG(uap, namebuf), namelen, NULL);
 1038         if (error == ENAMETOOLONG)
 1039                 error = ERANGE;
 1040         *retval = error;
 1041         return (0);
 1042 }
 1043 
 1044 /*
 1045  * Set login name.
 1046  */
 1047 int
 1048 sys_setlogin(struct proc *p, void *v, register_t *retval)
 1049 {
 1050         struct sys_setlogin_args /* {
 1051                 syscallarg(const char *) namebuf;
 1052         } */ *uap = v;
 1053         struct session *s = p->p_p->ps_pgrp->pg_session;
 1054         char buf[sizeof(s->s_login)];
 1055         int error;
 1056 
 1057         if ((error = suser(p)) != 0)
 1058                 return (error);
 1059         error = copyinstr(SCARG(uap, namebuf), buf, sizeof(buf), NULL);
 1060         if (error == 0)
 1061                 strlcpy(s->s_login, buf, sizeof(s->s_login));
 1062         else if (error == ENAMETOOLONG)
 1063                 error = EINVAL;
 1064         return (error);
 1065 }
 1066 
 1067 /*
 1068  * Check if a process is allowed to raise its privileges.
 1069  */
 1070 int
 1071 proc_cansugid(struct proc *p)
 1072 {
 1073         /* ptrace(2)d processes shouldn't. */
 1074         if ((p->p_p->ps_flags & PS_TRACED) != 0)
 1075                 return (0);
 1076 
 1077         /* processes with shared filedescriptors shouldn't. */
 1078         if (p->p_fd->fd_refcnt > 1)
 1079                 return (0);
 1080 
 1081         /* Allow. */
 1082         return (1);
 1083 }
 1084 
 1085 /*
 1086  * Set address of the proc's thread-control-block
 1087  */
 1088 int
 1089 sys___set_tcb(struct proc *p, void *v, register_t *retval)
 1090 {
 1091         struct sys___set_tcb_args /* {
 1092                 syscallarg(void *) tcb;
 1093         } */ *uap = v;
 1094         void *tcb = SCARG(uap, tcb);
 1095 
 1096 #ifdef TCB_INVALID
 1097         if (TCB_INVALID(tcb))
 1098                 return EINVAL;
 1099 #endif /* TCB_INVALID */
 1100         TCB_SET(p, tcb);
 1101         return (0);
 1102 }
 1103 
 1104 /*
 1105  * Get address of the proc's thread-control-block
 1106  */
 1107 int
 1108 sys___get_tcb(struct proc *p, void *v, register_t *retval)
 1109 {
 1110         *retval = (register_t)TCB_GET(p);
 1111         return (0);
 1112 }
 1113 
 1114 int
 1115 sys_getthrname(struct proc *curp, void *v, register_t *retval)
 1116 {
 1117         struct sys_getthrname_args /* {
 1118                 syscallarg(pid_t) tid;
 1119                 syscallarg(char *) name;
 1120                 syscallarg(size_t) len;
 1121         } */ *uap = v;
 1122         struct proc *p;
 1123         size_t len;
 1124         int tid = SCARG(uap, tid);
 1125         int error;
 1126 
 1127         p = tid ? tfind_user(tid, curp->p_p) : curp;
 1128         if (p == NULL)
 1129                 return ESRCH;
 1130 
 1131         len = SCARG(uap, len);
 1132         if (len > sizeof(p->p_name))
 1133                 len = sizeof(p->p_name);
 1134         error = copyoutstr(p->p_name, SCARG(uap, name), len, NULL);
 1135         if (error == ENAMETOOLONG)
 1136                 error = ERANGE;
 1137         *retval = error;
 1138         return 0;
 1139 }
 1140 
 1141 int
 1142 sys_setthrname(struct proc *curp, void *v, register_t *retval)
 1143 {
 1144         struct sys_setthrname_args /* {
 1145                 syscallarg(pid_t) tid;
 1146                 syscallarg(const char *) name;
 1147         } */ *uap = v;
 1148         struct proc *p;
 1149         char buf[sizeof p->p_name];
 1150         int tid = SCARG(uap, tid);
 1151         int error;
 1152 
 1153         p = tid ? tfind_user(tid, curp->p_p) : curp;
 1154         if (p == NULL)
 1155                 return ESRCH;
 1156 
 1157         error = copyinstr(SCARG(uap, name), buf, sizeof buf, NULL);
 1158         if (error == 0)
 1159                 strlcpy(p->p_name, buf, sizeof(p->p_name));
 1160         else if (error == ENAMETOOLONG)
 1161                 error = EINVAL;
 1162         *retval = error;
 1163         return 0;
 1164 }
 1165 
 1166 /*
 1167  * Refresh the thread's reference to the process's credentials
 1168  */
 1169 void
 1170 dorefreshcreds(struct process *pr, struct proc *p)
 1171 {
 1172         struct ucred *uc = p->p_ucred;
 1173 
 1174         KERNEL_LOCK();          /* XXX should be PROCESS_RLOCK(pr) */
 1175         if (uc != pr->ps_ucred) {
 1176                 p->p_ucred = pr->ps_ucred;
 1177                 crhold(p->p_ucred);
 1178                 crfree(uc);
 1179         }
 1180         KERNEL_UNLOCK();
 1181 }

Cache object: a2e23748031df94234ebdb28bd52b61b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.