1 /* $OpenBSD: kern_resource.c,v 1.61 2019/05/31 19:51:09 mpi 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 #include <sys/signalvar.h> 50 #include <sys/mutex.h> 51 #include <sys/mount.h> 52 #include <sys/syscallargs.h> 53 54 #include <uvm/uvm_extern.h> 55 56 void tuagg_sub(struct tusage *, struct tusage *); 57 58 /* 59 * Patchable maximum data and stack limits. 60 */ 61 rlim_t maxdmap = MAXDSIZ; 62 rlim_t maxsmap = MAXSSIZ; 63 64 /* 65 * Resource controls and accounting. 66 */ 67 68 int 69 sys_getpriority(struct proc *curp, void *v, register_t *retval) 70 { 71 struct sys_getpriority_args /* { 72 syscallarg(int) which; 73 syscallarg(id_t) who; 74 } */ *uap = v; 75 struct process *pr; 76 int low = NZERO + PRIO_MAX + 1; 77 78 switch (SCARG(uap, which)) { 79 80 case PRIO_PROCESS: 81 if (SCARG(uap, who) == 0) 82 pr = curp->p_p; 83 else 84 pr = prfind(SCARG(uap, who)); 85 if (pr == NULL) 86 break; 87 if (pr->ps_nice < low) 88 low = pr->ps_nice; 89 break; 90 91 case PRIO_PGRP: { 92 struct pgrp *pg; 93 94 if (SCARG(uap, who) == 0) 95 pg = curp->p_p->ps_pgrp; 96 else if ((pg = pgfind(SCARG(uap, who))) == NULL) 97 break; 98 LIST_FOREACH(pr, &pg->pg_members, ps_pglist) 99 if (pr->ps_nice < low) 100 low = pr->ps_nice; 101 break; 102 } 103 104 case PRIO_USER: 105 if (SCARG(uap, who) == 0) 106 SCARG(uap, who) = curp->p_ucred->cr_uid; 107 LIST_FOREACH(pr, &allprocess, ps_list) 108 if (pr->ps_ucred->cr_uid == SCARG(uap, who) && 109 pr->ps_nice < low) 110 low = pr->ps_nice; 111 break; 112 113 default: 114 return (EINVAL); 115 } 116 if (low == NZERO + PRIO_MAX + 1) 117 return (ESRCH); 118 *retval = low - NZERO; 119 return (0); 120 } 121 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)) 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 int 205 sys_setrlimit(struct proc *p, void *v, register_t *retval) 206 { 207 struct sys_setrlimit_args /* { 208 syscallarg(int) which; 209 syscallarg(const struct rlimit *) rlp; 210 } */ *uap = v; 211 struct rlimit alim; 212 int error; 213 214 error = copyin((caddr_t)SCARG(uap, rlp), (caddr_t)&alim, 215 sizeof (struct rlimit)); 216 if (error) 217 return (error); 218 #ifdef KTRACE 219 if (KTRPOINT(p, KTR_STRUCT)) 220 ktrrlimit(p, &alim); 221 #endif 222 return (dosetrlimit(p, SCARG(uap, which), &alim)); 223 } 224 225 int 226 dosetrlimit(struct proc *p, u_int which, struct rlimit *limp) 227 { 228 struct rlimit *alimp; 229 rlim_t maxlim; 230 int error; 231 232 if (which >= RLIM_NLIMITS || limp->rlim_cur > limp->rlim_max) 233 return (EINVAL); 234 235 alimp = &p->p_rlimit[which]; 236 if (limp->rlim_max > alimp->rlim_max) 237 if ((error = suser(p)) != 0) 238 return (error); 239 if (p->p_p->ps_limit->pl_refcnt > 1) { 240 struct plimit *l = p->p_p->ps_limit; 241 242 /* limcopy() can sleep, so copy before decrementing refcnt */ 243 p->p_p->ps_limit = limcopy(l); 244 limfree(l); 245 alimp = &p->p_rlimit[which]; 246 } 247 248 switch (which) { 249 case RLIMIT_DATA: 250 maxlim = maxdmap; 251 break; 252 case RLIMIT_STACK: 253 maxlim = maxsmap; 254 break; 255 case RLIMIT_NOFILE: 256 maxlim = maxfiles; 257 break; 258 case RLIMIT_NPROC: 259 maxlim = maxprocess; 260 break; 261 default: 262 maxlim = RLIM_INFINITY; 263 break; 264 } 265 266 if (limp->rlim_max > maxlim) 267 limp->rlim_max = maxlim; 268 if (limp->rlim_cur > limp->rlim_max) 269 limp->rlim_cur = limp->rlim_max; 270 271 if (which == RLIMIT_CPU && limp->rlim_cur != RLIM_INFINITY && 272 alimp->rlim_cur == RLIM_INFINITY) 273 timeout_add_msec(&p->p_p->ps_rucheck_to, RUCHECK_INTERVAL); 274 275 if (which == RLIMIT_STACK) { 276 /* 277 * Stack is allocated to the max at exec time with only 278 * "rlim_cur" bytes accessible. If stack limit is going 279 * up make more accessible, if going down make inaccessible. 280 */ 281 if (limp->rlim_cur != alimp->rlim_cur) { 282 vaddr_t addr; 283 vsize_t size; 284 vm_prot_t prot; 285 struct vmspace *vm = p->p_vmspace; 286 287 if (limp->rlim_cur > alimp->rlim_cur) { 288 prot = PROT_READ | PROT_WRITE; 289 size = limp->rlim_cur - alimp->rlim_cur; 290 #ifdef MACHINE_STACK_GROWS_UP 291 addr = (vaddr_t)vm->vm_maxsaddr + 292 alimp->rlim_cur; 293 #else 294 addr = (vaddr_t)vm->vm_minsaddr - 295 limp->rlim_cur; 296 #endif 297 } else { 298 prot = PROT_NONE; 299 size = alimp->rlim_cur - limp->rlim_cur; 300 #ifdef MACHINE_STACK_GROWS_UP 301 addr = (vaddr_t)vm->vm_maxsaddr + 302 limp->rlim_cur; 303 #else 304 addr = (vaddr_t)vm->vm_minsaddr - 305 alimp->rlim_cur; 306 #endif 307 } 308 addr = trunc_page(addr); 309 size = round_page(size); 310 (void) uvm_map_protect(&vm->vm_map, 311 addr, addr+size, prot, FALSE); 312 } 313 } 314 315 *alimp = *limp; 316 return (0); 317 } 318 319 int 320 sys_getrlimit(struct proc *p, void *v, register_t *retval) 321 { 322 struct sys_getrlimit_args /* { 323 syscallarg(int) which; 324 syscallarg(struct rlimit *) rlp; 325 } */ *uap = v; 326 struct rlimit *alimp; 327 int error; 328 329 if (SCARG(uap, which) < 0 || SCARG(uap, which) >= RLIM_NLIMITS) 330 return (EINVAL); 331 alimp = &p->p_rlimit[SCARG(uap, which)]; 332 error = copyout(alimp, SCARG(uap, rlp), sizeof(struct rlimit)); 333 #ifdef KTRACE 334 if (error == 0 && KTRPOINT(p, KTR_STRUCT)) 335 ktrrlimit(p, alimp); 336 #endif 337 return (error); 338 } 339 340 void 341 tuagg_sub(struct tusage *ttup, struct tusage *ftup) 342 { 343 timespecadd(&ttup->tu_runtime, &ftup->tu_runtime, &ttup->tu_runtime); 344 ttup->tu_uticks += ftup->tu_uticks; 345 ttup->tu_sticks += ftup->tu_sticks; 346 ttup->tu_iticks += ftup->tu_iticks; 347 } 348 349 /* 350 * Aggregate a single thread's immediate time counts into the running 351 * totals for the thread and process 352 */ 353 void 354 tuagg(struct proc *p, struct timespec *tsp) 355 { 356 struct process *pr = p->p_p; 357 struct tusage tu; 358 359 mtx_enter(&pr->ps_mtx); 360 tu.tu_uticks = p->p_uticks; 361 tu.tu_sticks = p->p_sticks; 362 tu.tu_iticks = p->p_iticks; 363 p->p_uticks = 0; 364 p->p_sticks = 0; 365 p->p_iticks = 0; 366 if (tsp != NULL) 367 timespecadd(&p->p_rtime, tsp, &p->p_rtime); 368 tu.tu_runtime = p->p_rtime; 369 timespecclear(&p->p_rtime); 370 tuagg_sub(&pr->ps_tu, &tu); 371 tuagg_sub(&p->p_tu, &tu); 372 mtx_leave(&pr->ps_mtx); 373 374 } 375 376 /* 377 * Transform the running time and tick information in a struct tusage 378 * into user, system, and interrupt time usage. 379 */ 380 void 381 calctsru(struct tusage *tup, struct timespec *up, struct timespec *sp, 382 struct timespec *ip) 383 { 384 u_quad_t st, ut, it; 385 int freq; 386 387 st = tup->tu_sticks; 388 ut = tup->tu_uticks; 389 it = tup->tu_iticks; 390 391 if (st + ut + it == 0) { 392 timespecclear(up); 393 timespecclear(sp); 394 if (ip != NULL) 395 timespecclear(ip); 396 return; 397 } 398 399 freq = stathz ? stathz : hz; 400 401 st = st * 1000000000 / freq; 402 sp->tv_sec = st / 1000000000; 403 sp->tv_nsec = st % 1000000000; 404 ut = ut * 1000000000 / freq; 405 up->tv_sec = ut / 1000000000; 406 up->tv_nsec = ut % 1000000000; 407 if (ip != NULL) { 408 it = it * 1000000000 / freq; 409 ip->tv_sec = it / 1000000000; 410 ip->tv_nsec = it % 1000000000; 411 } 412 } 413 414 void 415 calcru(struct tusage *tup, struct timeval *up, struct timeval *sp, 416 struct timeval *ip) 417 { 418 struct timespec u, s, i; 419 420 calctsru(tup, &u, &s, ip != NULL ? &i : NULL); 421 TIMESPEC_TO_TIMEVAL(up, &u); 422 TIMESPEC_TO_TIMEVAL(sp, &s); 423 if (ip != NULL) 424 TIMESPEC_TO_TIMEVAL(ip, &i); 425 } 426 427 int 428 sys_getrusage(struct proc *p, void *v, register_t *retval) 429 { 430 struct sys_getrusage_args /* { 431 syscallarg(int) who; 432 syscallarg(struct rusage *) rusage; 433 } */ *uap = v; 434 struct rusage ru; 435 int error; 436 437 error = dogetrusage(p, SCARG(uap, who), &ru); 438 if (error == 0) { 439 error = copyout(&ru, SCARG(uap, rusage), sizeof(ru)); 440 #ifdef KTRACE 441 if (error == 0 && KTRPOINT(p, KTR_STRUCT)) 442 ktrrusage(p, &ru); 443 #endif 444 } 445 return (error); 446 } 447 448 int 449 dogetrusage(struct proc *p, int who, struct rusage *rup) 450 { 451 struct process *pr = p->p_p; 452 struct proc *q; 453 454 switch (who) { 455 456 case RUSAGE_SELF: 457 /* start with the sum of dead threads, if any */ 458 if (pr->ps_ru != NULL) 459 *rup = *pr->ps_ru; 460 else 461 memset(rup, 0, sizeof(*rup)); 462 463 /* add on all living threads */ 464 TAILQ_FOREACH(q, &pr->ps_threads, p_thr_link) { 465 ruadd(rup, &q->p_ru); 466 tuagg(q, NULL); 467 } 468 469 mtx_enter(&pr->ps_mtx); 470 calcru(&pr->ps_tu, &rup->ru_utime, &rup->ru_stime, NULL); 471 mtx_leave(&pr->ps_mtx); 472 break; 473 474 case RUSAGE_THREAD: 475 *rup = p->p_ru; 476 mtx_enter(&pr->ps_mtx); 477 calcru(&p->p_tu, &rup->ru_utime, &rup->ru_stime, NULL); 478 mtx_leave(&pr->ps_mtx); 479 break; 480 481 case RUSAGE_CHILDREN: 482 *rup = pr->ps_cru; 483 break; 484 485 default: 486 return (EINVAL); 487 } 488 return (0); 489 } 490 491 void 492 ruadd(struct rusage *ru, struct rusage *ru2) 493 { 494 long *ip, *ip2; 495 int i; 496 497 timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime); 498 timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime); 499 if (ru->ru_maxrss < ru2->ru_maxrss) 500 ru->ru_maxrss = ru2->ru_maxrss; 501 ip = &ru->ru_first; ip2 = &ru2->ru_first; 502 for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--) 503 *ip++ += *ip2++; 504 } 505 506 /* 507 * Check if the process exceeds its cpu resource allocation. 508 * If over max, kill it. 509 */ 510 void 511 rucheck(void *arg) 512 { 513 struct process *pr = arg; 514 struct rlimit *rlim; 515 rlim_t runtime; 516 517 KERNEL_ASSERT_LOCKED(); 518 519 mtx_enter(&pr->ps_mtx); 520 runtime = pr->ps_tu.tu_runtime.tv_sec; 521 mtx_leave(&pr->ps_mtx); 522 523 rlim = &pr->ps_limit->pl_rlimit[RLIMIT_CPU]; 524 if (runtime >= rlim->rlim_cur) { 525 if (runtime >= rlim->rlim_max) { 526 prsignal(pr, SIGKILL); 527 } else { 528 prsignal(pr, SIGXCPU); 529 if (rlim->rlim_cur < rlim->rlim_max) 530 rlim->rlim_cur = MIN(rlim->rlim_cur + 5, 531 rlim->rlim_max); 532 } 533 } 534 535 timeout_add_msec(&pr->ps_rucheck_to, RUCHECK_INTERVAL); 536 } 537 538 struct pool plimit_pool; 539 540 /* 541 * Make a copy of the plimit structure. 542 * We share these structures copy-on-write after fork, 543 * and copy when a limit is changed. 544 */ 545 struct plimit * 546 limcopy(struct plimit *lim) 547 { 548 struct plimit *newlim; 549 static int initialized; 550 551 if (!initialized) { 552 pool_init(&plimit_pool, sizeof(struct plimit), 0, IPL_NONE, 553 PR_WAITOK, "plimitpl", NULL); 554 initialized = 1; 555 } 556 557 newlim = pool_get(&plimit_pool, PR_WAITOK); 558 memcpy(newlim->pl_rlimit, lim->pl_rlimit, 559 sizeof(struct rlimit) * RLIM_NLIMITS); 560 newlim->pl_refcnt = 1; 561 return (newlim); 562 } 563 564 void 565 limfree(struct plimit *lim) 566 { 567 if (--lim->pl_refcnt > 0) 568 return; 569 pool_put(&plimit_pool, lim); 570 } 571