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_resource.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 /*      $NetBSD: kern_resource.c,v 1.147.4.2 2009/08/14 21:15:16 snj Exp $      */
    2 
    3 /*-
    4  * Copyright (c) 1982, 1986, 1991, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  * (c) UNIX System Laboratories, Inc.
    7  * All or some portions of this file are derived from material licensed
    8  * to the University of California by American Telephone and Telegraph
    9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   10  * the permission of UNIX System Laboratories, Inc.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  *      @(#)kern_resource.c     8.8 (Berkeley) 2/14/95
   37  */
   38 
   39 #include <sys/cdefs.h>
   40 __KERNEL_RCSID(0, "$NetBSD: kern_resource.c,v 1.147.4.2 2009/08/14 21:15:16 snj Exp $");
   41 
   42 #include <sys/param.h>
   43 #include <sys/systm.h>
   44 #include <sys/kernel.h>
   45 #include <sys/file.h>
   46 #include <sys/resourcevar.h>
   47 #include <sys/malloc.h>
   48 #include <sys/kmem.h>
   49 #include <sys/namei.h>
   50 #include <sys/pool.h>
   51 #include <sys/proc.h>
   52 #include <sys/sysctl.h>
   53 #include <sys/timevar.h>
   54 #include <sys/kauth.h>
   55 #include <sys/atomic.h>
   56 #include <sys/mount.h>
   57 #include <sys/syscallargs.h>
   58 #include <sys/atomic.h>
   59 
   60 #include <uvm/uvm_extern.h>
   61 
   62 /*
   63  * Maximum process data and stack limits.
   64  * They are variables so they are patchable.
   65  */
   66 rlim_t maxdmap = MAXDSIZ;
   67 rlim_t maxsmap = MAXSSIZ;
   68 
   69 static pool_cache_t     plimit_cache;
   70 static pool_cache_t     pstats_cache;
   71 
   72 void
   73 resource_init(void)
   74 {
   75 
   76         plimit_cache = pool_cache_init(sizeof(struct plimit), 0, 0, 0,
   77             "plimitpl", NULL, IPL_NONE, NULL, NULL, NULL);
   78         pstats_cache = pool_cache_init(sizeof(struct pstats), 0, 0, 0,
   79             "pstatspl", NULL, IPL_NONE, NULL, NULL, NULL);
   80 }
   81 
   82 /*
   83  * Resource controls and accounting.
   84  */
   85 
   86 int
   87 sys_getpriority(struct lwp *l, const struct sys_getpriority_args *uap,
   88     register_t *retval)
   89 {
   90         /* {
   91                 syscallarg(int) which;
   92                 syscallarg(id_t) who;
   93         } */
   94         struct proc *curp = l->l_proc, *p;
   95         int low = NZERO + PRIO_MAX + 1;
   96         int who = SCARG(uap, who);
   97 
   98         mutex_enter(proc_lock);
   99         switch (SCARG(uap, which)) {
  100         case PRIO_PROCESS:
  101                 if (who == 0)
  102                         p = curp;
  103                 else
  104                         p = p_find(who, PFIND_LOCKED);
  105                 if (p != NULL)
  106                         low = p->p_nice;
  107                 break;
  108 
  109         case PRIO_PGRP: {
  110                 struct pgrp *pg;
  111 
  112                 if (who == 0)
  113                         pg = curp->p_pgrp;
  114                 else if ((pg = pg_find(who, PFIND_LOCKED)) == NULL)
  115                         break;
  116                 LIST_FOREACH(p, &pg->pg_members, p_pglist) {
  117                         if (p->p_nice < low)
  118                                 low = p->p_nice;
  119                 }
  120                 break;
  121         }
  122 
  123         case PRIO_USER:
  124                 if (who == 0)
  125                         who = (int)kauth_cred_geteuid(l->l_cred);
  126                 PROCLIST_FOREACH(p, &allproc) {
  127                         if ((p->p_flag & PK_MARKER) != 0)
  128                                 continue;
  129                         mutex_enter(p->p_lock);
  130                         if (kauth_cred_geteuid(p->p_cred) ==
  131                             (uid_t)who && p->p_nice < low)
  132                                 low = p->p_nice;
  133                         mutex_exit(p->p_lock);
  134                 }
  135                 break;
  136 
  137         default:
  138                 mutex_exit(proc_lock);
  139                 return (EINVAL);
  140         }
  141         mutex_exit(proc_lock);
  142 
  143         if (low == NZERO + PRIO_MAX + 1)
  144                 return (ESRCH);
  145         *retval = low - NZERO;
  146         return (0);
  147 }
  148 
  149 /* ARGSUSED */
  150 int
  151 sys_setpriority(struct lwp *l, const struct sys_setpriority_args *uap,
  152     register_t *retval)
  153 {
  154         /* {
  155                 syscallarg(int) which;
  156                 syscallarg(id_t) who;
  157                 syscallarg(int) prio;
  158         } */
  159         struct proc *curp = l->l_proc, *p;
  160         int found = 0, error = 0;
  161         int who = SCARG(uap, who);
  162 
  163         mutex_enter(proc_lock);
  164         switch (SCARG(uap, which)) {
  165         case PRIO_PROCESS:
  166                 if (who == 0)
  167                         p = curp;
  168                 else
  169                         p = p_find(who, PFIND_LOCKED);
  170                 if (p != 0) {
  171                         mutex_enter(p->p_lock);
  172                         error = donice(l, p, SCARG(uap, prio));
  173                         mutex_exit(p->p_lock);
  174                         found++;
  175                 }
  176                 break;
  177 
  178         case PRIO_PGRP: {
  179                 struct pgrp *pg;
  180 
  181                 if (who == 0)
  182                         pg = curp->p_pgrp;
  183                 else if ((pg = pg_find(who, PFIND_LOCKED)) == NULL)
  184                         break;
  185                 LIST_FOREACH(p, &pg->pg_members, p_pglist) {
  186                         mutex_enter(p->p_lock);
  187                         error = donice(l, p, SCARG(uap, prio));
  188                         mutex_exit(p->p_lock);
  189                         found++;
  190                 }
  191                 break;
  192         }
  193 
  194         case PRIO_USER:
  195                 if (who == 0)
  196                         who = (int)kauth_cred_geteuid(l->l_cred);
  197                 PROCLIST_FOREACH(p, &allproc) {
  198                         if ((p->p_flag & PK_MARKER) != 0)
  199                                 continue;
  200                         mutex_enter(p->p_lock);
  201                         if (kauth_cred_geteuid(p->p_cred) ==
  202                             (uid_t)SCARG(uap, who)) {
  203                                 error = donice(l, p, SCARG(uap, prio));
  204                                 found++;
  205                         }
  206                         mutex_exit(p->p_lock);
  207                 }
  208                 break;
  209 
  210         default:
  211                 mutex_exit(proc_lock);
  212                 return EINVAL;
  213         }
  214         mutex_exit(proc_lock);
  215         if (found == 0)
  216                 return (ESRCH);
  217         return (error);
  218 }
  219 
  220 /*
  221  * Renice a process.
  222  *
  223  * Call with the target process' credentials locked.
  224  */
  225 int
  226 donice(struct lwp *l, struct proc *chgp, int n)
  227 {
  228         kauth_cred_t cred = l->l_cred;
  229 
  230         KASSERT(mutex_owned(chgp->p_lock));
  231 
  232         if (kauth_cred_geteuid(cred) && kauth_cred_getuid(cred) &&
  233             kauth_cred_geteuid(cred) != kauth_cred_geteuid(chgp->p_cred) &&
  234             kauth_cred_getuid(cred) != kauth_cred_geteuid(chgp->p_cred))
  235                 return (EPERM);
  236 
  237         if (n > PRIO_MAX)
  238                 n = PRIO_MAX;
  239         if (n < PRIO_MIN)
  240                 n = PRIO_MIN;
  241         n += NZERO;
  242         if (kauth_authorize_process(cred, KAUTH_PROCESS_NICE, chgp,
  243             KAUTH_ARG(n), NULL, NULL))
  244                 return (EACCES);
  245         sched_nice(chgp, n);
  246         return (0);
  247 }
  248 
  249 /* ARGSUSED */
  250 int
  251 sys_setrlimit(struct lwp *l, const struct sys_setrlimit_args *uap,
  252     register_t *retval)
  253 {
  254         /* {
  255                 syscallarg(int) which;
  256                 syscallarg(const struct rlimit *) rlp;
  257         } */
  258         int which = SCARG(uap, which);
  259         struct rlimit alim;
  260         int error;
  261 
  262         error = copyin(SCARG(uap, rlp), &alim, sizeof(struct rlimit));
  263         if (error)
  264                 return (error);
  265         return (dosetrlimit(l, l->l_proc, which, &alim));
  266 }
  267 
  268 int
  269 dosetrlimit(struct lwp *l, struct proc *p, int which, struct rlimit *limp)
  270 {
  271         struct rlimit *alimp;
  272         int error;
  273 
  274         if ((u_int)which >= RLIM_NLIMITS)
  275                 return (EINVAL);
  276 
  277         if (limp->rlim_cur < 0 || limp->rlim_max < 0)
  278                 return (EINVAL);
  279 
  280         if (limp->rlim_cur > limp->rlim_max) {
  281                 /*
  282                  * This is programming error. According to SUSv2, we should
  283                  * return error in this case.
  284                  */
  285                 return (EINVAL);
  286         }
  287 
  288         alimp = &p->p_rlimit[which];
  289         /* if we don't change the value, no need to limcopy() */
  290         if (limp->rlim_cur == alimp->rlim_cur &&
  291             limp->rlim_max == alimp->rlim_max)
  292                 return 0;
  293 
  294         error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_RLIMIT,
  295             p, KAUTH_ARG(KAUTH_REQ_PROCESS_RLIMIT_SET), limp, KAUTH_ARG(which));
  296         if (error)
  297                 return (error);
  298 
  299         lim_privatise(p, false);
  300         /* p->p_limit is now unchangeable */
  301         alimp = &p->p_rlimit[which];
  302 
  303         switch (which) {
  304 
  305         case RLIMIT_DATA:
  306                 if (limp->rlim_cur > maxdmap)
  307                         limp->rlim_cur = maxdmap;
  308                 if (limp->rlim_max > maxdmap)
  309                         limp->rlim_max = maxdmap;
  310                 break;
  311 
  312         case RLIMIT_STACK:
  313                 if (limp->rlim_cur > maxsmap)
  314                         limp->rlim_cur = maxsmap;
  315                 if (limp->rlim_max > maxsmap)
  316                         limp->rlim_max = maxsmap;
  317 
  318                 /*
  319                  * Return EINVAL if the new stack size limit is lower than
  320                  * current usage. Otherwise, the process would get SIGSEGV the
  321                  * moment it would try to access anything on it's current stack.
  322                  * This conforms to SUSv2.
  323                  */
  324                 if (limp->rlim_cur < p->p_vmspace->vm_ssize * PAGE_SIZE
  325                     || limp->rlim_max < p->p_vmspace->vm_ssize * PAGE_SIZE) {
  326                         return (EINVAL);
  327                 }
  328 
  329                 /*
  330                  * Stack is allocated to the max at exec time with
  331                  * only "rlim_cur" bytes accessible (In other words,
  332                  * allocates stack dividing two contiguous regions at
  333                  * "rlim_cur" bytes boundary).
  334                  *
  335                  * Since allocation is done in terms of page, roundup
  336                  * "rlim_cur" (otherwise, contiguous regions
  337                  * overlap).  If stack limit is going up make more
  338                  * accessible, if going down make inaccessible.
  339                  */
  340                 limp->rlim_cur = round_page(limp->rlim_cur);
  341                 if (limp->rlim_cur != alimp->rlim_cur) {
  342                         vaddr_t addr;
  343                         vsize_t size;
  344                         vm_prot_t prot;
  345 
  346                         if (limp->rlim_cur > alimp->rlim_cur) {
  347                                 prot = VM_PROT_READ | VM_PROT_WRITE;
  348                                 size = limp->rlim_cur - alimp->rlim_cur;
  349                                 addr = (vaddr_t)p->p_vmspace->vm_minsaddr -
  350                                     limp->rlim_cur;
  351                         } else {
  352                                 prot = VM_PROT_NONE;
  353                                 size = alimp->rlim_cur - limp->rlim_cur;
  354                                 addr = (vaddr_t)p->p_vmspace->vm_minsaddr -
  355                                      alimp->rlim_cur;
  356                         }
  357                         (void) uvm_map_protect(&p->p_vmspace->vm_map,
  358                             addr, addr+size, prot, false);
  359                 }
  360                 break;
  361 
  362         case RLIMIT_NOFILE:
  363                 if (limp->rlim_cur > maxfiles)
  364                         limp->rlim_cur = maxfiles;
  365                 if (limp->rlim_max > maxfiles)
  366                         limp->rlim_max = maxfiles;
  367                 break;
  368 
  369         case RLIMIT_NPROC:
  370                 if (limp->rlim_cur > maxproc)
  371                         limp->rlim_cur = maxproc;
  372                 if (limp->rlim_max > maxproc)
  373                         limp->rlim_max = maxproc;
  374                 break;
  375         }
  376 
  377         mutex_enter(&p->p_limit->pl_lock);
  378         *alimp = *limp;
  379         mutex_exit(&p->p_limit->pl_lock);
  380         return (0);
  381 }
  382 
  383 /* ARGSUSED */
  384 int
  385 sys_getrlimit(struct lwp *l, const struct sys_getrlimit_args *uap,
  386     register_t *retval)
  387 {
  388         /* {
  389                 syscallarg(int) which;
  390                 syscallarg(struct rlimit *) rlp;
  391         } */
  392         struct proc *p = l->l_proc;
  393         int which = SCARG(uap, which);
  394         struct rlimit rl;
  395 
  396         if ((u_int)which >= RLIM_NLIMITS)
  397                 return (EINVAL);
  398 
  399         mutex_enter(p->p_lock);
  400         memcpy(&rl, &p->p_rlimit[which], sizeof(rl));
  401         mutex_exit(p->p_lock);
  402 
  403         return copyout(&rl, SCARG(uap, rlp), sizeof(rl));
  404 }
  405 
  406 /*
  407  * Transform the running time and tick information in proc p into user,
  408  * system, and interrupt time usage.
  409  *
  410  * Should be called with p->p_lock held unless called from exit1().
  411  */
  412 void
  413 calcru(struct proc *p, struct timeval *up, struct timeval *sp,
  414     struct timeval *ip, struct timeval *rp)
  415 {
  416         uint64_t u, st, ut, it, tot;
  417         struct lwp *l;
  418         struct bintime tm;
  419         struct timeval tv;
  420 
  421         mutex_spin_enter(&p->p_stmutex);
  422         st = p->p_sticks;
  423         ut = p->p_uticks;
  424         it = p->p_iticks;
  425         mutex_spin_exit(&p->p_stmutex);
  426 
  427         tm = p->p_rtime;
  428 
  429         LIST_FOREACH(l, &p->p_lwps, l_sibling) {
  430                 lwp_lock(l);
  431                 bintime_add(&tm, &l->l_rtime);
  432                 if ((l->l_pflag & LP_RUNNING) != 0) {
  433                         struct bintime diff;
  434                         /*
  435                          * Adjust for the current time slice.  This is
  436                          * actually fairly important since the error
  437                          * here is on the order of a time quantum,
  438                          * which is much greater than the sampling
  439                          * error.
  440                          */
  441                         binuptime(&diff);
  442                         bintime_sub(&diff, &l->l_stime);
  443                         bintime_add(&tm, &diff);
  444                 }
  445                 lwp_unlock(l);
  446         }
  447 
  448         tot = st + ut + it;
  449         bintime2timeval(&tm, &tv);
  450         u = (uint64_t)tv.tv_sec * 1000000ul + tv.tv_usec;
  451 
  452         if (tot == 0) {
  453                 /* No ticks, so can't use to share time out, split 50-50 */
  454                 st = ut = u / 2;
  455         } else {
  456                 st = (u * st) / tot;
  457                 ut = (u * ut) / tot;
  458         }
  459         if (sp != NULL) {
  460                 sp->tv_sec = st / 1000000;
  461                 sp->tv_usec = st % 1000000;
  462         }
  463         if (up != NULL) {
  464                 up->tv_sec = ut / 1000000;
  465                 up->tv_usec = ut % 1000000;
  466         }
  467         if (ip != NULL) {
  468                 if (it != 0)
  469                         it = (u * it) / tot;
  470                 ip->tv_sec = it / 1000000;
  471                 ip->tv_usec = it % 1000000;
  472         }
  473         if (rp != NULL) {
  474                 *rp = tv;
  475         }
  476 }
  477 
  478 /* ARGSUSED */
  479 int
  480 sys_getrusage(struct lwp *l, const struct sys_getrusage_args *uap,
  481     register_t *retval)
  482 {
  483         /* {
  484                 syscallarg(int) who;
  485                 syscallarg(struct rusage *) rusage;
  486         } */
  487         struct rusage ru;
  488         struct proc *p = l->l_proc;
  489 
  490         switch (SCARG(uap, who)) {
  491         case RUSAGE_SELF:
  492                 mutex_enter(p->p_lock);
  493                 memcpy(&ru, &p->p_stats->p_ru, sizeof(ru));
  494                 calcru(p, &ru.ru_utime, &ru.ru_stime, NULL, NULL);
  495                 rulwps(p, &ru);
  496                 mutex_exit(p->p_lock);
  497                 break;
  498 
  499         case RUSAGE_CHILDREN:
  500                 mutex_enter(p->p_lock);
  501                 memcpy(&ru, &p->p_stats->p_cru, sizeof(ru));
  502                 mutex_exit(p->p_lock);
  503                 break;
  504 
  505         default:
  506                 return EINVAL;
  507         }
  508 
  509         return copyout(&ru, SCARG(uap, rusage), sizeof(ru));
  510 }
  511 
  512 void
  513 ruadd(struct rusage *ru, struct rusage *ru2)
  514 {
  515         long *ip, *ip2;
  516         int i;
  517 
  518         timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime);
  519         timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime);
  520         if (ru->ru_maxrss < ru2->ru_maxrss)
  521                 ru->ru_maxrss = ru2->ru_maxrss;
  522         ip = &ru->ru_first; ip2 = &ru2->ru_first;
  523         for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
  524                 *ip++ += *ip2++;
  525 }
  526 
  527 void
  528 rulwps(proc_t *p, struct rusage *ru)
  529 {
  530         lwp_t *l;
  531 
  532         KASSERT(mutex_owned(p->p_lock));
  533 
  534         LIST_FOREACH(l, &p->p_lwps, l_sibling) {
  535                 ruadd(ru, &l->l_ru);
  536                 ru->ru_nvcsw += (l->l_ncsw - l->l_nivcsw);
  537                 ru->ru_nivcsw += l->l_nivcsw;
  538         }
  539 }
  540 
  541 /*
  542  * Make a copy of the plimit structure.
  543  * We share these structures copy-on-write after fork,
  544  * and copy when a limit is changed.
  545  *
  546  * Unfortunately (due to PL_SHAREMOD) it is possibly for the structure
  547  * we are copying to change beneath our feet!
  548  */
  549 struct plimit *
  550 lim_copy(struct plimit *lim)
  551 {
  552         struct plimit *newlim;
  553         char *corename;
  554         size_t alen, len;
  555 
  556         newlim = pool_cache_get(plimit_cache, PR_WAITOK);
  557         mutex_init(&newlim->pl_lock, MUTEX_DEFAULT, IPL_NONE);
  558         newlim->pl_flags = 0;
  559         newlim->pl_refcnt = 1;
  560         newlim->pl_sv_limit = NULL;
  561 
  562         mutex_enter(&lim->pl_lock);
  563         memcpy(newlim->pl_rlimit, lim->pl_rlimit,
  564             sizeof(struct rlimit) * RLIM_NLIMITS);
  565 
  566         alen = 0;
  567         corename = NULL;
  568         for (;;) {
  569                 if (lim->pl_corename == defcorename) {
  570                         newlim->pl_corename = defcorename;
  571                         break;
  572                 }
  573                 len = strlen(lim->pl_corename) + 1;
  574                 if (len <= alen) {
  575                         newlim->pl_corename = corename;
  576                         memcpy(corename, lim->pl_corename, len);
  577                         corename = NULL;
  578                         break;
  579                 }
  580                 mutex_exit(&lim->pl_lock);
  581                 if (corename != NULL)
  582                         free(corename, M_TEMP);
  583                 alen = len;
  584                 corename = malloc(alen, M_TEMP, M_WAITOK);
  585                 mutex_enter(&lim->pl_lock);
  586         }
  587         mutex_exit(&lim->pl_lock);
  588         if (corename != NULL)
  589                 free(corename, M_TEMP);
  590         return newlim;
  591 }
  592 
  593 void
  594 lim_addref(struct plimit *lim)
  595 {
  596         atomic_inc_uint(&lim->pl_refcnt);
  597 }
  598 
  599 /*
  600  * Give a process it's own private plimit structure.
  601  * This will only be shared (in fork) if modifications are to be shared.
  602  */
  603 void
  604 lim_privatise(struct proc *p, bool set_shared)
  605 {
  606         struct plimit *lim, *newlim;
  607 
  608         lim = p->p_limit;
  609         if (lim->pl_flags & PL_WRITEABLE) {
  610                 if (set_shared)
  611                         lim->pl_flags |= PL_SHAREMOD;
  612                 return;
  613         }
  614 
  615         if (set_shared && lim->pl_flags & PL_SHAREMOD)
  616                 return;
  617 
  618         newlim = lim_copy(lim);
  619 
  620         mutex_enter(p->p_lock);
  621         if (p->p_limit->pl_flags & PL_WRITEABLE) {
  622                 /* Someone crept in while we were busy */
  623                 mutex_exit(p->p_lock);
  624                 limfree(newlim);
  625                 if (set_shared)
  626                         p->p_limit->pl_flags |= PL_SHAREMOD;
  627                 return;
  628         }
  629 
  630         /*
  631          * Since most accesses to p->p_limit aren't locked, we must not
  632          * delete the old limit structure yet.
  633          */
  634         newlim->pl_sv_limit = p->p_limit;
  635         newlim->pl_flags |= PL_WRITEABLE;
  636         if (set_shared)
  637                 newlim->pl_flags |= PL_SHAREMOD;
  638         p->p_limit = newlim;
  639         mutex_exit(p->p_lock);
  640 }
  641 
  642 void
  643 limfree(struct plimit *lim)
  644 {
  645         struct plimit *sv_lim;
  646 
  647         do {
  648                 if (atomic_dec_uint_nv(&lim->pl_refcnt) > 0)
  649                         return;
  650                 if (lim->pl_corename != defcorename)
  651                         free(lim->pl_corename, M_TEMP);
  652                 sv_lim = lim->pl_sv_limit;
  653                 mutex_destroy(&lim->pl_lock);
  654                 pool_cache_put(plimit_cache, lim);
  655         } while ((lim = sv_lim) != NULL);
  656 }
  657 
  658 struct pstats *
  659 pstatscopy(struct pstats *ps)
  660 {
  661 
  662         struct pstats *newps;
  663 
  664         newps = pool_cache_get(pstats_cache, PR_WAITOK);
  665 
  666         memset(&newps->pstat_startzero, 0,
  667         (unsigned) ((char *)&newps->pstat_endzero -
  668                     (char *)&newps->pstat_startzero));
  669         memcpy(&newps->pstat_startcopy, &ps->pstat_startcopy,
  670         ((char *)&newps->pstat_endcopy -
  671          (char *)&newps->pstat_startcopy));
  672 
  673         return (newps);
  674 
  675 }
  676 
  677 void
  678 pstatsfree(struct pstats *ps)
  679 {
  680 
  681         pool_cache_put(pstats_cache, ps);
  682 }
  683 
  684 /*
  685  * sysctl interface in five parts
  686  */
  687 
  688 /*
  689  * a routine for sysctl proc subtree helpers that need to pick a valid
  690  * process by pid.
  691  */
  692 static int
  693 sysctl_proc_findproc(struct lwp *l, struct proc **p2, pid_t pid)
  694 {
  695         struct proc *ptmp;
  696         int error = 0;
  697 
  698         if (pid == PROC_CURPROC)
  699                 ptmp = l->l_proc;
  700         else if ((ptmp = pfind(pid)) == NULL)
  701                 error = ESRCH;
  702 
  703         *p2 = ptmp;
  704         return (error);
  705 }
  706 
  707 /*
  708  * sysctl helper routine for setting a process's specific corefile
  709  * name.  picks the process based on the given pid and checks the
  710  * correctness of the new value.
  711  */
  712 static int
  713 sysctl_proc_corename(SYSCTLFN_ARGS)
  714 {
  715         struct proc *ptmp;
  716         struct plimit *lim;
  717         int error = 0, len;
  718         char *cname;
  719         char *ocore;
  720         char *tmp;
  721         struct sysctlnode node;
  722 
  723         /*
  724          * is this all correct?
  725          */
  726         if (namelen != 0)
  727                 return (EINVAL);
  728         if (name[-1] != PROC_PID_CORENAME)
  729                 return (EINVAL);
  730 
  731         /*
  732          * whom are we tweaking?
  733          */
  734         error = sysctl_proc_findproc(l, &ptmp, (pid_t)name[-2]);
  735         if (error)
  736                 return (error);
  737 
  738         /* XXX-elad */
  739         error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSEE, ptmp,
  740             KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL);
  741         if (error)
  742                 return (error);
  743 
  744         if (newp == NULL) {
  745                 error = kauth_authorize_process(l->l_cred,
  746                     KAUTH_PROCESS_CORENAME, ptmp,
  747                     KAUTH_ARG(KAUTH_REQ_PROCESS_CORENAME_GET), NULL, NULL);
  748                 if (error)
  749                         return (error);
  750         }
  751 
  752         /*
  753          * let them modify a temporary copy of the core name
  754          */
  755         cname = PNBUF_GET();
  756         lim = ptmp->p_limit;
  757         mutex_enter(&lim->pl_lock);
  758         strlcpy(cname, lim->pl_corename, MAXPATHLEN);
  759         mutex_exit(&lim->pl_lock);
  760 
  761         node = *rnode;
  762         node.sysctl_data = cname;
  763         error = sysctl_lookup(SYSCTLFN_CALL(&node));
  764 
  765         /*
  766          * if that failed, or they have nothing new to say, or we've
  767          * heard it before...
  768          */
  769         if (error || newp == NULL)
  770                 goto done;
  771         lim = ptmp->p_limit;
  772         mutex_enter(&lim->pl_lock);
  773         error = strcmp(cname, lim->pl_corename);
  774         mutex_exit(&lim->pl_lock);
  775         if (error == 0)
  776                 /* Unchanged */
  777                 goto done;
  778 
  779         error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CORENAME,
  780             ptmp, KAUTH_ARG(KAUTH_REQ_PROCESS_CORENAME_SET), cname, NULL);
  781         if (error)
  782                 return (error);
  783 
  784         /*
  785          * no error yet and cname now has the new core name in it.
  786          * let's see if it looks acceptable.  it must be either "core"
  787          * or end in ".core" or "/core".
  788          */
  789         len = strlen(cname);
  790         if (len < 4) {
  791                 error = EINVAL;
  792         } else if (strcmp(cname + len - 4, "core") != 0) {
  793                 error = EINVAL;
  794         } else if (len > 4 && cname[len - 5] != '/' && cname[len - 5] != '.') {
  795                 error = EINVAL;
  796         }
  797         if (error != 0) {
  798                 goto done;
  799         }
  800 
  801         /*
  802          * hmm...looks good.  now...where do we put it?
  803          */
  804         tmp = malloc(len + 1, M_TEMP, M_WAITOK|M_CANFAIL);
  805         if (tmp == NULL) {
  806                 error = ENOMEM;
  807                 goto done;
  808         }
  809         memcpy(tmp, cname, len + 1);
  810 
  811         lim_privatise(ptmp, false);
  812         lim = ptmp->p_limit;
  813         mutex_enter(&lim->pl_lock);
  814         ocore = lim->pl_corename;
  815         lim->pl_corename = tmp;
  816         mutex_exit(&lim->pl_lock);
  817         if (ocore != defcorename)
  818                 free(ocore, M_TEMP);
  819 
  820 done:
  821         PNBUF_PUT(cname);
  822         return error;
  823 }
  824 
  825 /*
  826  * sysctl helper routine for checking/setting a process's stop flags,
  827  * one for fork and one for exec.
  828  */
  829 static int
  830 sysctl_proc_stop(SYSCTLFN_ARGS)
  831 {
  832         struct proc *ptmp;
  833         int i, f, error = 0;
  834         struct sysctlnode node;
  835 
  836         if (namelen != 0)
  837                 return (EINVAL);
  838 
  839         error = sysctl_proc_findproc(l, &ptmp, (pid_t)name[-2]);
  840         if (error)
  841                 return (error);
  842 
  843         /* XXX-elad */
  844         error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSEE, ptmp,
  845             KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL);
  846         if (error)
  847                 return (error);
  848 
  849         switch (rnode->sysctl_num) {
  850         case PROC_PID_STOPFORK:
  851                 f = PS_STOPFORK;
  852                 break;
  853         case PROC_PID_STOPEXEC:
  854                 f = PS_STOPEXEC;
  855                 break;
  856         case PROC_PID_STOPEXIT:
  857                 f = PS_STOPEXIT;
  858                 break;
  859         default:
  860                 return (EINVAL);
  861         }
  862 
  863         i = (ptmp->p_flag & f) ? 1 : 0;
  864         node = *rnode;
  865         node.sysctl_data = &i;
  866         error = sysctl_lookup(SYSCTLFN_CALL(&node));
  867         if (error || newp == NULL)
  868                 return (error);
  869 
  870         mutex_enter(ptmp->p_lock);
  871         error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_STOPFLAG,
  872             ptmp, KAUTH_ARG(f), NULL, NULL);
  873         if (!error) {
  874                 if (i) {
  875                         ptmp->p_sflag |= f;
  876                 } else {
  877                         ptmp->p_sflag &= ~f;
  878                 }
  879         }
  880         mutex_exit(ptmp->p_lock);
  881 
  882         return error;
  883 }
  884 
  885 /*
  886  * sysctl helper routine for a process's rlimits as exposed by sysctl.
  887  */
  888 static int
  889 sysctl_proc_plimit(SYSCTLFN_ARGS)
  890 {
  891         struct proc *ptmp;
  892         u_int limitno;
  893         int which, error = 0;
  894         struct rlimit alim;
  895         struct sysctlnode node;
  896 
  897         if (namelen != 0)
  898                 return (EINVAL);
  899 
  900         which = name[-1];
  901         if (which != PROC_PID_LIMIT_TYPE_SOFT &&
  902             which != PROC_PID_LIMIT_TYPE_HARD)
  903                 return (EINVAL);
  904 
  905         limitno = name[-2] - 1;
  906         if (limitno >= RLIM_NLIMITS)
  907                 return (EINVAL);
  908 
  909         if (name[-3] != PROC_PID_LIMIT)
  910                 return (EINVAL);
  911 
  912         error = sysctl_proc_findproc(l, &ptmp, (pid_t)name[-4]);
  913         if (error)
  914                 return (error);
  915 
  916         /* XXX-elad */
  917         error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSEE, ptmp,
  918             KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL);
  919         if (error)
  920                 return (error);
  921 
  922         /* Check if we can view limits. */
  923         if (newp == NULL) {
  924                 error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_RLIMIT,
  925                     ptmp, KAUTH_ARG(KAUTH_REQ_PROCESS_RLIMIT_GET), &alim,
  926                     KAUTH_ARG(which));
  927                 if (error)
  928                         return (error);
  929         }
  930 
  931         node = *rnode;
  932         memcpy(&alim, &ptmp->p_rlimit[limitno], sizeof(alim));
  933         if (which == PROC_PID_LIMIT_TYPE_HARD)
  934                 node.sysctl_data = &alim.rlim_max;
  935         else
  936                 node.sysctl_data = &alim.rlim_cur;
  937 
  938         error = sysctl_lookup(SYSCTLFN_CALL(&node));
  939         if (error || newp == NULL)
  940                 return (error);
  941 
  942         return (dosetrlimit(l, ptmp, limitno, &alim));
  943 }
  944 
  945 /*
  946  * and finally, the actually glue that sticks it to the tree
  947  */
  948 SYSCTL_SETUP(sysctl_proc_setup, "sysctl proc subtree setup")
  949 {
  950 
  951         sysctl_createv(clog, 0, NULL, NULL,
  952                        CTLFLAG_PERMANENT,
  953                        CTLTYPE_NODE, "proc", NULL,
  954                        NULL, 0, NULL, 0,
  955                        CTL_PROC, CTL_EOL);
  956         sysctl_createv(clog, 0, NULL, NULL,
  957                        CTLFLAG_PERMANENT|CTLFLAG_ANYNUMBER,
  958                        CTLTYPE_NODE, "curproc",
  959                        SYSCTL_DESCR("Per-process settings"),
  960                        NULL, 0, NULL, 0,
  961                        CTL_PROC, PROC_CURPROC, CTL_EOL);
  962 
  963         sysctl_createv(clog, 0, NULL, NULL,
  964                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE|CTLFLAG_ANYWRITE,
  965                        CTLTYPE_STRING, "corename",
  966                        SYSCTL_DESCR("Core file name"),
  967                        sysctl_proc_corename, 0, NULL, MAXPATHLEN,
  968                        CTL_PROC, PROC_CURPROC, PROC_PID_CORENAME, CTL_EOL);
  969         sysctl_createv(clog, 0, NULL, NULL,
  970                        CTLFLAG_PERMANENT,
  971                        CTLTYPE_NODE, "rlimit",
  972                        SYSCTL_DESCR("Process limits"),
  973                        NULL, 0, NULL, 0,
  974                        CTL_PROC, PROC_CURPROC, PROC_PID_LIMIT, CTL_EOL);
  975 
  976 #define create_proc_plimit(s, n) do {                                   \
  977         sysctl_createv(clog, 0, NULL, NULL,                             \
  978                        CTLFLAG_PERMANENT,                               \
  979                        CTLTYPE_NODE, s,                                 \
  980                        SYSCTL_DESCR("Process " s " limits"),            \
  981                        NULL, 0, NULL, 0,                                \
  982                        CTL_PROC, PROC_CURPROC, PROC_PID_LIMIT, n,       \
  983                        CTL_EOL);                                        \
  984         sysctl_createv(clog, 0, NULL, NULL,                             \
  985                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE|CTLFLAG_ANYWRITE, \
  986                        CTLTYPE_QUAD, "soft",                            \
  987                        SYSCTL_DESCR("Process soft " s " limit"),        \
  988                        sysctl_proc_plimit, 0, NULL, 0,                  \
  989                        CTL_PROC, PROC_CURPROC, PROC_PID_LIMIT, n,       \
  990                        PROC_PID_LIMIT_TYPE_SOFT, CTL_EOL);              \
  991         sysctl_createv(clog, 0, NULL, NULL,                             \
  992                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE|CTLFLAG_ANYWRITE, \
  993                        CTLTYPE_QUAD, "hard",                            \
  994                        SYSCTL_DESCR("Process hard " s " limit"),        \
  995                        sysctl_proc_plimit, 0, NULL, 0,                  \
  996                        CTL_PROC, PROC_CURPROC, PROC_PID_LIMIT, n,       \
  997                        PROC_PID_LIMIT_TYPE_HARD, CTL_EOL);              \
  998         } while (0/*CONSTCOND*/)
  999 
 1000         create_proc_plimit("cputime",           PROC_PID_LIMIT_CPU);
 1001         create_proc_plimit("filesize",          PROC_PID_LIMIT_FSIZE);
 1002         create_proc_plimit("datasize",          PROC_PID_LIMIT_DATA);
 1003         create_proc_plimit("stacksize",         PROC_PID_LIMIT_STACK);
 1004         create_proc_plimit("coredumpsize",      PROC_PID_LIMIT_CORE);
 1005         create_proc_plimit("memoryuse",         PROC_PID_LIMIT_RSS);
 1006         create_proc_plimit("memorylocked",      PROC_PID_LIMIT_MEMLOCK);
 1007         create_proc_plimit("maxproc",           PROC_PID_LIMIT_NPROC);
 1008         create_proc_plimit("descriptors",       PROC_PID_LIMIT_NOFILE);
 1009         create_proc_plimit("sbsize",            PROC_PID_LIMIT_SBSIZE);
 1010         create_proc_plimit("vmemoryuse",        PROC_PID_LIMIT_AS);
 1011 
 1012 #undef create_proc_plimit
 1013 
 1014         sysctl_createv(clog, 0, NULL, NULL,
 1015                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE|CTLFLAG_ANYWRITE,
 1016                        CTLTYPE_INT, "stopfork",
 1017                        SYSCTL_DESCR("Stop process at fork(2)"),
 1018                        sysctl_proc_stop, 0, NULL, 0,
 1019                        CTL_PROC, PROC_CURPROC, PROC_PID_STOPFORK, CTL_EOL);
 1020         sysctl_createv(clog, 0, NULL, NULL,
 1021                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE|CTLFLAG_ANYWRITE,
 1022                        CTLTYPE_INT, "stopexec",
 1023                        SYSCTL_DESCR("Stop process at execve(2)"),
 1024                        sysctl_proc_stop, 0, NULL, 0,
 1025                        CTL_PROC, PROC_CURPROC, PROC_PID_STOPEXEC, CTL_EOL);
 1026         sysctl_createv(clog, 0, NULL, NULL,
 1027                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE|CTLFLAG_ANYWRITE,
 1028                        CTLTYPE_INT, "stopexit",
 1029                        SYSCTL_DESCR("Stop process before completing exit"),
 1030                        sysctl_proc_stop, 0, NULL, 0,
 1031                        CTL_PROC, PROC_CURPROC, PROC_PID_STOPEXIT, CTL_EOL);
 1032 }

Cache object: b28b75859465c4f45e78f14c087b3b48


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