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