1 /* $OpenBSD: kern_resource.c,v 1.57 2016/09/15 02:00:16 dlg 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 int 122 sys_setpriority(struct proc *curp, void *v, register_t *retval) 123 { 124 struct sys_setpriority_args /* { 125 syscallarg(int) which; 126 syscallarg(id_t) who; 127 syscallarg(int) prio; 128 } */ *uap = v; 129 struct process *pr; 130 int found = 0, error = 0; 131 132 switch (SCARG(uap, which)) { 133 134 case PRIO_PROCESS: 135 if (SCARG(uap, who) == 0) 136 pr = curp->p_p; 137 else 138 pr = prfind(SCARG(uap, who)); 139 if (pr == NULL) 140 break; 141 error = donice(curp, pr, SCARG(uap, prio)); 142 found++; 143 break; 144 145 case PRIO_PGRP: { 146 struct pgrp *pg; 147 148 if (SCARG(uap, who) == 0) 149 pg = curp->p_p->ps_pgrp; 150 else if ((pg = pgfind(SCARG(uap, who))) == NULL) 151 break; 152 LIST_FOREACH(pr, &pg->pg_members, ps_pglist) { 153 error = donice(curp, pr, SCARG(uap, prio)); 154 found++; 155 } 156 break; 157 } 158 159 case PRIO_USER: 160 if (SCARG(uap, who) == 0) 161 SCARG(uap, who) = curp->p_ucred->cr_uid; 162 LIST_FOREACH(pr, &allprocess, ps_list) 163 if (pr->ps_ucred->cr_uid == SCARG(uap, who)) { 164 error = donice(curp, pr, SCARG(uap, prio)); 165 found++; 166 } 167 break; 168 169 default: 170 return (EINVAL); 171 } 172 if (found == 0) 173 return (ESRCH); 174 return (error); 175 } 176 177 int 178 donice(struct proc *curp, struct process *chgpr, int n) 179 { 180 struct ucred *ucred = curp->p_ucred; 181 struct proc *p; 182 int s; 183 184 if (ucred->cr_uid != 0 && ucred->cr_ruid != 0 && 185 ucred->cr_uid != chgpr->ps_ucred->cr_uid && 186 ucred->cr_ruid != chgpr->ps_ucred->cr_uid) 187 return (EPERM); 188 if (n > PRIO_MAX) 189 n = PRIO_MAX; 190 if (n < PRIO_MIN) 191 n = PRIO_MIN; 192 n += NZERO; 193 if (n < chgpr->ps_nice && suser(curp, 0)) 194 return (EACCES); 195 chgpr->ps_nice = n; 196 SCHED_LOCK(s); 197 TAILQ_FOREACH(p, &chgpr->ps_threads, p_thr_link) 198 (void)resetpriority(p); 199 SCHED_UNLOCK(s); 200 return (0); 201 } 202 203 int 204 sys_setrlimit(struct proc *p, void *v, register_t *retval) 205 { 206 struct sys_setrlimit_args /* { 207 syscallarg(int) which; 208 syscallarg(const struct rlimit *) rlp; 209 } */ *uap = v; 210 struct rlimit alim; 211 int error; 212 213 error = copyin((caddr_t)SCARG(uap, rlp), (caddr_t)&alim, 214 sizeof (struct rlimit)); 215 if (error) 216 return (error); 217 #ifdef KTRACE 218 if (KTRPOINT(p, KTR_STRUCT)) 219 ktrrlimit(p, &alim); 220 #endif 221 return (dosetrlimit(p, SCARG(uap, which), &alim)); 222 } 223 224 int 225 dosetrlimit(struct proc *p, u_int which, struct rlimit *limp) 226 { 227 struct rlimit *alimp; 228 rlim_t maxlim; 229 int error; 230 231 if (which >= RLIM_NLIMITS || limp->rlim_cur > limp->rlim_max) 232 return (EINVAL); 233 234 alimp = &p->p_rlimit[which]; 235 if (limp->rlim_max > alimp->rlim_max) 236 if ((error = suser(p, 0)) != 0) 237 return (error); 238 if (p->p_p->ps_limit->p_refcnt > 1) { 239 struct plimit *l = p->p_p->ps_limit; 240 241 /* limcopy() can sleep, so copy before decrementing refcnt */ 242 p->p_p->ps_limit = limcopy(l); 243 limfree(l); 244 alimp = &p->p_rlimit[which]; 245 } 246 247 switch (which) { 248 case RLIMIT_DATA: 249 maxlim = maxdmap; 250 break; 251 case RLIMIT_STACK: 252 maxlim = maxsmap; 253 break; 254 case RLIMIT_NOFILE: 255 maxlim = maxfiles; 256 break; 257 case RLIMIT_NPROC: 258 maxlim = maxprocess; 259 break; 260 default: 261 maxlim = RLIM_INFINITY; 262 break; 263 } 264 265 if (limp->rlim_max > maxlim) 266 limp->rlim_max = maxlim; 267 if (limp->rlim_cur > limp->rlim_max) 268 limp->rlim_cur = limp->rlim_max; 269 270 if (which == RLIMIT_STACK) { 271 /* 272 * Stack is allocated to the max at exec time with only 273 * "rlim_cur" bytes accessible. If stack limit is going 274 * up make more accessible, if going down make inaccessible. 275 */ 276 if (limp->rlim_cur != alimp->rlim_cur) { 277 vaddr_t addr; 278 vsize_t size; 279 vm_prot_t prot; 280 struct vmspace *vm = p->p_vmspace; 281 282 if (limp->rlim_cur > alimp->rlim_cur) { 283 prot = PROT_READ | PROT_WRITE; 284 size = limp->rlim_cur - alimp->rlim_cur; 285 #ifdef MACHINE_STACK_GROWS_UP 286 addr = (vaddr_t)vm->vm_maxsaddr + 287 alimp->rlim_cur; 288 #else 289 addr = (vaddr_t)vm->vm_minsaddr - 290 limp->rlim_cur; 291 #endif 292 } else { 293 prot = PROT_NONE; 294 size = alimp->rlim_cur - limp->rlim_cur; 295 #ifdef MACHINE_STACK_GROWS_UP 296 addr = (vaddr_t)vm->vm_maxsaddr + 297 limp->rlim_cur; 298 #else 299 addr = (vaddr_t)vm->vm_minsaddr - 300 alimp->rlim_cur; 301 #endif 302 } 303 addr = trunc_page(addr); 304 size = round_page(size); 305 (void) uvm_map_protect(&vm->vm_map, 306 addr, addr+size, prot, FALSE); 307 } 308 } 309 310 *alimp = *limp; 311 return (0); 312 } 313 314 int 315 sys_getrlimit(struct proc *p, void *v, register_t *retval) 316 { 317 struct sys_getrlimit_args /* { 318 syscallarg(int) which; 319 syscallarg(struct rlimit *) rlp; 320 } */ *uap = v; 321 struct rlimit *alimp; 322 int error; 323 324 if (SCARG(uap, which) < 0 || SCARG(uap, which) >= RLIM_NLIMITS) 325 return (EINVAL); 326 alimp = &p->p_rlimit[SCARG(uap, which)]; 327 error = copyout(alimp, SCARG(uap, rlp), sizeof(struct rlimit)); 328 #ifdef KTRACE 329 if (error == 0 && KTRPOINT(p, KTR_STRUCT)) 330 ktrrlimit(p, alimp); 331 #endif 332 return (error); 333 } 334 335 void 336 tuagg_sub(struct tusage *tup, struct proc *p) 337 { 338 timespecadd(&tup->tu_runtime, &p->p_rtime, &tup->tu_runtime); 339 tup->tu_uticks += p->p_uticks; 340 tup->tu_sticks += p->p_sticks; 341 tup->tu_iticks += p->p_iticks; 342 } 343 344 /* 345 * Aggregate a single thread's immediate time counts into the running 346 * totals for the thread and process 347 */ 348 void 349 tuagg_unlocked(struct process *pr, struct proc *p) 350 { 351 tuagg_sub(&pr->ps_tu, p); 352 tuagg_sub(&p->p_tu, p); 353 timespecclear(&p->p_rtime); 354 p->p_uticks = 0; 355 p->p_sticks = 0; 356 p->p_iticks = 0; 357 } 358 359 void 360 tuagg(struct process *pr, struct proc *p) 361 { 362 int s; 363 364 SCHED_LOCK(s); 365 tuagg_unlocked(pr, p); 366 SCHED_UNLOCK(s); 367 } 368 369 /* 370 * Transform the running time and tick information in a struct tusage 371 * into user, system, and interrupt time usage. 372 */ 373 void 374 calctsru(struct tusage *tup, struct timespec *up, struct timespec *sp, 375 struct timespec *ip) 376 { 377 u_quad_t st, ut, it; 378 int freq; 379 380 st = tup->tu_sticks; 381 ut = tup->tu_uticks; 382 it = tup->tu_iticks; 383 384 if (st + ut + it == 0) { 385 timespecclear(up); 386 timespecclear(sp); 387 if (ip != NULL) 388 timespecclear(ip); 389 return; 390 } 391 392 freq = stathz ? stathz : hz; 393 394 st = st * 1000000000 / freq; 395 sp->tv_sec = st / 1000000000; 396 sp->tv_nsec = st % 1000000000; 397 ut = ut * 1000000000 / freq; 398 up->tv_sec = ut / 1000000000; 399 up->tv_nsec = ut % 1000000000; 400 if (ip != NULL) { 401 it = it * 1000000000 / freq; 402 ip->tv_sec = it / 1000000000; 403 ip->tv_nsec = it % 1000000000; 404 } 405 } 406 407 void 408 calcru(struct tusage *tup, struct timeval *up, struct timeval *sp, 409 struct timeval *ip) 410 { 411 struct timespec u, s, i; 412 413 calctsru(tup, &u, &s, ip != NULL ? &i : NULL); 414 TIMESPEC_TO_TIMEVAL(up, &u); 415 TIMESPEC_TO_TIMEVAL(sp, &s); 416 if (ip != NULL) 417 TIMESPEC_TO_TIMEVAL(ip, &i); 418 } 419 420 int 421 sys_getrusage(struct proc *p, void *v, register_t *retval) 422 { 423 struct sys_getrusage_args /* { 424 syscallarg(int) who; 425 syscallarg(struct rusage *) rusage; 426 } */ *uap = v; 427 struct rusage ru; 428 int error; 429 430 error = dogetrusage(p, SCARG(uap, who), &ru); 431 if (error == 0) { 432 error = copyout(&ru, SCARG(uap, rusage), sizeof(ru)); 433 #ifdef KTRACE 434 if (error == 0 && KTRPOINT(p, KTR_STRUCT)) 435 ktrrusage(p, &ru); 436 #endif 437 } 438 return (error); 439 } 440 441 int 442 dogetrusage(struct proc *p, int who, struct rusage *rup) 443 { 444 struct process *pr = p->p_p; 445 struct proc *q; 446 447 switch (who) { 448 449 case RUSAGE_SELF: 450 /* start with the sum of dead threads, if any */ 451 if (pr->ps_ru != NULL) 452 *rup = *pr->ps_ru; 453 else 454 memset(rup, 0, sizeof(*rup)); 455 456 /* add on all living threads */ 457 TAILQ_FOREACH(q, &pr->ps_threads, p_thr_link) { 458 ruadd(rup, &q->p_ru); 459 tuagg(pr, q); 460 } 461 462 calcru(&pr->ps_tu, &rup->ru_utime, &rup->ru_stime, NULL); 463 break; 464 465 case RUSAGE_THREAD: 466 *rup = p->p_ru; 467 calcru(&p->p_tu, &rup->ru_utime, &rup->ru_stime, NULL); 468 break; 469 470 case RUSAGE_CHILDREN: 471 *rup = pr->ps_cru; 472 break; 473 474 default: 475 return (EINVAL); 476 } 477 return (0); 478 } 479 480 void 481 ruadd(struct rusage *ru, struct rusage *ru2) 482 { 483 long *ip, *ip2; 484 int i; 485 486 timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime); 487 timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime); 488 if (ru->ru_maxrss < ru2->ru_maxrss) 489 ru->ru_maxrss = ru2->ru_maxrss; 490 ip = &ru->ru_first; ip2 = &ru2->ru_first; 491 for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--) 492 *ip++ += *ip2++; 493 } 494 495 struct pool plimit_pool; 496 497 /* 498 * Make a copy of the plimit structure. 499 * We share these structures copy-on-write after fork, 500 * and copy when a limit is changed. 501 */ 502 struct plimit * 503 limcopy(struct plimit *lim) 504 { 505 struct plimit *newlim; 506 static int initialized; 507 508 if (!initialized) { 509 pool_init(&plimit_pool, sizeof(struct plimit), 0, IPL_NONE, 510 PR_WAITOK, "plimitpl", NULL); 511 initialized = 1; 512 } 513 514 newlim = pool_get(&plimit_pool, PR_WAITOK); 515 memcpy(newlim->pl_rlimit, lim->pl_rlimit, 516 sizeof(struct rlimit) * RLIM_NLIMITS); 517 newlim->p_refcnt = 1; 518 return (newlim); 519 } 520 521 void 522 limfree(struct plimit *lim) 523 { 524 if (--lim->p_refcnt > 0) 525 return; 526 pool_put(&plimit_pool, lim); 527 } 528