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