xref: /original-bsd/sys/kern/kern_resource.c (revision 03767421)
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  * %sccs.include.redist.c%
11  *
12  *	@(#)kern_resource.c	8.8 (Berkeley) 02/14/95
13  */
14 
15 #include <sys/param.h>
16 #include <sys/systm.h>
17 #include <sys/kernel.h>
18 #include <sys/file.h>
19 #include <sys/resourcevar.h>
20 #include <sys/malloc.h>
21 #include <sys/proc.h>
22 
23 #include <sys/mount.h>
24 #include <sys/syscallargs.h>
25 
26 #include <vm/vm.h>
27 
28 int	donice __P((struct proc *curp, struct proc *chgp, int n));
29 int	dosetrlimit __P((struct proc *p, u_int which, struct rlimit *limp));
30 
31 /*
32  * Resource controls and accounting.
33  */
34 
35 int
getpriority(curp,uap,retval)36 getpriority(curp, uap, retval)
37 	struct proc *curp;
38 	register struct getpriority_args /* {
39 		syscallarg(int) which;
40 		syscallarg(int) who;
41 	} */ *uap;
42 	register_t *retval;
43 {
44 	register struct proc *p;
45 	register int low = PRIO_MAX + 1;
46 
47 	switch (SCARG(uap, which)) {
48 
49 	case PRIO_PROCESS:
50 		if (SCARG(uap, who) == 0)
51 			p = curp;
52 		else
53 			p = pfind(SCARG(uap, who));
54 		if (p == 0)
55 			break;
56 		low = p->p_nice;
57 		break;
58 
59 	case PRIO_PGRP: {
60 		register struct pgrp *pg;
61 
62 		if (SCARG(uap, who) == 0)
63 			pg = curp->p_pgrp;
64 		else if ((pg = pgfind(SCARG(uap, who))) == NULL)
65 			break;
66 		for (p = pg->pg_members.lh_first; p != 0;
67 		     p = p->p_pglist.le_next) {
68 			if (p->p_nice < low)
69 				low = p->p_nice;
70 		}
71 		break;
72 	}
73 
74 	case PRIO_USER:
75 		if (SCARG(uap, who) == 0)
76 			SCARG(uap, who) = curp->p_ucred->cr_uid;
77 		for (p = allproc.lh_first; p != 0; p = p->p_list.le_next)
78 			if (p->p_ucred->cr_uid == SCARG(uap, who) &&
79 			    p->p_nice < low)
80 				low = p->p_nice;
81 		break;
82 
83 	default:
84 		return (EINVAL);
85 	}
86 	if (low == PRIO_MAX + 1)
87 		return (ESRCH);
88 	*retval = low;
89 	return (0);
90 }
91 
92 /* ARGSUSED */
93 int
setpriority(curp,uap,retval)94 setpriority(curp, uap, retval)
95 	struct proc *curp;
96 	register struct setpriority_args /* {
97 		syscallarg(int) which;
98 		syscallarg(int) who;
99 		syscallarg(int) prio;
100 	} */ *uap;
101 	register_t *retval;
102 {
103 	register struct proc *p;
104 	int found = 0, error = 0;
105 
106 	switch (SCARG(uap, which)) {
107 
108 	case PRIO_PROCESS:
109 		if (SCARG(uap, who) == 0)
110 			p = curp;
111 		else
112 			p = pfind(SCARG(uap, who));
113 		if (p == 0)
114 			break;
115 		error = donice(curp, p, SCARG(uap, prio));
116 		found++;
117 		break;
118 
119 	case PRIO_PGRP: {
120 		register struct pgrp *pg;
121 
122 		if (SCARG(uap, who) == 0)
123 			pg = curp->p_pgrp;
124 		else if ((pg = pgfind(SCARG(uap, who))) == NULL)
125 			break;
126 		for (p = pg->pg_members.lh_first; p != 0;
127 		    p = p->p_pglist.le_next) {
128 			error = donice(curp, p, SCARG(uap, prio));
129 			found++;
130 		}
131 		break;
132 	}
133 
134 	case PRIO_USER:
135 		if (SCARG(uap, who) == 0)
136 			SCARG(uap, who) = curp->p_ucred->cr_uid;
137 		for (p = allproc.lh_first; p != 0; p = p->p_list.le_next)
138 			if (p->p_ucred->cr_uid == SCARG(uap, who)) {
139 				error = donice(curp, p, SCARG(uap, prio));
140 				found++;
141 			}
142 		break;
143 
144 	default:
145 		return (EINVAL);
146 	}
147 	if (found == 0)
148 		return (ESRCH);
149 	return (error);
150 }
151 
152 int
donice(curp,chgp,n)153 donice(curp, chgp, n)
154 	register struct proc *curp, *chgp;
155 	register int n;
156 {
157 	register struct pcred *pcred = curp->p_cred;
158 
159 	if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
160 	    pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
161 	    pcred->p_ruid != chgp->p_ucred->cr_uid)
162 		return (EPERM);
163 	if (n > PRIO_MAX)
164 		n = PRIO_MAX;
165 	if (n < PRIO_MIN)
166 		n = PRIO_MIN;
167 	if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag))
168 		return (EACCES);
169 	chgp->p_nice = n;
170 	(void)resetpriority(chgp);
171 	return (0);
172 }
173 
174 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
175 /* ARGSUSED */
176 int
compat_43_setrlimit(p,uap,retval)177 compat_43_setrlimit(p, uap, retval)
178 	struct proc *p;
179 	struct compat_43_setrlimit_args /* {
180 		syscallarg(u_int) which;
181 		syscallarg(struct ogetrlimit *) rlp;
182 	} */ *uap;
183 	register_t *retval;
184 {
185 	struct orlimit olim;
186 	struct rlimit lim;
187 	int error;
188 
189 	if (error = copyin((caddr_t)SCARG(uap, rlp), (caddr_t)&olim,
190 	    sizeof (struct orlimit)))
191 		return (error);
192 	lim.rlim_cur = olim.rlim_cur;
193 	lim.rlim_max = olim.rlim_max;
194 	return (dosetrlimit(p, SCARG(uap, which), &lim));
195 }
196 
197 /* ARGSUSED */
198 int
compat_43_getrlimit(p,uap,retval)199 compat_43_getrlimit(p, uap, retval)
200 	struct proc *p;
201 	register struct compat_43_getrlimit_args /* {
202 		syscallarg(u_int) which;
203 		syscallarg(struct ogetrlimit *) rlp;
204 	} */ *uap;
205 	register_t *retval;
206 {
207 	struct orlimit olim;
208 
209 	if (SCARG(uap, which) >= RLIM_NLIMITS)
210 		return (EINVAL);
211 	olim.rlim_cur = p->p_rlimit[SCARG(uap, which)].rlim_cur;
212 	if (olim.rlim_cur == -1)
213 		olim.rlim_cur = 0x7fffffff;
214 	olim.rlim_max = p->p_rlimit[SCARG(uap, which)].rlim_max;
215 	if (olim.rlim_max == -1)
216 		olim.rlim_max = 0x7fffffff;
217 	return (copyout((caddr_t)&olim, (caddr_t)SCARG(uap, rlp),
218 	    sizeof(olim)));
219 }
220 #endif /* COMPAT_43 || COMPAT_SUNOS */
221 
222 /* ARGSUSED */
223 int
setrlimit(p,uap,retval)224 setrlimit(p, uap, retval)
225 	struct proc *p;
226 	register struct setrlimit_args /* {
227 		syscallarg(u_int) which;
228 		syscallarg(struct rlimit *) rlp;
229 	} */ *uap;
230 	register_t *retval;
231 {
232 	struct rlimit alim;
233 	int error;
234 
235 	if (error = copyin((caddr_t)SCARG(uap, rlp), (caddr_t)&alim,
236 	    sizeof (struct rlimit)))
237 		return (error);
238 	return (dosetrlimit(p, SCARG(uap, which), &alim));
239 }
240 
241 int
dosetrlimit(p,which,limp)242 dosetrlimit(p, which, limp)
243 	struct proc *p;
244 	u_int which;
245 	struct rlimit *limp;
246 {
247 	register struct rlimit *alimp;
248 	extern unsigned maxdmap;
249 	int error;
250 
251 	if (which >= RLIM_NLIMITS)
252 		return (EINVAL);
253 	alimp = &p->p_rlimit[which];
254 	if (limp->rlim_cur > alimp->rlim_max ||
255 	    limp->rlim_max > alimp->rlim_max)
256 		if (error = suser(p->p_ucred, &p->p_acflag))
257 			return (error);
258 	if (limp->rlim_cur > limp->rlim_max)
259 		limp->rlim_cur = limp->rlim_max;
260 	if (p->p_limit->p_refcnt > 1 &&
261 	    (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
262 		p->p_limit->p_refcnt--;
263 		p->p_limit = limcopy(p->p_limit);
264 		alimp = &p->p_rlimit[which];
265 	}
266 
267 	switch (which) {
268 
269 	case RLIMIT_DATA:
270 		if (limp->rlim_cur > maxdmap)
271 			limp->rlim_cur = maxdmap;
272 		if (limp->rlim_max > maxdmap)
273 			limp->rlim_max = maxdmap;
274 		break;
275 
276 	case RLIMIT_STACK:
277 		if (limp->rlim_cur > maxdmap)
278 			limp->rlim_cur = maxdmap;
279 		if (limp->rlim_max > maxdmap)
280 			limp->rlim_max = maxdmap;
281 		/*
282 		 * Stack is allocated to the max at exec time with only
283 		 * "rlim_cur" bytes accessible.  If stack limit is going
284 		 * up make more accessible, if going down make inaccessible.
285 		 */
286 		if (limp->rlim_cur != alimp->rlim_cur) {
287 			vm_offset_t addr;
288 			vm_size_t size;
289 			vm_prot_t prot;
290 
291 			if (limp->rlim_cur > alimp->rlim_cur) {
292 				prot = VM_PROT_ALL;
293 				size = limp->rlim_cur - alimp->rlim_cur;
294 				addr = USRSTACK - limp->rlim_cur;
295 			} else {
296 				prot = VM_PROT_NONE;
297 				size = alimp->rlim_cur - limp->rlim_cur;
298 				addr = USRSTACK - alimp->rlim_cur;
299 			}
300 			addr = trunc_page(addr);
301 			size = round_page(size);
302 			(void) vm_map_protect(&p->p_vmspace->vm_map,
303 					      addr, addr+size, prot, FALSE);
304 		}
305 		break;
306 
307 	case RLIMIT_NOFILE:
308 		if (limp->rlim_cur > maxfiles)
309 			limp->rlim_cur = maxfiles;
310 		if (limp->rlim_max > maxfiles)
311 			limp->rlim_max = maxfiles;
312 		break;
313 
314 	case RLIMIT_NPROC:
315 		if (limp->rlim_cur > maxproc)
316 			limp->rlim_cur = maxproc;
317 		if (limp->rlim_max > maxproc)
318 			limp->rlim_max = maxproc;
319 		break;
320 	}
321 	*alimp = *limp;
322 	return (0);
323 }
324 
325 /* ARGSUSED */
326 int
getrlimit(p,uap,retval)327 getrlimit(p, uap, retval)
328 	struct proc *p;
329 	register struct getrlimit_args /* {
330 		syscallarg(u_int) which;
331 		syscallarg(struct rlimit *) rlp;
332 	} */ *uap;
333 	register_t *retval;
334 {
335 
336 	if (SCARG(uap, which) >= RLIM_NLIMITS)
337 		return (EINVAL);
338 	return (copyout((caddr_t)&p->p_rlimit[SCARG(uap, which)],
339 	    (caddr_t)SCARG(uap, rlp), sizeof (struct rlimit)));
340 }
341 
342 /*
343  * Transform the running time and tick information in proc p into user,
344  * system, and interrupt time usage.
345  */
346 void
calcru(p,up,sp,ip)347 calcru(p, up, sp, ip)
348 	register struct proc *p;
349 	register struct timeval *up;
350 	register struct timeval *sp;
351 	register struct timeval *ip;
352 {
353 	register u_quad_t u, st, ut, it, tot;
354 	register u_long sec, usec;
355 	register int s;
356 	struct timeval tv;
357 
358 	s = splstatclock();
359 	st = p->p_sticks;
360 	ut = p->p_uticks;
361 	it = p->p_iticks;
362 	splx(s);
363 
364 	tot = st + ut + it;
365 	if (tot == 0) {
366 		up->tv_sec = up->tv_usec = 0;
367 		sp->tv_sec = sp->tv_usec = 0;
368 		if (ip != NULL)
369 			ip->tv_sec = ip->tv_usec = 0;
370 		return;
371 	}
372 
373 	sec = p->p_rtime.tv_sec;
374 	usec = p->p_rtime.tv_usec;
375 	if (p == curproc) {
376 		/*
377 		 * Adjust for the current time slice.  This is actually fairly
378 		 * important since the error here is on the order of a time
379 		 * quantum, which is much greater than the sampling error.
380 		 */
381 		microtime(&tv);
382 		sec += tv.tv_sec - runtime.tv_sec;
383 		usec += tv.tv_usec - runtime.tv_usec;
384 	}
385 	u = sec * 1000000 + usec;
386 	st = (u * st) / tot;
387 	sp->tv_sec = st / 1000000;
388 	sp->tv_usec = st % 1000000;
389 	ut = (u * ut) / tot;
390 	up->tv_sec = ut / 1000000;
391 	up->tv_usec = ut % 1000000;
392 	if (ip != NULL) {
393 		it = (u * it) / tot;
394 		ip->tv_sec = it / 1000000;
395 		ip->tv_usec = it % 1000000;
396 	}
397 }
398 
399 /* ARGSUSED */
400 int
getrusage(p,uap,retval)401 getrusage(p, uap, retval)
402 	register struct proc *p;
403 	register struct getrusage_args /* {
404 		syscallarg(int) who;
405 		syscallarg(struct rusage *) rusage;
406 	} */ *uap;
407 	register_t *retval;
408 {
409 	register struct rusage *rup;
410 
411 	switch (SCARG(uap, who)) {
412 
413 	case RUSAGE_SELF:
414 		rup = &p->p_stats->p_ru;
415 		calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
416 		break;
417 
418 	case RUSAGE_CHILDREN:
419 		rup = &p->p_stats->p_cru;
420 		break;
421 
422 	default:
423 		return (EINVAL);
424 	}
425 	return (copyout((caddr_t)rup, (caddr_t)SCARG(uap, rusage),
426 	    sizeof (struct rusage)));
427 }
428 
429 void
ruadd(ru,ru2)430 ruadd(ru, ru2)
431 	register struct rusage *ru, *ru2;
432 {
433 	register long *ip, *ip2;
434 	register int i;
435 
436 	timevaladd(&ru->ru_utime, &ru2->ru_utime);
437 	timevaladd(&ru->ru_stime, &ru2->ru_stime);
438 	if (ru->ru_maxrss < ru2->ru_maxrss)
439 		ru->ru_maxrss = ru2->ru_maxrss;
440 	ip = &ru->ru_first; ip2 = &ru2->ru_first;
441 	for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
442 		*ip++ += *ip2++;
443 }
444 
445 /*
446  * Make a copy of the plimit structure.
447  * We share these structures copy-on-write after fork,
448  * and copy when a limit is changed.
449  */
450 struct plimit *
limcopy(lim)451 limcopy(lim)
452 	struct plimit *lim;
453 {
454 	register struct plimit *copy;
455 
456 	MALLOC(copy, struct plimit *, sizeof(struct plimit),
457 	    M_SUBPROC, M_WAITOK);
458 	bcopy(lim->pl_rlimit, copy->pl_rlimit,
459 	    sizeof(struct rlimit) * RLIM_NLIMITS);
460 	copy->p_lflags = 0;
461 	copy->p_refcnt = 1;
462 	return (copy);
463 }
464