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