Home | History | Annotate | Download | only in syscall
      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