1 /* $NetBSD: kern_resource.c,v 1.60 2001/02/06 19:54:43 eeh Exp $ */ 2 3 /*- 4 * Copyright (c) 1982, 1986, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * (c) UNIX System Laboratories, Inc. 7 * All or some portions of this file are derived from material licensed 8 * to the University of California by American Telephone and Telegraph 9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10 * the permission of UNIX System Laboratories, Inc. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * @(#)kern_resource.c 8.8 (Berkeley) 2/14/95 41 */ 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/kernel.h> 46 #include <sys/file.h> 47 #include <sys/resourcevar.h> 48 #include <sys/malloc.h> 49 #include <sys/pool.h> 50 #include <sys/proc.h> 51 52 #include <sys/mount.h> 53 #include <sys/syscallargs.h> 54 55 #include <uvm/uvm_extern.h> 56 57 /* 58 * Maximum process data and stack limits. 59 * They are variables so they are patchable. 60 * 61 * XXXX Do we really need them to be patchable? 62 */ 63 rlim_t maxdmap = MAXDSIZ; 64 rlim_t maxsmap = MAXSSIZ; 65 66 /* 67 * Resource controls and accounting. 68 */ 69 70 int 71 sys_getpriority(curp, v, retval) 72 struct proc *curp; 73 void *v; 74 register_t *retval; 75 { 76 struct sys_getpriority_args /* { 77 syscallarg(int) which; 78 syscallarg(int) who; 79 } */ *uap = v; 80 struct proc *p; 81 int low = NZERO + PRIO_MAX + 1; 82 83 switch (SCARG(uap, which)) { 84 85 case PRIO_PROCESS: 86 if (SCARG(uap, who) == 0) 87 p = curp; 88 else 89 p = pfind(SCARG(uap, who)); 90 if (p == 0) 91 break; 92 low = p->p_nice; 93 break; 94 95 case PRIO_PGRP: { 96 struct pgrp *pg; 97 98 if (SCARG(uap, who) == 0) 99 pg = curp->p_pgrp; 100 else if ((pg = pgfind(SCARG(uap, who))) == NULL) 101 break; 102 for (p = pg->pg_members.lh_first; p != 0; 103 p = p->p_pglist.le_next) { 104 if (p->p_nice < low) 105 low = p->p_nice; 106 } 107 break; 108 } 109 110 case PRIO_USER: 111 if (SCARG(uap, who) == 0) 112 SCARG(uap, who) = curp->p_ucred->cr_uid; 113 proclist_lock_read(); 114 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) 115 if (p->p_ucred->cr_uid == SCARG(uap, who) && 116 p->p_nice < low) 117 low = p->p_nice; 118 proclist_unlock_read(); 119 break; 120 121 default: 122 return (EINVAL); 123 } 124 if (low == NZERO + PRIO_MAX + 1) 125 return (ESRCH); 126 *retval = low - NZERO; 127 return (0); 128 } 129 130 /* ARGSUSED */ 131 int 132 sys_setpriority(curp, v, retval) 133 struct proc *curp; 134 void *v; 135 register_t *retval; 136 { 137 struct sys_setpriority_args /* { 138 syscallarg(int) which; 139 syscallarg(int) who; 140 syscallarg(int) prio; 141 } */ *uap = v; 142 struct proc *p; 143 int found = 0, error = 0; 144 145 switch (SCARG(uap, which)) { 146 147 case PRIO_PROCESS: 148 if (SCARG(uap, who) == 0) 149 p = curp; 150 else 151 p = pfind(SCARG(uap, who)); 152 if (p == 0) 153 break; 154 error = donice(curp, p, SCARG(uap, prio)); 155 found++; 156 break; 157 158 case PRIO_PGRP: { 159 struct pgrp *pg; 160 161 if (SCARG(uap, who) == 0) 162 pg = curp->p_pgrp; 163 else if ((pg = pgfind(SCARG(uap, who))) == NULL) 164 break; 165 for (p = pg->pg_members.lh_first; p != 0; 166 p = p->p_pglist.le_next) { 167 error = donice(curp, p, SCARG(uap, prio)); 168 found++; 169 } 170 break; 171 } 172 173 case PRIO_USER: 174 if (SCARG(uap, who) == 0) 175 SCARG(uap, who) = curp->p_ucred->cr_uid; 176 proclist_lock_read(); 177 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) 178 if (p->p_ucred->cr_uid == SCARG(uap, who)) { 179 error = donice(curp, p, SCARG(uap, prio)); 180 found++; 181 } 182 proclist_unlock_read(); 183 break; 184 185 default: 186 return (EINVAL); 187 } 188 if (found == 0) 189 return (ESRCH); 190 return (error); 191 } 192 193 int 194 donice(curp, chgp, n) 195 struct proc *curp, *chgp; 196 int n; 197 { 198 struct pcred *pcred = curp->p_cred; 199 int s; 200 201 if (pcred->pc_ucred->cr_uid && pcred->p_ruid && 202 pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid && 203 pcred->p_ruid != chgp->p_ucred->cr_uid) 204 return (EPERM); 205 if (n > PRIO_MAX) 206 n = PRIO_MAX; 207 if (n < PRIO_MIN) 208 n = PRIO_MIN; 209 n += NZERO; 210 if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag)) 211 return (EACCES); 212 chgp->p_nice = n; 213 SCHED_LOCK(s); 214 (void)resetpriority(chgp); 215 SCHED_UNLOCK(s); 216 return (0); 217 } 218 219 /* ARGSUSED */ 220 int 221 sys_setrlimit(p, v, retval) 222 struct proc *p; 223 void *v; 224 register_t *retval; 225 { 226 struct sys_setrlimit_args /* { 227 syscallarg(int) which; 228 syscallarg(const struct rlimit *) rlp; 229 } */ *uap = v; 230 int which = SCARG(uap, which); 231 struct rlimit alim; 232 int error; 233 234 error = copyin(SCARG(uap, rlp), &alim, sizeof(struct rlimit)); 235 if (error) 236 return (error); 237 return (dosetrlimit(p, p->p_cred, which, &alim)); 238 } 239 240 int 241 dosetrlimit(p, cred, which, limp) 242 struct proc *p; 243 struct pcred *cred; 244 int which; 245 struct rlimit *limp; 246 { 247 struct rlimit *alimp; 248 struct plimit *newplim; 249 int error; 250 251 if ((u_int)which >= RLIM_NLIMITS) 252 return (EINVAL); 253 254 if (limp->rlim_cur < 0 || limp->rlim_max < 0) 255 return (EINVAL); 256 257 alimp = &p->p_rlimit[which]; 258 /* if we don't change the value, no need to limcopy() */ 259 if (limp->rlim_cur == alimp->rlim_cur && 260 limp->rlim_max == alimp->rlim_max) 261 return 0; 262 263 if (limp->rlim_cur > alimp->rlim_max || 264 limp->rlim_max > alimp->rlim_max) 265 if ((error = suser(cred->pc_ucred, &p->p_acflag)) != 0) 266 return (error); 267 if (limp->rlim_cur > limp->rlim_max) 268 limp->rlim_cur = limp->rlim_max; 269 if (p->p_limit->p_refcnt > 1 && 270 (p->p_limit->p_lflags & PL_SHAREMOD) == 0) { 271 newplim = limcopy(p->p_limit); 272 limfree(p->p_limit); 273 p->p_limit = newplim; 274 alimp = &p->p_rlimit[which]; 275 } 276 277 switch (which) { 278 279 case RLIMIT_DATA: 280 if (limp->rlim_cur > maxdmap) 281 limp->rlim_cur = maxdmap; 282 if (limp->rlim_max > maxdmap) 283 limp->rlim_max = maxdmap; 284 break; 285 286 case RLIMIT_STACK: 287 if (limp->rlim_cur > maxsmap) 288 limp->rlim_cur = maxsmap; 289 if (limp->rlim_max > maxsmap) 290 limp->rlim_max = maxsmap; 291 292 /* 293 * Stack is allocated to the max at exec time with 294 * only "rlim_cur" bytes accessible (In other words, 295 * allocates stack dividing two contiguous regions at 296 * "rlim_cur" bytes boundary). 297 * 298 * Since allocation is done in terms of page, roundup 299 * "rlim_cur" (otherwise, contiguous regions 300 * overlap). If stack limit is going up make more 301 * accessible, if going down make inaccessible. 302 */ 303 limp->rlim_cur = round_page(limp->rlim_cur); 304 if (limp->rlim_cur != alimp->rlim_cur) { 305 vaddr_t addr; 306 vsize_t size; 307 vm_prot_t prot; 308 309 if (limp->rlim_cur > alimp->rlim_cur) { 310 prot = VM_PROT_ALL; 311 size = limp->rlim_cur - alimp->rlim_cur; 312 addr = USRSTACK - limp->rlim_cur; 313 } else { 314 prot = VM_PROT_NONE; 315 size = alimp->rlim_cur - limp->rlim_cur; 316 addr = USRSTACK - alimp->rlim_cur; 317 } 318 (void) uvm_map_protect(&p->p_vmspace->vm_map, 319 addr, addr+size, prot, FALSE); 320 } 321 break; 322 323 case RLIMIT_NOFILE: 324 if (limp->rlim_cur > maxfiles) 325 limp->rlim_cur = maxfiles; 326 if (limp->rlim_max > maxfiles) 327 limp->rlim_max = maxfiles; 328 break; 329 330 case RLIMIT_NPROC: 331 if (limp->rlim_cur > maxproc) 332 limp->rlim_cur = maxproc; 333 if (limp->rlim_max > maxproc) 334 limp->rlim_max = maxproc; 335 break; 336 } 337 *alimp = *limp; 338 return (0); 339 } 340 341 /* ARGSUSED */ 342 int 343 sys_getrlimit(p, v, retval) 344 struct proc *p; 345 void *v; 346 register_t *retval; 347 { 348 struct sys_getrlimit_args /* { 349 syscallarg(int) which; 350 syscallarg(struct rlimit *) rlp; 351 } */ *uap = v; 352 int which = SCARG(uap, which); 353 354 if ((u_int)which >= RLIM_NLIMITS) 355 return (EINVAL); 356 return (copyout(&p->p_rlimit[which], SCARG(uap, rlp), 357 sizeof(struct rlimit))); 358 } 359 360 /* 361 * Transform the running time and tick information in proc p into user, 362 * system, and interrupt time usage. 363 */ 364 void 365 calcru(p, up, sp, ip) 366 struct proc *p; 367 struct timeval *up; 368 struct timeval *sp; 369 struct timeval *ip; 370 { 371 u_quad_t u, st, ut, it, tot; 372 long sec, usec; 373 int s; 374 struct timeval tv; 375 376 s = splstatclock(); 377 st = p->p_sticks; 378 ut = p->p_uticks; 379 it = p->p_iticks; 380 splx(s); 381 382 tot = st + ut + it; 383 if (tot == 0) { 384 up->tv_sec = up->tv_usec = 0; 385 sp->tv_sec = sp->tv_usec = 0; 386 if (ip != NULL) 387 ip->tv_sec = ip->tv_usec = 0; 388 return; 389 } 390 391 sec = p->p_rtime.tv_sec; 392 usec = p->p_rtime.tv_usec; 393 if (p->p_stat == SONPROC) { 394 struct schedstate_percpu *spc; 395 396 KDASSERT(p->p_cpu != NULL); 397 spc = &p->p_cpu->ci_schedstate; 398 399 /* 400 * Adjust for the current time slice. This is actually fairly 401 * important since the error here is on the order of a time 402 * quantum, which is much greater than the sampling error. 403 */ 404 microtime(&tv); 405 sec += tv.tv_sec - spc->spc_runtime.tv_sec; 406 usec += tv.tv_usec - spc->spc_runtime.tv_usec; 407 } 408 u = (u_quad_t) sec * 1000000 + usec; 409 st = (u * st) / tot; 410 sp->tv_sec = st / 1000000; 411 sp->tv_usec = st % 1000000; 412 ut = (u * ut) / tot; 413 up->tv_sec = ut / 1000000; 414 up->tv_usec = ut % 1000000; 415 if (ip != NULL) { 416 it = (u * it) / tot; 417 ip->tv_sec = it / 1000000; 418 ip->tv_usec = it % 1000000; 419 } 420 } 421 422 /* ARGSUSED */ 423 int 424 sys_getrusage(p, v, retval) 425 struct proc *p; 426 void *v; 427 register_t *retval; 428 { 429 struct sys_getrusage_args /* { 430 syscallarg(int) who; 431 syscallarg(struct rusage *) rusage; 432 } */ *uap = v; 433 struct rusage *rup; 434 435 switch (SCARG(uap, who)) { 436 437 case RUSAGE_SELF: 438 rup = &p->p_stats->p_ru; 439 calcru(p, &rup->ru_utime, &rup->ru_stime, NULL); 440 break; 441 442 case RUSAGE_CHILDREN: 443 rup = &p->p_stats->p_cru; 444 break; 445 446 default: 447 return (EINVAL); 448 } 449 return (copyout(rup, SCARG(uap, rusage), sizeof(struct rusage))); 450 } 451 452 void 453 ruadd(ru, ru2) 454 struct rusage *ru, *ru2; 455 { 456 long *ip, *ip2; 457 int i; 458 459 timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime); 460 timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime); 461 if (ru->ru_maxrss < ru2->ru_maxrss) 462 ru->ru_maxrss = ru2->ru_maxrss; 463 ip = &ru->ru_first; ip2 = &ru2->ru_first; 464 for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--) 465 *ip++ += *ip2++; 466 } 467 468 /* 469 * Make a copy of the plimit structure. 470 * We share these structures copy-on-write after fork, 471 * and copy when a limit is changed. 472 */ 473 struct plimit * 474 limcopy(lim) 475 struct plimit *lim; 476 { 477 struct plimit *newlim; 478 479 newlim = pool_get(&plimit_pool, PR_WAITOK); 480 memcpy(newlim->pl_rlimit, lim->pl_rlimit, 481 sizeof(struct rlimit) * RLIM_NLIMITS); 482 if (lim->pl_corename == defcorename) { 483 newlim->pl_corename = defcorename; 484 } else { 485 newlim->pl_corename = malloc(strlen(lim->pl_corename)+1, 486 M_TEMP, M_WAITOK); 487 strcpy(newlim->pl_corename, lim->pl_corename); 488 } 489 newlim->p_lflags = 0; 490 newlim->p_refcnt = 1; 491 return (newlim); 492 } 493 494 void 495 limfree(lim) 496 struct plimit *lim; 497 { 498 499 if (--lim->p_refcnt > 0) 500 return; 501 #ifdef DIAGNOSTIC 502 if (lim->p_refcnt < 0) 503 panic("limfree"); 504 #endif 505 if (lim->pl_corename != defcorename) 506 free(lim->pl_corename, M_TEMP); 507 pool_put(&plimit_pool, lim); 508 } 509