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