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