Annotation of XNU/bsd/kern/kern_resource.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */
                     23: /*-
                     24:  * Copyright (c) 1982, 1986, 1991, 1993
                     25:  *     The Regents of the University of California.  All rights reserved.
                     26:  * (c) UNIX System Laboratories, Inc.
                     27:  * All or some portions of this file are derived from material licensed
                     28:  * to the University of California by American Telephone and Telegraph
                     29:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
                     30:  * the permission of UNIX System Laboratories, Inc.
                     31:  *
                     32:  * Redistribution and use in source and binary forms, with or without
                     33:  * modification, are permitted provided that the following conditions
                     34:  * are met:
                     35:  * 1. Redistributions of source code must retain the above copyright
                     36:  *    notice, this list of conditions and the following disclaimer.
                     37:  * 2. Redistributions in binary form must reproduce the above copyright
                     38:  *    notice, this list of conditions and the following disclaimer in the
                     39:  *    documentation and/or other materials provided with the distribution.
                     40:  * 3. All advertising materials mentioning features or use of this software
                     41:  *    must display the following acknowledgement:
                     42:  *     This product includes software developed by the University of
                     43:  *     California, Berkeley and its contributors.
                     44:  * 4. Neither the name of the University nor the names of its contributors
                     45:  *    may be used to endorse or promote products derived from this software
                     46:  *    without specific prior written permission.
                     47:  *
                     48:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     49:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     50:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     51:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     52:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     53:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     54:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     55:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     56:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     57:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     58:  * SUCH DAMAGE.
                     59:  *
                     60:  *     @(#)kern_resource.c     8.5 (Berkeley) 1/21/94
                     61:  */
                     62: 
                     63: #include <sys/param.h>
                     64: #include <sys/systm.h>
                     65: #include <sys/kernel.h>
                     66: #include <sys/file.h>
                     67: #include <sys/resourcevar.h>
                     68: #include <sys/malloc.h>
                     69: #include <sys/proc.h>
                     70: #include <machine/spl.h>
                     71: 
                     72: #include <sys/mount.h>
                     73: 
                     74: #include <machine/vmparam.h>
                     75: 
                     76: #include <mach/mach_types.h>
                     77: #include <mach/time_value.h>
                     78: #include <mach/task_info.h>
                     79: 
                     80: #include <vm/vm_map.h>
                     81: 
                     82: int    donice __P((struct proc *curp, struct proc *chgp, int n));
                     83: int    dosetrlimit __P((struct proc *p, u_int which, struct rlimit *limp));
                     84: 
                     85: rlim_t maxdmap = MAXDSIZ;      /* XXX */ 
                     86: rlim_t maxsmap = MAXSSIZ;      /* XXX */ 
                     87: 
                     88: /*
                     89:  * Resource controls and accounting.
                     90:  */
                     91: struct getpriority_args  {
                     92:                int which;
                     93:                int who;
                     94: };
                     95: int
                     96: getpriority(curp, uap, retval)
                     97:        struct proc *curp;
                     98:        register struct getpriority_args *uap;
                     99:        register_t *retval;
                    100: {
                    101:        register struct proc *p;
                    102:        register int low = PRIO_MAX + 1;
                    103: 
                    104:        switch (uap->which) {
                    105: 
                    106:        case PRIO_PROCESS:
                    107:                if (uap->who == 0)
                    108:                        p = curp;
                    109:                else
                    110:                        p = pfind(uap->who);
                    111:                if (p == 0)
                    112:                        break;
                    113:                low = p->p_nice;
                    114:                break;
                    115: 
                    116:        case PRIO_PGRP: {
                    117:                register struct pgrp *pg;
                    118: 
                    119:                if (uap->who == 0)
                    120:                        pg = curp->p_pgrp;
                    121:                else if ((pg = pgfind(uap->who)) == NULL)
                    122:                        break;
                    123:                for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) {
                    124:                        if (p->p_nice < low)
                    125:                                low = p->p_nice;
                    126:                }
                    127:                break;
                    128:        }
                    129: 
                    130:        case PRIO_USER:
                    131:                if (uap->who == 0)
                    132:                        uap->who = curp->p_ucred->cr_uid;
                    133:                for (p = allproc.lh_first; p != 0; p = p->p_list.le_next)
                    134:                        if (p->p_ucred->cr_uid == uap->who &&
                    135:                            p->p_nice < low)
                    136:                                low = p->p_nice;
                    137:                break;
                    138: 
                    139:        default:
                    140:                return (EINVAL);
                    141:        }
                    142:        if (low == PRIO_MAX + 1)
                    143:                return (ESRCH);
                    144:        *retval = low;
                    145:        return (0);
                    146: }
                    147: 
                    148: struct setpriority_args {
                    149:                int which;
                    150:                int who;
                    151:                int prio;
                    152: };
                    153: /* ARGSUSED */
                    154: int
                    155: setpriority(curp, uap, retval)
                    156:        struct proc *curp;
                    157:        register struct setpriority_args *uap;
                    158:        register_t *retval;
                    159: {
                    160:        register struct proc *p;
                    161:        int found = 0, error = 0;
                    162: 
                    163:        switch (uap->which) {
                    164: 
                    165:        case PRIO_PROCESS:
                    166:                if (uap->who == 0)
                    167:                        p = curp;
                    168:                else
                    169:                        p = pfind(uap->who);
                    170:                if (p == 0)
                    171:                        break;
                    172:                error = donice(curp, p, uap->prio);
                    173:                found++;
                    174:                break;
                    175: 
                    176:        case PRIO_PGRP: {
                    177:                register struct pgrp *pg;
                    178:                 
                    179:                if (uap->who == 0)
                    180:                        pg = curp->p_pgrp;
                    181:                else if ((pg = pgfind(uap->who)) == NULL)
                    182:                        break;
                    183:                for (p = pg->pg_members.lh_first; p != 0;
                    184:                    p = p->p_pglist.le_next) {
                    185:                        error = donice(curp, p, uap->prio);
                    186:                        found++;
                    187:                }
                    188:                break;
                    189:        }
                    190: 
                    191:        case PRIO_USER:
                    192:                if (uap->who == 0)
                    193:                        uap->who = curp->p_ucred->cr_uid;
                    194:                for (p = allproc.lh_first; p != 0; p = p->p_list.le_next)
                    195:                        if (p->p_ucred->cr_uid == uap->who) {
                    196:                                error = donice(curp, p, uap->prio);
                    197:                                found++;
                    198:                        }
                    199:                break;
                    200: 
                    201:        default:
                    202:                return (EINVAL);
                    203:        }
                    204:        if (found == 0)
                    205:                return (ESRCH);
                    206:        return (error);
                    207: }
                    208: 
                    209: int
                    210: donice(curp, chgp, n)
                    211:        register struct proc *curp, *chgp;
                    212:        register int n;
                    213: {
                    214:        register struct pcred *pcred = curp->p_cred;
                    215: 
                    216:        if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
                    217:            pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
                    218:            pcred->p_ruid != chgp->p_ucred->cr_uid)
                    219:                return (EPERM);
                    220:        if (n > PRIO_MAX)
                    221:                n = PRIO_MAX;
                    222:        if (n < PRIO_MIN)
                    223:                n = PRIO_MIN;
                    224:        if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag))
                    225:                return (EACCES);
                    226:        chgp->p_nice = n;
                    227:        (void)resetpriority(chgp);
                    228:        return (0);
                    229: }
                    230: 
                    231: #if COMPAT_43
                    232: struct osetrlimit_args {
                    233:                u_int which;
                    234:                struct ogetrlimit * rlp;
                    235: };
                    236: /* ARGSUSED */
                    237: int
                    238: osetrlimit(p, uap, retval)
                    239:        struct proc *p;
                    240:        struct osetrlimit_args *uap;
                    241:        register_t *retval;
                    242: {
                    243:        struct orlimit olim;
                    244:        struct rlimit lim;
                    245:        int error;
                    246: 
                    247:        if (error = copyin((caddr_t)uap->rlp, (caddr_t)&olim,
                    248:            sizeof (struct orlimit)))
                    249:                return (error);
                    250:        lim.rlim_cur = olim.rlim_cur;
                    251:        lim.rlim_max = olim.rlim_max;
                    252:        return (dosetrlimit(p, uap->which, &lim));
                    253: }
                    254: 
                    255: struct ogetrlimit_args {
                    256:                u_int which;
                    257:                struct ogetrlimit * rlp;
                    258: };
                    259: /* ARGSUSED */
                    260: int
                    261: ogetrlimit(p, uap, retval)
                    262:        struct proc *p;
                    263:        struct ogetrlimit_args *uap;
                    264:        register_t *retval;
                    265: {
                    266:        struct orlimit olim;
                    267: 
                    268:        if (uap->which >= RLIM_NLIMITS)
                    269:                return (EINVAL);
                    270:        olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur;
                    271:        if (olim.rlim_cur == -1)
                    272:                olim.rlim_cur = 0x7fffffff;
                    273:        olim.rlim_max = p->p_rlimit[uap->which].rlim_max;
                    274:        if (olim.rlim_max == -1)
                    275:                olim.rlim_max = 0x7fffffff;
                    276:        return (copyout((caddr_t)&olim, (caddr_t)uap->rlp,
                    277:            sizeof(olim)));
                    278: }
                    279: #endif /* COMPAT_43 */
                    280: 
                    281: struct setrlimit_args {
                    282:                u_int which;
                    283:                struct rlimit * rlp;
                    284: };
                    285: /* ARGSUSED */
                    286: int
                    287: setrlimit(p, uap, retval)
                    288:        struct proc *p;
                    289:        register struct setrlimit_args *uap;
                    290:        register_t *retval;
                    291: {
                    292:        struct rlimit alim;
                    293:        int error;
                    294: 
                    295:        if (error = copyin((caddr_t)uap->rlp, (caddr_t)&alim,
                    296:            sizeof (struct rlimit)))
                    297:                return (error);
                    298:        return (dosetrlimit(p, uap->which, &alim));
                    299: }
                    300: 
                    301: int
                    302: dosetrlimit(p, which, limp)
                    303:        struct proc *p;
                    304:        u_int which;
                    305:        struct rlimit *limp;
                    306: {
                    307:        register struct rlimit *alimp;
                    308:        extern rlim_t maxdmap, maxsmap;
                    309:        int error;
                    310: 
                    311:        if (which >= RLIM_NLIMITS)
                    312:                return (EINVAL);
                    313:        alimp = &p->p_rlimit[which];
                    314:        if (limp->rlim_cur > alimp->rlim_max || 
                    315:            limp->rlim_max > alimp->rlim_max)
                    316:                if (error = suser(p->p_ucred, &p->p_acflag))
                    317:                        return (error);
                    318:        if (limp->rlim_cur > limp->rlim_max)
                    319:                limp->rlim_cur = limp->rlim_max;
                    320:        if (p->p_limit->p_refcnt > 1 &&
                    321:            (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
                    322:                p->p_limit->p_refcnt--;
                    323:                p->p_limit = limcopy(p->p_limit);
                    324:                alimp = &p->p_rlimit[which];
                    325:        }
                    326: 
                    327:        switch (which) {
                    328: 
                    329:        case RLIMIT_DATA:
                    330:                if (limp->rlim_cur > maxdmap)
                    331:                        limp->rlim_cur = maxdmap;
                    332:                if (limp->rlim_max > maxdmap)
                    333:                        limp->rlim_max = maxdmap;
                    334:                break;
                    335: 
                    336:        case RLIMIT_STACK:
                    337:                if (limp->rlim_cur > maxsmap)
                    338:                        limp->rlim_cur = maxsmap;
                    339:                if (limp->rlim_max > maxsmap)
                    340:                        limp->rlim_max = maxsmap;
                    341:                /*
                    342:                 * Stack is allocated to the max at exec time with only
                    343:                 * "rlim_cur" bytes accessible.  If stack limit is going
                    344:                 * up make more accessible, if going down make inaccessible.
                    345:                 */
                    346:                if (limp->rlim_cur != alimp->rlim_cur) {
                    347:                        vm_offset_t addr;
                    348:                        vm_size_t size;
                    349:                        vm_prot_t prot;
                    350:                        
                    351:                        if (limp->rlim_cur > alimp->rlim_cur) {
                    352:                                /* grow stack */
                    353:                                size = round_page(limp->rlim_cur);
                    354:                                size -= round_page(alimp->rlim_cur);
                    355: 
                    356: #if STACK_GROWTH_UP
                    357:                                /* go to top of current stack */
                    358:                                addr = trunc_page(p->user_stack + alimp->rlim_cur);
                    359: #else STACK_GROWTH_UP
                    360:                                addr = trunc_page(p->user_stack - alimp->rlim_cur);
                    361:                                addr -= size;
                    362: #endif /* STACK_GROWTH_UP */
                    363:                                if (vm_allocate(current_map(),
                    364:                                                &addr, size, FALSE) != KERN_SUCCESS)
                    365:                                        return(EINVAL);
                    366:                        } else {
                    367:                                /* shrink stack */
                    368:                        }
                    369:                }
                    370:                break;
                    371: 
                    372:        case RLIMIT_NOFILE:
                    373:        /* 
                    374:         * Only root can get the maxfiles limits, as it is systemwide resource
                    375:         */
                    376:                if (is_suser()) {
                    377:                        if (limp->rlim_cur > maxfiles)
                    378:                                limp->rlim_cur = maxfiles;
                    379:                        if (limp->rlim_max > maxfiles)
                    380:                                limp->rlim_max = maxfiles;
                    381:                } else {
                    382:                        if (limp->rlim_cur > OPEN_MAX)
                    383:                                limp->rlim_cur = OPEN_MAX;
                    384:                        if (limp->rlim_max > OPEN_MAX)
                    385:                                limp->rlim_max = OPEN_MAX;
                    386:                }
                    387:                break;
                    388: 
                    389:        case RLIMIT_NPROC:
                    390:        /* 
                    391:         * Only root can get the maxproc limits, as it is systemwide resource
                    392:         */
                    393:                if (is_suser()) {
                    394:                        if (limp->rlim_cur > maxproc)
                    395:                                limp->rlim_cur = maxproc;
                    396:                        if (limp->rlim_max > maxproc)
                    397:                                limp->rlim_max = maxproc;
                    398:                } else {
                    399:                        if (limp->rlim_cur > CHILD_MAX)
                    400:                                limp->rlim_cur = CHILD_MAX;
                    401:                        if (limp->rlim_max > CHILD_MAX)
                    402:                                limp->rlim_max = CHILD_MAX;
                    403:                }
                    404:                break;
                    405:        }
                    406:        *alimp = *limp;
                    407:        return (0);
                    408: }
                    409: 
                    410: struct getrlimit_args {
                    411:                u_int which;
                    412:                struct rlimit * rlp;
                    413: };
                    414: /* ARGSUSED */
                    415: int
                    416: getrlimit(p, uap, retval)
                    417:        struct proc *p;
                    418:        register struct getrlimit_args *uap;
                    419:        register_t *retval;
                    420: {
                    421: 
                    422:        if (uap->which >= RLIM_NLIMITS)
                    423:                return (EINVAL);
                    424:        return (copyout((caddr_t)&p->p_rlimit[uap->which],
                    425:            (caddr_t)uap->rlp, sizeof (struct rlimit)));
                    426: }
                    427: 
                    428: /*
                    429:  * Transform the running time and tick information in proc p into user,
                    430:  * system, and interrupt time usage.
                    431:  */
                    432: void
                    433: calcru(p, up, sp, ip)
                    434:        register struct proc *p;
                    435:        register struct timeval *up;
                    436:        register struct timeval *sp;
                    437:        register struct timeval *ip;
                    438: {
                    439:        task_t                  task;
                    440:        struct timeval ut,st;
                    441:        task_thread_times_info_data_t tinfo;
                    442:        int     task_info_stuff;
                    443: 
                    444:        timerclear(up);
                    445:        timerclear(sp);
                    446:        if (ip != NULL)
                    447:                timerclear(ip);
                    448: 
                    449:        task = p->task;
                    450:        task_info_stuff = TASK_THREAD_TIMES_INFO_COUNT;
                    451:        if (task) {
                    452:                task_info(task, TASK_THREAD_TIMES_INFO,&tinfo, &task_info_stuff);
                    453:                ut.tv_sec = tinfo.user_time.seconds;
                    454:                ut.tv_usec = tinfo.user_time.microseconds;
                    455:                st.tv_sec = tinfo.system_time.seconds;
                    456:                st.tv_usec = tinfo.system_time.microseconds;
                    457:                timeradd(&ut,up,up);
                    458:                timeradd(&st,up,up);
                    459:        }
                    460: }
                    461: 
                    462: struct getrusage_args {
                    463:                int who;
                    464:                struct rusage * rusage;
                    465: };
                    466: /* ARGSUSED */
                    467: int
                    468: getrusage(p, uap, retval)
                    469:        register struct proc *p;
                    470:        register struct getrusage_args *uap;
                    471:        register_t *retval;
                    472: {
                    473:        struct rusage *rup, rubuf;
                    474: 
                    475:        switch (uap->who) {
                    476: 
                    477:        case RUSAGE_SELF:
                    478:                rup = &p->p_stats->p_ru;
                    479:                calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
                    480:                rubuf = *rup;
                    481:                break;
                    482: 
                    483:        case RUSAGE_CHILDREN:
                    484:                rup = &p->p_stats->p_cru;
                    485:                rubuf = *rup;
                    486:                break;
                    487: 
                    488:        default:
                    489:                return (EINVAL);
                    490:        }
                    491:        return (copyout((caddr_t)&rubuf, (caddr_t)uap->rusage,
                    492:            sizeof (struct rusage)));
                    493: }
                    494: 
                    495: void
                    496: ruadd(ru, ru2)
                    497:        register struct rusage *ru, *ru2;
                    498: {
                    499:        register long *ip, *ip2;
                    500:        register int i;
                    501: 
                    502:        timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime);
                    503:        timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime);
                    504:        if (ru->ru_maxrss < ru2->ru_maxrss)
                    505:                ru->ru_maxrss = ru2->ru_maxrss;
                    506:        ip = &ru->ru_first; ip2 = &ru2->ru_first;
                    507:        for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
                    508:                *ip++ += *ip2++;
                    509: }
                    510: 
                    511: /*
                    512:  * Make a copy of the plimit structure.
                    513:  * We share these structures copy-on-write after fork,
                    514:  * and copy when a limit is changed.
                    515:  */
                    516: struct plimit *
                    517: limcopy(lim)
                    518:        struct plimit *lim;
                    519: {
                    520:        register struct plimit *copy;
                    521: 
                    522:        MALLOC_ZONE(copy, struct plimit *,
                    523:                        sizeof(struct plimit), M_SUBPROC, M_WAITOK);
                    524:        bcopy(lim->pl_rlimit, copy->pl_rlimit,
                    525:            sizeof(struct rlimit) * RLIM_NLIMITS);
                    526:        copy->p_lflags = 0;
                    527:        copy->p_refcnt = 1;
                    528:        return (copy);
                    529: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.