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 /*
    2  * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  * (c) UNIX System Laboratories, Inc.
    5  * All or some portions of this file are derived from material licensed
    6  * to the University of California by American Telephone and Telegraph
    7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
    8  * the permission of UNIX System Laboratories, Inc.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. Neither the name of the University nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  *
   34  *      @(#)kern_prot.c 8.6 (Berkeley) 1/21/94
   35  * $FreeBSD: src/sys/kern/kern_prot.c,v 1.53.2.9 2002/03/09 05:20:26 dd Exp $
   36  */
   37 
   38 /*
   39  * System calls related to processes and protection
   40  */
   41 
   42 #include "opt_compat.h"
   43 
   44 #include <sys/param.h>
   45 #include <sys/acct.h>
   46 #include <sys/systm.h>
   47 #include <sys/sysproto.h>
   48 #include <sys/kernel.h>
   49 #include <sys/lock.h>
   50 #include <sys/proc.h>
   51 #include <sys/priv.h>
   52 #include <sys/malloc.h>
   53 #include <sys/pioctl.h>
   54 #include <sys/resourcevar.h>
   55 #include <sys/jail.h>
   56 #include <sys/lockf.h>
   57 #include <sys/spinlock.h>
   58 
   59 #include <sys/thread2.h>
   60 #include <sys/spinlock2.h>
   61 
   62 static MALLOC_DEFINE(M_CRED, "cred", "credentials");
   63 
   64 int
   65 sys_getpid(struct getpid_args *uap)
   66 {
   67         struct proc *p = curproc;
   68 
   69         uap->sysmsg_fds[0] = p->p_pid;
   70 #if defined(COMPAT_43)
   71         lwkt_gettoken_shared(&p->p_token);
   72         uap->sysmsg_fds[1] = p->p_pptr->p_pid;
   73         lwkt_reltoken(&p->p_token);
   74 #endif
   75         return (0);
   76 }
   77 
   78 int
   79 sys_getppid(struct getppid_args *uap)
   80 {
   81         struct proc *p = curproc;
   82 
   83         lwkt_gettoken_shared(&p->p_token);
   84         uap->sysmsg_result = p->p_pptr->p_pid;
   85         lwkt_reltoken(&p->p_token);
   86 
   87         return (0);
   88 }
   89 
   90 int
   91 sys_lwp_gettid(struct lwp_gettid_args *uap)
   92 {
   93         struct lwp *lp = curthread->td_lwp;
   94         uap->sysmsg_result = lp->lwp_tid;
   95         return (0);
   96 }
   97 
   98 /* 
   99  * Get process group ID; note that POSIX getpgrp takes no parameter 
  100  */
  101 int
  102 sys_getpgrp(struct getpgrp_args *uap)
  103 {
  104         struct proc *p = curproc;
  105 
  106         lwkt_gettoken_shared(&p->p_token);
  107         uap->sysmsg_result = p->p_pgrp->pg_id;
  108         lwkt_reltoken(&p->p_token);
  109 
  110         return (0);
  111 }
  112 
  113 /*
  114  * Get an arbitrary pid's process group id 
  115  */
  116 int
  117 sys_getpgid(struct getpgid_args *uap)
  118 {
  119         struct proc *p = curproc;
  120         struct proc *pt;
  121         int error;
  122 
  123         error = 0;
  124 
  125         if (uap->pid == 0) {
  126                 pt = p;
  127                 PHOLD(pt);
  128         } else {
  129                 pt = pfind(uap->pid);
  130                 if (pt == NULL)
  131                         error = ESRCH;
  132         }
  133         if (error == 0) {
  134                 lwkt_gettoken_shared(&pt->p_token);
  135                 uap->sysmsg_result = pt->p_pgrp->pg_id;
  136                 lwkt_reltoken(&pt->p_token);
  137         }
  138         if (pt)
  139                 PRELE(pt);
  140         return (error);
  141 }
  142 
  143 /*
  144  * Get an arbitrary pid's session id.
  145  */
  146 int
  147 sys_getsid(struct getsid_args *uap)
  148 {
  149         struct proc *p = curproc;
  150         struct proc *pt;
  151         int error;
  152 
  153         error = 0;
  154 
  155         if (uap->pid == 0) {
  156                 pt = p;
  157                 PHOLD(pt);
  158         } else {
  159                 pt = pfind(uap->pid);
  160                 if (pt == NULL)
  161                         error = ESRCH;
  162         }
  163         if (error == 0)
  164                 uap->sysmsg_result = pt->p_session->s_sid;
  165         if (pt)
  166                 PRELE(pt);
  167         return (error);
  168 }
  169 
  170 
  171 /*
  172  * getuid()
  173  */
  174 int
  175 sys_getuid(struct getuid_args *uap)
  176 {
  177         struct ucred *cred = curthread->td_ucred;
  178 
  179         uap->sysmsg_fds[0] = cred->cr_ruid;
  180 #if defined(COMPAT_43)
  181         uap->sysmsg_fds[1] = cred->cr_uid;
  182 #endif
  183         return (0);
  184 }
  185 
  186 /*
  187  * geteuid()
  188  */
  189 int
  190 sys_geteuid(struct geteuid_args *uap)
  191 {
  192         struct ucred *cred = curthread->td_ucred;
  193 
  194         uap->sysmsg_result = cred->cr_uid;
  195         return (0);
  196 }
  197 
  198 /*
  199  * getgid()
  200  */
  201 int
  202 sys_getgid(struct getgid_args *uap)
  203 {
  204         struct ucred *cred = curthread->td_ucred;
  205 
  206         uap->sysmsg_fds[0] = cred->cr_rgid;
  207 #if defined(COMPAT_43)
  208         uap->sysmsg_fds[1] = cred->cr_groups[0];
  209 #endif
  210         return (0);
  211 }
  212 
  213 /*
  214  * Get effective group ID.  The "egid" is groups[0], and could be obtained
  215  * via getgroups.  This syscall exists because it is somewhat painful to do
  216  * correctly in a library function.
  217  */
  218 int
  219 sys_getegid(struct getegid_args *uap)
  220 {
  221         struct ucred *cred = curthread->td_ucred;
  222 
  223         uap->sysmsg_result = cred->cr_groups[0];
  224         return (0);
  225 }
  226 
  227 int
  228 sys_getgroups(struct getgroups_args *uap)
  229 {
  230         struct ucred *cr;
  231         u_int ngrp;
  232         int error;
  233 
  234         cr = curthread->td_ucred;
  235         if ((ngrp = uap->gidsetsize) == 0) {
  236                 uap->sysmsg_result = cr->cr_ngroups;
  237                 return (0);
  238         }
  239         if (ngrp < cr->cr_ngroups)
  240                 return (EINVAL);
  241         ngrp = cr->cr_ngroups;
  242         error = copyout((caddr_t)cr->cr_groups,
  243                         (caddr_t)uap->gidset, ngrp * sizeof(gid_t));
  244         if (error == 0)
  245                 uap->sysmsg_result = ngrp;
  246         return (error);
  247 }
  248 
  249 int
  250 sys_setsid(struct setsid_args *uap)
  251 {
  252         struct proc *p = curproc;
  253         struct pgrp *pg = NULL;
  254         int error;
  255 
  256         lwkt_gettoken(&p->p_token);
  257         if (p->p_pgid == p->p_pid || (pg = pgfind(p->p_pid)) != NULL) {
  258                 error = EPERM;
  259                 if (pg)
  260                         pgrel(pg);
  261         } else {
  262                 enterpgrp(p, p->p_pid, 1);
  263                 uap->sysmsg_result = p->p_pid;
  264                 error = 0;
  265         }
  266         lwkt_reltoken(&p->p_token);
  267         return (error);
  268 }
  269 
  270 /*
  271  * set process group (setpgid/old setpgrp)
  272  *
  273  * caller does setpgid(targpid, targpgid)
  274  *
  275  * pid must be caller or child of caller (ESRCH)
  276  * if a child
  277  *      pid must be in same session (EPERM)
  278  *      pid can't have done an exec (EACCES)
  279  * if pgid != pid
  280  *      there must exist some pid in same session having pgid (EPERM)
  281  * pid must not be session leader (EPERM)
  282  */
  283 int
  284 sys_setpgid(struct setpgid_args *uap)
  285 {
  286         struct proc *curp = curproc;
  287         struct proc *targp;             /* target process */
  288         struct pgrp *pgrp = NULL;       /* target pgrp */
  289         int error;
  290 
  291         if (uap->pgid < 0)
  292                 return (EINVAL);
  293 
  294         if (uap->pid != 0 && uap->pid != curp->p_pid) {
  295                 if ((targp = pfind(uap->pid)) == NULL || !inferior(targp)) {
  296                         if (targp)
  297                                 PRELE(targp);
  298                         error = ESRCH;
  299                         targp = NULL;
  300                         goto done;
  301                 }
  302                 lwkt_gettoken(&targp->p_token);
  303                 /* targp now referenced and its token is held */
  304 
  305                 if (targp->p_pgrp == NULL ||
  306                     targp->p_session != curp->p_session) {
  307                         error = EPERM;
  308                         goto done;
  309                 }
  310                 if (targp->p_flags & P_EXEC) {
  311                         error = EACCES;
  312                         goto done;
  313                 }
  314         } else {
  315                 targp = curp;
  316                 PHOLD(targp);
  317                 lwkt_gettoken(&targp->p_token);
  318         }
  319         if (SESS_LEADER(targp)) {
  320                 error = EPERM;
  321                 goto done;
  322         }
  323         if (uap->pgid == 0) {
  324                 uap->pgid = targp->p_pid;
  325         } else if (uap->pgid != targp->p_pid) {
  326                 if ((pgrp = pgfind(uap->pgid)) == NULL ||
  327                     pgrp->pg_session != curp->p_session) {
  328                         error = EPERM;
  329                         goto done;
  330                 }
  331         }
  332         error = enterpgrp(targp, uap->pgid, 0);
  333 done:
  334         if (pgrp)
  335                 pgrel(pgrp);
  336         if (targp) {
  337                 lwkt_reltoken(&targp->p_token);
  338                 PRELE(targp);
  339         }
  340         return (error);
  341 }
  342 
  343 /*
  344  * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
  345  * compatible.  It says that setting the uid/gid to euid/egid is a special
  346  * case of "appropriate privilege".  Once the rules are expanded out, this
  347  * basically means that setuid(nnn) sets all three id's, in all permitted
  348  * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
  349  * does not set the saved id - this is dangerous for traditional BSD
  350  * programs.  For this reason, we *really* do not want to set
  351  * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
  352  */
  353 #define POSIX_APPENDIX_B_4_2_2
  354 
  355 int
  356 sys_setuid(struct setuid_args *uap)
  357 {
  358         struct proc *p = curproc;
  359         struct ucred *cr;
  360         uid_t uid;
  361         int error;
  362 
  363         lwkt_gettoken(&p->p_token);
  364         cr = p->p_ucred;
  365 
  366         /*
  367          * See if we have "permission" by POSIX 1003.1 rules.
  368          *
  369          * Note that setuid(geteuid()) is a special case of 
  370          * "appropriate privileges" in appendix B.4.2.2.  We need
  371          * to use this clause to be compatible with traditional BSD
  372          * semantics.  Basically, it means that "setuid(xx)" sets all
  373          * three id's (assuming you have privs).
  374          *
  375          * Notes on the logic.  We do things in three steps.
  376          * 1: We determine if the euid is going to change, and do EPERM
  377          *    right away.  We unconditionally change the euid later if this
  378          *    test is satisfied, simplifying that part of the logic.
  379          * 2: We determine if the real and/or saved uid's are going to
  380          *    change.  Determined by compile options.
  381          * 3: Change euid last. (after tests in #2 for "appropriate privs")
  382          */
  383         uid = uap->uid;
  384         if (uid != cr->cr_ruid &&               /* allow setuid(getuid()) */
  385 #ifdef _POSIX_SAVED_IDS
  386             uid != crc->cr_svuid &&             /* allow setuid(saved gid) */
  387 #endif
  388 #ifdef POSIX_APPENDIX_B_4_2_2   /* Use BSD-compat clause from B.4.2.2 */
  389             uid != cr->cr_uid &&        /* allow setuid(geteuid()) */
  390 #endif
  391             (error = priv_check_cred(cr, PRIV_CRED_SETUID, 0)))
  392                 goto done;
  393 
  394 #ifdef _POSIX_SAVED_IDS
  395         /*
  396          * Do we have "appropriate privileges" (are we root or uid == euid)
  397          * If so, we are changing the real uid and/or saved uid.
  398          */
  399         if (
  400 #ifdef POSIX_APPENDIX_B_4_2_2   /* Use the clause from B.4.2.2 */
  401             uid == cr->cr_uid ||
  402 #endif
  403             priv_check_cred(cr, PRIV_CRED_SETUID, 0) == 0) /* we are using privs */
  404 #endif
  405         {
  406                 /*
  407                  * Set the real uid and transfer proc count to new user.
  408                  */
  409                 if (uid != cr->cr_ruid) {
  410                         cr = change_ruid(uid);
  411                         setsugid();
  412                 }
  413                 /*
  414                  * Set saved uid
  415                  *
  416                  * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
  417                  * the security of seteuid() depends on it.  B.4.2.2 says it
  418                  * is important that we should do this.
  419                  */
  420                 if (cr->cr_svuid != uid) {
  421                         cr = cratom(&p->p_ucred);
  422                         cr->cr_svuid = uid;
  423                         setsugid();
  424                 }
  425         }
  426 
  427         /*
  428          * In all permitted cases, we are changing the euid.
  429          * Copy credentials so other references do not see our changes.
  430          */
  431         if (cr->cr_uid != uid) {
  432                 change_euid(uid);
  433                 setsugid();
  434         }
  435         error = 0;
  436 done:
  437         lwkt_reltoken(&p->p_token);
  438         return (error);
  439 }
  440 
  441 int
  442 sys_seteuid(struct seteuid_args *uap)
  443 {
  444         struct proc *p = curproc;
  445         struct ucred *cr;
  446         uid_t euid;
  447         int error;
  448 
  449         lwkt_gettoken(&p->p_token);
  450         cr = p->p_ucred;
  451         euid = uap->euid;
  452         if (euid != cr->cr_ruid &&              /* allow seteuid(getuid()) */
  453             euid != cr->cr_svuid &&             /* allow seteuid(saved uid) */
  454             (error = priv_check_cred(cr, PRIV_CRED_SETEUID, 0))) {
  455                 lwkt_reltoken(&p->p_token);
  456                 return (error);
  457         }
  458 
  459         /*
  460          * Everything's okay, do it.  Copy credentials so other references do
  461          * not see our changes.
  462          */
  463         if (cr->cr_uid != euid) {
  464                 change_euid(euid);
  465                 setsugid();
  466         }
  467         lwkt_reltoken(&p->p_token);
  468         return (0);
  469 }
  470 
  471 int
  472 sys_setgid(struct setgid_args *uap)
  473 {
  474         struct proc *p = curproc;
  475         struct ucred *cr;
  476         gid_t gid;
  477         int error;
  478 
  479         lwkt_gettoken(&p->p_token);
  480         cr = p->p_ucred;
  481 
  482         /*
  483          * See if we have "permission" by POSIX 1003.1 rules.
  484          *
  485          * Note that setgid(getegid()) is a special case of
  486          * "appropriate privileges" in appendix B.4.2.2.  We need
  487          * to use this clause to be compatible with traditional BSD
  488          * semantics.  Basically, it means that "setgid(xx)" sets all
  489          * three id's (assuming you have privs).
  490          *
  491          * For notes on the logic here, see setuid() above.
  492          */
  493         gid = uap->gid;
  494         if (gid != cr->cr_rgid &&               /* allow setgid(getgid()) */
  495 #ifdef _POSIX_SAVED_IDS
  496             gid != cr->cr_svgid &&              /* allow setgid(saved gid) */
  497 #endif
  498 #ifdef POSIX_APPENDIX_B_4_2_2   /* Use BSD-compat clause from B.4.2.2 */
  499             gid != cr->cr_groups[0] && /* allow setgid(getegid()) */
  500 #endif
  501             (error = priv_check_cred(cr, PRIV_CRED_SETGID, 0))) {
  502                 goto done;
  503         }
  504 
  505 #ifdef _POSIX_SAVED_IDS
  506         /*
  507          * Do we have "appropriate privileges" (are we root or gid == egid)
  508          * If so, we are changing the real uid and saved gid.
  509          */
  510         if (
  511 #ifdef POSIX_APPENDIX_B_4_2_2   /* use the clause from B.4.2.2 */
  512             gid == cr->cr_groups[0] ||
  513 #endif
  514             priv_check_cred(cr, PRIV_CRED_SETGID, 0) == 0) /* we are using privs */
  515 #endif
  516         {
  517                 /*
  518                  * Set real gid
  519                  */
  520                 if (cr->cr_rgid != gid) {
  521                         cr = cratom(&p->p_ucred);
  522                         cr->cr_rgid = gid;
  523                         setsugid();
  524                 }
  525                 /*
  526                  * Set saved gid
  527                  *
  528                  * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
  529                  * the security of setegid() depends on it.  B.4.2.2 says it
  530                  * is important that we should do this.
  531                  */
  532                 if (cr->cr_svgid != gid) {
  533                         cr = cratom(&p->p_ucred);
  534                         cr->cr_svgid = gid;
  535                         setsugid();
  536                 }
  537         }
  538         /*
  539          * In all cases permitted cases, we are changing the egid.
  540          * Copy credentials so other references do not see our changes.
  541          */
  542         if (cr->cr_groups[0] != gid) {
  543                 cr = cratom(&p->p_ucred);
  544                 cr->cr_groups[0] = gid;
  545                 setsugid();
  546         }
  547         error = 0;
  548 done:
  549         lwkt_reltoken(&p->p_token);
  550         return (error);
  551 }
  552 
  553 int
  554 sys_setegid(struct setegid_args *uap)
  555 {
  556         struct proc *p = curproc;
  557         struct ucred *cr;
  558         gid_t egid;
  559         int error;
  560 
  561         lwkt_gettoken(&p->p_token);
  562         cr = p->p_ucred;
  563         egid = uap->egid;
  564         if (egid != cr->cr_rgid &&              /* allow setegid(getgid()) */
  565             egid != cr->cr_svgid &&             /* allow setegid(saved gid) */
  566             (error = priv_check_cred(cr, PRIV_CRED_SETEGID, 0))) {
  567                 goto done;
  568         }
  569         if (cr->cr_groups[0] != egid) {
  570                 cr = cratom(&p->p_ucred);
  571                 cr->cr_groups[0] = egid;
  572                 setsugid();
  573         }
  574         error = 0;
  575 done:
  576         lwkt_reltoken(&p->p_token);
  577         return (error);
  578 }
  579 
  580 int
  581 sys_setgroups(struct setgroups_args *uap)
  582 {
  583         struct proc *p = curproc;
  584         struct ucred *cr;
  585         u_int ngrp;
  586         int error;
  587 
  588         lwkt_gettoken(&p->p_token);
  589         cr = p->p_ucred;
  590 
  591         if ((error = priv_check_cred(cr, PRIV_CRED_SETGROUPS, 0)))
  592                 goto done;
  593         ngrp = uap->gidsetsize;
  594         if (ngrp > NGROUPS) {
  595                 error = EINVAL;
  596                 goto done;
  597         }
  598         /*
  599          * XXX A little bit lazy here.  We could test if anything has
  600          * changed before cratom() and setting P_SUGID.
  601          */
  602         cr = cratom(&p->p_ucred);
  603         if (ngrp < 1) {
  604                 /*
  605                  * setgroups(0, NULL) is a legitimate way of clearing the
  606                  * groups vector on non-BSD systems (which generally do not
  607                  * have the egid in the groups[0]).  We risk security holes
  608                  * when running non-BSD software if we do not do the same.
  609                  */
  610                 cr->cr_ngroups = 1;
  611         } else {
  612                 error = copyin(uap->gidset, cr->cr_groups,
  613                                ngrp * sizeof(gid_t));
  614                 if (error)
  615                         goto done;
  616                 cr->cr_ngroups = ngrp;
  617         }
  618         setsugid();
  619         error = 0;
  620 done:
  621         lwkt_reltoken(&p->p_token);
  622         return (error);
  623 }
  624 
  625 int
  626 sys_setreuid(struct setreuid_args *uap)
  627 {
  628         struct proc *p = curproc;
  629         struct ucred *cr;
  630         uid_t ruid, euid;
  631         int error;
  632 
  633         lwkt_gettoken(&p->p_token);
  634         cr = p->p_ucred;
  635 
  636         ruid = uap->ruid;
  637         euid = uap->euid;
  638         if (((ruid != (uid_t)-1 && ruid != cr->cr_ruid && ruid != cr->cr_svuid) ||
  639              (euid != (uid_t)-1 && euid != cr->cr_uid &&
  640              euid != cr->cr_ruid && euid != cr->cr_svuid)) &&
  641             (error = priv_check_cred(cr, PRIV_CRED_SETREUID, 0)) != 0) {
  642                 goto done;
  643         }
  644 
  645         if (euid != (uid_t)-1 && cr->cr_uid != euid) {
  646                 cr = change_euid(euid);
  647                 setsugid();
  648         }
  649         if (ruid != (uid_t)-1 && cr->cr_ruid != ruid) {
  650                 cr = change_ruid(ruid);
  651                 setsugid();
  652         }
  653         if ((ruid != (uid_t)-1 || cr->cr_uid != cr->cr_ruid) &&
  654             cr->cr_svuid != cr->cr_uid) {
  655                 cr = cratom(&p->p_ucred);
  656                 cr->cr_svuid = cr->cr_uid;
  657                 setsugid();
  658         }
  659         error = 0;
  660 done:
  661         lwkt_reltoken(&p->p_token);
  662         return (error);
  663 }
  664 
  665 int
  666 sys_setregid(struct setregid_args *uap)
  667 {
  668         struct proc *p = curproc;
  669         struct ucred *cr;
  670         gid_t rgid, egid;
  671         int error;
  672 
  673         lwkt_gettoken(&p->p_token);
  674         cr = p->p_ucred;
  675 
  676         rgid = uap->rgid;
  677         egid = uap->egid;
  678         if (((rgid != (gid_t)-1 && rgid != cr->cr_rgid && rgid != cr->cr_svgid) ||
  679              (egid != (gid_t)-1 && egid != cr->cr_groups[0] &&
  680              egid != cr->cr_rgid && egid != cr->cr_svgid)) &&
  681             (error = priv_check_cred(cr, PRIV_CRED_SETREGID, 0)) != 0) {
  682                 goto done;
  683         }
  684 
  685         if (egid != (gid_t)-1 && cr->cr_groups[0] != egid) {
  686                 cr = cratom(&p->p_ucred);
  687                 cr->cr_groups[0] = egid;
  688                 setsugid();
  689         }
  690         if (rgid != (gid_t)-1 && cr->cr_rgid != rgid) {
  691                 cr = cratom(&p->p_ucred);
  692                 cr->cr_rgid = rgid;
  693                 setsugid();
  694         }
  695         if ((rgid != (gid_t)-1 || cr->cr_groups[0] != cr->cr_rgid) &&
  696             cr->cr_svgid != cr->cr_groups[0]) {
  697                 cr = cratom(&p->p_ucred);
  698                 cr->cr_svgid = cr->cr_groups[0];
  699                 setsugid();
  700         }
  701         error = 0;
  702 done:
  703         lwkt_reltoken(&p->p_token);
  704         return (error);
  705 }
  706 
  707 /*
  708  * setresuid(ruid, euid, suid) is like setreuid except control over the
  709  * saved uid is explicit.
  710  */
  711 int
  712 sys_setresuid(struct setresuid_args *uap)
  713 {
  714         struct proc *p = curproc;
  715         struct ucred *cr;
  716         uid_t ruid, euid, suid;
  717         int error;
  718 
  719         lwkt_gettoken(&p->p_token);
  720         cr = p->p_ucred;
  721 
  722         ruid = uap->ruid;
  723         euid = uap->euid;
  724         suid = uap->suid;
  725         if (((ruid != (uid_t)-1 && ruid != cr->cr_ruid && ruid != cr->cr_svuid &&
  726               ruid != cr->cr_uid) ||
  727              (euid != (uid_t)-1 && euid != cr->cr_ruid && euid != cr->cr_svuid &&
  728               euid != cr->cr_uid) ||
  729              (suid != (uid_t)-1 && suid != cr->cr_ruid && suid != cr->cr_svuid &&
  730               suid != cr->cr_uid)) &&
  731             (error = priv_check_cred(cr, PRIV_CRED_SETRESUID, 0)) != 0) {
  732                 goto done;
  733         }
  734         if (euid != (uid_t)-1 && cr->cr_uid != euid) {
  735                 cr = change_euid(euid);
  736                 setsugid();
  737         }
  738         if (ruid != (uid_t)-1 && cr->cr_ruid != ruid) {
  739                 cr = change_ruid(ruid);
  740                 setsugid();
  741         }
  742         if (suid != (uid_t)-1 && cr->cr_svuid != suid) {
  743                 cr = cratom(&p->p_ucred);
  744                 cr->cr_svuid = suid;
  745                 setsugid();
  746         }
  747         error = 0;
  748 done:
  749         lwkt_reltoken(&p->p_token);
  750         return (error);
  751 }
  752 
  753 /*
  754  * setresgid(rgid, egid, sgid) is like setregid except control over the
  755  * saved gid is explicit.
  756  */
  757 int
  758 sys_setresgid(struct setresgid_args *uap)
  759 {
  760         struct proc *p = curproc;
  761         struct ucred *cr;
  762         gid_t rgid, egid, sgid;
  763         int error;
  764 
  765         lwkt_gettoken(&p->p_token);
  766         cr = p->p_ucred;
  767         rgid = uap->rgid;
  768         egid = uap->egid;
  769         sgid = uap->sgid;
  770         if (((rgid != (gid_t)-1 && rgid != cr->cr_rgid && rgid != cr->cr_svgid &&
  771               rgid != cr->cr_groups[0]) ||
  772              (egid != (gid_t)-1 && egid != cr->cr_rgid && egid != cr->cr_svgid &&
  773               egid != cr->cr_groups[0]) ||
  774              (sgid != (gid_t)-1 && sgid != cr->cr_rgid && sgid != cr->cr_svgid &&
  775               sgid != cr->cr_groups[0])) &&
  776             (error = priv_check_cred(cr, PRIV_CRED_SETRESGID, 0)) != 0) {
  777                 goto done;
  778         }
  779 
  780         if (egid != (gid_t)-1 && cr->cr_groups[0] != egid) {
  781                 cr = cratom(&p->p_ucred);
  782                 cr->cr_groups[0] = egid;
  783                 setsugid();
  784         }
  785         if (rgid != (gid_t)-1 && cr->cr_rgid != rgid) {
  786                 cr = cratom(&p->p_ucred);
  787                 cr->cr_rgid = rgid;
  788                 setsugid();
  789         }
  790         if (sgid != (gid_t)-1 && cr->cr_svgid != sgid) {
  791                 cr = cratom(&p->p_ucred);
  792                 cr->cr_svgid = sgid;
  793                 setsugid();
  794         }
  795         error = 0;
  796 done:
  797         lwkt_reltoken(&p->p_token);
  798         return (error);
  799 }
  800 
  801 int
  802 sys_getresuid(struct getresuid_args *uap)
  803 {
  804         struct ucred *cr;
  805         int error1 = 0, error2 = 0, error3 = 0;
  806 
  807         /*
  808          * copyout's can fault synchronously so we cannot use a shared
  809          * token here.
  810          */
  811         cr = curthread->td_ucred;
  812         if (uap->ruid)
  813                 error1 = copyout((caddr_t)&cr->cr_ruid,
  814                     (caddr_t)uap->ruid, sizeof(cr->cr_ruid));
  815         if (uap->euid)
  816                 error2 = copyout((caddr_t)&cr->cr_uid,
  817                     (caddr_t)uap->euid, sizeof(cr->cr_uid));
  818         if (uap->suid)
  819                 error3 = copyout((caddr_t)&cr->cr_svuid,
  820                     (caddr_t)uap->suid, sizeof(cr->cr_svuid));
  821         return error1 ? error1 : (error2 ? error2 : error3);
  822 }
  823 
  824 int
  825 sys_getresgid(struct getresgid_args *uap)
  826 {
  827         struct ucred *cr;
  828         int error1 = 0, error2 = 0, error3 = 0;
  829 
  830         cr = curthread->td_ucred;
  831         if (uap->rgid)
  832                 error1 = copyout(&cr->cr_rgid, uap->rgid,
  833                                  sizeof(cr->cr_rgid));
  834         if (uap->egid)
  835                 error2 = copyout(&cr->cr_groups[0], uap->egid,
  836                                  sizeof(cr->cr_groups[0]));
  837         if (uap->sgid)
  838                 error3 = copyout(&cr->cr_svgid, uap->sgid,
  839                                  sizeof(cr->cr_svgid));
  840         return error1 ? error1 : (error2 ? error2 : error3);
  841 }
  842 
  843 
  844 /*
  845  * NOTE: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
  846  * we use P_SUGID because we consider changing the owners as
  847  * "tainting" as well.
  848  * This is significant for procs that start as root and "become"
  849  * a user without an exec - programs cannot know *everything*
  850  * that libc *might* have put in their data segment.
  851  */
  852 int
  853 sys_issetugid(struct issetugid_args *uap)
  854 {
  855         uap->sysmsg_result = (curproc->p_flags & P_SUGID) ? 1 : 0;
  856         return (0);
  857 }
  858 
  859 /*
  860  * Check if gid is a member of the group set.
  861  */
  862 int
  863 groupmember(gid_t gid, struct ucred *cred)
  864 {
  865         gid_t *gp;
  866         gid_t *egp;
  867 
  868         egp = &(cred->cr_groups[cred->cr_ngroups]);
  869         for (gp = cred->cr_groups; gp < egp; gp++) {
  870                 if (*gp == gid)
  871                         return (1);
  872         }
  873         return (0);
  874 }
  875 
  876 /*
  877  * Test whether the specified credentials have the privilege
  878  * in question.
  879  *
  880  * A kernel thread without a process context is assumed to have 
  881  * the privilege in question.  In situations where the caller always 
  882  * expect a cred to exist, the cred should be passed separately and 
  883  * priv_check_cred() should be used instead of priv_check().
  884  *
  885  * Returns 0 or error.
  886  */
  887 int
  888 priv_check(struct thread *td, int priv)
  889 {
  890         if (td->td_lwp != NULL)
  891                 return priv_check_cred(td->td_ucred, priv, 0);
  892         return (0);
  893 }
  894 
  895 /*
  896  * Check a credential for privilege.
  897  *
  898  * A non-null credential is expected unless NULL_CRED_OKAY is set.
  899  */
  900 int
  901 priv_check_cred(struct ucred *cred, int priv, int flags)
  902 {
  903         int error;
  904 
  905         KASSERT(PRIV_VALID(priv), ("priv_check_cred: invalid privilege"));
  906 
  907         KASSERT(cred != NULL || (flags & NULL_CRED_OKAY),
  908                 ("priv_check_cred: NULL cred!"));
  909 
  910         if (cred == NULL) {
  911                 if (flags & NULL_CRED_OKAY)
  912                         return (0);
  913                 else
  914                         return (EPERM);
  915         }
  916         if (cred->cr_uid != 0) 
  917                 return (EPERM);
  918 
  919         error = prison_priv_check(cred, priv);
  920         if (error)
  921                 return (error);
  922 
  923         /* NOTE: accounting for suser access (p_acflag/ASU) removed */
  924         return (0);
  925 }
  926 
  927 /*
  928  * Return zero if p1 can fondle p2, return errno (EPERM/ESRCH) otherwise.
  929  */
  930 int
  931 p_trespass(struct ucred *cr1, struct ucred *cr2)
  932 {
  933         if (cr1 == cr2)
  934                 return (0);
  935         if (!PRISON_CHECK(cr1, cr2))
  936                 return (ESRCH);
  937         if (cr1->cr_ruid == cr2->cr_ruid)
  938                 return (0);
  939         if (cr1->cr_uid == cr2->cr_ruid)
  940                 return (0);
  941         if (cr1->cr_ruid == cr2->cr_uid)
  942                 return (0);
  943         if (cr1->cr_uid == cr2->cr_uid)
  944                 return (0);
  945         if (priv_check_cred(cr1, PRIV_PROC_TRESPASS, 0) == 0)
  946                 return (0);
  947         return (EPERM);
  948 }
  949 
  950 static __inline void
  951 _crinit(struct ucred *cr)
  952 {
  953         cr->cr_ref = 1;
  954 }
  955 
  956 void
  957 crinit(struct ucred *cr)
  958 {
  959         bzero(cr, sizeof(*cr));
  960         _crinit(cr);
  961 }
  962 
  963 /*
  964  * Allocate a zeroed cred structure.
  965  */
  966 struct ucred *
  967 crget(void)
  968 {
  969         struct ucred *cr;
  970 
  971         cr = kmalloc(sizeof(*cr), M_CRED, M_WAITOK|M_ZERO);
  972         _crinit(cr);
  973         return (cr);
  974 }
  975 
  976 /*
  977  * Claim another reference to a ucred structure.  Can be used with special
  978  * creds.
  979  *
  980  * It must be possible to call this routine with spinlocks held, meaning
  981  * that this routine itself cannot obtain a spinlock.
  982  */
  983 struct ucred *
  984 crhold(struct ucred *cr)
  985 {
  986         if (cr != NOCRED && cr != FSCRED)
  987                 atomic_add_int(&cr->cr_ref, 1);
  988         return(cr);
  989 }
  990 
  991 /*
  992  * Drop a reference from the cred structure, free it if the reference count
  993  * reaches 0. 
  994  *
  995  * NOTE: because we used atomic_add_int() above, without a spinlock, we
  996  * must also use atomic_subtract_int() below.  A spinlock is required
  997  * in crfree() to handle multiple callers racing the refcount to 0.
  998  */
  999 void
 1000 crfree(struct ucred *cr)
 1001 {
 1002         if (cr->cr_ref <= 0)
 1003                 panic("Freeing already free credential! %p", cr);
 1004         if (atomic_fetchadd_int(&cr->cr_ref, -1) == 1) {
 1005                 /*
 1006                  * Some callers of crget(), such as nfs_statfs(),
 1007                  * allocate a temporary credential, but don't
 1008                  * allocate a uidinfo structure.
 1009                  */
 1010                 if (cr->cr_uidinfo != NULL) {
 1011                         uidrop(cr->cr_uidinfo);
 1012                         cr->cr_uidinfo = NULL;
 1013                 }
 1014                 if (cr->cr_ruidinfo != NULL) {
 1015                         uidrop(cr->cr_ruidinfo);
 1016                         cr->cr_ruidinfo = NULL;
 1017                 }
 1018 
 1019                 /*
 1020                  * Destroy empty prisons
 1021                  */
 1022                 if (jailed(cr))
 1023                         prison_free(cr->cr_prison);
 1024                 cr->cr_prison = NULL;   /* safety */
 1025 
 1026                 kfree((caddr_t)cr, M_CRED);
 1027         }
 1028 }
 1029 
 1030 /*
 1031  * Atomize a cred structure so it can be modified without polluting
 1032  * other references to it.
 1033  *
 1034  * MPSAFE (however, *pcr must be stable)
 1035  */
 1036 struct ucred *
 1037 cratom(struct ucred **pcr)
 1038 {
 1039         struct ucred *oldcr;
 1040         struct ucred *newcr;
 1041 
 1042         oldcr = *pcr;
 1043         if (oldcr->cr_ref == 1)
 1044                 return (oldcr);
 1045         newcr = crget();
 1046         *newcr = *oldcr;
 1047         if (newcr->cr_uidinfo)
 1048                 uihold(newcr->cr_uidinfo);
 1049         if (newcr->cr_ruidinfo)
 1050                 uihold(newcr->cr_ruidinfo);
 1051         if (jailed(newcr))
 1052                 prison_hold(newcr->cr_prison);
 1053         newcr->cr_ref = 1;
 1054         crfree(oldcr);
 1055         *pcr = newcr;
 1056         return (newcr);
 1057 }
 1058 
 1059 /*
 1060  * Dup cred struct to a new held one.
 1061  */
 1062 struct ucred *
 1063 crdup(struct ucred *cr)
 1064 {
 1065         struct ucred *newcr;
 1066 
 1067         newcr = crget();
 1068         *newcr = *cr;
 1069         if (newcr->cr_uidinfo)
 1070                 uihold(newcr->cr_uidinfo);
 1071         if (newcr->cr_ruidinfo)
 1072                 uihold(newcr->cr_ruidinfo);
 1073         if (jailed(newcr))
 1074                 prison_hold(newcr->cr_prison);
 1075         newcr->cr_ref = 1;
 1076         return (newcr);
 1077 }
 1078 
 1079 /*
 1080  * Fill in a struct xucred based on a struct ucred.
 1081  */
 1082 void
 1083 cru2x(struct ucred *cr, struct xucred *xcr)
 1084 {
 1085 
 1086         bzero(xcr, sizeof(*xcr));
 1087         xcr->cr_version = XUCRED_VERSION;
 1088         xcr->cr_uid = cr->cr_uid;
 1089         xcr->cr_ngroups = cr->cr_ngroups;
 1090         bcopy(cr->cr_groups, xcr->cr_groups, sizeof(cr->cr_groups));
 1091 }
 1092 
 1093 /*
 1094  * Get login name, if available.
 1095  */
 1096 int
 1097 sys_getlogin(struct getlogin_args *uap)
 1098 {
 1099         struct proc *p = curproc;
 1100         char buf[MAXLOGNAME];
 1101         int error;
 1102 
 1103         if (uap->namelen > MAXLOGNAME)          /* namelen is unsigned */
 1104                 uap->namelen = MAXLOGNAME;
 1105         bzero(buf, sizeof(buf));
 1106         lwkt_gettoken_shared(&p->p_token);
 1107         bcopy(p->p_pgrp->pg_session->s_login, buf, uap->namelen);
 1108         lwkt_reltoken(&p->p_token);
 1109 
 1110         error = copyout(buf, uap->namebuf, uap->namelen);
 1111         return (error);
 1112 }
 1113 
 1114 /*
 1115  * Set login name.
 1116  */
 1117 int
 1118 sys_setlogin(struct setlogin_args *uap)
 1119 {
 1120         struct thread *td = curthread;
 1121         struct proc *p;
 1122         struct ucred *cred;
 1123         char buf[MAXLOGNAME];
 1124         int error;
 1125 
 1126         cred = td->td_ucred;
 1127         p = td->td_proc;
 1128 
 1129         if ((error = priv_check_cred(cred, PRIV_PROC_SETLOGIN, 0)))
 1130                 return (error);
 1131         bzero(buf, sizeof(buf));
 1132         error = copyinstr(uap->namebuf, buf, sizeof(buf), NULL);
 1133         if (error == ENAMETOOLONG)
 1134                 error = EINVAL;
 1135         if (error == 0) {
 1136                 lwkt_gettoken_shared(&p->p_token);
 1137                 memcpy(p->p_pgrp->pg_session->s_login, buf, sizeof(buf));
 1138                 lwkt_reltoken(&p->p_token);
 1139         }
 1140         return (error);
 1141 }
 1142 
 1143 void
 1144 setsugid(void)
 1145 {
 1146         struct proc *p = curproc;
 1147 
 1148         KKASSERT(p != NULL);
 1149         lwkt_gettoken(&p->p_token);
 1150         p->p_flags |= P_SUGID;
 1151         if (!(p->p_pfsflags & PF_ISUGID))
 1152                 p->p_stops = 0;
 1153         lwkt_reltoken(&p->p_token);
 1154 }
 1155 
 1156 /*
 1157  * Helper function to change the effective uid of a process
 1158  */
 1159 struct ucred *
 1160 change_euid(uid_t euid)
 1161 {
 1162         struct  proc *p = curproc;
 1163         struct  ucred *cr;
 1164 
 1165         KKASSERT(p != NULL);
 1166         lf_count_adjust(p, 0);
 1167         cr = cratom(&p->p_ucred);
 1168         cr->cr_uid = euid;
 1169         uireplace(&cr->cr_uidinfo, uifind(euid));
 1170         lf_count_adjust(p, 1);
 1171         return (cr);
 1172 }
 1173 
 1174 /*
 1175  * Helper function to change the real uid of a process
 1176  *
 1177  * The per-uid process count for this process is transfered from
 1178  * the old uid to the new uid.
 1179  */
 1180 struct ucred *
 1181 change_ruid(uid_t ruid)
 1182 {
 1183         struct  proc *p = curproc;
 1184         struct  ucred *cr;
 1185 
 1186         KKASSERT(p != NULL);
 1187 
 1188         cr = cratom(&p->p_ucred);
 1189         chgproccnt(cr->cr_ruidinfo, -1, 0);
 1190         cr->cr_ruid = ruid;
 1191         uireplace(&cr->cr_ruidinfo, uifind(ruid));
 1192         chgproccnt(cr->cr_ruidinfo, 1, 0);
 1193         return (cr);
 1194 }

Cache object: 3a064d813587447a6163ca519d869be3


[ 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.