kern_resource.c revision 12201
1/*-
2 * Copyright (c) 1982, 1986, 1991, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *	This product includes software developed by the University of
21 *	California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 *	@(#)kern_resource.c	8.5 (Berkeley) 1/21/94
39 * $Id: kern_resource.c,v 1.14 1995/10/23 19:05:50 bde Exp $
40 */
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/kernel.h>
45#include <sys/file.h>
46#include <sys/resourcevar.h>
47#include <sys/malloc.h>
48#include <sys/proc.h>
49
50#include <vm/vm.h>
51
52int	donice __P((struct proc *, struct proc *, int));
53int	dosetrlimit __P((struct proc *, u_int, struct rlimit *));
54
55/*
56 * Resource controls and accounting.
57 */
58
59struct getpriority_args {
60	int	which;
61	int	who;
62};
63int
64getpriority(curp, uap, retval)
65	struct proc *curp;
66	register struct getpriority_args *uap;
67	int *retval;
68{
69	register struct proc *p;
70	register int low = PRIO_MAX + 1;
71
72	switch (uap->which) {
73
74	case PRIO_PROCESS:
75		if (uap->who == 0)
76			p = curp;
77		else
78			p = pfind(uap->who);
79		if (p == 0)
80			break;
81		low = p->p_nice;
82		break;
83
84	case PRIO_PGRP: {
85		register struct pgrp *pg;
86
87		if (uap->who == 0)
88			pg = curp->p_pgrp;
89		else if ((pg = pgfind(uap->who)) == NULL)
90			break;
91		for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) {
92			if (p->p_nice < low)
93				low = p->p_nice;
94		}
95		break;
96	}
97
98	case PRIO_USER:
99		if (uap->who == 0)
100			uap->who = curp->p_ucred->cr_uid;
101		for (p = (struct proc *)allproc; p != NULL; p = p->p_next) {
102			if (p->p_ucred->cr_uid == uap->who &&
103			    p->p_nice < low)
104				low = p->p_nice;
105		}
106		break;
107
108	default:
109		return (EINVAL);
110	}
111	if (low == PRIO_MAX + 1)
112		return (ESRCH);
113	*retval = low;
114	return (0);
115}
116
117struct setpriority_args {
118	int	which;
119	int	who;
120	int	prio;
121};
122/* ARGSUSED */
123int
124setpriority(curp, uap, retval)
125	struct proc *curp;
126	register struct setpriority_args *uap;
127	int *retval;
128{
129	register struct proc *p;
130	int found = 0, error = 0;
131
132	switch (uap->which) {
133
134	case PRIO_PROCESS:
135		if (uap->who == 0)
136			p = curp;
137		else
138			p = pfind(uap->who);
139		if (p == 0)
140			break;
141		error = donice(curp, p, uap->prio);
142		found++;
143		break;
144
145	case PRIO_PGRP: {
146		register struct pgrp *pg;
147
148		if (uap->who == 0)
149			pg = curp->p_pgrp;
150		else if ((pg = pgfind(uap->who)) == NULL)
151			break;
152		for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) {
153			error = donice(curp, p, uap->prio);
154			found++;
155		}
156		break;
157	}
158
159	case PRIO_USER:
160		if (uap->who == 0)
161			uap->who = curp->p_ucred->cr_uid;
162		for (p = (struct proc *)allproc; p != NULL; p = p->p_next)
163			if (p->p_ucred->cr_uid == uap->who) {
164				error = donice(curp, p, uap->prio);
165				found++;
166			}
167		break;
168
169	default:
170		return (EINVAL);
171	}
172	if (found == 0)
173		return (ESRCH);
174	return (error);
175}
176
177int
178donice(curp, chgp, n)
179	register struct proc *curp, *chgp;
180	register int n;
181{
182	register struct pcred *pcred = curp->p_cred;
183
184	if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
185	    pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
186	    pcred->p_ruid != chgp->p_ucred->cr_uid)
187		return (EPERM);
188	if (n > PRIO_MAX)
189		n = PRIO_MAX;
190	if (n < PRIO_MIN)
191		n = PRIO_MIN;
192	if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag))
193		return (EACCES);
194	chgp->p_nice = n;
195	(void)resetpriority(chgp);
196	return (0);
197}
198
199/* rtprio system call */
200struct rtprio_args {
201	int		function;
202	pid_t		pid;
203	struct rtprio	*rtp;
204};
205
206/*
207 * Set realtime priority
208 */
209
210/* ARGSUSED */
211int
212rtprio(curp, uap, retval)
213	struct proc *curp;
214	register struct rtprio_args *uap;
215	int *retval;
216{
217	register struct proc *p;
218	register struct pcred *pcred = curp->p_cred;
219	struct rtprio rtp;
220	int error;
221
222	error = copyin(uap->rtp, &rtp, sizeof(struct rtprio));
223	if (error)
224		return (error);
225
226	if (uap->pid == 0)
227		p = curp;
228	else
229		p = pfind(uap->pid);
230
231	if (p == 0)
232		return (ESRCH);
233
234	switch (uap->function) {
235	case RTP_LOOKUP:
236		return (copyout(&p->p_rtprio, uap->rtp, sizeof(struct rtprio)));
237	case RTP_SET:
238		if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
239		    pcred->pc_ucred->cr_uid != p->p_ucred->cr_uid &&
240		    pcred->p_ruid != p->p_ucred->cr_uid)
241		        return (EPERM);
242		/* disallow setting rtprio in most cases if not superuser */
243		if (suser(pcred->pc_ucred, &curp->p_acflag)) {
244			/* can't set someone else's */
245			if (uap->pid)
246				return (EPERM);
247			/* can't set realtime priority */
248			if (rtp.type == RTP_PRIO_REALTIME)
249				return (EPERM);
250		}
251		switch (rtp.type) {
252		case RTP_PRIO_REALTIME:
253		case RTP_PRIO_NORMAL:
254		case RTP_PRIO_IDLE:
255			if (rtp.prio > RTP_PRIO_MAX)
256				return (EINVAL);
257			p->p_rtprio = rtp;
258			return (0);
259		default:
260			return (EINVAL);
261		}
262
263	default:
264		return (EINVAL);
265	}
266}
267
268#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
269struct osetrlimit_args {
270	u_int	which;
271	struct	orlimit *rlp;
272};
273/* ARGSUSED */
274int
275osetrlimit(p, uap, retval)
276	struct proc *p;
277	register struct osetrlimit_args *uap;
278	int *retval;
279{
280	struct orlimit olim;
281	struct rlimit lim;
282	int error;
283
284	if ((error =
285	    copyin((caddr_t)uap->rlp, (caddr_t)&olim, sizeof(struct orlimit))))
286		return (error);
287	lim.rlim_cur = olim.rlim_cur;
288	lim.rlim_max = olim.rlim_max;
289	return (dosetrlimit(p, uap->which, &lim));
290}
291
292struct ogetrlimit_args {
293	u_int	which;
294	struct	orlimit *rlp;
295};
296/* ARGSUSED */
297int
298ogetrlimit(p, uap, retval)
299	struct proc *p;
300	register struct ogetrlimit_args *uap;
301	int *retval;
302{
303	struct orlimit olim;
304
305	if (uap->which >= RLIM_NLIMITS)
306		return (EINVAL);
307	olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur;
308	if (olim.rlim_cur == -1)
309		olim.rlim_cur = 0x7fffffff;
310	olim.rlim_max = p->p_rlimit[uap->which].rlim_max;
311	if (olim.rlim_max == -1)
312		olim.rlim_max = 0x7fffffff;
313	return (copyout((caddr_t)&olim, (caddr_t)uap->rlp, sizeof(olim)));
314}
315#endif /* COMPAT_43 || COMPAT_SUNOS */
316
317struct __setrlimit_args {
318	u_int	which;
319	struct	rlimit *rlp;
320};
321/* ARGSUSED */
322int
323setrlimit(p, uap, retval)
324	struct proc *p;
325	register struct __setrlimit_args *uap;
326	int *retval;
327{
328	struct rlimit alim;
329	int error;
330
331	if ((error =
332	    copyin((caddr_t)uap->rlp, (caddr_t)&alim, sizeof (struct rlimit))))
333		return (error);
334	return (dosetrlimit(p, uap->which, &alim));
335}
336
337int
338dosetrlimit(p, which, limp)
339	struct proc *p;
340	u_int which;
341	struct rlimit *limp;
342{
343	register struct rlimit *alimp;
344	int error;
345
346	if (which >= RLIM_NLIMITS)
347		return (EINVAL);
348	alimp = &p->p_rlimit[which];
349
350	/*
351	 * Preserve historical bugs by treating negative limits as unsigned.
352	 */
353	if (limp->rlim_cur < 0)
354		limp->rlim_cur = RLIM_INFINITY;
355	if (limp->rlim_max < 0)
356		limp->rlim_max = RLIM_INFINITY;
357
358	if (limp->rlim_cur > alimp->rlim_max ||
359	    limp->rlim_max > alimp->rlim_max)
360		if ((error = suser(p->p_ucred, &p->p_acflag)))
361			return (error);
362	if (limp->rlim_cur > limp->rlim_max)
363		limp->rlim_cur = limp->rlim_max;
364	if (p->p_limit->p_refcnt > 1 &&
365	    (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
366		p->p_limit->p_refcnt--;
367		p->p_limit = limcopy(p->p_limit);
368		alimp = &p->p_rlimit[which];
369	}
370
371	switch (which) {
372
373	case RLIMIT_DATA:
374		if (limp->rlim_cur > MAXDSIZ)
375			limp->rlim_cur = MAXDSIZ;
376		if (limp->rlim_max > MAXDSIZ)
377			limp->rlim_max = MAXDSIZ;
378		break;
379
380	case RLIMIT_STACK:
381		if (limp->rlim_cur > MAXSSIZ)
382			limp->rlim_cur = MAXSSIZ;
383		if (limp->rlim_max > MAXSSIZ)
384			limp->rlim_max = MAXSSIZ;
385		/*
386		 * Stack is allocated to the max at exec time with only
387		 * "rlim_cur" bytes accessible.  If stack limit is going
388		 * up make more accessible, if going down make inaccessible.
389		 */
390		if (limp->rlim_cur != alimp->rlim_cur) {
391			vm_offset_t addr;
392			vm_size_t size;
393			vm_prot_t prot;
394
395			if (limp->rlim_cur > alimp->rlim_cur) {
396				prot = VM_PROT_ALL;
397				size = limp->rlim_cur - alimp->rlim_cur;
398				addr = USRSTACK - limp->rlim_cur;
399			} else {
400				prot = VM_PROT_NONE;
401				size = alimp->rlim_cur - limp->rlim_cur;
402				addr = USRSTACK - alimp->rlim_cur;
403			}
404			addr = trunc_page(addr);
405			size = round_page(size);
406			(void) vm_map_protect(&p->p_vmspace->vm_map,
407					      addr, addr+size, prot, FALSE);
408		}
409		break;
410
411	case RLIMIT_NOFILE:
412		if (limp->rlim_cur > maxfilesperproc)
413			limp->rlim_cur = maxfilesperproc;
414		if (limp->rlim_max > maxfilesperproc)
415			limp->rlim_max = maxfilesperproc;
416		break;
417
418	case RLIMIT_NPROC:
419		if (limp->rlim_cur > maxprocperuid)
420			limp->rlim_cur = maxprocperuid;
421		if (limp->rlim_max > maxprocperuid)
422			limp->rlim_max = maxprocperuid;
423		break;
424	}
425	*alimp = *limp;
426	return (0);
427}
428
429struct __getrlimit_args {
430	u_int	which;
431	struct	rlimit *rlp;
432};
433/* ARGSUSED */
434int
435getrlimit(p, uap, retval)
436	struct proc *p;
437	register struct __getrlimit_args *uap;
438	int *retval;
439{
440
441	if (uap->which >= RLIM_NLIMITS)
442		return (EINVAL);
443	return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp,
444	    sizeof (struct rlimit)));
445}
446
447/*
448 * Transform the running time and tick information in proc p into user,
449 * system, and interrupt time usage.
450 */
451void
452calcru(p, up, sp, ip)
453	register struct proc *p;
454	register struct timeval *up;
455	register struct timeval *sp;
456	register struct timeval *ip;
457{
458	register quad_t totusec;
459	register u_quad_t u, st, ut, it, tot;
460	register long sec, usec;
461	register int s;
462	struct timeval tv;
463
464	s = splstatclock();
465	st = p->p_sticks;
466	ut = p->p_uticks;
467	it = p->p_iticks;
468	splx(s);
469
470	tot = st + ut + it;
471	if (tot == 0) {
472		up->tv_sec = up->tv_usec = 0;
473		sp->tv_sec = sp->tv_usec = 0;
474		if (ip != NULL)
475			ip->tv_sec = ip->tv_usec = 0;
476		return;
477	}
478
479	sec = p->p_rtime.tv_sec;
480	usec = p->p_rtime.tv_usec;
481	if (p == curproc) {
482		/*
483		 * Adjust for the current time slice.  This is actually fairly
484		 * important since the error here is on the order of a time
485		 * quantum, which is much greater than the sampling error.
486		 */
487		microtime(&tv);
488		sec += tv.tv_sec - runtime.tv_sec;
489		usec += tv.tv_usec - runtime.tv_usec;
490	}
491	totusec = (quad_t)sec * 1000000 + usec;
492	if (totusec < 0) {
493		printf("calcru: negative time: %qd usec\n", totusec);
494		totusec = 0;
495	}
496	u = totusec;
497	st = (u * st) / tot;
498	sp->tv_sec = st / 1000000;
499	sp->tv_usec = st % 1000000;
500	ut = (u * ut) / tot;
501	up->tv_sec = ut / 1000000;
502	up->tv_usec = ut % 1000000;
503	if (ip != NULL) {
504		it = (u * it) / tot;
505		ip->tv_sec = it / 1000000;
506		ip->tv_usec = it % 1000000;
507	}
508}
509
510struct getrusage_args {
511	int	who;
512	struct	rusage *rusage;
513};
514/* ARGSUSED */
515int
516getrusage(p, uap, retval)
517	register struct proc *p;
518	register struct getrusage_args *uap;
519	int *retval;
520{
521	register struct rusage *rup;
522
523	switch (uap->who) {
524
525	case RUSAGE_SELF:
526		rup = &p->p_stats->p_ru;
527		calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
528		break;
529
530	case RUSAGE_CHILDREN:
531		rup = &p->p_stats->p_cru;
532		break;
533
534	default:
535		return (EINVAL);
536	}
537	return (copyout((caddr_t)rup, (caddr_t)uap->rusage,
538	    sizeof (struct rusage)));
539}
540
541void
542ruadd(ru, ru2)
543	register struct rusage *ru, *ru2;
544{
545	register long *ip, *ip2;
546	register int i;
547
548	timevaladd(&ru->ru_utime, &ru2->ru_utime);
549	timevaladd(&ru->ru_stime, &ru2->ru_stime);
550	if (ru->ru_maxrss < ru2->ru_maxrss)
551		ru->ru_maxrss = ru2->ru_maxrss;
552	ip = &ru->ru_first; ip2 = &ru2->ru_first;
553	for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
554		*ip++ += *ip2++;
555}
556
557/*
558 * Make a copy of the plimit structure.
559 * We share these structures copy-on-write after fork,
560 * and copy when a limit is changed.
561 */
562struct plimit *
563limcopy(lim)
564	struct plimit *lim;
565{
566	register struct plimit *copy;
567
568	MALLOC(copy, struct plimit *, sizeof(struct plimit),
569	    M_SUBPROC, M_WAITOK);
570	bcopy(lim->pl_rlimit, copy->pl_rlimit,
571	    sizeof(struct rlimit) * RLIM_NLIMITS);
572	copy->p_lflags = 0;
573	copy->p_refcnt = 1;
574	return (copy);
575}
576