xref: /386bsd/usr/src/kernel/kern/resource.c (revision a2142627)
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