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
1316