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