]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_resource.c
xnu-517.9.4.tar.gz
[apple/xnu.git] / bsd / kern / kern_resource.c
1 /*
2 * Copyright (c) 2004 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/sysctl.h>
66 #include <sys/kernel.h>
67 #include <sys/file.h>
68 #include <sys/resourcevar.h>
69 #include <sys/malloc.h>
70 #include <sys/proc.h>
71 #include <sys/mount.h>
72
73 #include <bsm/audit_kernel.h>
74
75 #include <machine/spl.h>
76 #include <machine/vmparam.h>
77
78 #include <mach/mach_types.h>
79 #include <mach/time_value.h>
80 #include <mach/task_info.h>
81
82 #include <vm/vm_map.h>
83
84 int donice __P((struct proc *curp, struct proc *chgp, int n));
85 int dosetrlimit __P((struct proc *p, u_int which, struct rlimit *limp));
86
87 rlim_t maxdmap = MAXDSIZ; /* XXX */
88 rlim_t maxsmap = MAXSSIZ; /* XXX */
89
90 /*
91 * Limits on the number of open files per process, and the number
92 * of child processes per process.
93 *
94 * Note: would be in kern/subr_param.c in FreeBSD.
95 */
96 int maxprocperuid = CHILD_MAX; /* max # of procs per user */
97 int maxfilesperproc = OPEN_MAX; /* per-proc open files limit */
98
99 SYSCTL_INT( _kern, KERN_MAXPROCPERUID, maxprocperuid, CTLFLAG_RW,
100 &maxprocperuid, 0, "Maximum processes allowed per userid" );
101
102 SYSCTL_INT( _kern, KERN_MAXFILESPERPROC, maxfilesperproc, CTLFLAG_RW,
103 &maxfilesperproc, 0, "Maximum files allowed open per process" );
104
105
106 /*
107 * Resource controls and accounting.
108 */
109 struct getpriority_args {
110 int which;
111 int who;
112 };
113 int
114 getpriority(curp, uap, retval)
115 struct proc *curp;
116 register struct getpriority_args *uap;
117 register_t *retval;
118 {
119 register struct proc *p;
120 register int low = PRIO_MAX + 1;
121
122 switch (uap->which) {
123
124 case PRIO_PROCESS:
125 if (uap->who == 0)
126 p = curp;
127 else
128 p = pfind(uap->who);
129 if (p == 0)
130 break;
131 low = p->p_nice;
132 break;
133
134 case PRIO_PGRP: {
135 register struct pgrp *pg;
136
137 if (uap->who == 0)
138 pg = curp->p_pgrp;
139 else if ((pg = pgfind(uap->who)) == NULL)
140 break;
141 for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) {
142 if (p->p_nice < low)
143 low = p->p_nice;
144 }
145 break;
146 }
147
148 case PRIO_USER:
149 if (uap->who == 0)
150 uap->who = curp->p_ucred->cr_uid;
151 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next)
152 if (p->p_ucred->cr_uid == uap->who &&
153 p->p_nice < low)
154 low = p->p_nice;
155 break;
156
157 default:
158 return (EINVAL);
159 }
160 if (low == PRIO_MAX + 1)
161 return (ESRCH);
162 *retval = low;
163 return (0);
164 }
165
166 struct setpriority_args {
167 int which;
168 int who;
169 int prio;
170 };
171 /* ARGSUSED */
172 int
173 setpriority(curp, uap, retval)
174 struct proc *curp;
175 register struct setpriority_args *uap;
176 register_t *retval;
177 {
178 register struct proc *p;
179 int found = 0, error = 0;
180
181 AUDIT_ARG(cmd, uap->which);
182 AUDIT_ARG(owner, uap->who, 0);
183 AUDIT_ARG(value, uap->prio);
184
185 switch (uap->which) {
186
187 case PRIO_PROCESS:
188 if (uap->who == 0)
189 p = curp;
190 else
191 p = pfind(uap->who);
192 if (p == 0)
193 break;
194 error = donice(curp, p, uap->prio);
195 found++;
196 break;
197
198 case PRIO_PGRP: {
199 register struct pgrp *pg;
200
201 if (uap->who == 0)
202 pg = curp->p_pgrp;
203 else if ((pg = pgfind(uap->who)) == NULL)
204 break;
205 for (p = pg->pg_members.lh_first; p != 0;
206 p = p->p_pglist.le_next) {
207 error = donice(curp, p, uap->prio);
208 found++;
209 }
210 break;
211 }
212
213 case PRIO_USER:
214 if (uap->who == 0)
215 uap->who = curp->p_ucred->cr_uid;
216 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next)
217 if (p->p_ucred->cr_uid == uap->who) {
218 error = donice(curp, p, uap->prio);
219 found++;
220 }
221 break;
222
223 default:
224 return (EINVAL);
225 }
226 if (found == 0)
227 return (ESRCH);
228 return (error);
229 }
230
231 int
232 donice(curp, chgp, n)
233 register struct proc *curp, *chgp;
234 register int n;
235 {
236 register struct pcred *pcred = curp->p_cred;
237
238 if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
239 pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
240 pcred->p_ruid != chgp->p_ucred->cr_uid)
241 return (EPERM);
242 if (n > PRIO_MAX)
243 n = PRIO_MAX;
244 if (n < PRIO_MIN)
245 n = PRIO_MIN;
246 if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag))
247 return (EACCES);
248 chgp->p_nice = n;
249 (void)resetpriority(chgp);
250 return (0);
251 }
252
253 #if COMPAT_43
254 struct osetrlimit_args {
255 u_int which;
256 struct ogetrlimit * rlp;
257 };
258 /* ARGSUSED */
259 int
260 osetrlimit(p, uap, retval)
261 struct proc *p;
262 struct osetrlimit_args *uap;
263 register_t *retval;
264 {
265 struct orlimit olim;
266 struct rlimit lim;
267 int error;
268
269 if (error = copyin((caddr_t)uap->rlp, (caddr_t)&olim,
270 sizeof (struct orlimit)))
271 return (error);
272 lim.rlim_cur = olim.rlim_cur;
273 lim.rlim_max = olim.rlim_max;
274 return (dosetrlimit(p, uap->which, &lim));
275 }
276
277 struct ogetrlimit_args {
278 u_int which;
279 struct ogetrlimit * rlp;
280 };
281 /* ARGSUSED */
282 int
283 ogetrlimit(p, uap, retval)
284 struct proc *p;
285 struct ogetrlimit_args *uap;
286 register_t *retval;
287 {
288 struct orlimit olim;
289
290 if (uap->which >= RLIM_NLIMITS)
291 return (EINVAL);
292 olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur;
293 if (olim.rlim_cur == -1)
294 olim.rlim_cur = 0x7fffffff;
295 olim.rlim_max = p->p_rlimit[uap->which].rlim_max;
296 if (olim.rlim_max == -1)
297 olim.rlim_max = 0x7fffffff;
298 return (copyout((caddr_t)&olim, (caddr_t)uap->rlp,
299 sizeof(olim)));
300 }
301 #endif /* COMPAT_43 */
302
303 struct setrlimit_args {
304 u_int which;
305 struct rlimit * rlp;
306 };
307 /* ARGSUSED */
308 int
309 setrlimit(p, uap, retval)
310 struct proc *p;
311 register struct setrlimit_args *uap;
312 register_t *retval;
313 {
314 struct rlimit alim;
315 int error;
316
317 if (error = copyin((caddr_t)uap->rlp, (caddr_t)&alim,
318 sizeof (struct rlimit)))
319 return (error);
320 return (dosetrlimit(p, uap->which, &alim));
321 }
322
323 int
324 dosetrlimit(p, which, limp)
325 struct proc *p;
326 u_int which;
327 struct rlimit *limp;
328 {
329 register struct rlimit *alimp;
330 extern rlim_t maxdmap, maxsmap;
331 int error;
332
333 if (which >= RLIM_NLIMITS)
334 return (EINVAL);
335 alimp = &p->p_rlimit[which];
336 if (limp->rlim_cur > alimp->rlim_max ||
337 limp->rlim_max > alimp->rlim_max)
338 if (error = suser(p->p_ucred, &p->p_acflag))
339 return (error);
340 if (limp->rlim_cur > limp->rlim_max)
341 limp->rlim_cur = limp->rlim_max;
342 if (p->p_limit->p_refcnt > 1 &&
343 (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
344 p->p_limit->p_refcnt--;
345 p->p_limit = limcopy(p->p_limit);
346 alimp = &p->p_rlimit[which];
347 }
348
349 switch (which) {
350
351 case RLIMIT_DATA:
352 if (limp->rlim_cur > maxdmap)
353 limp->rlim_cur = maxdmap;
354 if (limp->rlim_max > maxdmap)
355 limp->rlim_max = maxdmap;
356 break;
357
358 case RLIMIT_STACK:
359 if (limp->rlim_cur > maxsmap)
360 limp->rlim_cur = maxsmap;
361 if (limp->rlim_max > maxsmap)
362 limp->rlim_max = maxsmap;
363 /*
364 * Stack is allocated to the max at exec time with only
365 * "rlim_cur" bytes accessible. If stack limit is going
366 * up make more accessible, if going down make inaccessible.
367 */
368 if (limp->rlim_cur != alimp->rlim_cur) {
369 vm_offset_t addr;
370 vm_size_t size;
371 vm_prot_t prot;
372
373 if (limp->rlim_cur > alimp->rlim_cur) {
374 /* grow stack */
375 size = round_page_64(limp->rlim_cur);
376 size -= round_page_64(alimp->rlim_cur);
377
378 #if STACK_GROWTH_UP
379 /* go to top of current stack */
380 addr = trunc_page((unsigned int)(p->user_stack + alimp->rlim_cur));
381 #else STACK_GROWTH_UP
382 addr = trunc_page_32((unsigned int)(p->user_stack - alimp->rlim_cur));
383 addr -= size;
384 #endif /* STACK_GROWTH_UP */
385 if (vm_allocate(current_map(),
386 &addr, size, FALSE) != KERN_SUCCESS)
387 return(EINVAL);
388 } else {
389 /* shrink stack */
390 }
391 }
392 break;
393
394 case RLIMIT_NOFILE:
395 /*
396 * Only root can set the maxfiles limits, as it is systemwide resource
397 */
398 if ( is_suser() ) {
399 if (limp->rlim_cur > maxfiles)
400 limp->rlim_cur = maxfiles;
401 if (limp->rlim_max > maxfiles)
402 limp->rlim_max = maxfiles;
403 }
404 else {
405 if (limp->rlim_cur > maxfilesperproc)
406 limp->rlim_cur = maxfilesperproc;
407 if (limp->rlim_max > maxfilesperproc)
408 limp->rlim_max = maxfilesperproc;
409 }
410 break;
411
412 case RLIMIT_NPROC:
413 /*
414 * Only root can set to the maxproc limits, as it is
415 * systemwide resource; all others are limited to
416 * maxprocperuid (presumably less than maxproc).
417 */
418 if ( is_suser() ) {
419 if (limp->rlim_cur > maxproc)
420 limp->rlim_cur = maxproc;
421 if (limp->rlim_max > maxproc)
422 limp->rlim_max = maxproc;
423 }
424 else {
425 if (limp->rlim_cur > maxprocperuid)
426 limp->rlim_cur = maxprocperuid;
427 if (limp->rlim_max > maxprocperuid)
428 limp->rlim_max = maxprocperuid;
429 }
430 break;
431
432 } /* switch... */
433 *alimp = *limp;
434 return (0);
435 }
436
437 struct getrlimit_args {
438 u_int which;
439 struct rlimit * rlp;
440 };
441 /* ARGSUSED */
442 int
443 getrlimit(p, uap, retval)
444 struct proc *p;
445 register struct getrlimit_args *uap;
446 register_t *retval;
447 {
448
449 if (uap->which >= RLIM_NLIMITS)
450 return (EINVAL);
451 return (copyout((caddr_t)&p->p_rlimit[uap->which],
452 (caddr_t)uap->rlp, sizeof (struct rlimit)));
453 }
454
455 /*
456 * Transform the running time and tick information in proc p into user,
457 * system, and interrupt time usage.
458 */
459 void
460 calcru(p, up, sp, ip)
461 register struct proc *p;
462 register struct timeval *up;
463 register struct timeval *sp;
464 register struct timeval *ip;
465 {
466 task_t task;
467
468 timerclear(up);
469 timerclear(sp);
470 if (ip != NULL)
471 timerclear(ip);
472
473 task = p->task;
474 if (task) {
475 task_basic_info_data_t tinfo;
476 task_thread_times_info_data_t ttimesinfo;
477 int task_info_stuff, task_ttimes_stuff;
478 struct timeval ut,st;
479
480 task_info_stuff = TASK_BASIC_INFO_COUNT;
481 task_info(task, TASK_BASIC_INFO,
482 &tinfo, &task_info_stuff);
483 ut.tv_sec = tinfo.user_time.seconds;
484 ut.tv_usec = tinfo.user_time.microseconds;
485 st.tv_sec = tinfo.system_time.seconds;
486 st.tv_usec = tinfo.system_time.microseconds;
487 timeradd(&ut, up, up);
488 timeradd(&st, sp, sp);
489
490 task_ttimes_stuff = TASK_THREAD_TIMES_INFO_COUNT;
491 task_info(task, TASK_THREAD_TIMES_INFO,
492 &ttimesinfo, &task_ttimes_stuff);
493
494 ut.tv_sec = ttimesinfo.user_time.seconds;
495 ut.tv_usec = ttimesinfo.user_time.microseconds;
496 st.tv_sec = ttimesinfo.system_time.seconds;
497 st.tv_usec = ttimesinfo.system_time.microseconds;
498 timeradd(&ut, up, up);
499 timeradd(&st, sp, sp);
500 }
501 }
502
503 struct getrusage_args {
504 int who;
505 struct rusage * rusage;
506 };
507 /* ARGSUSED */
508 int
509 getrusage(p, uap, retval)
510 register struct proc *p;
511 register struct getrusage_args *uap;
512 register_t *retval;
513 {
514 struct rusage *rup, rubuf;
515
516 switch (uap->who) {
517
518 case RUSAGE_SELF:
519 rup = &p->p_stats->p_ru;
520 calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
521 rubuf = *rup;
522 break;
523
524 case RUSAGE_CHILDREN:
525 rup = &p->p_stats->p_cru;
526 rubuf = *rup;
527 break;
528
529 default:
530 return (EINVAL);
531 }
532 return (copyout((caddr_t)&rubuf, (caddr_t)uap->rusage,
533 sizeof (struct rusage)));
534 }
535
536 void
537 ruadd(ru, ru2)
538 register struct rusage *ru, *ru2;
539 {
540 register long *ip, *ip2;
541 register int i;
542
543 timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime);
544 timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime);
545 if (ru->ru_maxrss < ru2->ru_maxrss)
546 ru->ru_maxrss = ru2->ru_maxrss;
547 ip = &ru->ru_first; ip2 = &ru2->ru_first;
548 for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
549 *ip++ += *ip2++;
550 }
551
552 /*
553 * Make a copy of the plimit structure.
554 * We share these structures copy-on-write after fork,
555 * and copy when a limit is changed.
556 */
557 struct plimit *
558 limcopy(lim)
559 struct plimit *lim;
560 {
561 register struct plimit *copy;
562
563 MALLOC_ZONE(copy, struct plimit *,
564 sizeof(struct plimit), M_SUBPROC, M_WAITOK);
565 bcopy(lim->pl_rlimit, copy->pl_rlimit,
566 sizeof(struct rlimit) * RLIM_NLIMITS);
567 copy->p_lflags = 0;
568 copy->p_refcnt = 1;
569 return (copy);
570 }