1 /* $OpenBSD: kern_resource.c,v 1.54 2015/02/09 09:39:09 miod Exp $ */ 2 /* $NetBSD: kern_resource.c,v 1.38 1996/10/23 07:19:38 matthias 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. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)kern_resource.c 8.5 (Berkeley) 1/21/94 38 */ 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/kernel.h> 43 #include <sys/file.h> 44 #include <sys/resourcevar.h> 45 #include <sys/pool.h> 46 #include <sys/proc.h> 47 #include <sys/ktrace.h> 48 #include <sys/sched.h> 49 50 #include <sys/mount.h> 51 #include <sys/syscallargs.h> 52 53 #include <uvm/uvm_extern.h> 54 55 void tuagg_sub(struct tusage *, struct proc *); 56 57 /* 58 * Patchable maximum data and stack limits. 59 */ 60 rlim_t maxdmap = MAXDSIZ; 61 rlim_t maxsmap = MAXSSIZ; 62 63 /* 64 * Resource controls and accounting. 65 */ 66 67 int 68 sys_getpriority(struct proc *curp, void *v, register_t *retval) 69 { 70 struct sys_getpriority_args /* { 71 syscallarg(int) which; 72 syscallarg(id_t) who; 73 } */ *uap = v; 74 struct process *pr; 75 int low = NZERO + PRIO_MAX + 1; 76 77 switch (SCARG(uap, which)) { 78 79 case PRIO_PROCESS: 80 if (SCARG(uap, who) == 0) 81 pr = curp->p_p; 82 else 83 pr = prfind(SCARG(uap, who)); 84 if (pr == NULL) 85 break; 86 if (pr->ps_nice < low) 87 low = pr->ps_nice; 88 break; 89 90 case PRIO_PGRP: { 91 struct pgrp *pg; 92 93 if (SCARG(uap, who) == 0) 94 pg = curp->p_p->ps_pgrp; 95 else if ((pg = pgfind(SCARG(uap, who))) == NULL) 96 break; 97 LIST_FOREACH(pr, &pg->pg_members, ps_pglist) 98 if (pr->ps_nice < low) 99 low = pr->ps_nice; 100 break; 101 } 102 103 case PRIO_USER: 104 if (SCARG(uap, who) == 0) 105 SCARG(uap, who) = curp->p_ucred->cr_uid; 106 LIST_FOREACH(pr, &allprocess, ps_list) 107 if (pr->ps_ucred->cr_uid == SCARG(uap, who) && 108 pr->ps_nice < low) 109 low = pr->ps_nice; 110 break; 111 112 default: 113 return (EINVAL); 114 } 115 if (low == NZERO + PRIO_MAX + 1) 116 return (ESRCH); 117 *retval = low - NZERO; 118 return (0); 119 } 120 121 /* ARGSUSED */ 122 int 123 sys_setpriority(struct proc *curp, void *v, register_t *retval) 124 { 125 struct sys_setpriority_args /* { 126 syscallarg(int) which; 127 syscallarg(id_t) who; 128 syscallarg(int) prio; 129 } */ *uap = v; 130 struct process *pr; 131 int found = 0, error = 0; 132 133 switch (SCARG(uap, which)) { 134 135 case PRIO_PROCESS: 136 if (SCARG(uap, who) == 0) 137 pr = curp->p_p; 138 else 139 pr = prfind(SCARG(uap, who)); 140 if (pr == NULL) 141 break; 142 error = donice(curp, pr, SCARG(uap, prio)); 143 found++; 144 break; 145 146 case PRIO_PGRP: { 147 struct pgrp *pg; 148 149 if (SCARG(uap, who) == 0) 150 pg = curp->p_p->ps_pgrp; 151 else if ((pg = pgfind(SCARG(uap, who))) == NULL) 152 break; 153 LIST_FOREACH(pr, &pg->pg_members, ps_pglist) { 154 error = donice(curp, pr, SCARG(uap, prio)); 155 found++; 156 } 157 break; 158 } 159 160 case PRIO_USER: 161 if (SCARG(uap, who) == 0) 162 SCARG(uap, who) = curp->p_ucred->cr_uid; 163 LIST_FOREACH(pr, &allprocess, ps_list) 164 if (pr->ps_ucred->cr_uid == SCARG(uap, who)) { 165 error = donice(curp, pr, SCARG(uap, prio)); 166 found++; 167 } 168 break; 169 170 default: 171 return (EINVAL); 172 } 173 if (found == 0) 174 return (ESRCH); 175 return (error); 176 } 177 178 int 179 donice(struct proc *curp, struct process *chgpr, int n) 180 { 181 struct ucred *ucred = curp->p_ucred; 182 struct proc *p; 183 int s; 184 185 if (ucred->cr_uid != 0 && ucred->cr_ruid != 0 && 186 ucred->cr_uid != chgpr->ps_ucred->cr_uid && 187 ucred->cr_ruid != chgpr->ps_ucred->cr_uid) 188 return (EPERM); 189 if (n > PRIO_MAX) 190 n = PRIO_MAX; 191 if (n < PRIO_MIN) 192 n = PRIO_MIN; 193 n += NZERO; 194 if (n < chgpr->ps_nice && suser(curp, 0)) 195 return (EACCES); 196 chgpr->ps_nice = n; 197 SCHED_LOCK(s); 198 TAILQ_FOREACH(p, &chgpr->ps_threads, p_thr_link) 199 (void)resetpriority(p); 200 SCHED_UNLOCK(s); 201 return (0); 202 } 203 204 /* ARGSUSED */ 205 int 206 sys_setrlimit(struct proc *p, void *v, register_t *retval) 207 { 208 struct sys_setrlimit_args /* { 209 syscallarg(int) which; 210 syscallarg(const struct rlimit *) rlp; 211 } */ *uap = v; 212 struct rlimit alim; 213 int error; 214 215 error = copyin((caddr_t)SCARG(uap, rlp), (caddr_t)&alim, 216 sizeof (struct rlimit)); 217 if (error) 218 return (error); 219 #ifdef KTRACE 220 if (KTRPOINT(p, KTR_STRUCT)) 221 ktrrlimit(p, &alim); 222 #endif 223 return (dosetrlimit(p, SCARG(uap, which), &alim)); 224 } 225 226 int 227 dosetrlimit(struct proc *p, u_int which, struct rlimit *limp) 228 { 229 struct rlimit *alimp; 230 rlim_t maxlim; 231 int error; 232 233 if (which >= RLIM_NLIMITS || limp->rlim_cur > limp->rlim_max) 234 return (EINVAL); 235 236 alimp = &p->p_rlimit[which]; 237 if (limp->rlim_max > alimp->rlim_max) 238 if ((error = suser(p, 0)) != 0) 239 return (error); 240 if (p->p_p->ps_limit->p_refcnt > 1) { 241 struct plimit *l = p->p_p->ps_limit; 242 243 /* limcopy() can sleep, so copy before decrementing refcnt */ 244 p->p_p->ps_limit = limcopy(l); 245 limfree(l); 246 alimp = &p->p_rlimit[which]; 247 } 248 249 switch (which) { 250 case RLIMIT_DATA: 251 maxlim = maxdmap; 252 break; 253 case RLIMIT_STACK: 254 maxlim = maxsmap; 255 break; 256 case RLIMIT_NOFILE: 257 maxlim = maxfiles; 258 break; 259 case RLIMIT_NPROC: 260 maxlim = maxprocess; 261 break; 262 default: 263 maxlim = RLIM_INFINITY; 264 break; 265 } 266 267 if (limp->rlim_max > maxlim) 268 limp->rlim_max = maxlim; 269 if (limp->rlim_cur > limp->rlim_max) 270 limp->rlim_cur = limp->rlim_max; 271 272 if (which == RLIMIT_STACK) { 273 /* 274 * Stack is allocated to the max at exec time with only 275 * "rlim_cur" bytes accessible. If stack limit is going 276 * up make more accessible, if going down make inaccessible. 277 */ 278 if (limp->rlim_cur != alimp->rlim_cur) { 279 vaddr_t addr; 280 vsize_t size; 281 vm_prot_t prot; 282 struct vmspace *vm = p->p_vmspace; 283 284 if (limp->rlim_cur > alimp->rlim_cur) { 285 prot = PROT_READ | PROT_WRITE; 286 size = limp->rlim_cur - alimp->rlim_cur; 287 #ifdef MACHINE_STACK_GROWS_UP 288 addr = (vaddr_t)vm->vm_maxsaddr + 289 alimp->rlim_cur; 290 #else 291 addr = (vaddr_t)vm->vm_minsaddr - 292 limp->rlim_cur; 293 #endif 294 } else { 295 prot = PROT_NONE; 296 size = alimp->rlim_cur - limp->rlim_cur; 297 #ifdef MACHINE_STACK_GROWS_UP 298 addr = (vaddr_t)vm->vm_maxsaddr + 299 limp->rlim_cur; 300 #else 301 addr = (vaddr_t)vm->vm_minsaddr - 302 alimp->rlim_cur; 303 #endif 304 } 305 addr = trunc_page(addr); 306 size = round_page(size); 307 (void) uvm_map_protect(&vm->vm_map, 308 addr, addr+size, prot, FALSE); 309 } 310 } 311 312 *alimp = *limp; 313 return (0); 314 } 315 316 /* ARGSUSED */ 317 int 318 sys_getrlimit(struct proc *p, void *v, register_t *retval) 319 { 320 struct sys_getrlimit_args /* { 321 syscallarg(int) which; 322 syscallarg(struct rlimit *) rlp; 323 } */ *uap = v; 324 struct rlimit *alimp; 325 int error; 326 327 if (SCARG(uap, which) < 0 || SCARG(uap, which) >= RLIM_NLIMITS) 328 return (EINVAL); 329 alimp = &p->p_rlimit[SCARG(uap, which)]; 330 error = copyout(alimp, SCARG(uap, rlp), sizeof(struct rlimit)); 331 #ifdef KTRACE 332 if (error == 0 && KTRPOINT(p, KTR_STRUCT)) 333 ktrrlimit(p, alimp); 334 #endif 335 return (error); 336 } 337 338 void 339 tuagg_sub(struct tusage *tup, struct proc *p) 340 { 341 timespecadd(&tup->tu_runtime, &p->p_rtime, &tup->tu_runtime); 342 tup->tu_uticks += p->p_uticks; 343 tup->tu_sticks += p->p_sticks; 344 tup->tu_iticks += p->p_iticks; 345 } 346 347 /* 348 * Aggregate a single thread's immediate time counts into the running 349 * totals for the thread and process 350 */ 351 void 352 tuagg_unlocked(struct process *pr, struct proc *p) 353 { 354 tuagg_sub(&pr->ps_tu, p); 355 tuagg_sub(&p->p_tu, p); 356 timespecclear(&p->p_rtime); 357 p->p_uticks = 0; 358 p->p_sticks = 0; 359 p->p_iticks = 0; 360 } 361 362 void 363 tuagg(struct process *pr, struct proc *p) 364 { 365 int s; 366 367 SCHED_LOCK(s); 368 tuagg_unlocked(pr, p); 369 SCHED_UNLOCK(s); 370 } 371 372 /* 373 * Transform the running time and tick information in a struct tusage 374 * into user, system, and interrupt time usage. 375 */ 376 void 377 calctsru(struct tusage *tup, struct timespec *up, struct timespec *sp, 378 struct timespec *ip) 379 { 380 u_quad_t st, ut, it; 381 int freq; 382 383 st = tup->tu_sticks; 384 ut = tup->tu_uticks; 385 it = tup->tu_iticks; 386 387 if (st + ut + it == 0) { 388 timespecclear(up); 389 timespecclear(sp); 390 if (ip != NULL) 391 timespecclear(ip); 392 return; 393 } 394 395 freq = stathz ? stathz : hz; 396 397 st = st * 1000000000 / freq; 398 sp->tv_sec = st / 1000000000; 399 sp->tv_nsec = st % 1000000000; 400 ut = ut * 1000000000 / freq; 401 up->tv_sec = ut / 1000000000; 402 up->tv_nsec = ut % 1000000000; 403 if (ip != NULL) { 404 it = it * 1000000000 / freq; 405 ip->tv_sec = it / 1000000000; 406 ip->tv_nsec = it % 1000000000; 407 } 408 } 409 410 void 411 calcru(struct tusage *tup, struct timeval *up, struct timeval *sp, 412 struct timeval *ip) 413 { 414 struct timespec u, s, i; 415 416 calctsru(tup, &u, &s, ip != NULL ? &i : NULL); 417 TIMESPEC_TO_TIMEVAL(up, &u); 418 TIMESPEC_TO_TIMEVAL(sp, &s); 419 if (ip != NULL) 420 TIMESPEC_TO_TIMEVAL(ip, &i); 421 } 422 423 /* ARGSUSED */ 424 int 425 sys_getrusage(struct proc *p, void *v, register_t *retval) 426 { 427 struct sys_getrusage_args /* { 428 syscallarg(int) who; 429 syscallarg(struct rusage *) rusage; 430 } */ *uap = v; 431 struct rusage ru; 432 int error; 433 434 error = dogetrusage(p, SCARG(uap, who), &ru); 435 if (error == 0) { 436 error = copyout(&ru, SCARG(uap, rusage), sizeof(ru)); 437 #ifdef KTRACE 438 if (error == 0 && KTRPOINT(p, KTR_STRUCT)) 439 ktrrusage(p, &ru); 440 #endif 441 } 442 return (error); 443 } 444 445 int 446 dogetrusage(struct proc *p, int who, struct rusage *rup) 447 { 448 struct process *pr = p->p_p; 449 struct proc *q; 450 451 switch (who) { 452 453 case RUSAGE_SELF: 454 /* start with the sum of dead threads, if any */ 455 if (pr->ps_ru != NULL) 456 *rup = *pr->ps_ru; 457 else 458 memset(rup, 0, sizeof(*rup)); 459 460 /* add on all living threads */ 461 TAILQ_FOREACH(q, &pr->ps_threads, p_thr_link) { 462 ruadd(rup, &q->p_ru); 463 tuagg(pr, q); 464 } 465 466 calcru(&pr->ps_tu, &rup->ru_utime, &rup->ru_stime, NULL); 467 break; 468 469 case RUSAGE_THREAD: 470 *rup = p->p_ru; 471 calcru(&p->p_tu, &rup->ru_utime, &rup->ru_stime, NULL); 472 break; 473 474 case RUSAGE_CHILDREN: 475 *rup = pr->ps_cru; 476 break; 477 478 default: 479 return (EINVAL); 480 } 481 return (0); 482 } 483 484 void 485 ruadd(struct rusage *ru, struct rusage *ru2) 486 { 487 long *ip, *ip2; 488 int i; 489 490 timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime); 491 timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime); 492 if (ru->ru_maxrss < ru2->ru_maxrss) 493 ru->ru_maxrss = ru2->ru_maxrss; 494 ip = &ru->ru_first; ip2 = &ru2->ru_first; 495 for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--) 496 *ip++ += *ip2++; 497 } 498 499 struct pool plimit_pool; 500 501 /* 502 * Make a copy of the plimit structure. 503 * We share these structures copy-on-write after fork, 504 * and copy when a limit is changed. 505 */ 506 struct plimit * 507 limcopy(struct plimit *lim) 508 { 509 struct plimit *newlim; 510 static int initialized; 511 512 if (!initialized) { 513 pool_init(&plimit_pool, sizeof(struct plimit), 0, 0, PR_WAITOK, 514 "plimitpl", NULL); 515 initialized = 1; 516 } 517 518 newlim = pool_get(&plimit_pool, PR_WAITOK); 519 memcpy(newlim->pl_rlimit, lim->pl_rlimit, 520 sizeof(struct rlimit) * RLIM_NLIMITS); 521 newlim->p_refcnt = 1; 522 return (newlim); 523 } 524 525 void 526 limfree(struct plimit *lim) 527 { 528 if (--lim->p_refcnt > 0) 529 return; 530 pool_put(&plimit_pool, lim); 531 } 532