1 /*-
2 * Copyright (c) 1982, 1986, 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * $Id: resource.c,v 1.1 94/10/20 00:03:13 bill Exp $
34 */
35
36 #include "sys/param.h"
37 #include "sys/errno.h"
38 #include "proc.h"
39 #include "privilege.h"
40 #include "resourcevar.h"
41 #include "malloc.h"
42 #include "vm.h"
43 #include "vmspace.h"
44 #include "prototypes.h"
45
46 /*
47 * Resource controls and accounting.
48 */
49
50 getpriority(curp, uap, retval)
51 struct proc *curp;
52 register struct args {
53 int which;
54 int who;
55 } *uap;
56 int *retval;
57 {
58 register struct proc *p;
59 register int low = PRIO_MAX + 1;
60
61 switch (uap->which) {
62
63 case PRIO_PROCESS:
64 if (uap->who == 0)
65 p = curp;
66 else
67 p = pfind(uap->who);
68 if (p == 0)
69 break;
70 low = p->p_nice;
71 break;
72
73 case PRIO_PGRP: {
74 register struct pgrp *pg;
75
76 if (uap->who == 0)
77 pg = curp->p_pgrp;
78 else if ((pg = pgfind(uap->who)) == NULL)
79 break;
80 for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) {
81 if (p->p_nice < low)
82 low = p->p_nice;
83 }
84 break;
85 }
86
87 case PRIO_USER:
88 if (uap->who == 0)
89 uap->who = curp->p_ucred->cr_uid;
90 for (p = allproc; p != NULL; p = p->p_nxt) {
91 if (p->p_ucred->cr_uid == uap->who &&
92 p->p_nice < low)
93 low = p->p_nice;
94 }
95 break;
96
97 default:
98 return (EINVAL);
99 }
100 if (low == PRIO_MAX + 1)
101 return (ESRCH);
102 *retval = low;
103 return (0);
104 }
105
106 /* ARGSUSED */
107 setpriority(curp, uap, retval)
108 struct proc *curp;
109 register struct args {
110 int which;
111 int who;
112 int prio;
113 } *uap;
114 int *retval;
115 {
116 register struct proc *p;
117 int found = 0, error = 0;
118
119 switch (uap->which) {
120
121 case PRIO_PROCESS:
122 if (uap->who == 0)
123 p = curp;
124 else
125 p = pfind(uap->who);
126 if (p == 0)
127 break;
128 error = donice(curp, p, uap->prio);
129 found++;
130 break;
131
132 case PRIO_PGRP: {
133 register struct pgrp *pg;
134
135 if (uap->who == 0)
136 pg = curp->p_pgrp;
137 else if ((pg = pgfind(uap->who)) == NULL)
138 break;
139 for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) {
140 error = donice(curp, p, uap->prio);
141 found++;
142 }
143 break;
144 }
145
146 case PRIO_USER:
147 if (uap->who == 0)
148 uap->who = curp->p_ucred->cr_uid;
149 for (p = allproc; p != NULL; p = p->p_nxt)
150 if (p->p_ucred->cr_uid == uap->who) {
151 error = donice(curp, p, uap->prio);
152 found++;
153 }
154 break;
155
156 default:
157 return (EINVAL);
158 }
159 if (found == 0)
160 return (ESRCH);
161 return (0);
162 }
163
donice(curp,chgp,n)164 donice(curp, chgp, n)
165 register struct proc *curp, *chgp;
166 register int n;
167 {
168 register struct pcred *pcred = curp->p_cred;
169
170 if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
171 pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
172 pcred->p_ruid != chgp->p_ucred->cr_uid)
173 return (EPERM);
174 if (n > PRIO_MAX)
175 n = PRIO_MAX;
176 if (n < PRIO_MIN)
177 n = PRIO_MIN;
178
179 /* need a priviledge to change priority? */
180 if (n < chgp->p_nice &&
181 use_priv(pcred->pc_ucred, PRV_NICE, curp))
182 return (EACCES);
183
184 chgp->p_nice = n;
185 (void) setpri(chgp);
186 return (0);
187 }
188
189 /* priviledge associated with resource limit */
190 static cr_priv_t limit_priv[RLIM_NLIMITS] = {
191 PRV_RLIMIT_CPU, PRV_RLIMIT_FSIZE, PRV_RLIMIT_DATA, PRV_RLIMIT_STACK,
192 PRV_RLIMIT_CORE, PRV_RLIMIT_RSS, PRV_RLIMIT_MEMLOCK, PRV_RLIMIT_NPROC,
193 PRV_RLIMIT_OFILE,
194 };
195
196 /* ARGSUSED */
197 setrlimit(p, uap, retval)
198 struct proc *p;
199 register struct args {
200 u_int which;
201 struct rlimit *lim;
202 } *uap;
203 int *retval;
204 {
205 struct rlimit alim;
206 register struct rlimit *alimp;
207 int error;
208
209 /* within bounds of currently implemented resource limits ? */
210 if (uap->which >= RLIM_NLIMITS)
211 return (EINVAL);
212
213 /* fetch new limit entry into temp buffer to examine it */
214 alimp = &p->p_rlimit[uap->which];
215 if (error =
216 copyin(p, (caddr_t)uap->lim, (caddr_t)&alim, sizeof (struct rlimit)))
217 return (error);
218
219 /* if exceeding maxium limit, check for priviledge to do so */
220 if (alim.rlim_cur > alimp->rlim_max || alim.rlim_max > alimp->rlim_max)
221 if (error =
222 use_priv(p->p_ucred, limit_priv[uap->which], p))
223 return (error);
224
225 /* need to unshare limits ? */
226 if (p->p_limit->p_refcnt > 1 &&
227 (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
228 p->p_limit->p_refcnt--;
229 p->p_limit = limcopy(p->p_limit);
230 }
231
232 switch (uap->which) {
233
234 case RLIMIT_RSS:
235 if (alim.rlim_cur > proc0.p_stats->p_ru.ru_maxrss)
236 alim.rlim_cur = proc0.p_stats->p_ru.ru_maxrss;
237 if (alim.rlim_max > proc0.p_stats->p_ru.ru_maxrss)
238 alim.rlim_max = proc0.p_stats->p_ru.ru_maxrss;
239 p->p_stats->p_ru.ru_maxrss = alim.rlim_cur;
240 break;
241
242 case RLIMIT_DATA:
243 if (alim.rlim_cur > MAXDSIZ)
244 alim.rlim_cur = MAXDSIZ;
245 if (alim.rlim_max > MAXDSIZ)
246 alim.rlim_max = MAXDSIZ;
247 break;
248
249 case RLIMIT_STACK:
250 if (alim.rlim_cur > MAXDSIZ)
251 alim.rlim_cur = MAXDSIZ;
252 if (alim.rlim_max > MAXDSIZ)
253 alim.rlim_max = MAXDSIZ;
254 /*
255 * Stack is allocated to the max at exec time with only
256 * "rlim_cur" bytes accessible. If stack limit is going
257 * up make more accessible, if going down make inaccessible.
258 */
259 if (alim.rlim_cur != alimp->rlim_cur) {
260 vm_offset_t addr;
261 vm_size_t size;
262 vm_prot_t prot;
263 struct vmspace *vm = p->p_vmspace;
264
265 addr = (unsigned) vm->vm_maxsaddr + MAXSSIZ;
266 if (alim.rlim_cur > alimp->rlim_cur) {
267 prot = VM_PROT_ALL;
268 size = alim.rlim_cur - alimp->rlim_cur;
269 addr -= alim.rlim_cur;
270 } else {
271 prot = VM_PROT_NONE;
272 size = alimp->rlim_cur - alim.rlim_cur;
273 addr -= alimp->rlim_cur;
274 }
275 (void) vmspace_protect(p->p_vmspace,
276 (caddr_t)addr, size, prot, FALSE);
277 }
278 break;
279 }
280 p->p_rlimit[uap->which] = alim;
281 return (0);
282 }
283
284 /* ARGSUSED */
285 getrlimit(p, uap, retval)
286 struct proc *p;
287 register struct args {
288 u_int which;
289 struct rlimit *rlp;
290 } *uap;
291 int *retval;
292 {
293
294 if (uap->which >= RLIM_NLIMITS)
295 return (EINVAL);
296 return (copyout(p, (caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp,
297 sizeof (struct rlimit)));
298 }
299
300 /* ARGSUSED */
getrusage(p,uap,retval)301 getrusage(p, uap, retval)
302 register struct proc *p;
303 register struct args {
304 int who;
305 struct rusage *rusage;
306 } *uap;
307 int *retval;
308 {
309 register struct rusage *rup;
310
311 switch (uap->who) {
312
313 case RUSAGE_SELF: {
314 int s;
315
316 rup = &p->p_stats->p_ru;
317 s = splclock();
318 rup->ru_stime = p->p_stime;
319 rup->ru_utime = p->p_utime;
320 splx(s);
321 break;
322 }
323
324 case RUSAGE_CHILDREN:
325 rup = &p->p_stats->p_cru;
326 break;
327
328 default:
329 return (EINVAL);
330 }
331 return (copyout(p, (caddr_t)rup, (caddr_t)uap->rusage,
332 sizeof (struct rusage)));
333 }
334
335 void
ruadd(struct rusage * ru,struct rusage * ru2)336 ruadd(struct rusage *ru, struct rusage *ru2)
337 {
338 long *ip, *ip2;
339 int i;
340
341 timevaladd(&ru->ru_utime, &ru2->ru_utime);
342 timevaladd(&ru->ru_stime, &ru2->ru_stime);
343 if (ru->ru_maxrss < ru2->ru_maxrss)
344 ru->ru_maxrss = ru2->ru_maxrss;
345 ip = &ru->ru_first; ip2 = &ru2->ru_first;
346 for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
347 *ip++ += *ip2++;
348 }
349
350 /*
351 * Make a copy of the plimit structure.
352 * We share these structures copy-on-write after fork,
353 * and copy when a limit is changed.
354 */
355 struct plimit *
limcopy(lim)356 limcopy(lim)
357 struct plimit *lim;
358 {
359 register struct plimit *copy;
360
361 MALLOC(copy, struct plimit *, sizeof(struct plimit),
362 M_SUBPROC, M_WAITOK);
363 memcpy(copy->pl_rlimit, lim->pl_rlimit,
364 sizeof(struct rlimit) * RLIM_NLIMITS);
365 copy->p_lflags = 0;
366 copy->p_refcnt = 1;
367 return (copy);
368 }
369