2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 /* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */
30 * Copyright (c) 1982, 1986, 1991, 1993
31 * The Regents of the University of California. All rights reserved.
32 * (c) UNIX System Laboratories, Inc.
33 * All or some portions of this file are derived from material licensed
34 * to the University of California by American Telephone and Telegraph
35 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
36 * the permission of UNIX System Laboratories, Inc.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the University of
49 * California, Berkeley and its contributors.
50 * 4. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 * @(#)kern_resource.c 8.5 (Berkeley) 1/21/94
69 #include <sys/param.h>
70 #include <sys/systm.h>
71 #include <sys/sysctl.h>
72 #include <sys/kernel.h>
73 #include <sys/file_internal.h>
74 #include <sys/resourcevar.h>
75 #include <sys/malloc.h>
76 #include <sys/proc_internal.h>
77 #include <sys/kauth.h>
78 #include <machine/spl.h>
80 #include <sys/mount_internal.h>
81 #include <sys/sysproto.h>
83 #include <bsm/audit_kernel.h>
85 #include <machine/vmparam.h>
87 #include <mach/mach_types.h>
88 #include <mach/time_value.h>
89 #include <mach/task_info.h>
90 #include <mach/vm_map.h>
92 #include <vm/vm_map.h>
94 int donice(struct proc
*curp
, struct proc
*chgp
, int n
);
95 int dosetrlimit(struct proc
*p
, u_int which
, struct rlimit
*limp
);
97 rlim_t maxdmap
= MAXDSIZ
; /* XXX */
98 rlim_t maxsmap
= MAXSSIZ
; /* XXX */
101 * Limits on the number of open files per process, and the number
102 * of child processes per process.
104 * Note: would be in kern/subr_param.c in FreeBSD.
106 int maxprocperuid
= CHILD_MAX
; /* max # of procs per user */
107 int maxfilesperproc
= OPEN_MAX
; /* per-proc open files limit */
109 SYSCTL_INT( _kern
, KERN_MAXPROCPERUID
, maxprocperuid
, CTLFLAG_RW
,
110 &maxprocperuid
, 0, "Maximum processes allowed per userid" );
112 SYSCTL_INT( _kern
, KERN_MAXFILESPERPROC
, maxfilesperproc
, CTLFLAG_RW
,
113 &maxfilesperproc
, 0, "Maximum files allowed open per process" );
117 * Resource controls and accounting.
120 getpriority(struct proc
*curp
, struct getpriority_args
*uap
, register_t
*retval
)
122 register struct proc
*p
;
123 register int low
= PRIO_MAX
+ 1;
128 switch (uap
->which
) {
141 register struct pgrp
*pg
;
145 else if ((pg
= pgfind(uap
->who
)) == NULL
)
147 for (p
= pg
->pg_members
.lh_first
; p
!= 0; p
= p
->p_pglist
.le_next
) {
156 uap
->who
= kauth_cred_getuid(kauth_cred_get());
157 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
)
158 if (kauth_cred_getuid(p
->p_ucred
) == uap
->who
&&
166 if (low
== PRIO_MAX
+ 1)
174 setpriority(struct proc
*curp
, struct setpriority_args
*uap
, __unused register_t
*retval
)
176 register struct proc
*p
;
177 int found
= 0, error
= 0;
179 AUDIT_ARG(cmd
, uap
->which
);
180 AUDIT_ARG(owner
, uap
->who
, 0);
181 AUDIT_ARG(value
, uap
->prio
);
186 switch (uap
->which
) {
195 error
= donice(curp
, p
, uap
->prio
);
200 register struct pgrp
*pg
;
204 else if ((pg
= pgfind(uap
->who
)) == NULL
)
206 for (p
= pg
->pg_members
.lh_first
; p
!= 0;
207 p
= p
->p_pglist
.le_next
) {
208 error
= donice(curp
, p
, uap
->prio
);
216 uap
->who
= kauth_cred_getuid(kauth_cred_get());
217 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
)
218 if (kauth_cred_getuid(p
->p_ucred
) == uap
->who
) {
219 error
= donice(curp
, p
, uap
->prio
);
233 donice(curp
, chgp
, n
)
234 register struct proc
*curp
, *chgp
;
237 kauth_cred_t ucred
= curp
->p_ucred
;
239 if (suser(ucred
, NULL
) && ucred
->cr_ruid
&&
240 kauth_cred_getuid(ucred
) != kauth_cred_getuid(chgp
->p_ucred
) &&
241 ucred
->cr_ruid
!= kauth_cred_getuid(chgp
->p_ucred
))
247 if (n
< chgp
->p_nice
&& suser(ucred
, &curp
->p_acflag
))
250 (void)resetpriority(chgp
);
257 setrlimit(struct proc
*p
, register struct setrlimit_args
*uap
, __unused register_t
*retval
)
262 if ((error
= copyin(uap
->rlp
, (caddr_t
)&alim
,
263 sizeof (struct rlimit
))))
265 return (dosetrlimit(p
, uap
->which
, &alim
));
269 dosetrlimit(p
, which
, limp
)
274 register struct rlimit
*alimp
;
277 if (which
>= RLIM_NLIMITS
)
279 alimp
= &p
->p_rlimit
[which
];
280 if (limp
->rlim_cur
> alimp
->rlim_max
||
281 limp
->rlim_max
> alimp
->rlim_max
)
282 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
284 if (limp
->rlim_cur
> limp
->rlim_max
)
285 limp
->rlim_cur
= limp
->rlim_max
;
286 if (p
->p_limit
->p_refcnt
> 1 &&
287 (p
->p_limit
->p_lflags
& PL_SHAREMOD
) == 0) {
288 p
->p_limit
->p_refcnt
--;
289 p
->p_limit
= limcopy(p
->p_limit
);
290 alimp
= &p
->p_rlimit
[which
];
296 if (limp
->rlim_cur
> maxdmap
)
297 limp
->rlim_cur
= maxdmap
;
298 if (limp
->rlim_max
> maxdmap
)
299 limp
->rlim_max
= maxdmap
;
303 if (limp
->rlim_cur
> maxsmap
)
304 limp
->rlim_cur
= maxsmap
;
305 if (limp
->rlim_max
> maxsmap
)
306 limp
->rlim_max
= maxsmap
;
308 * Stack is allocated to the max at exec time with only
309 * "rlim_cur" bytes accessible. If stack limit is going
310 * up make more accessible, if going down make inaccessible.
312 if (limp
->rlim_cur
!= alimp
->rlim_cur
) {
316 if (limp
->rlim_cur
> alimp
->rlim_cur
) {
318 size
= round_page_64(limp
->rlim_cur
);
319 size
-= round_page_64(alimp
->rlim_cur
);
322 /* go to top of current stack */
323 addr
= p
->user_stack
+ alimp
->rlim_cur
;
324 #else STACK_GROWTH_UP
325 addr
= p
->user_stack
- alimp
->rlim_cur
;
327 #endif /* STACK_GROWTH_UP */
328 if (mach_vm_allocate(current_map(),
330 VM_FLAGS_FIXED
) != KERN_SUCCESS
)
340 * Only root can set the maxfiles limits, as it is systemwide resource
343 if (limp
->rlim_cur
> maxfiles
)
344 limp
->rlim_cur
= maxfiles
;
345 if (limp
->rlim_max
> maxfiles
)
346 limp
->rlim_max
= maxfiles
;
349 if (limp
->rlim_cur
> maxfilesperproc
)
350 limp
->rlim_cur
= maxfilesperproc
;
351 if (limp
->rlim_max
> maxfilesperproc
)
352 limp
->rlim_max
= maxfilesperproc
;
358 * Only root can set to the maxproc limits, as it is
359 * systemwide resource; all others are limited to
360 * maxprocperuid (presumably less than maxproc).
363 if (limp
->rlim_cur
> maxproc
)
364 limp
->rlim_cur
= maxproc
;
365 if (limp
->rlim_max
> maxproc
)
366 limp
->rlim_max
= maxproc
;
369 if (limp
->rlim_cur
> maxprocperuid
)
370 limp
->rlim_cur
= maxprocperuid
;
371 if (limp
->rlim_max
> maxprocperuid
)
372 limp
->rlim_max
= maxprocperuid
;
383 getrlimit(struct proc
*p
, register struct getrlimit_args
*uap
, __unused register_t
*retval
)
385 if (uap
->which
>= RLIM_NLIMITS
)
387 return (copyout((caddr_t
)&p
->p_rlimit
[uap
->which
],
388 uap
->rlp
, sizeof (struct rlimit
)));
392 * Transform the running time and tick information in proc p into user,
393 * system, and interrupt time usage.
396 calcru(p
, up
, sp
, ip
)
397 register struct proc
*p
;
398 register struct timeval
*up
;
399 register struct timeval
*sp
;
400 register struct timeval
*ip
;
411 task_basic_info_data_t tinfo
;
412 task_thread_times_info_data_t ttimesinfo
;
413 int task_info_stuff
, task_ttimes_stuff
;
414 struct timeval ut
,st
;
416 task_info_stuff
= TASK_BASIC_INFO_COUNT
;
417 task_info(task
, TASK_BASIC_INFO
,
418 &tinfo
, &task_info_stuff
);
419 ut
.tv_sec
= tinfo
.user_time
.seconds
;
420 ut
.tv_usec
= tinfo
.user_time
.microseconds
;
421 st
.tv_sec
= tinfo
.system_time
.seconds
;
422 st
.tv_usec
= tinfo
.system_time
.microseconds
;
423 timeradd(&ut
, up
, up
);
424 timeradd(&st
, sp
, sp
);
426 task_ttimes_stuff
= TASK_THREAD_TIMES_INFO_COUNT
;
427 task_info(task
, TASK_THREAD_TIMES_INFO
,
428 &ttimesinfo
, &task_ttimes_stuff
);
430 ut
.tv_sec
= ttimesinfo
.user_time
.seconds
;
431 ut
.tv_usec
= ttimesinfo
.user_time
.microseconds
;
432 st
.tv_sec
= ttimesinfo
.system_time
.seconds
;
433 st
.tv_usec
= ttimesinfo
.system_time
.microseconds
;
434 timeradd(&ut
, up
, up
);
435 timeradd(&st
, sp
, sp
);
439 __private_extern__
void munge_rusage(struct rusage
*a_rusage_p
, struct user_rusage
*a_user_rusage_p
);
443 getrusage(register struct proc
*p
, register struct getrusage_args
*uap
, __unused register_t
*retval
)
445 struct rusage
*rup
, rubuf
;
446 struct user_rusage rubuf64
;
447 size_t retsize
= sizeof(rubuf
); /* default: 32 bits */
448 caddr_t retbuf
= (caddr_t
)&rubuf
; /* default: 32 bits */
452 rup
= &p
->p_stats
->p_ru
;
453 calcru(p
, &rup
->ru_utime
, &rup
->ru_stime
, NULL
);
454 // LP64todo: proc struct should have 64 bit version of struct
458 case RUSAGE_CHILDREN
:
459 rup
= &p
->p_stats
->p_cru
;
466 if (IS_64BIT_PROCESS(p
)) {
467 retsize
= sizeof(rubuf64
);
468 retbuf
= (caddr_t
)&rubuf64
;
469 munge_rusage(&rubuf
, &rubuf64
);
471 return (copyout(retbuf
, uap
->rusage
, retsize
));
476 register struct rusage
*ru
, *ru2
;
478 register long *ip
, *ip2
;
481 timeradd(&ru
->ru_utime
, &ru2
->ru_utime
, &ru
->ru_utime
);
482 timeradd(&ru
->ru_stime
, &ru2
->ru_stime
, &ru
->ru_stime
);
483 if (ru
->ru_maxrss
< ru2
->ru_maxrss
)
484 ru
->ru_maxrss
= ru2
->ru_maxrss
;
485 ip
= &ru
->ru_first
; ip2
= &ru2
->ru_first
;
486 for (i
= &ru
->ru_last
- &ru
->ru_first
; i
>= 0; i
--)
491 * Make a copy of the plimit structure.
492 * We share these structures copy-on-write after fork,
493 * and copy when a limit is changed.
499 register struct plimit
*copy
;
501 MALLOC_ZONE(copy
, struct plimit
*,
502 sizeof(struct plimit
), M_SUBPROC
, M_WAITOK
);
505 bcopy(lim
->pl_rlimit
, copy
->pl_rlimit
,
506 sizeof(struct rlimit
) * RLIM_NLIMITS
);