1 /* $OpenBSD: kern_resource.c,v 1.5 1996/07/02 09:23:19 deraadt Exp $ */ 2 /* $NetBSD: kern_resource.c,v 1.34.4.1 1996/06/13 23:31:14 jtc Exp $ */ 3 4 /*- 5 * Copyright (c) 1982, 1986, 1991, 1993 6 * The Regents of the University of California. All rights reserved. 7 * (c) UNIX System Laboratories, Inc. 8 * All or some portions of this file are derived from material licensed 9 * to the University of California by American Telephone and Telegraph 10 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 11 * the permission of UNIX System Laboratories, Inc. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. All advertising materials mentioning features or use of this software 22 * must display the following acknowledgement: 23 * This product includes software developed by the University of 24 * California, Berkeley and its contributors. 25 * 4. Neither the name of the University nor the names of its contributors 26 * may be used to endorse or promote products derived from this software 27 * without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 * 41 * @(#)kern_resource.c 8.5 (Berkeley) 1/21/94 42 */ 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/kernel.h> 47 #include <sys/file.h> 48 #include <sys/resourcevar.h> 49 #include <sys/malloc.h> 50 #include <sys/proc.h> 51 52 #include <sys/mount.h> 53 #include <sys/syscallargs.h> 54 55 #include <vm/vm.h> 56 57 void limfree __P((struct plimit *)); 58 /* 59 * Resource controls and accounting. 60 */ 61 62 int 63 sys_getpriority(curp, v, retval) 64 struct proc *curp; 65 void *v; 66 register_t *retval; 67 { 68 register struct sys_getpriority_args /* { 69 syscallarg(int) which; 70 syscallarg(int) who; 71 } */ *uap = v; 72 register struct proc *p; 73 register int low = PRIO_MAX + 1; 74 75 switch (SCARG(uap, which)) { 76 77 case PRIO_PROCESS: 78 if (SCARG(uap, who) == 0) 79 p = curp; 80 else 81 p = pfind(SCARG(uap, who)); 82 if (p == 0) 83 break; 84 low = p->p_nice; 85 break; 86 87 case PRIO_PGRP: { 88 register struct pgrp *pg; 89 90 if (SCARG(uap, who) == 0) 91 pg = curp->p_pgrp; 92 else if ((pg = pgfind(SCARG(uap, who))) == NULL) 93 break; 94 for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) { 95 if (p->p_nice < low) 96 low = p->p_nice; 97 } 98 break; 99 } 100 101 case PRIO_USER: 102 if (SCARG(uap, who) == 0) 103 SCARG(uap, who) = curp->p_ucred->cr_uid; 104 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) 105 if (p->p_ucred->cr_uid == SCARG(uap, who) && 106 p->p_nice < low) 107 low = p->p_nice; 108 break; 109 110 default: 111 return (EINVAL); 112 } 113 if (low == PRIO_MAX + 1) 114 return (ESRCH); 115 *retval = low; 116 return (0); 117 } 118 119 /* ARGSUSED */ 120 int 121 sys_setpriority(curp, v, retval) 122 struct proc *curp; 123 void *v; 124 register_t *retval; 125 { 126 register struct sys_setpriority_args /* { 127 syscallarg(int) which; 128 syscallarg(int) who; 129 syscallarg(int) prio; 130 } */ *uap = v; 131 register struct proc *p; 132 int found = 0, error = 0; 133 134 switch (SCARG(uap, which)) { 135 136 case PRIO_PROCESS: 137 if (SCARG(uap, who) == 0) 138 p = curp; 139 else 140 p = pfind(SCARG(uap, who)); 141 if (p == 0) 142 break; 143 error = donice(curp, p, SCARG(uap, prio)); 144 found++; 145 break; 146 147 case PRIO_PGRP: { 148 register struct pgrp *pg; 149 150 if (SCARG(uap, who) == 0) 151 pg = curp->p_pgrp; 152 else if ((pg = pgfind(SCARG(uap, who))) == NULL) 153 break; 154 for (p = pg->pg_members.lh_first; p != 0; 155 p = p->p_pglist.le_next) { 156 error = donice(curp, p, SCARG(uap, prio)); 157 found++; 158 } 159 break; 160 } 161 162 case PRIO_USER: 163 if (SCARG(uap, who) == 0) 164 SCARG(uap, who) = curp->p_ucred->cr_uid; 165 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) 166 if (p->p_ucred->cr_uid == SCARG(uap, who)) { 167 error = donice(curp, p, SCARG(uap, prio)); 168 found++; 169 } 170 break; 171 172 default: 173 return (EINVAL); 174 } 175 if (found == 0) 176 return (ESRCH); 177 return (error); 178 } 179 180 int 181 donice(curp, chgp, n) 182 register struct proc *curp, *chgp; 183 register int n; 184 { 185 register struct pcred *pcred = curp->p_cred; 186 187 if (pcred->pc_ucred->cr_uid && pcred->p_ruid && 188 pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid && 189 pcred->p_ruid != chgp->p_ucred->cr_uid) 190 return (EPERM); 191 if (n > PRIO_MAX) 192 n = PRIO_MAX; 193 if (n < PRIO_MIN) 194 n = PRIO_MIN; 195 if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag)) 196 return (EACCES); 197 chgp->p_nice = n; 198 (void)resetpriority(chgp); 199 return (0); 200 } 201 202 /* ARGSUSED */ 203 int 204 sys_setrlimit(p, v, retval) 205 struct proc *p; 206 void *v; 207 register_t *retval; 208 { 209 register struct sys_setrlimit_args /* { 210 syscallarg(u_int) which; 211 syscallarg(struct rlimit *) rlp; 212 } */ *uap = v; 213 struct rlimit alim; 214 int error; 215 216 error = copyin((caddr_t)SCARG(uap, rlp), (caddr_t)&alim, 217 sizeof (struct rlimit)); 218 if (error) 219 return (error); 220 return (dosetrlimit(p, SCARG(uap, which), &alim)); 221 } 222 223 int 224 dosetrlimit(p, which, limp) 225 struct proc *p; 226 u_int which; 227 struct rlimit *limp; 228 { 229 register struct rlimit *alimp; 230 extern unsigned maxdmap, maxsmap; 231 int error; 232 233 if (which >= RLIM_NLIMITS) 234 return (EINVAL); 235 alimp = &p->p_rlimit[which]; 236 if (limp->rlim_cur > alimp->rlim_max || 237 limp->rlim_max > alimp->rlim_max) 238 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 239 return (error); 240 if (limp->rlim_cur > limp->rlim_max) 241 limp->rlim_cur = limp->rlim_max; 242 if (p->p_limit->p_refcnt > 1 && 243 (p->p_limit->p_lflags & PL_SHAREMOD) == 0) { 244 p->p_limit->p_refcnt--; 245 p->p_limit = limcopy(p->p_limit); 246 alimp = &p->p_rlimit[which]; 247 } 248 249 switch (which) { 250 251 case RLIMIT_DATA: 252 if (limp->rlim_cur > maxdmap) 253 limp->rlim_cur = maxdmap; 254 if (limp->rlim_max > maxdmap) 255 limp->rlim_max = maxdmap; 256 break; 257 258 case RLIMIT_STACK: 259 if (limp->rlim_cur > maxsmap) 260 limp->rlim_cur = maxsmap; 261 if (limp->rlim_max > maxsmap) 262 limp->rlim_max = maxsmap; 263 /* 264 * Stack is allocated to the max at exec time with only 265 * "rlim_cur" bytes accessible. If stack limit is going 266 * up make more accessible, if going down make inaccessible. 267 */ 268 if (limp->rlim_cur != alimp->rlim_cur) { 269 vm_offset_t addr; 270 vm_size_t size; 271 vm_prot_t prot; 272 273 if (limp->rlim_cur > alimp->rlim_cur) { 274 prot = VM_PROT_ALL; 275 size = limp->rlim_cur - alimp->rlim_cur; 276 addr = USRSTACK - limp->rlim_cur; 277 } else { 278 prot = VM_PROT_NONE; 279 size = alimp->rlim_cur - limp->rlim_cur; 280 addr = USRSTACK - alimp->rlim_cur; 281 } 282 addr = trunc_page(addr); 283 size = round_page(size); 284 (void) vm_map_protect(&p->p_vmspace->vm_map, 285 addr, addr+size, prot, FALSE); 286 } 287 break; 288 289 case RLIMIT_NOFILE: 290 if (limp->rlim_cur > maxfiles) 291 limp->rlim_cur = maxfiles; 292 if (limp->rlim_max > maxfiles) 293 limp->rlim_max = maxfiles; 294 break; 295 296 case RLIMIT_NPROC: 297 if (limp->rlim_cur > maxproc) 298 limp->rlim_cur = maxproc; 299 if (limp->rlim_max > maxproc) 300 limp->rlim_max = maxproc; 301 break; 302 } 303 *alimp = *limp; 304 return (0); 305 } 306 307 /* ARGSUSED */ 308 int 309 sys_getrlimit(p, v, retval) 310 struct proc *p; 311 void *v; 312 register_t *retval; 313 { 314 register struct sys_getrlimit_args /* { 315 syscallarg(u_int) which; 316 syscallarg(struct rlimit *) rlp; 317 } */ *uap = v; 318 319 if (SCARG(uap, which) >= RLIM_NLIMITS) 320 return (EINVAL); 321 return (copyout((caddr_t)&p->p_rlimit[SCARG(uap, which)], 322 (caddr_t)SCARG(uap, rlp), sizeof (struct rlimit))); 323 } 324 325 /* 326 * Transform the running time and tick information in proc p into user, 327 * system, and interrupt time usage. 328 */ 329 void 330 calcru(p, up, sp, ip) 331 register struct proc *p; 332 register struct timeval *up; 333 register struct timeval *sp; 334 register struct timeval *ip; 335 { 336 register u_quad_t u, st, ut, it, tot; 337 register u_long sec; 338 register long usec; 339 register int s; 340 struct timeval tv; 341 342 s = splstatclock(); 343 st = p->p_sticks; 344 ut = p->p_uticks; 345 it = p->p_iticks; 346 splx(s); 347 348 tot = st + ut + it; 349 if (tot == 0) { 350 up->tv_sec = up->tv_usec = 0; 351 sp->tv_sec = sp->tv_usec = 0; 352 if (ip != NULL) 353 ip->tv_sec = ip->tv_usec = 0; 354 return; 355 } 356 357 sec = p->p_rtime.tv_sec; 358 usec = p->p_rtime.tv_usec; 359 if (p == curproc) { 360 /* 361 * Adjust for the current time slice. This is actually fairly 362 * important since the error here is on the order of a time 363 * quantum, which is much greater than the sampling error. 364 */ 365 microtime(&tv); 366 sec += tv.tv_sec - runtime.tv_sec; 367 usec += tv.tv_usec - runtime.tv_usec; 368 } 369 u = (u_quad_t) sec * 1000000 + usec; 370 st = (u * st) / tot; 371 sp->tv_sec = st / 1000000; 372 sp->tv_usec = st % 1000000; 373 ut = (u * ut) / tot; 374 up->tv_sec = ut / 1000000; 375 up->tv_usec = ut % 1000000; 376 if (ip != NULL) { 377 it = (u * it) / tot; 378 ip->tv_sec = it / 1000000; 379 ip->tv_usec = it % 1000000; 380 } 381 } 382 383 /* ARGSUSED */ 384 int 385 sys_getrusage(p, v, retval) 386 register struct proc *p; 387 void *v; 388 register_t *retval; 389 { 390 register struct sys_getrusage_args /* { 391 syscallarg(int) who; 392 syscallarg(struct rusage *) rusage; 393 } */ *uap = v; 394 register struct rusage *rup; 395 396 switch (SCARG(uap, who)) { 397 398 case RUSAGE_SELF: 399 rup = &p->p_stats->p_ru; 400 calcru(p, &rup->ru_utime, &rup->ru_stime, NULL); 401 break; 402 403 case RUSAGE_CHILDREN: 404 rup = &p->p_stats->p_cru; 405 break; 406 407 default: 408 return (EINVAL); 409 } 410 return (copyout((caddr_t)rup, (caddr_t)SCARG(uap, rusage), 411 sizeof (struct rusage))); 412 } 413 414 void 415 ruadd(ru, ru2) 416 register struct rusage *ru, *ru2; 417 { 418 register long *ip, *ip2; 419 register int i; 420 421 timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime); 422 timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime); 423 if (ru->ru_maxrss < ru2->ru_maxrss) 424 ru->ru_maxrss = ru2->ru_maxrss; 425 ip = &ru->ru_first; ip2 = &ru2->ru_first; 426 for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--) 427 *ip++ += *ip2++; 428 } 429 430 /* 431 * Make a copy of the plimit structure. 432 * We share these structures copy-on-write after fork, 433 * and copy when a limit is changed. 434 */ 435 struct plimit * 436 limcopy(lim) 437 struct plimit *lim; 438 { 439 register struct plimit *newlim; 440 441 MALLOC(newlim, struct plimit *, sizeof(struct plimit), 442 M_SUBPROC, M_WAITOK); 443 bcopy(lim->pl_rlimit, newlim->pl_rlimit, 444 sizeof(struct rlimit) * RLIM_NLIMITS); 445 newlim->p_lflags = 0; 446 newlim->p_refcnt = 1; 447 return (newlim); 448 } 449 450 void 451 limfree(lim) 452 struct plimit *lim; 453 { 454 455 if (--lim->p_refcnt > 0) 456 return; 457 FREE(lim, M_SUBPROC); 458 } 459