1 /* $OpenBSD: kern_resource.c,v 1.40 2012/04/10 15:50:52 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) 240 return (EINVAL); 241 242 alimp = &p->p_rlimit[which]; 243 if (limp->rlim_cur > alimp->rlim_max || 244 limp->rlim_max > alimp->rlim_max) 245 if ((error = suser(p, 0)) != 0) 246 return (error); 247 if (p->p_p->ps_limit->p_refcnt > 1) { 248 struct plimit *l = p->p_p->ps_limit; 249 250 /* limcopy() can sleep, so copy before decrementing refcnt */ 251 p->p_p->ps_limit = limcopy(l); 252 l->p_refcnt--; 253 alimp = &p->p_rlimit[which]; 254 } 255 256 switch (which) { 257 case RLIMIT_DATA: 258 maxlim = maxdmap; 259 break; 260 case RLIMIT_STACK: 261 maxlim = maxsmap; 262 break; 263 case RLIMIT_NOFILE: 264 maxlim = maxfiles; 265 break; 266 case RLIMIT_NPROC: 267 maxlim = maxprocess; 268 break; 269 default: 270 maxlim = RLIM_INFINITY; 271 break; 272 } 273 274 if (limp->rlim_max > maxlim) 275 limp->rlim_max = maxlim; 276 if (limp->rlim_cur > limp->rlim_max) 277 limp->rlim_cur = limp->rlim_max; 278 279 if (which == RLIMIT_STACK) { 280 /* 281 * Stack is allocated to the max at exec time with only 282 * "rlim_cur" bytes accessible. If stack limit is going 283 * up make more accessible, if going down make inaccessible. 284 */ 285 if (limp->rlim_cur != alimp->rlim_cur) { 286 vaddr_t addr; 287 vsize_t size; 288 vm_prot_t prot; 289 290 if (limp->rlim_cur > alimp->rlim_cur) { 291 prot = VM_PROT_READ|VM_PROT_WRITE; 292 size = limp->rlim_cur - alimp->rlim_cur; 293 #ifdef MACHINE_STACK_GROWS_UP 294 addr = USRSTACK + alimp->rlim_cur; 295 #else 296 addr = USRSTACK - limp->rlim_cur; 297 #endif 298 } else { 299 prot = VM_PROT_NONE; 300 size = alimp->rlim_cur - limp->rlim_cur; 301 #ifdef MACHINE_STACK_GROWS_UP 302 addr = USRSTACK + limp->rlim_cur; 303 #else 304 addr = USRSTACK - alimp->rlim_cur; 305 #endif 306 } 307 addr = trunc_page(addr); 308 size = round_page(size); 309 (void) uvm_map_protect(&p->p_vmspace->vm_map, 310 addr, addr+size, prot, FALSE); 311 } 312 } 313 314 *alimp = *limp; 315 return (0); 316 } 317 318 /* ARGSUSED */ 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 *tup, struct proc *p) 342 { 343 timeradd(&tup->tu_runtime, &p->p_rtime, &tup->tu_runtime); 344 tup->tu_uticks += p->p_uticks; 345 tup->tu_sticks += p->p_sticks; 346 tup->tu_iticks += p->p_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_unlocked(struct process *pr, struct proc *p) 355 { 356 tuagg_sub(&pr->ps_tu, p); 357 tuagg_sub(&p->p_tu, p); 358 timerclear(&p->p_rtime); 359 p->p_uticks = 0; 360 p->p_sticks = 0; 361 p->p_iticks = 0; 362 } 363 364 void 365 tuagg(struct process *pr, struct proc *p) 366 { 367 int s; 368 369 SCHED_LOCK(s); 370 tuagg_unlocked(pr, p); 371 SCHED_UNLOCK(s); 372 } 373 374 /* 375 * Transform the running time and tick information in a struct tusage 376 * into user, system, and interrupt time usage. 377 */ 378 void 379 calcru(struct tusage *tup, struct timeval *up, struct timeval *sp, 380 struct timeval *ip) 381 { 382 u_quad_t st, ut, it; 383 int freq; 384 385 st = tup->tu_sticks; 386 ut = tup->tu_uticks; 387 it = tup->tu_iticks; 388 389 if (st + ut + it == 0) { 390 timerclear(up); 391 timerclear(sp); 392 if (ip != NULL) 393 timerclear(ip); 394 return; 395 } 396 397 freq = stathz ? stathz : hz; 398 399 st = st * 1000000 / freq; 400 sp->tv_sec = st / 1000000; 401 sp->tv_usec = st % 1000000; 402 ut = ut * 1000000 / freq; 403 up->tv_sec = ut / 1000000; 404 up->tv_usec = ut % 1000000; 405 if (ip != NULL) { 406 it = it * 1000000 / freq; 407 ip->tv_sec = it / 1000000; 408 ip->tv_usec = it % 1000000; 409 } 410 } 411 412 /* ARGSUSED */ 413 int 414 sys_getrusage(struct proc *p, void *v, register_t *retval) 415 { 416 struct sys_getrusage_args /* { 417 syscallarg(int) who; 418 syscallarg(struct rusage *) rusage; 419 } */ *uap = v; 420 struct process *pr = p->p_p; 421 struct proc *q; 422 struct rusage ru; 423 struct rusage *rup; 424 425 switch (SCARG(uap, who)) { 426 427 case RUSAGE_SELF: 428 /* start with the sum of dead threads, if any */ 429 if (pr->ps_ru != NULL) 430 ru = *pr->ps_ru; 431 else 432 bzero(&ru, sizeof(ru)); 433 rup = &ru; 434 435 /* add on all living threads */ 436 TAILQ_FOREACH(q, &pr->ps_threads, p_thr_link) { 437 ruadd(rup, &q->p_ru); 438 tuagg(pr, q); 439 } 440 441 calcru(&pr->ps_tu, &rup->ru_utime, &rup->ru_stime, NULL); 442 break; 443 444 case RUSAGE_THREAD: 445 rup = &p->p_ru; 446 calcru(&p->p_tu, &rup->ru_utime, &rup->ru_stime, NULL); 447 break; 448 449 case RUSAGE_CHILDREN: 450 rup = &pr->ps_cru; 451 break; 452 453 default: 454 return (EINVAL); 455 } 456 return (copyout((caddr_t)rup, (caddr_t)SCARG(uap, rusage), 457 sizeof (struct rusage))); 458 } 459 460 void 461 ruadd(struct rusage *ru, struct rusage *ru2) 462 { 463 long *ip, *ip2; 464 int i; 465 466 timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime); 467 timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime); 468 if (ru->ru_maxrss < ru2->ru_maxrss) 469 ru->ru_maxrss = ru2->ru_maxrss; 470 ip = &ru->ru_first; ip2 = &ru2->ru_first; 471 for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--) 472 *ip++ += *ip2++; 473 } 474 475 struct pool plimit_pool; 476 477 /* 478 * Make a copy of the plimit structure. 479 * We share these structures copy-on-write after fork, 480 * and copy when a limit is changed. 481 */ 482 struct plimit * 483 limcopy(struct plimit *lim) 484 { 485 struct plimit *newlim; 486 static int initialized; 487 488 if (!initialized) { 489 pool_init(&plimit_pool, sizeof(struct plimit), 0, 0, 0, 490 "plimitpl", &pool_allocator_nointr); 491 initialized = 1; 492 } 493 494 newlim = pool_get(&plimit_pool, PR_WAITOK); 495 bcopy(lim->pl_rlimit, newlim->pl_rlimit, 496 sizeof(struct rlimit) * RLIM_NLIMITS); 497 newlim->p_refcnt = 1; 498 return (newlim); 499 } 500 501 void 502 limfree(struct plimit *lim) 503 { 504 if (--lim->p_refcnt > 0) 505 return; 506 pool_put(&plimit_pool, lim); 507 } 508