]> git.saurik.com Git - apple/xnu.git/blame_incremental - bsd/kern/kern_resource.c
xnu-2050.48.11.tar.gz
[apple/xnu.git] / bsd / kern / kern_resource.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */
29/*-
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.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
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.
53 *
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
64 * SUCH DAMAGE.
65 *
66 * @(#)kern_resource.c 8.5 (Berkeley) 1/21/94
67 */
68/*
69 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
70 * support for mandatory and extensible security protections. This notice
71 * is included in support of clause 2.2 (b) of the Apple Public License,
72 * Version 2.0.
73 */
74
75#include <sys/param.h>
76#include <sys/systm.h>
77#include <sys/sysctl.h>
78#include <sys/kernel.h>
79#include <sys/file_internal.h>
80#include <sys/resourcevar.h>
81#include <sys/malloc.h>
82#include <sys/proc_internal.h>
83#include <sys/kauth.h>
84#include <machine/spl.h>
85
86#include <sys/mount_internal.h>
87#include <sys/sysproto.h>
88
89#include <security/audit/audit.h>
90
91#include <machine/vmparam.h>
92
93#include <mach/mach_types.h>
94#include <mach/time_value.h>
95#include <mach/task.h>
96#include <mach/task_info.h>
97#include <mach/vm_map.h>
98#include <mach/mach_vm.h>
99#include <mach/thread_act.h> /* for thread_policy_set( ) */
100#include <kern/lock.h>
101#include <kern/thread.h>
102
103#include <kern/task.h>
104#include <kern/clock.h> /* for absolutetime_to_microtime() */
105#include <netinet/in.h> /* for TRAFFIC_MGT_SO_* */
106#include <sys/socketvar.h> /* for struct socket */
107
108#include <vm/vm_map.h>
109
110int donice(struct proc *curp, struct proc *chgp, int n);
111int dosetrlimit(struct proc *p, u_int which, struct rlimit *limp);
112int uthread_get_background_state(uthread_t);
113static void do_background_socket(struct proc *p, thread_t thread, int priority);
114static int do_background_thread(struct proc *curp, thread_t thread, int priority);
115static int do_background_proc(struct proc *curp, struct proc *targetp, int priority);
116void proc_apply_task_networkbg_internal(proc_t, thread_t);
117void proc_restore_task_networkbg_internal(proc_t, thread_t);
118
119rlim_t maxdmap = MAXDSIZ; /* XXX */
120rlim_t maxsmap = MAXSSIZ - PAGE_SIZE; /* XXX */
121
122/*
123 * Limits on the number of open files per process, and the number
124 * of child processes per process.
125 *
126 * Note: would be in kern/subr_param.c in FreeBSD.
127 */
128__private_extern__ int maxfilesperproc = OPEN_MAX; /* per-proc open files limit */
129
130SYSCTL_INT(_kern, KERN_MAXPROCPERUID, maxprocperuid, CTLFLAG_RW | CTLFLAG_LOCKED,
131 &maxprocperuid, 0, "Maximum processes allowed per userid" );
132
133SYSCTL_INT(_kern, KERN_MAXFILESPERPROC, maxfilesperproc, CTLFLAG_RW | CTLFLAG_LOCKED,
134 &maxfilesperproc, 0, "Maximum files allowed open per process" );
135
136/* Args and fn for proc_iteration callback used in setpriority */
137struct puser_nice_args {
138 proc_t curp;
139 int prio;
140 id_t who;
141 int * foundp;
142 int * errorp;
143};
144static int puser_donice_callback(proc_t p, void * arg);
145
146
147/* Args and fn for proc_iteration callback used in setpriority */
148struct ppgrp_nice_args {
149 proc_t curp;
150 int prio;
151 int * foundp;
152 int * errorp;
153};
154static int ppgrp_donice_callback(proc_t p, void * arg);
155
156/*
157 * Resource controls and accounting.
158 */
159int
160getpriority(struct proc *curp, struct getpriority_args *uap, int32_t *retval)
161{
162 struct proc *p;
163 int low = PRIO_MAX + 1;
164 kauth_cred_t my_cred;
165
166 /* would also test (uap->who < 0), but id_t is unsigned */
167 if (uap->who > 0x7fffffff)
168 return (EINVAL);
169
170 switch (uap->which) {
171
172 case PRIO_PROCESS:
173 if (uap->who == 0) {
174 p = curp;
175 low = p->p_nice;
176 } else {
177 p = proc_find(uap->who);
178 if (p == 0)
179 break;
180 low = p->p_nice;
181 proc_rele(p);
182
183 }
184 break;
185
186 case PRIO_PGRP: {
187 struct pgrp *pg = PGRP_NULL;
188
189 if (uap->who == 0) {
190 /* returns the pgrp to ref */
191 pg = proc_pgrp(curp);
192 } else if ((pg = pgfind(uap->who)) == PGRP_NULL) {
193 break;
194 }
195 /* No need for iteration as it is a simple scan */
196 pgrp_lock(pg);
197 for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) {
198 if (p->p_nice < low)
199 low = p->p_nice;
200 }
201 pgrp_unlock(pg);
202 pg_rele(pg);
203 break;
204 }
205
206 case PRIO_USER:
207 if (uap->who == 0)
208 uap->who = kauth_cred_getuid(kauth_cred_get());
209
210 proc_list_lock();
211
212 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
213 my_cred = kauth_cred_proc_ref(p);
214 if (kauth_cred_getuid(my_cred) == uap->who &&
215 p->p_nice < low)
216 low = p->p_nice;
217 kauth_cred_unref(&my_cred);
218 }
219
220 proc_list_unlock();
221
222 break;
223
224 case PRIO_DARWIN_THREAD: {
225 thread_t thread;
226 struct uthread *ut;
227
228 /* we currently only support the current thread */
229 if (uap->who != 0) {
230 return (EINVAL);
231 }
232
233 thread = current_thread();
234 ut = get_bsdthread_info(thread);
235
236 low = 0;
237 if ( (ut->uu_flag & UT_BACKGROUND_TRAFFIC_MGT) != 0 ) {
238 low = 1;
239 }
240 break;
241 }
242
243 default:
244 return (EINVAL);
245 }
246 if (low == PRIO_MAX + 1)
247 return (ESRCH);
248 *retval = low;
249 return (0);
250}
251
252/* call back function used for proc iteration in PRIO_USER */
253static int
254puser_donice_callback(proc_t p, void * arg)
255{
256 int error, n;
257 struct puser_nice_args * pun = (struct puser_nice_args *)arg;
258 kauth_cred_t my_cred;
259
260 my_cred = kauth_cred_proc_ref(p);
261 if (kauth_cred_getuid(my_cred) == pun->who) {
262 error = donice(pun->curp, p, pun->prio);
263 if (pun->errorp != NULL)
264 *pun->errorp = error;
265 if (pun->foundp != NULL) {
266 n = *pun->foundp;
267 *pun->foundp = n+1;
268 }
269 }
270 kauth_cred_unref(&my_cred);
271
272 return(PROC_RETURNED);
273}
274
275/* call back function used for proc iteration in PRIO_PGRP */
276static int
277ppgrp_donice_callback(proc_t p, void * arg)
278{
279 int error;
280 struct ppgrp_nice_args * pun = (struct ppgrp_nice_args *)arg;
281 int n;
282
283 error = donice(pun->curp, p, pun->prio);
284 if (pun->errorp != NULL)
285 *pun->errorp = error;
286 if (pun->foundp!= NULL) {
287 n = *pun->foundp;
288 *pun->foundp = n+1;
289 }
290
291 return(PROC_RETURNED);
292}
293
294/*
295 * Returns: 0 Success
296 * EINVAL
297 * ESRCH
298 * donice:EPERM
299 * donice:EACCES
300 */
301/* ARGSUSED */
302int
303setpriority(struct proc *curp, struct setpriority_args *uap, __unused int32_t *retval)
304{
305 struct proc *p;
306 int found = 0, error = 0;
307 int refheld = 0;
308
309 AUDIT_ARG(cmd, uap->which);
310 AUDIT_ARG(owner, uap->who, 0);
311 AUDIT_ARG(value32, uap->prio);
312
313 /* would also test (uap->who < 0), but id_t is unsigned */
314 if (uap->who > 0x7fffffff)
315 return (EINVAL);
316
317 switch (uap->which) {
318
319 case PRIO_PROCESS:
320 if (uap->who == 0)
321 p = curp;
322 else {
323 p = proc_find(uap->who);
324 if (p == 0)
325 break;
326 refheld = 1;
327 }
328 error = donice(curp, p, uap->prio);
329 found++;
330 if (refheld != 0)
331 proc_rele(p);
332 break;
333
334 case PRIO_PGRP: {
335 struct pgrp *pg = PGRP_NULL;
336 struct ppgrp_nice_args ppgrp;
337
338 if (uap->who == 0) {
339 pg = proc_pgrp(curp);
340 } else if ((pg = pgfind(uap->who)) == PGRP_NULL)
341 break;
342
343 ppgrp.curp = curp;
344 ppgrp.prio = uap->prio;
345 ppgrp.foundp = &found;
346 ppgrp.errorp = &error;
347
348 /* PGRP_DROPREF drops the reference on process group */
349 pgrp_iterate(pg, PGRP_DROPREF, ppgrp_donice_callback, (void *)&ppgrp, NULL, NULL);
350
351 break;
352 }
353
354 case PRIO_USER: {
355 struct puser_nice_args punice;
356
357 if (uap->who == 0)
358 uap->who = kauth_cred_getuid(kauth_cred_get());
359
360 punice.curp = curp;
361 punice.prio = uap->prio;
362 punice.who = uap->who;
363 punice.foundp = &found;
364 error = 0;
365 punice.errorp = &error;
366 proc_iterate(PROC_ALLPROCLIST, puser_donice_callback, (void *)&punice, NULL, NULL);
367
368 break;
369 }
370
371 case PRIO_DARWIN_THREAD: {
372 /* process marked for termination no priority management */
373 if ((curp->p_lflag & P_LPTERMINATE) != 0)
374 return(EINVAL);
375 /* we currently only support the current thread */
376 if (uap->who != 0) {
377 return (EINVAL);
378 }
379 error = do_background_thread(curp, current_thread(), uap->prio);
380 if (!error) {
381 (void) do_background_socket(curp, current_thread(), uap->prio);
382 }
383 found++;
384 break;
385 }
386
387 case PRIO_DARWIN_PROCESS: {
388 if (uap->who == 0)
389 p = curp;
390 else {
391 p = proc_find(uap->who);
392 if (p == 0)
393 break;
394 refheld = 1;
395 }
396
397 /* process marked for termination no priority management */
398 if ((p->p_lflag & P_LPTERMINATE) != 0) {
399 error = EINVAL;
400 } else {
401 error = do_background_proc(curp, p, uap->prio);
402 if (!error) {
403 (void) do_background_socket(p, NULL, uap->prio);
404 }
405
406 }
407 found++;
408 if (refheld != 0)
409 proc_rele(p);
410 break;
411 }
412
413 default:
414 return (EINVAL);
415 }
416 if (found == 0)
417 return (ESRCH);
418 return (error);
419}
420
421
422/*
423 * Returns: 0 Success
424 * EPERM
425 * EACCES
426 * mac_check_proc_sched:???
427 */
428int
429donice(struct proc *curp, struct proc *chgp, int n)
430{
431 int error = 0;
432 kauth_cred_t ucred;
433 kauth_cred_t my_cred;
434
435 ucred = kauth_cred_proc_ref(curp);
436 my_cred = kauth_cred_proc_ref(chgp);
437
438 if (suser(ucred, NULL) && kauth_cred_getruid(ucred) &&
439 kauth_cred_getuid(ucred) != kauth_cred_getuid(my_cred) &&
440 kauth_cred_getruid(ucred) != kauth_cred_getuid(my_cred)) {
441 error = EPERM;
442 goto out;
443 }
444 if (n > PRIO_MAX)
445 n = PRIO_MAX;
446 if (n < PRIO_MIN)
447 n = PRIO_MIN;
448 if (n < chgp->p_nice && suser(ucred, &curp->p_acflag)) {
449 error = EACCES;
450 goto out;
451 }
452#if CONFIG_MACF
453 error = mac_proc_check_sched(curp, chgp);
454 if (error)
455 goto out;
456#endif
457 proc_lock(chgp);
458 chgp->p_nice = n;
459 proc_unlock(chgp);
460 (void)resetpriority(chgp);
461out:
462 kauth_cred_unref(&ucred);
463 kauth_cred_unref(&my_cred);
464 return (error);
465}
466
467static int
468do_background_proc(struct proc *curp, struct proc *targetp, int priority)
469{
470 int error = 0;
471 kauth_cred_t ucred;
472 kauth_cred_t target_cred;
473
474 ucred = kauth_cred_get();
475 target_cred = kauth_cred_proc_ref(targetp);
476
477 if (!kauth_cred_issuser(ucred) && kauth_cred_getruid(ucred) &&
478 kauth_cred_getuid(ucred) != kauth_cred_getuid(target_cred) &&
479 kauth_cred_getruid(ucred) != kauth_cred_getuid(target_cred))
480 {
481 error = EPERM;
482 goto out;
483 }
484
485#if CONFIG_MACF
486 error = mac_proc_check_sched(curp, targetp);
487 if (error)
488 goto out;
489#endif
490
491 if (priority == PRIO_DARWIN_NONUI)
492 error = proc_apply_task_gpuacc(targetp->task, TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS);
493 else
494 error = proc_set_and_apply_bgtaskpolicy(targetp->task, priority);
495 if (error)
496 goto out;
497
498out:
499 kauth_cred_unref(&target_cred);
500 return (error);
501}
502
503static void
504do_background_socket(struct proc *p, thread_t thread, int priority)
505{
506 struct filedesc *fdp;
507 struct fileproc *fp;
508 int i;
509
510 if (priority == PRIO_DARWIN_BG) {
511 /*
512 * For PRIO_DARWIN_PROCESS (thread is NULL), simply mark
513 * the sockets with the background flag. There's nothing
514 * to do here for the PRIO_DARWIN_THREAD case.
515 */
516 if (thread == NULL) {
517 proc_fdlock(p);
518 fdp = p->p_fd;
519
520 for (i = 0; i < fdp->fd_nfiles; i++) {
521 struct socket *sockp;
522
523 fp = fdp->fd_ofiles[i];
524 if (fp == NULL || (fdp->fd_ofileflags[i] & UF_RESERVED) != 0 ||
525 fp->f_fglob->fg_type != DTYPE_SOCKET) {
526 continue;
527 }
528 sockp = (struct socket *)fp->f_fglob->fg_data;
529 socket_set_traffic_mgt_flags(sockp, TRAFFIC_MGT_SO_BACKGROUND);
530 sockp->so_background_thread = NULL;
531 }
532 proc_fdunlock(p);
533 }
534
535 } else {
536
537 /* disable networking IO throttle.
538 * NOTE - It is a known limitation of the current design that we
539 * could potentially clear TRAFFIC_MGT_SO_BACKGROUND bit for
540 * sockets created by other threads within this process.
541 */
542 proc_fdlock(p);
543 fdp = p->p_fd;
544 for ( i = 0; i < fdp->fd_nfiles; i++ ) {
545 struct socket *sockp;
546
547 fp = fdp->fd_ofiles[ i ];
548 if ( fp == NULL || (fdp->fd_ofileflags[ i ] & UF_RESERVED) != 0 ||
549 fp->f_fglob->fg_type != DTYPE_SOCKET ) {
550 continue;
551 }
552 sockp = (struct socket *)fp->f_fglob->fg_data;
553 /* skip if only clearing this thread's sockets */
554 if ((thread) && (sockp->so_background_thread != thread)) {
555 continue;
556 }
557 socket_clear_traffic_mgt_flags(sockp, TRAFFIC_MGT_SO_BACKGROUND);
558 sockp->so_background_thread = NULL;
559 }
560 proc_fdunlock(p);
561 }
562}
563
564
565/*
566 * do_background_thread
567 * Returns: 0 Success
568 * XXX - todo - does this need a MACF hook?
569 *
570 * NOTE: To maintain binary compatibility with PRIO_DARWIN_THREAD with respect
571 * to network traffic management, UT_BACKGROUND_TRAFFIC_MGT is set/cleared
572 * along with UT_BACKGROUND flag, as the latter alone no longer implies
573 * any form of traffic regulation (it simply means that the thread is
574 * background.) With PRIO_DARWIN_PROCESS, any form of network traffic
575 * management must be explicitly requested via whatever means appropriate,
576 * and only TRAFFIC_MGT_SO_BACKGROUND is set via do_background_socket().
577 */
578static int
579do_background_thread(struct proc *curp __unused, thread_t thread, int priority)
580{
581 struct uthread *ut;
582 int error = 0;
583
584 ut = get_bsdthread_info(thread);
585
586 /* Backgrounding is unsupported for threads in vfork */
587 if ( (ut->uu_flag & UT_VFORK) != 0) {
588 return(EPERM);
589 }
590
591 error = proc_set_and_apply_bgthreadpolicy(curp->task, thread_tid(thread), priority);
592 return(error);
593
594}
595
596#if CONFIG_EMBEDDED
597int mach_do_background_thread(thread_t thread, int prio);
598
599int
600mach_do_background_thread(thread_t thread, int prio)
601{
602 int error = 0;
603 struct proc *curp = NULL;
604 struct proc *targetp = NULL;
605 kauth_cred_t ucred;
606
607 targetp = get_bsdtask_info(get_threadtask(thread));
608 if (!targetp) {
609 return KERN_INVALID_ARGUMENT;
610 }
611
612 curp = proc_self();
613 if (curp == PROC_NULL) {
614 return KERN_FAILURE;
615 }
616
617 ucred = kauth_cred_proc_ref(curp);
618
619 if (suser(ucred, NULL) && curp != targetp) {
620 error = KERN_PROTECTION_FAILURE;
621 goto out;
622 }
623
624 error = do_background_thread(curp, thread, prio);
625 if (!error) {
626 (void) do_background_socket(curp, thread, prio);
627 } else {
628 if (error == EPERM) {
629 error = KERN_PROTECTION_FAILURE;
630 } else {
631 error = KERN_FAILURE;
632 }
633 }
634
635out:
636 proc_rele(curp);
637 kauth_cred_unref(&ucred);
638 return error;
639}
640#endif /* CONFIG_EMBEDDED */
641
642/*
643 * Returns: 0 Success
644 * copyin:EFAULT
645 * dosetrlimit:
646 */
647/* ARGSUSED */
648int
649setrlimit(struct proc *p, struct setrlimit_args *uap, __unused int32_t *retval)
650{
651 struct rlimit alim;
652 int error;
653
654 if ((error = copyin(uap->rlp, (caddr_t)&alim,
655 sizeof (struct rlimit))))
656 return (error);
657
658 return (dosetrlimit(p, uap->which, &alim));
659}
660
661/*
662 * Returns: 0 Success
663 * EINVAL
664 * ENOMEM Cannot copy limit structure
665 * suser:EPERM
666 *
667 * Notes: EINVAL is returned both for invalid arguments, and in the
668 * case that the current usage (e.g. RLIMIT_STACK) is already
669 * in excess of the requested limit.
670 */
671int
672dosetrlimit(struct proc *p, u_int which, struct rlimit *limp)
673{
674 struct rlimit *alimp;
675 int error;
676 kern_return_t kr;
677 int posix = (which & _RLIMIT_POSIX_FLAG) ? 1 : 0;
678
679 /* Mask out POSIX flag, saved above */
680 which &= ~_RLIMIT_POSIX_FLAG;
681
682 if (which >= RLIM_NLIMITS)
683 return (EINVAL);
684
685 alimp = &p->p_rlimit[which];
686 if (limp->rlim_cur > limp->rlim_max)
687 return EINVAL;
688
689 if (limp->rlim_cur > alimp->rlim_max ||
690 limp->rlim_max > alimp->rlim_max)
691 if ((error = suser(kauth_cred_get(), &p->p_acflag))) {
692 return (error);
693 }
694
695 proc_limitblock(p);
696
697 if ((error = proc_limitreplace(p)) != 0) {
698 proc_limitunblock(p);
699 return(error);
700 }
701
702 alimp = &p->p_rlimit[which];
703
704 switch (which) {
705
706 case RLIMIT_CPU:
707 if (limp->rlim_cur == RLIM_INFINITY) {
708 task_vtimer_clear(p->task, TASK_VTIMER_RLIM);
709 timerclear(&p->p_rlim_cpu);
710 }
711 else {
712 task_absolutetime_info_data_t tinfo;
713 mach_msg_type_number_t count;
714 struct timeval ttv, tv;
715 clock_sec_t tv_sec;
716 clock_usec_t tv_usec;
717
718 count = TASK_ABSOLUTETIME_INFO_COUNT;
719 task_info(p->task, TASK_ABSOLUTETIME_INFO,
720 (task_info_t)&tinfo, &count);
721 absolutetime_to_microtime(tinfo.total_user + tinfo.total_system,
722 &tv_sec, &tv_usec);
723 ttv.tv_sec = tv_sec;
724 ttv.tv_usec = tv_usec;
725
726 tv.tv_sec = (limp->rlim_cur > __INT_MAX__ ? __INT_MAX__ : limp->rlim_cur);
727 tv.tv_usec = 0;
728 timersub(&tv, &ttv, &p->p_rlim_cpu);
729
730 timerclear(&tv);
731 if (timercmp(&p->p_rlim_cpu, &tv, >))
732 task_vtimer_set(p->task, TASK_VTIMER_RLIM);
733 else {
734 task_vtimer_clear(p->task, TASK_VTIMER_RLIM);
735
736 timerclear(&p->p_rlim_cpu);
737
738 psignal(p, SIGXCPU);
739 }
740 }
741 break;
742
743 case RLIMIT_DATA:
744 if (limp->rlim_cur > maxdmap)
745 limp->rlim_cur = maxdmap;
746 if (limp->rlim_max > maxdmap)
747 limp->rlim_max = maxdmap;
748 break;
749
750 case RLIMIT_STACK:
751 /* Disallow illegal stack size instead of clipping */
752 if (limp->rlim_cur > maxsmap ||
753 limp->rlim_max > maxsmap) {
754 if (posix) {
755 error = EINVAL;
756 goto out;
757 }
758 else {
759 /*
760 * 4797860 - workaround poorly written installers by
761 * doing previous implementation (< 10.5) when caller
762 * is non-POSIX conforming.
763 */
764 if (limp->rlim_cur > maxsmap)
765 limp->rlim_cur = maxsmap;
766 if (limp->rlim_max > maxsmap)
767 limp->rlim_max = maxsmap;
768 }
769 }
770
771 /*
772 * Stack is allocated to the max at exec time with only
773 * "rlim_cur" bytes accessible. If stack limit is going
774 * up make more accessible, if going down make inaccessible.
775 */
776 if (limp->rlim_cur > alimp->rlim_cur) {
777 user_addr_t addr;
778 user_size_t size;
779
780 /* grow stack */
781 size = round_page_64(limp->rlim_cur);
782 size -= round_page_64(alimp->rlim_cur);
783
784 addr = p->user_stack - round_page_64(limp->rlim_cur);
785 kr = mach_vm_protect(current_map(),
786 addr, size,
787 FALSE, VM_PROT_DEFAULT);
788 if (kr != KERN_SUCCESS) {
789 error = EINVAL;
790 goto out;
791 }
792 } else if (limp->rlim_cur < alimp->rlim_cur) {
793 user_addr_t addr;
794 user_size_t size;
795 user_addr_t cur_sp;
796
797 /* shrink stack */
798
799 /*
800 * First check if new stack limit would agree
801 * with current stack usage.
802 * Get the current thread's stack pointer...
803 */
804 cur_sp = thread_adjuserstack(current_thread(),
805 0);
806 if (cur_sp <= p->user_stack &&
807 cur_sp > (p->user_stack -
808 round_page_64(alimp->rlim_cur))) {
809 /* stack pointer is in main stack */
810 if (cur_sp <= (p->user_stack -
811 round_page_64(limp->rlim_cur))) {
812 /*
813 * New limit would cause
814 * current usage to be invalid:
815 * reject new limit.
816 */
817 error = EINVAL;
818 goto out;
819 }
820 } else {
821 /* not on the main stack: reject */
822 error = EINVAL;
823 goto out;
824 }
825
826 size = round_page_64(alimp->rlim_cur);
827 size -= round_page_64(limp->rlim_cur);
828
829 addr = p->user_stack - round_page_64(alimp->rlim_cur);
830
831 kr = mach_vm_protect(current_map(),
832 addr, size,
833 FALSE, VM_PROT_NONE);
834 if (kr != KERN_SUCCESS) {
835 error = EINVAL;
836 goto out;
837 }
838 } else {
839 /* no change ... */
840 }
841 break;
842
843 case RLIMIT_NOFILE:
844 /*
845 * Only root can set the maxfiles limits, as it is
846 * systemwide resource. If we are expecting POSIX behavior,
847 * instead of clamping the value, return EINVAL. We do this
848 * because historically, people have been able to attempt to
849 * set RLIM_INFINITY to get "whatever the maximum is".
850 */
851 if ( is_suser() ) {
852 if (limp->rlim_cur != alimp->rlim_cur &&
853 limp->rlim_cur > (rlim_t)maxfiles) {
854 if (posix) {
855 error = EINVAL;
856 goto out;
857 }
858 limp->rlim_cur = maxfiles;
859 }
860 if (limp->rlim_max != alimp->rlim_max &&
861 limp->rlim_max > (rlim_t)maxfiles)
862 limp->rlim_max = maxfiles;
863 }
864 else {
865 if (limp->rlim_cur != alimp->rlim_cur &&
866 limp->rlim_cur > (rlim_t)maxfilesperproc) {
867 if (posix) {
868 error = EINVAL;
869 goto out;
870 }
871 limp->rlim_cur = maxfilesperproc;
872 }
873 if (limp->rlim_max != alimp->rlim_max &&
874 limp->rlim_max > (rlim_t)maxfilesperproc)
875 limp->rlim_max = maxfilesperproc;
876 }
877 break;
878
879 case RLIMIT_NPROC:
880 /*
881 * Only root can set to the maxproc limits, as it is
882 * systemwide resource; all others are limited to
883 * maxprocperuid (presumably less than maxproc).
884 */
885 if ( is_suser() ) {
886 if (limp->rlim_cur > (rlim_t)maxproc)
887 limp->rlim_cur = maxproc;
888 if (limp->rlim_max > (rlim_t)maxproc)
889 limp->rlim_max = maxproc;
890 }
891 else {
892 if (limp->rlim_cur > (rlim_t)maxprocperuid)
893 limp->rlim_cur = maxprocperuid;
894 if (limp->rlim_max > (rlim_t)maxprocperuid)
895 limp->rlim_max = maxprocperuid;
896 }
897 break;
898
899 case RLIMIT_MEMLOCK:
900 /*
901 * Tell the Mach VM layer about the new limit value.
902 */
903
904 vm_map_set_user_wire_limit(current_map(), limp->rlim_cur);
905 break;
906
907 } /* switch... */
908 proc_lock(p);
909 *alimp = *limp;
910 proc_unlock(p);
911 error = 0;
912out:
913 proc_limitunblock(p);
914 return (error);
915}
916
917/* ARGSUSED */
918int
919getrlimit(struct proc *p, struct getrlimit_args *uap, __unused int32_t *retval)
920{
921 struct rlimit lim;
922
923 /*
924 * Take out flag now in case we need to use it to trigger variant
925 * behaviour later.
926 */
927 uap->which &= ~_RLIMIT_POSIX_FLAG;
928
929 if (uap->which >= RLIM_NLIMITS)
930 return (EINVAL);
931 proc_limitget(p, uap->which, &lim);
932 return (copyout((caddr_t)&lim,
933 uap->rlp, sizeof (struct rlimit)));
934}
935
936/*
937 * Transform the running time and tick information in proc p into user,
938 * system, and interrupt time usage.
939 */
940/* No lock on proc is held for this.. */
941void
942calcru(struct proc *p, struct timeval *up, struct timeval *sp, struct timeval *ip)
943{
944 task_t task;
945
946 timerclear(up);
947 timerclear(sp);
948 if (ip != NULL)
949 timerclear(ip);
950
951 task = p->task;
952 if (task) {
953 mach_task_basic_info_data_t tinfo;
954 task_thread_times_info_data_t ttimesinfo;
955 task_events_info_data_t teventsinfo;
956 mach_msg_type_number_t task_info_count, task_ttimes_count;
957 mach_msg_type_number_t task_events_count;
958 struct timeval ut,st;
959
960 task_info_count = MACH_TASK_BASIC_INFO_COUNT;
961 task_info(task, MACH_TASK_BASIC_INFO,
962 (task_info_t)&tinfo, &task_info_count);
963 ut.tv_sec = tinfo.user_time.seconds;
964 ut.tv_usec = tinfo.user_time.microseconds;
965 st.tv_sec = tinfo.system_time.seconds;
966 st.tv_usec = tinfo.system_time.microseconds;
967 timeradd(&ut, up, up);
968 timeradd(&st, sp, sp);
969
970 task_ttimes_count = TASK_THREAD_TIMES_INFO_COUNT;
971 task_info(task, TASK_THREAD_TIMES_INFO,
972 (task_info_t)&ttimesinfo, &task_ttimes_count);
973
974 ut.tv_sec = ttimesinfo.user_time.seconds;
975 ut.tv_usec = ttimesinfo.user_time.microseconds;
976 st.tv_sec = ttimesinfo.system_time.seconds;
977 st.tv_usec = ttimesinfo.system_time.microseconds;
978 timeradd(&ut, up, up);
979 timeradd(&st, sp, sp);
980
981 task_events_count = TASK_EVENTS_INFO_COUNT;
982 task_info(task, TASK_EVENTS_INFO,
983 (task_info_t)&teventsinfo, &task_events_count);
984
985 /*
986 * No need to lock "p": this does not need to be
987 * completely consistent, right ?
988 */
989 p->p_stats->p_ru.ru_minflt = (teventsinfo.faults -
990 teventsinfo.pageins);
991 p->p_stats->p_ru.ru_majflt = teventsinfo.pageins;
992 p->p_stats->p_ru.ru_nivcsw = (teventsinfo.csw -
993 p->p_stats->p_ru.ru_nvcsw);
994 if (p->p_stats->p_ru.ru_nivcsw < 0)
995 p->p_stats->p_ru.ru_nivcsw = 0;
996
997 p->p_stats->p_ru.ru_maxrss = tinfo.resident_size_max;
998 }
999}
1000
1001__private_extern__ void munge_user64_rusage(struct rusage *a_rusage_p, struct user64_rusage *a_user_rusage_p);
1002__private_extern__ void munge_user32_rusage(struct rusage *a_rusage_p, struct user32_rusage *a_user_rusage_p);
1003
1004/* ARGSUSED */
1005int
1006getrusage(struct proc *p, struct getrusage_args *uap, __unused int32_t *retval)
1007{
1008 struct rusage *rup, rubuf;
1009 struct user64_rusage rubuf64;
1010 struct user32_rusage rubuf32;
1011 size_t retsize = sizeof(rubuf); /* default: 32 bits */
1012 caddr_t retbuf = (caddr_t)&rubuf; /* default: 32 bits */
1013 struct timeval utime;
1014 struct timeval stime;
1015
1016
1017 switch (uap->who) {
1018 case RUSAGE_SELF:
1019 calcru(p, &utime, &stime, NULL);
1020 proc_lock(p);
1021 rup = &p->p_stats->p_ru;
1022 rup->ru_utime = utime;
1023 rup->ru_stime = stime;
1024
1025 rubuf = *rup;
1026 proc_unlock(p);
1027
1028 break;
1029
1030 case RUSAGE_CHILDREN:
1031 proc_lock(p);
1032 rup = &p->p_stats->p_cru;
1033 rubuf = *rup;
1034 proc_unlock(p);
1035 break;
1036
1037 default:
1038 return (EINVAL);
1039 }
1040 if (IS_64BIT_PROCESS(p)) {
1041 retsize = sizeof(rubuf64);
1042 retbuf = (caddr_t)&rubuf64;
1043 munge_user64_rusage(&rubuf, &rubuf64);
1044 } else {
1045 retsize = sizeof(rubuf32);
1046 retbuf = (caddr_t)&rubuf32;
1047 munge_user32_rusage(&rubuf, &rubuf32);
1048 }
1049
1050 return (copyout(retbuf, uap->rusage, retsize));
1051}
1052
1053void
1054ruadd(struct rusage *ru, struct rusage *ru2)
1055{
1056 long *ip, *ip2;
1057 long i;
1058
1059 timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime);
1060 timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime);
1061 if (ru->ru_maxrss < ru2->ru_maxrss)
1062 ru->ru_maxrss = ru2->ru_maxrss;
1063 ip = &ru->ru_first; ip2 = &ru2->ru_first;
1064 for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
1065 *ip++ += *ip2++;
1066}
1067
1068void
1069proc_limitget(proc_t p, int which, struct rlimit * limp)
1070{
1071 proc_list_lock();
1072 limp->rlim_cur = p->p_rlimit[which].rlim_cur;
1073 limp->rlim_max = p->p_rlimit[which].rlim_max;
1074 proc_list_unlock();
1075}
1076
1077
1078void
1079proc_limitdrop(proc_t p, int exiting)
1080{
1081 struct plimit * freelim = NULL;
1082 struct plimit * freeoldlim = NULL;
1083
1084 proc_list_lock();
1085
1086 if (--p->p_limit->pl_refcnt == 0) {
1087 freelim = p->p_limit;
1088 p->p_limit = NULL;
1089 }
1090 if ((exiting != 0) && (p->p_olimit != NULL) && (--p->p_olimit->pl_refcnt == 0)) {
1091 freeoldlim = p->p_olimit;
1092 p->p_olimit = NULL;
1093 }
1094
1095 proc_list_unlock();
1096 if (freelim != NULL)
1097 FREE_ZONE(freelim, sizeof *p->p_limit, M_PLIMIT);
1098 if (freeoldlim != NULL)
1099 FREE_ZONE(freeoldlim, sizeof *p->p_olimit, M_PLIMIT);
1100}
1101
1102
1103void
1104proc_limitfork(proc_t parent, proc_t child)
1105{
1106 proc_list_lock();
1107 child->p_limit = parent->p_limit;
1108 child->p_limit->pl_refcnt++;
1109 child->p_olimit = NULL;
1110 proc_list_unlock();
1111}
1112
1113void
1114proc_limitblock(proc_t p)
1115{
1116 proc_lock(p);
1117 while (p->p_lflag & P_LLIMCHANGE) {
1118 p->p_lflag |= P_LLIMWAIT;
1119 msleep(&p->p_olimit, &p->p_mlock, 0, "proc_limitblock", NULL);
1120 }
1121 p->p_lflag |= P_LLIMCHANGE;
1122 proc_unlock(p);
1123
1124}
1125
1126
1127void
1128proc_limitunblock(proc_t p)
1129{
1130 proc_lock(p);
1131 p->p_lflag &= ~P_LLIMCHANGE;
1132 if (p->p_lflag & P_LLIMWAIT) {
1133 p->p_lflag &= ~P_LLIMWAIT;
1134 wakeup(&p->p_olimit);
1135 }
1136 proc_unlock(p);
1137}
1138
1139/* This is called behind serialization provided by proc_limitblock/unlbock */
1140int
1141proc_limitreplace(proc_t p)
1142{
1143 struct plimit *copy;
1144
1145
1146 proc_list_lock();
1147
1148 if (p->p_limit->pl_refcnt == 1) {
1149 proc_list_unlock();
1150 return(0);
1151 }
1152
1153 proc_list_unlock();
1154
1155 MALLOC_ZONE(copy, struct plimit *,
1156 sizeof(struct plimit), M_PLIMIT, M_WAITOK);
1157 if (copy == NULL) {
1158 return(ENOMEM);
1159 }
1160
1161 proc_list_lock();
1162 bcopy(p->p_limit->pl_rlimit, copy->pl_rlimit,
1163 sizeof(struct rlimit) * RLIM_NLIMITS);
1164 copy->pl_refcnt = 1;
1165 /* hang on to reference to old till process exits */
1166 p->p_olimit = p->p_limit;
1167 p->p_limit = copy;
1168 proc_list_unlock();
1169
1170 return(0);
1171}
1172
1173
1174/*
1175 * iopolicysys
1176 *
1177 * Description: System call MUX for use in manipulating I/O policy attributes of the current process or thread
1178 *
1179 * Parameters: cmd Policy command
1180 * arg Pointer to policy arguments
1181 *
1182 * Returns: 0 Success
1183 * EINVAL Invalid command or invalid policy arguments
1184 *
1185 */
1186int
1187iopolicysys(__unused struct proc *p, __unused struct iopolicysys_args *uap, __unused int32_t *retval)
1188{
1189 int error = 0;
1190 struct _iopol_param_t iop_param;
1191 int processwide = 0;
1192
1193 if ((error = copyin(uap->arg, &iop_param, sizeof(iop_param))) != 0)
1194 goto out;
1195
1196 if (iop_param.iop_iotype != IOPOL_TYPE_DISK) {
1197 error = EINVAL;
1198 goto out;
1199 }
1200
1201 switch (iop_param.iop_scope) {
1202 case IOPOL_SCOPE_PROCESS:
1203 processwide = 1;
1204 break;
1205 case IOPOL_SCOPE_THREAD:
1206 processwide = 0;
1207 break;
1208 default:
1209 error = EINVAL;
1210 goto out;
1211 }
1212
1213 switch(uap->cmd) {
1214 case IOPOL_CMD_SET:
1215 switch (iop_param.iop_policy) {
1216 case IOPOL_DEFAULT:
1217 case IOPOL_NORMAL:
1218 case IOPOL_THROTTLE:
1219 case IOPOL_PASSIVE:
1220 case IOPOL_UTILITY:
1221 if(processwide != 0)
1222 proc_apply_task_diskacc(current_task(), iop_param.iop_policy);
1223 else
1224 proc_apply_thread_selfdiskacc(iop_param.iop_policy);
1225
1226 break;
1227 default:
1228 error = EINVAL;
1229 goto out;
1230 }
1231 break;
1232
1233 case IOPOL_CMD_GET:
1234 if(processwide != 0)
1235 iop_param.iop_policy = proc_get_task_disacc(current_task());
1236 else
1237 iop_param.iop_policy = proc_get_thread_selfdiskacc();
1238
1239 error = copyout((caddr_t)&iop_param, uap->arg, sizeof(iop_param));
1240
1241 break;
1242 default:
1243 error = EINVAL; // unknown command
1244 break;
1245 }
1246
1247out:
1248 *retval = error;
1249 return (error);
1250}
1251
1252
1253boolean_t thread_is_io_throttled(void);
1254
1255boolean_t
1256thread_is_io_throttled(void)
1257{
1258 return(proc_get_task_selfdiskacc() == IOPOL_THROTTLE);
1259}
1260
1261void
1262proc_apply_task_networkbg(void * bsd_info)
1263{
1264 proc_t p = PROC_NULL;
1265 proc_t curp = (proc_t)bsd_info;
1266 pid_t pid;
1267
1268 pid = curp->p_pid;
1269 p = proc_find(pid);
1270 if (p != PROC_NULL) {
1271 do_background_socket(p, NULL, PRIO_DARWIN_BG);
1272 proc_rele(p);
1273 }
1274}
1275
1276void
1277proc_restore_task_networkbg(void * bsd_info)
1278{
1279 proc_t p = PROC_NULL;
1280 proc_t curp = (proc_t)bsd_info;
1281 pid_t pid;
1282
1283 pid = curp->p_pid;
1284 p = proc_find(pid);
1285 if (p != PROC_NULL) {
1286 do_background_socket(p, NULL, 0);
1287 proc_rele(p);
1288 }
1289
1290}
1291
1292void
1293proc_set_task_networkbg(void * bsdinfo, int setbg)
1294{
1295 if (setbg != 0)
1296 proc_apply_task_networkbg(bsdinfo);
1297 else
1298 proc_restore_task_networkbg(bsdinfo);
1299}
1300
1301void
1302proc_apply_task_networkbg_internal(proc_t p, thread_t thread)
1303{
1304 if (p != PROC_NULL) {
1305 do_background_socket(p, thread, PRIO_DARWIN_BG);
1306 }
1307}
1308void
1309proc_restore_task_networkbg_internal(proc_t p, thread_t thread)
1310{
1311 if (p != PROC_NULL) {
1312 do_background_socket(p, thread, PRIO_DARWIN_BG);
1313 }
1314}
1315