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