1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include <sys/param.h> 34 #include <sys/types.h> 35 #include <sys/inttypes.h> 36 #include <sys/sysmacros.h> 37 #include <sys/systm.h> 38 #include <sys/tuneable.h> 39 #include <sys/user.h> 40 #include <sys/errno.h> 41 #include <sys/vnode.h> 42 #include <sys/file.h> 43 #include <sys/proc.h> 44 #include <sys/resource.h> 45 #include <sys/ulimit.h> 46 #include <sys/debug.h> 47 #include <sys/rctl.h> 48 49 #include <vm/as.h> 50 51 /* 52 * Perhaps ulimit could be moved into a user library, as calls to 53 * getrlimit and setrlimit, were it not for binary compatibility 54 * restrictions. 55 */ 56 long 57 ulimit(int cmd, long arg) 58 { 59 proc_t *p = curproc; 60 long retval; 61 62 switch (cmd) { 63 64 case UL_GFILLIM: /* Return current file size limit. */ 65 { 66 rlim64_t filesize; 67 68 mutex_enter(&p->p_lock); 69 filesize = rctl_enforced_value(rctlproc_legacy[RLIMIT_FSIZE], 70 p->p_rctls, p); 71 mutex_exit(&p->p_lock); 72 73 if (get_udatamodel() == DATAMODEL_ILP32) { 74 /* 75 * File size is returned in blocks for ulimit. 76 * This function is deprecated and therefore LFS API 77 * didn't define the behaviour of ulimit. 78 * Here we return maximum value of file size possible 79 * so that applications that do not check errors 80 * continue to work. 81 */ 82 if (filesize > MAXOFF32_T) 83 filesize = MAXOFF32_T; 84 retval = ((int)filesize >> SCTRSHFT); 85 } else 86 retval = filesize >> SCTRSHFT; 87 break; 88 } 89 90 case UL_SFILLIM: /* Set new file size limit. */ 91 { 92 int error = 0; 93 rlim64_t lim = (rlim64_t)arg; 94 struct rlimit64 rl64; 95 rctl_alloc_gp_t *gp = rctl_rlimit_set_prealloc(1); 96 97 if (lim >= (((rlim64_t)MAXOFFSET_T) >> SCTRSHFT)) 98 lim = (rlim64_t)RLIM64_INFINITY; 99 else 100 lim <<= SCTRSHFT; 101 102 rl64.rlim_max = rl64.rlim_cur = lim; 103 mutex_enter(&p->p_lock); 104 if (error = rctl_rlimit_set(rctlproc_legacy[RLIMIT_FSIZE], p, 105 &rl64, gp, RCTL_LOCAL_DENY | RCTL_LOCAL_SIGNAL, SIGXFSZ, 106 CRED())) { 107 mutex_exit(&p->p_lock); 108 rctl_prealloc_destroy(gp); 109 return (set_errno(error)); 110 } 111 mutex_exit(&p->p_lock); 112 rctl_prealloc_destroy(gp); 113 retval = arg; 114 break; 115 } 116 117 case UL_GMEMLIM: /* Return maximum possible break value. */ 118 { 119 struct seg *seg; 120 struct seg *nextseg; 121 struct as *as = p->p_as; 122 caddr_t brkend; 123 caddr_t brkbase; 124 size_t size; 125 rlim64_t size_ctl; 126 rlim64_t vmem_ctl; 127 128 /* 129 * Find the segment with a virtual address 130 * greater than the end of the current break. 131 */ 132 nextseg = NULL; 133 mutex_enter(&p->p_lock); 134 brkbase = (caddr_t)p->p_brkbase; 135 brkend = (caddr_t)p->p_brkbase + p->p_brksize; 136 mutex_exit(&p->p_lock); 137 138 /* 139 * Since we can't return less than the current break, 140 * initialize the return value to the current break 141 */ 142 retval = (long)brkend; 143 144 AS_LOCK_ENTER(as, &as->a_lock, RW_READER); 145 for (seg = as_findseg(as, brkend, 0); seg != NULL; 146 seg = AS_SEGNEXT(as, seg)) { 147 if (seg->s_base >= brkend) { 148 nextseg = seg; 149 break; 150 } 151 } 152 153 mutex_enter(&p->p_lock); 154 size_ctl = rctl_enforced_value(rctlproc_legacy[RLIMIT_DATA], 155 p->p_rctls, p); 156 vmem_ctl = rctl_enforced_value(rctlproc_legacy[RLIMIT_VMEM], 157 p->p_rctls, p); 158 mutex_exit(&p->p_lock); 159 160 /* 161 * First, calculate the maximum break value based on 162 * the user's RLIMIT_DATA, but also taking into account 163 * that this value cannot be greater than as->a_userlimit. 164 * We also take care to make sure that we don't overflow 165 * in the calculation. 166 */ 167 /* 168 * Since we are casting the RLIMIT_DATA value to a 169 * ulong (a 32-bit value in the 32-bit kernel) we have 170 * to pass this assertion. 171 */ 172 ASSERT32((size_t)size_ctl <= UINT32_MAX); 173 174 size = (size_t)size_ctl; 175 if (as->a_userlimit - brkbase > size) 176 retval = MAX((size_t)retval, (size_t)(brkbase + size)); 177 /* don't return less than current */ 178 else 179 retval = (long)as->a_userlimit; 180 181 /* 182 * The max break cannot extend into the next segment 183 */ 184 if (nextseg != NULL) 185 retval = MIN((uintptr_t)retval, 186 (uintptr_t)nextseg->s_base); 187 188 /* 189 * Handle the case where there is an limit on RLIMIT_VMEM 190 */ 191 if (vmem_ctl < UINT64_MAX) { 192 /* calculate brkend based on the end of page */ 193 caddr_t brkendpg = (caddr_t)roundup((uintptr_t)brkend, 194 PAGESIZE); 195 /* 196 * Large Files: The following assertion has to pass 197 * through to ensure the correctness of the cast. 198 */ 199 ASSERT32(vmem_ctl <= UINT32_MAX); 200 201 size = (size_t)(vmem_ctl & PAGEMASK); 202 203 if (as->a_size < size) 204 size -= as->a_size; 205 else 206 size = 0; 207 /* 208 * Take care to not overflow the calculation 209 */ 210 if (as->a_userlimit - brkendpg > size) 211 retval = MIN((size_t)retval, 212 (size_t)(brkendpg + size)); 213 } 214 215 AS_LOCK_EXIT(as, &as->a_lock); 216 217 /* truncate to same boundary as sbrk */ 218 219 switch (get_udatamodel()) { 220 default: 221 case DATAMODEL_ILP32: 222 retval = retval & ~(8-1); 223 break; 224 case DATAMODEL_LP64: 225 retval = retval & ~(16-1); 226 break; 227 } 228 break; 229 } 230 231 case UL_GDESLIM: /* Return approximate number of open files */ 232 { 233 rlim64_t fdno_ctl; 234 235 mutex_enter(&curproc->p_lock); 236 fdno_ctl = rctl_enforced_value(rctlproc_legacy[RLIMIT_NOFILE], 237 curproc->p_rctls, curproc); 238 ASSERT(fdno_ctl <= INT_MAX); 239 retval = (rlim_t)fdno_ctl; 240 mutex_exit(&curproc->p_lock); 241 break; 242 } 243 244 default: 245 return (set_errno(EINVAL)); 246 247 } 248 return (retval); 249 } 250 251 #ifdef _SYSCALL32_IMPL 252 253 int 254 ulimit32(int cmd, int arg) 255 { 256 return ((int)ulimit(cmd, (long)arg)); 257 } 258 259 #endif /* _SYSCALL32_IMPL */ 260 261 #if defined(_ILP32) || defined(_SYSCALL32_IMPL) 262 263 /* 264 * Large Files: getrlimit returns RLIM_SAVED_CUR or RLIM_SAVED_MAX when 265 * rlim_cur or rlim_max is not representable in 32-bit rlim_t. These 266 * values are just tokens which will be used in setrlimit to set the 267 * correct limits. The current limits are saved in the saved_rlimit members 268 * in user structures when the token is returned. setrlimit restores 269 * the limit values to these saved values when the token is passed. 270 * Consider the following common scenario of the apps: 271 * 272 * limit = getrlimit(); 273 * savedlimit = limit; 274 * limit = limit1; 275 * setrlimit(limit) 276 * // execute all processes in the new rlimit state. 277 * setrlimit(savedlimit) // restore the old values. 278 * 279 * Most apps don't check error returns from getrlimit or setrlimit 280 * and this is why we return tokens when the correct value 281 * cannot be represented in rlim_t. For more discussion refer to 282 * the LFS API document. 283 * 284 * In the 64-bit kernel, all existing resource limits are treated in this 285 * manner. In the 32-bit kernel, CPU time is treated equivalently to the 286 * file size limit above; the VM-related limits are not. The macro, 287 * RLIM_SAVED(x), returns true if the resource limit should be handled in 288 * this way on the current kernel. 289 */ 290 int 291 getrlimit32(int resource, struct rlimit32 *rlp) 292 { 293 struct rlimit32 rlim32; 294 struct rlimit64 rlim64; 295 struct proc *p = curproc; 296 struct user *up = PTOU(p); 297 int savecur = 0; 298 int savemax = 0; 299 300 if (resource < 0 || resource >= RLIM_NLIMITS) 301 return (set_errno(EINVAL)); 302 303 mutex_enter(&p->p_lock); 304 (void) rctl_rlimit_get(rctlproc_legacy[resource], p, &rlim64); 305 mutex_exit(&p->p_lock); 306 307 if (rlim64.rlim_max > (rlim64_t)UINT32_MAX) { 308 309 if (rlim64.rlim_max == RLIM64_INFINITY) 310 rlim32.rlim_max = RLIM32_INFINITY; 311 else { 312 savemax = 1; 313 rlim32.rlim_max = RLIM32_SAVED_MAX; 314 /*CONSTCOND*/ 315 ASSERT(RLIM_SAVED(resource)); 316 } 317 318 if (rlim64.rlim_cur == RLIM64_INFINITY) 319 rlim32.rlim_cur = RLIM32_INFINITY; 320 else if (rlim64.rlim_cur == rlim64.rlim_max) { 321 savecur = 1; 322 rlim32.rlim_cur = RLIM32_SAVED_MAX; 323 /*CONSTCOND*/ 324 ASSERT(RLIM_SAVED(resource)); 325 } else if (rlim64.rlim_cur > (rlim64_t)UINT32_MAX) { 326 savecur = 1; 327 rlim32.rlim_cur = RLIM32_SAVED_CUR; 328 /*CONSTCOND*/ 329 ASSERT(RLIM_SAVED(resource)); 330 } else 331 rlim32.rlim_cur = rlim64.rlim_cur; 332 333 /* 334 * save the current limits in user structure. 335 */ 336 /*CONSTCOND*/ 337 if (RLIM_SAVED(resource)) { 338 mutex_enter(&p->p_lock); 339 if (savemax) 340 up->u_saved_rlimit[resource].rlim_max = 341 rlim64.rlim_max; 342 if (savecur) 343 up->u_saved_rlimit[resource].rlim_cur = 344 rlim64.rlim_cur; 345 mutex_exit(&p->p_lock); 346 } 347 } else { 348 ASSERT(rlim64.rlim_cur <= (rlim64_t)UINT32_MAX); 349 rlim32.rlim_max = rlim64.rlim_max; 350 rlim32.rlim_cur = rlim64.rlim_cur; 351 } 352 353 if (copyout(&rlim32, rlp, sizeof (rlim32))) 354 return (set_errno(EFAULT)); 355 356 return (0); 357 } 358 359 /* 360 * See comments above getrlimit32(). When the tokens are passed in the 361 * rlimit structure the values are considered equal to the values 362 * stored in saved_rlimit members of user structure. 363 * When the user passes RLIM_INFINITY to set the resource limit to 364 * unlimited internally understand this value as RLIM64_INFINITY and 365 * let rlimit() do the job. 366 */ 367 int 368 setrlimit32(int resource, struct rlimit32 *rlp) 369 { 370 struct rlimit32 rlim32; 371 struct rlimit64 rlim64; 372 struct rlimit64 saved_rlim; 373 int error; 374 struct proc *p = ttoproc(curthread); 375 struct user *up = PTOU(p); 376 rctl_alloc_gp_t *gp; 377 378 if (resource < 0 || resource >= RLIM_NLIMITS) 379 return (set_errno(EINVAL)); 380 if (copyin(rlp, &rlim32, sizeof (rlim32))) 381 return (set_errno(EFAULT)); 382 383 gp = rctl_rlimit_set_prealloc(1); 384 385 /* 386 * Disallow resource limit tunnelling 387 */ 388 /*CONSTCOND*/ 389 if (RLIM_SAVED(resource)) { 390 mutex_enter(&p->p_lock); 391 saved_rlim = up->u_saved_rlimit[resource]; 392 mutex_exit(&p->p_lock); 393 } else { 394 saved_rlim.rlim_max = (rlim64_t)rlim32.rlim_max; 395 saved_rlim.rlim_cur = (rlim64_t)rlim32.rlim_cur; 396 } 397 398 switch (rlim32.rlim_cur) { 399 case RLIM32_INFINITY: 400 rlim64.rlim_cur = RLIM64_INFINITY; 401 break; 402 case RLIM32_SAVED_CUR: 403 rlim64.rlim_cur = saved_rlim.rlim_cur; 404 break; 405 case RLIM32_SAVED_MAX: 406 rlim64.rlim_cur = saved_rlim.rlim_max; 407 break; 408 default: 409 rlim64.rlim_cur = (rlim64_t)rlim32.rlim_cur; 410 break; 411 } 412 413 switch (rlim32.rlim_max) { 414 case RLIM32_INFINITY: 415 rlim64.rlim_max = RLIM64_INFINITY; 416 break; 417 case RLIM32_SAVED_MAX: 418 rlim64.rlim_max = saved_rlim.rlim_max; 419 break; 420 case RLIM32_SAVED_CUR: 421 rlim64.rlim_max = saved_rlim.rlim_cur; 422 break; 423 default: 424 rlim64.rlim_max = (rlim64_t)rlim32.rlim_max; 425 break; 426 } 427 428 mutex_enter(&p->p_lock); 429 if (error = rctl_rlimit_set(rctlproc_legacy[resource], p, &rlim64, gp, 430 rctlproc_flags[resource], rctlproc_signals[resource], CRED())) { 431 mutex_exit(&p->p_lock); 432 rctl_prealloc_destroy(gp); 433 return (set_errno(error)); 434 } 435 mutex_exit(&p->p_lock); 436 rctl_prealloc_destroy(gp); 437 438 return (0); 439 } 440 441 #endif /* _ILP32 && _SYSCALL32_IMPL */ 442 443 int 444 getrlimit64(int resource, struct rlimit64 *rlp) 445 { 446 struct rlimit64 rlim64; 447 struct proc *p = ttoproc(curthread); 448 449 if (resource < 0 || resource >= RLIM_NLIMITS) 450 return (set_errno(EINVAL)); 451 452 mutex_enter(&p->p_lock); 453 (void) rctl_rlimit_get(rctlproc_legacy[resource], p, &rlim64); 454 mutex_exit(&p->p_lock); 455 456 if (copyout(&rlim64, rlp, sizeof (rlim64))) 457 return (set_errno(EFAULT)); 458 return (0); 459 } 460 461 int 462 setrlimit64(int resource, struct rlimit64 *rlp) 463 { 464 struct rlimit64 rlim64; 465 struct proc *p = ttoproc(curthread); 466 int error; 467 rctl_alloc_gp_t *gp; 468 469 if (resource < 0 || resource >= RLIM_NLIMITS) 470 return (set_errno(EINVAL)); 471 if (copyin(rlp, &rlim64, sizeof (rlim64))) 472 return (set_errno(EFAULT)); 473 474 gp = rctl_rlimit_set_prealloc(1); 475 476 mutex_enter(&p->p_lock); 477 if (error = rctl_rlimit_set(rctlproc_legacy[resource], p, &rlim64, gp, 478 rctlproc_flags[resource], rctlproc_signals[resource], CRED())) { 479 mutex_exit(&p->p_lock); 480 rctl_prealloc_destroy(gp); 481 return (set_errno(error)); 482 } 483 mutex_exit(&p->p_lock); 484 rctl_prealloc_destroy(gp); 485 return (0); 486 487 } 488