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 }