[BACK]Return to kern_resource.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Annotation of src/sys/kern/kern_resource.c, Revision 1.106

1.106   ! elad        1: /*     $NetBSD: kern_resource.c,v 1.105 2006/09/13 10:07:42 elad Exp $ */
1.20      cgd         2:
1.17      cgd         3: /*-
1.19      cgd         4:  * Copyright (c) 1982, 1986, 1991, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
1.17      cgd         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.
1.72      agc        20:  * 3. Neither the name of the University nor the names of its contributors
1.17      cgd        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:  *
1.45      fvdl       36:  *     @(#)kern_resource.c     8.8 (Berkeley) 2/14/95
1.17      cgd        37:  */
1.61      lukem      38:
                     39: #include <sys/cdefs.h>
1.106   ! elad       40: __KERNEL_RCSID(0, "$NetBSD: kern_resource.c,v 1.105 2006/09/13 10:07:42 elad Exp $");
1.44      mrg        41:
1.17      cgd        42: #include <sys/param.h>
1.22      cgd        43: #include <sys/systm.h>
1.17      cgd        44: #include <sys/kernel.h>
1.19      cgd        45: #include <sys/file.h>
1.17      cgd        46: #include <sys/resourcevar.h>
                     47: #include <sys/malloc.h>
1.100     yamt       48: #include <sys/namei.h>
1.49      thorpej    49: #include <sys/pool.h>
1.17      cgd        50: #include <sys/proc.h>
1.74      atatat     51: #include <sys/sysctl.h>
1.101     elad       52: #include <sys/kauth.h>
1.17      cgd        53:
1.22      cgd        54: #include <sys/mount.h>
1.68      thorpej    55: #include <sys/sa.h>
1.22      cgd        56: #include <sys/syscallargs.h>
1.17      cgd        57:
1.43      mrg        58: #include <uvm/uvm_extern.h>
                     59:
1.17      cgd        60: /*
1.60      eeh        61:  * Maximum process data and stack limits.
                     62:  * They are variables so they are patchable.
                     63:  */
                     64: rlim_t maxdmap = MAXDSIZ;
                     65: rlim_t maxsmap = MAXSSIZ;
                     66:
1.82      matt       67: struct uihashhead *uihashtbl;
                     68: u_long uihash;         /* size of hash table - 1 */
1.88      christos   69: struct simplelock uihashtbl_slock = SIMPLELOCK_INITIALIZER;
1.82      matt       70:
1.79      christos   71:
1.60      eeh        72: /*
1.17      cgd        73:  * Resource controls and accounting.
                     74:  */
                     75:
1.25      cgd        76: int
1.98      thorpej    77: sys_getpriority(struct lwp *l, void *v, register_t *retval)
1.30      thorpej    78: {
1.54      augustss   79:        struct sys_getpriority_args /* {
1.22      cgd        80:                syscallarg(int) which;
1.81      kleink     81:                syscallarg(id_t) who;
1.30      thorpej    82:        } */ *uap = v;
1.68      thorpej    83:        struct proc *curp = l->l_proc, *p;
1.54      augustss   84:        int low = NZERO + PRIO_MAX + 1;
1.17      cgd        85:
1.22      cgd        86:        switch (SCARG(uap, which)) {
1.17      cgd        87:
                     88:        case PRIO_PROCESS:
1.22      cgd        89:                if (SCARG(uap, who) == 0)
1.17      cgd        90:                        p = curp;
                     91:                else
1.22      cgd        92:                        p = pfind(SCARG(uap, who));
1.17      cgd        93:                if (p == 0)
                     94:                        break;
                     95:                low = p->p_nice;
                     96:                break;
                     97:
                     98:        case PRIO_PGRP: {
1.54      augustss   99:                struct pgrp *pg;
1.17      cgd       100:
1.22      cgd       101:                if (SCARG(uap, who) == 0)
1.17      cgd       102:                        pg = curp->p_pgrp;
1.22      cgd       103:                else if ((pg = pgfind(SCARG(uap, who))) == NULL)
1.17      cgd       104:                        break;
1.64      matt      105:                LIST_FOREACH(p, &pg->pg_members, p_pglist) {
1.17      cgd       106:                        if (p->p_nice < low)
                    107:                                low = p->p_nice;
                    108:                }
                    109:                break;
                    110:        }
                    111:
                    112:        case PRIO_USER:
1.22      cgd       113:                if (SCARG(uap, who) == 0)
1.102     ad        114:                        SCARG(uap, who) = kauth_cred_geteuid(l->l_cred);
1.52      thorpej   115:                proclist_lock_read();
1.86      yamt      116:                PROCLIST_FOREACH(p, &allproc) {
1.102     ad        117:                        if (kauth_cred_geteuid(p->p_cred) ==
                    118:                            (uid_t) SCARG(uap, who) && p->p_nice < low)
1.17      cgd       119:                                low = p->p_nice;
1.64      matt      120:                }
1.51      thorpej   121:                proclist_unlock_read();
1.17      cgd       122:                break;
                    123:
                    124:        default:
                    125:                return (EINVAL);
                    126:        }
1.37      ws        127:        if (low == NZERO + PRIO_MAX + 1)
1.17      cgd       128:                return (ESRCH);
1.37      ws        129:        *retval = low - NZERO;
1.17      cgd       130:        return (0);
                    131: }
                    132:
                    133: /* ARGSUSED */
1.25      cgd       134: int
1.98      thorpej   135: sys_setpriority(struct lwp *l, void *v, register_t *retval)
1.30      thorpej   136: {
1.54      augustss  137:        struct sys_setpriority_args /* {
1.22      cgd       138:                syscallarg(int) which;
1.81      kleink    139:                syscallarg(id_t) who;
1.22      cgd       140:                syscallarg(int) prio;
1.30      thorpej   141:        } */ *uap = v;
1.68      thorpej   142:        struct proc *curp = l->l_proc, *p;
1.17      cgd       143:        int found = 0, error = 0;
                    144:
1.22      cgd       145:        switch (SCARG(uap, which)) {
1.17      cgd       146:
                    147:        case PRIO_PROCESS:
1.22      cgd       148:                if (SCARG(uap, who) == 0)
1.17      cgd       149:                        p = curp;
                    150:                else
1.22      cgd       151:                        p = pfind(SCARG(uap, who));
1.17      cgd       152:                if (p == 0)
                    153:                        break;
1.102     ad        154:                error = donice(l, p, SCARG(uap, prio));
1.17      cgd       155:                found++;
                    156:                break;
                    157:
                    158:        case PRIO_PGRP: {
1.54      augustss  159:                struct pgrp *pg;
1.87      perry     160:
1.22      cgd       161:                if (SCARG(uap, who) == 0)
1.17      cgd       162:                        pg = curp->p_pgrp;
1.22      cgd       163:                else if ((pg = pgfind(SCARG(uap, who))) == NULL)
1.17      cgd       164:                        break;
1.64      matt      165:                LIST_FOREACH(p, &pg->pg_members, p_pglist) {
1.102     ad        166:                        error = donice(l, p, SCARG(uap, prio));
1.17      cgd       167:                        found++;
                    168:                }
                    169:                break;
                    170:        }
                    171:
                    172:        case PRIO_USER:
1.22      cgd       173:                if (SCARG(uap, who) == 0)
1.102     ad        174:                        SCARG(uap, who) = kauth_cred_geteuid(l->l_cred);
1.52      thorpej   175:                proclist_lock_read();
1.86      yamt      176:                PROCLIST_FOREACH(p, &allproc) {
1.102     ad        177:                        if (kauth_cred_geteuid(p->p_cred) ==
                    178:                            (uid_t)SCARG(uap, who)) {
                    179:                                error = donice(l, p, SCARG(uap, prio));
1.17      cgd       180:                                found++;
                    181:                        }
1.64      matt      182:                }
1.51      thorpej   183:                proclist_unlock_read();
1.17      cgd       184:                break;
                    185:
                    186:        default:
                    187:                return (EINVAL);
                    188:        }
                    189:        if (found == 0)
                    190:                return (ESRCH);
                    191:        return (error);
                    192: }
                    193:
1.25      cgd       194: int
1.102     ad        195: donice(struct lwp *l, struct proc *chgp, int n)
1.17      cgd       196: {
1.102     ad        197:        kauth_cred_t cred = l->l_cred;
1.59      thorpej   198:        int s;
1.17      cgd       199:
1.101     elad      200:        if (kauth_cred_geteuid(cred) && kauth_cred_getuid(cred) &&
                    201:            kauth_cred_geteuid(cred) != kauth_cred_geteuid(chgp->p_cred) &&
                    202:            kauth_cred_getuid(cred) != kauth_cred_geteuid(chgp->p_cred))
1.17      cgd       203:                return (EPERM);
                    204:        if (n > PRIO_MAX)
                    205:                n = PRIO_MAX;
                    206:        if (n < PRIO_MIN)
                    207:                n = PRIO_MIN;
1.37      ws        208:        n += NZERO;
1.104     elad      209:        if (n < chgp->p_nice && kauth_authorize_process(cred,
                    210:            KAUTH_PROCESS_RESOURCE, chgp, (void *)KAUTH_REQ_PROCESS_RESOURCE_NICE,
                    211:            (void *)(u_long)n, NULL))
1.17      cgd       212:                return (EACCES);
                    213:        chgp->p_nice = n;
1.59      thorpej   214:        SCHED_LOCK(s);
1.68      thorpej   215:        (void)resetprocpriority(chgp);
1.59      thorpej   216:        SCHED_UNLOCK(s);
1.17      cgd       217:        return (0);
                    218: }
                    219:
                    220: /* ARGSUSED */
1.25      cgd       221: int
1.98      thorpej   222: sys_setrlimit(struct lwp *l, void *v, register_t *retval)
1.30      thorpej   223: {
1.54      augustss  224:        struct sys_setrlimit_args /* {
1.42      mycroft   225:                syscallarg(int) which;
1.39      cgd       226:                syscallarg(const struct rlimit *) rlp;
1.30      thorpej   227:        } */ *uap = v;
1.42      mycroft   228:        int which = SCARG(uap, which);
1.19      cgd       229:        struct rlimit alim;
1.17      cgd       230:        int error;
                    231:
1.46      perry     232:        error = copyin(SCARG(uap, rlp), &alim, sizeof(struct rlimit));
1.33      christos  233:        if (error)
1.17      cgd       234:                return (error);
1.102     ad        235:        return (dosetrlimit(l, l->l_proc, which, &alim));
1.17      cgd       236: }
                    237:
                    238: int
1.102     ad        239: dosetrlimit(struct lwp *l, struct proc *p, int which, struct rlimit *limp)
1.17      cgd       240: {
1.54      augustss  241:        struct rlimit *alimp;
1.83      pk        242:        struct plimit *oldplim;
1.17      cgd       243:        int error;
                    244:
1.67      itojun    245:        if ((u_int)which >= RLIM_NLIMITS)
1.17      cgd       246:                return (EINVAL);
1.38      matthias  247:
                    248:        if (limp->rlim_cur < 0 || limp->rlim_max < 0)
                    249:                return (EINVAL);
                    250:
1.17      cgd       251:        alimp = &p->p_rlimit[which];
1.53      bouyer    252:        /* if we don't change the value, no need to limcopy() */
                    253:        if (limp->rlim_cur == alimp->rlim_cur &&
                    254:            limp->rlim_max == alimp->rlim_max)
                    255:                return 0;
                    256:
1.62      jdolecek  257:        if (limp->rlim_cur > limp->rlim_max) {
                    258:                /*
                    259:                 * This is programming error. According to SUSv2, we should
                    260:                 * return error in this case.
                    261:                 */
                    262:                return (EINVAL);
                    263:        }
1.102     ad        264:        if (limp->rlim_max > alimp->rlim_max && (error =
1.104     elad      265:            kauth_authorize_process(l->l_cred, KAUTH_PROCESS_RESOURCE,
                    266:            p, (void *)KAUTH_REQ_PROCESS_RESOURCE_RLIMIT, limp,
1.105     elad      267:            (void *)(u_long)which)))
1.17      cgd       268:                        return (error);
1.62      jdolecek  269:
1.17      cgd       270:        if (p->p_limit->p_refcnt > 1 &&
                    271:            (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
1.83      pk        272:                p->p_limit = limcopy(oldplim = p->p_limit);
                    273:                limfree(oldplim);
1.17      cgd       274:                alimp = &p->p_rlimit[which];
                    275:        }
                    276:
                    277:        switch (which) {
                    278:
                    279:        case RLIMIT_DATA:
1.19      cgd       280:                if (limp->rlim_cur > maxdmap)
                    281:                        limp->rlim_cur = maxdmap;
                    282:                if (limp->rlim_max > maxdmap)
                    283:                        limp->rlim_max = maxdmap;
1.17      cgd       284:                break;
                    285:
                    286:        case RLIMIT_STACK:
1.19      cgd       287:                if (limp->rlim_cur > maxsmap)
                    288:                        limp->rlim_cur = maxsmap;
                    289:                if (limp->rlim_max > maxsmap)
                    290:                        limp->rlim_max = maxsmap;
1.62      jdolecek  291:
                    292:                /*
                    293:                 * Return EINVAL if the new stack size limit is lower than
                    294:                 * current usage. Otherwise, the process would get SIGSEGV the
                    295:                 * moment it would try to access anything on it's current stack.
                    296:                 * This conforms to SUSv2.
                    297:                 */
                    298:                if (limp->rlim_cur < p->p_vmspace->vm_ssize * PAGE_SIZE
                    299:                    || limp->rlim_max < p->p_vmspace->vm_ssize * PAGE_SIZE)
                    300:                        return (EINVAL);
1.40      enami     301:
1.17      cgd       302:                /*
1.40      enami     303:                 * Stack is allocated to the max at exec time with
                    304:                 * only "rlim_cur" bytes accessible (In other words,
                    305:                 * allocates stack dividing two contiguous regions at
                    306:                 * "rlim_cur" bytes boundary).
                    307:                 *
                    308:                 * Since allocation is done in terms of page, roundup
                    309:                 * "rlim_cur" (otherwise, contiguous regions
                    310:                 * overlap).  If stack limit is going up make more
                    311:                 * accessible, if going down make inaccessible.
1.17      cgd       312:                 */
1.40      enami     313:                limp->rlim_cur = round_page(limp->rlim_cur);
1.17      cgd       314:                if (limp->rlim_cur != alimp->rlim_cur) {
1.48      eeh       315:                        vaddr_t addr;
                    316:                        vsize_t size;
1.17      cgd       317:                        vm_prot_t prot;
                    318:
                    319:                        if (limp->rlim_cur > alimp->rlim_cur) {
1.73      chs       320:                                prot = VM_PROT_READ | VM_PROT_WRITE;
1.17      cgd       321:                                size = limp->rlim_cur - alimp->rlim_cur;
1.91      fvdl      322:                                addr = (vaddr_t)p->p_vmspace->vm_minsaddr -
                    323:                                    limp->rlim_cur;
1.17      cgd       324:                        } else {
                    325:                                prot = VM_PROT_NONE;
                    326:                                size = alimp->rlim_cur - limp->rlim_cur;
1.91      fvdl      327:                                addr = (vaddr_t)p->p_vmspace->vm_minsaddr -
                    328:                                     alimp->rlim_cur;
1.17      cgd       329:                        }
1.43      mrg       330:                        (void) uvm_map_protect(&p->p_vmspace->vm_map,
1.102     ad        331:                            addr, addr+size, prot, FALSE);
1.17      cgd       332:                }
                    333:                break;
1.19      cgd       334:
                    335:        case RLIMIT_NOFILE:
                    336:                if (limp->rlim_cur > maxfiles)
                    337:                        limp->rlim_cur = maxfiles;
                    338:                if (limp->rlim_max > maxfiles)
                    339:                        limp->rlim_max = maxfiles;
                    340:                break;
                    341:
                    342:        case RLIMIT_NPROC:
                    343:                if (limp->rlim_cur > maxproc)
                    344:                        limp->rlim_cur = maxproc;
                    345:                if (limp->rlim_max > maxproc)
                    346:                        limp->rlim_max = maxproc;
                    347:                break;
1.17      cgd       348:        }
                    349:        *alimp = *limp;
                    350:        return (0);
                    351: }
                    352:
                    353: /* ARGSUSED */
1.25      cgd       354: int
1.98      thorpej   355: sys_getrlimit(struct lwp *l, void *v, register_t *retval)
1.30      thorpej   356: {
1.54      augustss  357:        struct sys_getrlimit_args /* {
1.42      mycroft   358:                syscallarg(int) which;
1.22      cgd       359:                syscallarg(struct rlimit *) rlp;
1.30      thorpej   360:        } */ *uap = v;
1.68      thorpej   361:        struct proc *p = l->l_proc;
1.42      mycroft   362:        int which = SCARG(uap, which);
1.17      cgd       363:
1.67      itojun    364:        if ((u_int)which >= RLIM_NLIMITS)
1.17      cgd       365:                return (EINVAL);
1.42      mycroft   366:        return (copyout(&p->p_rlimit[which], SCARG(uap, rlp),
1.46      perry     367:            sizeof(struct rlimit)));
1.17      cgd       368: }
                    369:
                    370: /*
                    371:  * Transform the running time and tick information in proc p into user,
                    372:  * system, and interrupt time usage.
                    373:  */
1.25      cgd       374: void
1.98      thorpej   375: calcru(struct proc *p, struct timeval *up, struct timeval *sp,
                    376:     struct timeval *ip)
1.17      cgd       377: {
1.54      augustss  378:        u_quad_t u, st, ut, it, tot;
1.70      dsl       379:        unsigned long sec;
                    380:        long usec;
1.54      augustss  381:        int s;
1.17      cgd       382:        struct timeval tv;
1.68      thorpej   383:        struct lwp *l;
1.17      cgd       384:
                    385:        s = splstatclock();
                    386:        st = p->p_sticks;
                    387:        ut = p->p_uticks;
                    388:        it = p->p_iticks;
                    389:        splx(s);
                    390:
                    391:        sec = p->p_rtime.tv_sec;
                    392:        usec = p->p_rtime.tv_usec;
1.70      dsl       393:        LIST_FOREACH(l, &p->p_lwps, l_sibling) {
1.68      thorpej   394:                if (l->l_stat == LSONPROC) {
                    395:                        struct schedstate_percpu *spc;
1.87      perry     396:
1.68      thorpej   397:                        KDASSERT(l->l_cpu != NULL);
                    398:                        spc = &l->l_cpu->ci_schedstate;
1.87      perry     399:
1.68      thorpej   400:                        /*
                    401:                         * Adjust for the current time slice.  This is
                    402:                         * actually fairly important since the error
                    403:                         * here is on the order of a time quantum,
                    404:                         * which is much greater than the sampling
1.87      perry     405:                         * error.
1.68      thorpej   406:                         */
                    407:                        microtime(&tv);
                    408:                        sec += tv.tv_sec - spc->spc_runtime.tv_sec;
                    409:                        usec += tv.tv_usec - spc->spc_runtime.tv_usec;
                    410:                }
1.17      cgd       411:        }
1.69      dsl       412:
                    413:        tot = st + ut + it;
1.70      dsl       414:        u = sec * 1000000ull + usec;
                    415:
1.69      dsl       416:        if (tot == 0) {
                    417:                /* No ticks, so can't use to share time out, split 50-50 */
1.70      dsl       418:                st = ut = u / 2;
                    419:        } else {
                    420:                st = (u * st) / tot;
                    421:                ut = (u * ut) / tot;
1.69      dsl       422:        }
1.17      cgd       423:        sp->tv_sec = st / 1000000;
                    424:        sp->tv_usec = st % 1000000;
                    425:        up->tv_sec = ut / 1000000;
                    426:        up->tv_usec = ut % 1000000;
                    427:        if (ip != NULL) {
1.70      dsl       428:                if (it != 0)
                    429:                        it = (u * it) / tot;
1.17      cgd       430:                ip->tv_sec = it / 1000000;
                    431:                ip->tv_usec = it % 1000000;
                    432:        }
                    433: }
                    434:
                    435: /* ARGSUSED */
1.25      cgd       436: int
1.98      thorpej   437: sys_getrusage(struct lwp *l, void *v, register_t *retval)
1.30      thorpej   438: {
1.54      augustss  439:        struct sys_getrusage_args /* {
1.22      cgd       440:                syscallarg(int) who;
                    441:                syscallarg(struct rusage *) rusage;
1.30      thorpej   442:        } */ *uap = v;
1.54      augustss  443:        struct rusage *rup;
1.68      thorpej   444:        struct proc *p = l->l_proc;
1.17      cgd       445:
1.22      cgd       446:        switch (SCARG(uap, who)) {
1.17      cgd       447:
1.19      cgd       448:        case RUSAGE_SELF:
1.17      cgd       449:                rup = &p->p_stats->p_ru;
                    450:                calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
                    451:                break;
                    452:
                    453:        case RUSAGE_CHILDREN:
                    454:                rup = &p->p_stats->p_cru;
                    455:                break;
                    456:
                    457:        default:
                    458:                return (EINVAL);
                    459:        }
1.46      perry     460:        return (copyout(rup, SCARG(uap, rusage), sizeof(struct rusage)));
1.17      cgd       461: }
                    462:
1.25      cgd       463: void
1.98      thorpej   464: ruadd(struct rusage *ru, struct rusage *ru2)
1.17      cgd       465: {
1.54      augustss  466:        long *ip, *ip2;
                    467:        int i;
1.17      cgd       468:
1.27      mycroft   469:        timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime);
                    470:        timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime);
1.17      cgd       471:        if (ru->ru_maxrss < ru2->ru_maxrss)
                    472:                ru->ru_maxrss = ru2->ru_maxrss;
                    473:        ip = &ru->ru_first; ip2 = &ru2->ru_first;
                    474:        for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
                    475:                *ip++ += *ip2++;
                    476: }
                    477:
                    478: /*
                    479:  * Make a copy of the plimit structure.
                    480:  * We share these structures copy-on-write after fork,
                    481:  * and copy when a limit is changed.
                    482:  */
                    483: struct plimit *
1.98      thorpej   484: limcopy(struct plimit *lim)
1.17      cgd       485: {
1.54      augustss  486:        struct plimit *newlim;
1.83      pk        487:        size_t l = 0;
                    488:
                    489:        simple_lock(&lim->p_slock);
                    490:        if (lim->pl_corename != defcorename)
                    491:                l = strlen(lim->pl_corename) + 1;
                    492:        simple_unlock(&lim->p_slock);
1.17      cgd       493:
1.49      thorpej   494:        newlim = pool_get(&plimit_pool, PR_WAITOK);
1.83      pk        495:        simple_lock_init(&newlim->p_slock);
                    496:        newlim->p_lflags = 0;
                    497:        newlim->p_refcnt = 1;
                    498:        newlim->pl_corename = (l != 0)
                    499:                ? malloc(l, M_TEMP, M_WAITOK)
                    500:                : defcorename;
                    501:
                    502:        simple_lock(&lim->p_slock);
1.47      perry     503:        memcpy(newlim->pl_rlimit, lim->pl_rlimit,
1.17      cgd       504:            sizeof(struct rlimit) * RLIM_NLIMITS);
1.83      pk        505:
                    506:        if (l != 0)
1.71      itojun    507:                strlcpy(newlim->pl_corename, lim->pl_corename, l);
1.83      pk        508:        simple_unlock(&lim->p_slock);
                    509:
1.32      mycroft   510:        return (newlim);
                    511: }
                    512:
                    513: void
1.98      thorpej   514: limfree(struct plimit *lim)
1.32      mycroft   515: {
1.84      christos  516:        int n;
1.85      kleink    517:
1.83      pk        518:        simple_lock(&lim->p_slock);
1.84      christos  519:        n = --lim->p_refcnt;
1.83      pk        520:        simple_unlock(&lim->p_slock);
                    521:        if (n > 0)
1.32      mycroft   522:                return;
1.53      bouyer    523: #ifdef DIAGNOSTIC
1.83      pk        524:        if (n < 0)
1.53      bouyer    525:                panic("limfree");
                    526: #endif
                    527:        if (lim->pl_corename != defcorename)
                    528:                free(lim->pl_corename, M_TEMP);
1.49      thorpej   529:        pool_put(&plimit_pool, lim);
1.68      thorpej   530: }
                    531:
                    532: struct pstats *
1.98      thorpej   533: pstatscopy(struct pstats *ps)
1.68      thorpej   534: {
1.87      perry     535:
1.68      thorpej   536:        struct pstats *newps;
                    537:
                    538:        newps = pool_get(&pstats_pool, PR_WAITOK);
                    539:
                    540:        memset(&newps->pstat_startzero, 0,
                    541:        (unsigned) ((caddr_t)&newps->pstat_endzero -
                    542:                    (caddr_t)&newps->pstat_startzero));
                    543:        memcpy(&newps->pstat_startcopy, &ps->pstat_startcopy,
                    544:        ((caddr_t)&newps->pstat_endcopy -
                    545:         (caddr_t)&newps->pstat_startcopy));
                    546:
                    547:        return (newps);
                    548:
                    549: }
                    550:
                    551: void
1.98      thorpej   552: pstatsfree(struct pstats *ps)
1.68      thorpej   553: {
                    554:
                    555:        pool_put(&pstats_pool, ps);
1.74      atatat    556: }
                    557:
                    558: /*
                    559:  * sysctl interface in five parts
                    560:  */
                    561:
                    562: /*
                    563:  * a routine for sysctl proc subtree helpers that need to pick a valid
                    564:  * process by pid.
                    565:  */
                    566: static int
1.102     ad        567: sysctl_proc_findproc(struct lwp *l, struct proc **p2, pid_t pid)
1.74      atatat    568: {
                    569:        struct proc *ptmp;
1.101     elad      570:        int error = 0;
1.74      atatat    571:
                    572:        if (pid == PROC_CURPROC)
1.102     ad        573:                ptmp = l->l_proc;
1.74      atatat    574:        else if ((ptmp = pfind(pid)) == NULL)
                    575:                error = ESRCH;
                    576:        else {
1.104     elad      577:                boolean_t isroot = kauth_authorize_generic(l->l_cred,
                    578:                    KAUTH_GENERIC_ISSUSER, NULL);
1.74      atatat    579:                /*
                    580:                 * suid proc of ours or proc not ours
                    581:                 */
1.102     ad        582:                if (kauth_cred_getuid(l->l_cred) !=
                    583:                    kauth_cred_getuid(ptmp->p_cred) ||
                    584:                    kauth_cred_getuid(l->l_cred) !=
                    585:                    kauth_cred_getsvuid(ptmp->p_cred))
1.104     elad      586:                        error = isroot ? 0 : EPERM;
1.74      atatat    587:
                    588:                /*
                    589:                 * sgid proc has sgid back to us temporarily
                    590:                 */
1.102     ad        591:                else if (kauth_cred_getgid(ptmp->p_cred) !=
                    592:                    kauth_cred_getsvgid(ptmp->p_cred))
1.104     elad      593:                        error = isroot ? 0 : EPERM;
1.74      atatat    594:
                    595:                /*
                    596:                 * our rgid must be in target's group list (ie,
                    597:                 * sub-processes started by a sgid process)
                    598:                 */
                    599:                else {
1.101     elad      600:                        int ismember = 0;
                    601:
1.102     ad        602:                        if (kauth_cred_ismember_gid(l->l_cred,
1.101     elad      603:                            kauth_cred_getgid(ptmp->p_cred), &ismember) != 0 ||
                    604:                            !ismember) {
1.104     elad      605:                                error = isroot ? 0 : EPERM;
1.74      atatat    606:                        }
                    607:                }
                    608:        }
                    609:
                    610:        *p2 = ptmp;
                    611:        return (error);
                    612: }
                    613:
                    614: /*
                    615:  * sysctl helper routine for setting a process's specific corefile
                    616:  * name.  picks the process based on the given pid and checks the
                    617:  * correctness of the new value.
                    618:  */
                    619: static int
                    620: sysctl_proc_corename(SYSCTLFN_ARGS)
                    621: {
1.102     ad        622:        struct proc *ptmp;
1.83      pk        623:        struct plimit *lim;
1.74      atatat    624:        int error = 0, len;
1.100     yamt      625:        char *cname;
                    626:        char *tmp;
1.74      atatat    627:        struct sysctlnode node;
                    628:
                    629:        /*
                    630:         * is this all correct?
                    631:         */
                    632:        if (namelen != 0)
                    633:                return (EINVAL);
                    634:        if (name[-1] != PROC_PID_CORENAME)
                    635:                return (EINVAL);
                    636:
                    637:        /*
                    638:         * whom are we tweaking?
                    639:         */
1.102     ad        640:        error = sysctl_proc_findproc(l, &ptmp, (pid_t)name[-2]);
1.74      atatat    641:        if (error)
                    642:                return (error);
                    643:
1.100     yamt      644:        cname = PNBUF_GET();
1.74      atatat    645:        /*
                    646:         * let them modify a temporary copy of the core name
                    647:         */
                    648:        node = *rnode;
1.100     yamt      649:        strlcpy(cname, ptmp->p_limit->pl_corename, MAXPATHLEN);
1.74      atatat    650:        node.sysctl_data = cname;
                    651:        error = sysctl_lookup(SYSCTLFN_CALL(&node));
                    652:
                    653:        /*
                    654:         * if that failed, or they have nothing new to say, or we've
                    655:         * heard it before...
                    656:         */
                    657:        if (error || newp == NULL ||
1.100     yamt      658:            strcmp(cname, ptmp->p_limit->pl_corename) == 0) {
                    659:                goto done;
                    660:        }
1.74      atatat    661:
1.106   ! elad      662:        if (kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CORENAME,
        !           663:            l->l_proc, NULL, NULL, NULL) != 0)
1.103     elad      664:                return (EPERM);
                    665:
1.74      atatat    666:        /*
                    667:         * no error yet and cname now has the new core name in it.
                    668:         * let's see if it looks acceptable.  it must be either "core"
                    669:         * or end in ".core" or "/core".
                    670:         */
                    671:        len = strlen(cname);
1.100     yamt      672:        if (len < 4) {
                    673:                error = EINVAL;
                    674:        } else if (strcmp(cname + len - 4, "core") != 0) {
                    675:                error = EINVAL;
                    676:        } else if (len > 4 && cname[len - 5] != '/' && cname[len - 5] != '.') {
                    677:                error = EINVAL;
                    678:        }
                    679:        if (error != 0) {
                    680:                goto done;
                    681:        }
1.74      atatat    682:
                    683:        /*
                    684:         * hmm...looks good.  now...where do we put it?
                    685:         */
                    686:        tmp = malloc(len + 1, M_TEMP, M_WAITOK|M_CANFAIL);
1.100     yamt      687:        if (tmp == NULL) {
                    688:                error = ENOMEM;
                    689:                goto done;
                    690:        }
1.74      atatat    691:        strlcpy(tmp, cname, len + 1);
                    692:
1.83      pk        693:        lim = ptmp->p_limit;
                    694:        if (lim->p_refcnt > 1 && (lim->p_lflags & PL_SHAREMOD) == 0) {
                    695:                ptmp->p_limit = limcopy(lim);
                    696:                limfree(lim);
                    697:                lim = ptmp->p_limit;
                    698:        }
                    699:        if (lim->pl_corename != defcorename)
                    700:                free(lim->pl_corename, M_TEMP);
                    701:        lim->pl_corename = tmp;
1.100     yamt      702: done:
                    703:        PNBUF_PUT(cname);
                    704:        return error;
1.74      atatat    705: }
                    706:
                    707: /*
                    708:  * sysctl helper routine for checking/setting a process's stop flags,
                    709:  * one for fork and one for exec.
                    710:  */
                    711: static int
                    712: sysctl_proc_stop(SYSCTLFN_ARGS)
                    713: {
1.102     ad        714:        struct proc *ptmp;
1.74      atatat    715:        int i, f, error = 0;
                    716:        struct sysctlnode node;
                    717:
                    718:        if (namelen != 0)
                    719:                return (EINVAL);
                    720:
1.102     ad        721:        error = sysctl_proc_findproc(l, &ptmp, (pid_t)name[-2]);
1.74      atatat    722:        if (error)
                    723:                return (error);
                    724:
                    725:        switch (rnode->sysctl_num) {
                    726:        case PROC_PID_STOPFORK:
                    727:                f = P_STOPFORK;
                    728:                break;
                    729:        case PROC_PID_STOPEXEC:
                    730:                f = P_STOPEXEC;
                    731:                break;
                    732:        case PROC_PID_STOPEXIT:
                    733:                f = P_STOPEXIT;
                    734:                break;
                    735:        default:
                    736:                return (EINVAL);
                    737:        }
                    738:
                    739:        i = (ptmp->p_flag & f) ? 1 : 0;
                    740:        node = *rnode;
                    741:        node.sysctl_data = &i;
                    742:        error = sysctl_lookup(SYSCTLFN_CALL(&node));
                    743:        if (error || newp == NULL)
                    744:                return (error);
                    745:
                    746:        if (i)
                    747:                ptmp->p_flag |= f;
                    748:        else
                    749:                ptmp->p_flag &= ~f;
                    750:
                    751:        return (0);
                    752: }
                    753:
                    754: /*
                    755:  * sysctl helper routine for a process's rlimits as exposed by sysctl.
                    756:  */
                    757: static int
                    758: sysctl_proc_plimit(SYSCTLFN_ARGS)
                    759: {
1.102     ad        760:        struct proc *ptmp;
1.74      atatat    761:        u_int limitno;
                    762:        int which, error = 0;
                    763:         struct rlimit alim;
                    764:        struct sysctlnode node;
                    765:
                    766:        if (namelen != 0)
                    767:                return (EINVAL);
                    768:
                    769:        which = name[-1];
                    770:        if (which != PROC_PID_LIMIT_TYPE_SOFT &&
                    771:            which != PROC_PID_LIMIT_TYPE_HARD)
                    772:                return (EINVAL);
                    773:
                    774:        limitno = name[-2] - 1;
                    775:        if (limitno >= RLIM_NLIMITS)
                    776:                return (EINVAL);
                    777:
                    778:        if (name[-3] != PROC_PID_LIMIT)
                    779:                return (EINVAL);
                    780:
1.102     ad        781:        error = sysctl_proc_findproc(l, &ptmp, (pid_t)name[-4]);
1.74      atatat    782:        if (error)
                    783:                return (error);
                    784:
                    785:        node = *rnode;
                    786:        memcpy(&alim, &ptmp->p_rlimit[limitno], sizeof(alim));
                    787:        if (which == PROC_PID_LIMIT_TYPE_HARD)
                    788:                node.sysctl_data = &alim.rlim_max;
                    789:        else
                    790:                node.sysctl_data = &alim.rlim_cur;
                    791:
                    792:        error = sysctl_lookup(SYSCTLFN_CALL(&node));
                    793:        if (error || newp == NULL)
                    794:                return (error);
                    795:
1.102     ad        796:        return (dosetrlimit(l, ptmp, limitno, &alim));
1.74      atatat    797: }
                    798:
                    799: /*
                    800:  * and finally, the actually glue that sticks it to the tree
                    801:  */
                    802: SYSCTL_SETUP(sysctl_proc_setup, "sysctl proc subtree setup")
                    803: {
                    804:
1.76      atatat    805:        sysctl_createv(clog, 0, NULL, NULL,
                    806:                       CTLFLAG_PERMANENT,
1.74      atatat    807:                       CTLTYPE_NODE, "proc", NULL,
                    808:                       NULL, 0, NULL, 0,
                    809:                       CTL_PROC, CTL_EOL);
1.76      atatat    810:        sysctl_createv(clog, 0, NULL, NULL,
                    811:                       CTLFLAG_PERMANENT|CTLFLAG_ANYNUMBER,
1.78      atatat    812:                       CTLTYPE_NODE, "curproc",
                    813:                       SYSCTL_DESCR("Per-process settings"),
1.74      atatat    814:                       NULL, 0, NULL, 0,
                    815:                       CTL_PROC, PROC_CURPROC, CTL_EOL);
                    816:
1.76      atatat    817:        sysctl_createv(clog, 0, NULL, NULL,
1.103     elad      818:                       CTLFLAG_PERMANENT|CTLFLAG_READWRITE|CTLFLAG_ANYWRITE,
1.78      atatat    819:                       CTLTYPE_STRING, "corename",
                    820:                       SYSCTL_DESCR("Core file name"),
1.74      atatat    821:                       sysctl_proc_corename, 0, NULL, MAXPATHLEN,
                    822:                       CTL_PROC, PROC_CURPROC, PROC_PID_CORENAME, CTL_EOL);
1.76      atatat    823:        sysctl_createv(clog, 0, NULL, NULL,
                    824:                       CTLFLAG_PERMANENT,
1.78      atatat    825:                       CTLTYPE_NODE, "rlimit",
                    826:                       SYSCTL_DESCR("Process limits"),
1.74      atatat    827:                       NULL, 0, NULL, 0,
                    828:                       CTL_PROC, PROC_CURPROC, PROC_PID_LIMIT, CTL_EOL);
                    829:
                    830: #define create_proc_plimit(s, n) do {                                  \
1.76      atatat    831:        sysctl_createv(clog, 0, NULL, NULL,                             \
                    832:                       CTLFLAG_PERMANENT,                               \
1.78      atatat    833:                       CTLTYPE_NODE, s,                                 \
                    834:                       SYSCTL_DESCR("Process " s " limits"),            \
1.74      atatat    835:                       NULL, 0, NULL, 0,                                \
                    836:                       CTL_PROC, PROC_CURPROC, PROC_PID_LIMIT, n,       \
                    837:                       CTL_EOL);                                        \
1.76      atatat    838:        sysctl_createv(clog, 0, NULL, NULL,                             \
                    839:                       CTLFLAG_PERMANENT|CTLFLAG_READWRITE|CTLFLAG_ANYWRITE, \
1.78      atatat    840:                       CTLTYPE_QUAD, "soft",                            \
                    841:                       SYSCTL_DESCR("Process soft " s " limit"),        \
1.74      atatat    842:                       sysctl_proc_plimit, 0, NULL, 0,                  \
                    843:                       CTL_PROC, PROC_CURPROC, PROC_PID_LIMIT, n,       \
                    844:                       PROC_PID_LIMIT_TYPE_SOFT, CTL_EOL);              \
1.76      atatat    845:        sysctl_createv(clog, 0, NULL, NULL,                             \
                    846:                       CTLFLAG_PERMANENT|CTLFLAG_READWRITE|CTLFLAG_ANYWRITE, \
1.78      atatat    847:                       CTLTYPE_QUAD, "hard",                            \
                    848:                       SYSCTL_DESCR("Process hard " s " limit"),        \
1.74      atatat    849:                       sysctl_proc_plimit, 0, NULL, 0,                  \
                    850:                       CTL_PROC, PROC_CURPROC, PROC_PID_LIMIT, n,       \
                    851:                       PROC_PID_LIMIT_TYPE_HARD, CTL_EOL);              \
                    852:        } while (0/*CONSTCOND*/)
                    853:
                    854:        create_proc_plimit("cputime",           PROC_PID_LIMIT_CPU);
                    855:        create_proc_plimit("filesize",          PROC_PID_LIMIT_FSIZE);
                    856:        create_proc_plimit("datasize",          PROC_PID_LIMIT_DATA);
                    857:        create_proc_plimit("stacksize",         PROC_PID_LIMIT_STACK);
                    858:        create_proc_plimit("coredumpsize",      PROC_PID_LIMIT_CORE);
                    859:        create_proc_plimit("memoryuse",         PROC_PID_LIMIT_RSS);
                    860:        create_proc_plimit("memorylocked",      PROC_PID_LIMIT_MEMLOCK);
                    861:        create_proc_plimit("maxproc",           PROC_PID_LIMIT_NPROC);
                    862:        create_proc_plimit("descriptors",       PROC_PID_LIMIT_NOFILE);
1.79      christos  863:        create_proc_plimit("sbsize",            PROC_PID_LIMIT_SBSIZE);
1.74      atatat    864:
                    865: #undef create_proc_plimit
                    866:
1.76      atatat    867:        sysctl_createv(clog, 0, NULL, NULL,
                    868:                       CTLFLAG_PERMANENT|CTLFLAG_READWRITE|CTLFLAG_ANYWRITE,
1.78      atatat    869:                       CTLTYPE_INT, "stopfork",
                    870:                       SYSCTL_DESCR("Stop process at fork(2)"),
1.74      atatat    871:                       sysctl_proc_stop, 0, NULL, 0,
                    872:                       CTL_PROC, PROC_CURPROC, PROC_PID_STOPFORK, CTL_EOL);
1.76      atatat    873:        sysctl_createv(clog, 0, NULL, NULL,
                    874:                       CTLFLAG_PERMANENT|CTLFLAG_READWRITE|CTLFLAG_ANYWRITE,
1.78      atatat    875:                       CTLTYPE_INT, "stopexec",
                    876:                       SYSCTL_DESCR("Stop process at execve(2)"),
1.74      atatat    877:                       sysctl_proc_stop, 0, NULL, 0,
                    878:                       CTL_PROC, PROC_CURPROC, PROC_PID_STOPEXEC, CTL_EOL);
1.76      atatat    879:        sysctl_createv(clog, 0, NULL, NULL,
                    880:                       CTLFLAG_PERMANENT|CTLFLAG_READWRITE|CTLFLAG_ANYWRITE,
1.78      atatat    881:                       CTLTYPE_INT, "stopexit",
                    882:                       SYSCTL_DESCR("Stop process before completing exit"),
1.74      atatat    883:                       sysctl_proc_stop, 0, NULL, 0,
                    884:                       CTL_PROC, PROC_CURPROC, PROC_PID_STOPEXIT, CTL_EOL);
1.17      cgd       885: }
1.79      christos  886:
1.88      christos  887: struct uidinfo *
                    888: uid_find(uid_t uid)
1.79      christos  889: {
                    890:        struct uidinfo *uip;
1.90      christos  891:        struct uidinfo *newuip = NULL;
1.79      christos  892:        struct uihashhead *uipp;
                    893:
                    894:        uipp = UIHASH(uid);
                    895:
1.90      christos  896: again:
1.89      christos  897:        simple_lock(&uihashtbl_slock);
1.79      christos  898:        LIST_FOREACH(uip, uipp, ui_hash)
1.88      christos  899:                if (uip->ui_uid == uid) {
                    900:                        simple_unlock(&uihashtbl_slock);
1.90      christos  901:                        if (newuip)
                    902:                                free(newuip, M_PROC);
1.79      christos  903:                        return uip;
1.88      christos  904:                }
1.79      christos  905:
1.90      christos  906:        if (newuip == NULL) {
                    907:                simple_unlock(&uihashtbl_slock);
                    908:                newuip = malloc(sizeof(*uip), M_PROC, M_WAITOK | M_ZERO);
                    909:                goto again;
                    910:        }
                    911:        uip = newuip;
1.89      christos  912:
1.79      christos  913:        LIST_INSERT_HEAD(uipp, uip, ui_hash);
                    914:        uip->ui_uid = uid;
1.94      christos  915:        simple_lock_init(&uip->ui_slock);
1.88      christos  916:        simple_unlock(&uihashtbl_slock);
1.89      christos  917:
1.79      christos  918:        return uip;
                    919: }
                    920:
                    921: /*
                    922:  * Change the count associated with number of processes
                    923:  * a given user is using.
                    924:  */
                    925: int
                    926: chgproccnt(uid_t uid, int diff)
                    927: {
                    928:        struct uidinfo *uip;
1.96      christos  929:        int s;
1.79      christos  930:
                    931:        if (diff == 0)
                    932:                return 0;
                    933:
1.88      christos  934:        uip = uid_find(uid);
1.96      christos  935:        UILOCK(uip, s);
1.88      christos  936:        uip->ui_proccnt += diff;
                    937:        KASSERT(uip->ui_proccnt >= 0);
1.96      christos  938:        UIUNLOCK(uip, s);
1.88      christos  939:        return uip->ui_proccnt;
1.79      christos  940: }
                    941:
                    942: int
1.97      christos  943: chgsbsize(struct uidinfo *uip, u_long *hiwat, u_long to, rlim_t xmax)
1.79      christos  944: {
                    945:        rlim_t nsb;
1.96      christos  946:        int s;
1.79      christos  947:
1.96      christos  948:        UILOCK(uip, s);
1.80      yamt      949:        nsb = uip->ui_sbsize + to - *hiwat;
1.97      christos  950:        if (to > *hiwat && nsb > xmax) {
1.96      christos  951:                UIUNLOCK(uip, s);
1.95      christos  952:                splx(s);
1.88      christos  953:                return 0;
1.94      christos  954:        }
1.79      christos  955:        *hiwat = to;
                    956:        uip->ui_sbsize = nsb;
                    957:        KASSERT(uip->ui_sbsize >= 0);
1.96      christos  958:        UIUNLOCK(uip, s);
1.88      christos  959:        return 1;
1.79      christos  960: }

CVSweb <webmaster@jp.NetBSD.org>