4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <sys/cmn_err.h>
28 #include <sys/sysmacros.h>
31 #include <sys/rctl_impl.h>
32 #include <sys/port_kernel.h>
33 #include <sys/signal.h>
36 #include <sys/vmparam.h>
37 #include <sys/machparam.h>
40 * Process-based resource controls
41 * The structure of the kernel leaves us no particular place where the process
42 * abstraction can be declared--it is intertwined with the growth of the Unix
43 * kernel. Accordingly, we place all of the resource control logic associated
44 * with processes, both existing and future, in this file.
47 rctl_hndl_t rctlproc_legacy
[RLIM_NLIMITS
];
48 uint_t rctlproc_flags
[RLIM_NLIMITS
] = {
49 RCTL_LOCAL_SIGNAL
, /* RLIMIT_CPU */
50 RCTL_LOCAL_DENY
| RCTL_LOCAL_SIGNAL
, /* RLIMIT_FSIZE */
51 RCTL_LOCAL_DENY
, /* RLIMIT_DATA */
52 RCTL_LOCAL_DENY
, /* RLIMIT_STACK */
53 RCTL_LOCAL_DENY
, /* RLIMIT_CORE */
54 RCTL_LOCAL_DENY
, /* RLIMIT_NOFILE */
55 RCTL_LOCAL_DENY
/* RLIMIT_VMEM */
57 int rctlproc_signals
[RLIM_NLIMITS
] = {
58 SIGXCPU
, /* RLIMIT_CPU */
59 SIGXFSZ
, /* RLIMIT_FSIZE */
60 0, 0, 0, 0, 0 /* remainder do not signal */
63 rctl_hndl_t rc_process_msgmnb
;
64 rctl_hndl_t rc_process_msgtql
;
65 rctl_hndl_t rc_process_semmsl
;
66 rctl_hndl_t rc_process_semopm
;
67 rctl_hndl_t rc_process_portev
;
68 rctl_hndl_t rc_process_sigqueue
;
71 * process.max-cpu-time / RLIMIT_CPU
75 proc_cpu_time_test(struct rctl
*rctl
, struct proc
*p
, rctl_entity_p_t
*e
,
76 rctl_val_t
*rval
, rctl_qty_t inc
, uint_t flags
)
78 return (inc
>= rval
->rcv_value
);
81 static rctl_ops_t proc_cpu_time_ops
= {
89 * process.max-file-size / RLIMIT_FSIZE
92 proc_filesize_set(rctl_t
*rctl
, struct proc
*p
, rctl_entity_p_t
*e
,
95 if (p
->p_model
== DATAMODEL_NATIVE
)
96 nv
= MIN(nv
, rctl
->rc_dict_entry
->rcd_max_native
);
98 nv
= MIN(nv
, rctl
->rc_dict_entry
->rcd_max_ilp32
);
100 ASSERT(e
->rcep_t
== RCENTITY_PROCESS
);
101 e
->rcep_p
.proc
->p_fsz_ctl
= nv
;
106 static rctl_ops_t proc_filesize_ops
= {
114 * process.max-data / RLIMIT_DATA
118 * process.max-stack-size / RLIMIT_STACK
121 proc_stack_set(rctl_t
*rctl
, struct proc
*p
, rctl_entity_p_t
*e
,
124 klwp_t
*lwp
= ttolwp(curthread
);
126 if (p
->p_model
== DATAMODEL_NATIVE
)
127 nv
= MIN(nv
, rctl
->rc_dict_entry
->rcd_max_native
);
129 nv
= MIN(nv
, rctl
->rc_dict_entry
->rcd_max_ilp32
);
132 * In the process of changing the rlimit, this function actually
133 * gets called a number of times. We only want to save the current
134 * rlimit the first time we come through here. In post_syscall(),
135 * we copyin() the lwp's ustack, and compare it to the rlimit we
136 * save here; if the two match, we adjust the ustack to reflect
137 * the new stack bounds.
139 * We check to make sure that we're changing the rlimit of our
140 * own process rather than on behalf of some other process. The
141 * notion of changing this resource limit on behalf of another
142 * process is problematic at best, and changing the amount of stack
143 * space a process is allowed to consume is a rather antiquated
144 * notion that has limited applicability in our multithreaded
147 ASSERT(e
->rcep_t
== RCENTITY_PROCESS
);
148 if (lwp
!= NULL
&& lwp
->lwp_procp
== e
->rcep_p
.proc
&&
149 lwp
->lwp_ustack
&& lwp
->lwp_old_stk_ctl
== 0) {
150 lwp
->lwp_old_stk_ctl
= (size_t)e
->rcep_p
.proc
->p_stk_ctl
;
151 curthread
->t_post_sys
= 1;
154 e
->rcep_p
.proc
->p_stk_ctl
= nv
;
159 static rctl_ops_t proc_stack_ops
= {
167 * process.max-file-descriptors / RLIMIT_NOFILE
170 proc_nofile_set(rctl_t
*rctl
, struct proc
*p
, rctl_entity_p_t
*e
, rctl_qty_t nv
)
172 ASSERT(e
->rcep_t
== RCENTITY_PROCESS
);
173 if (p
->p_model
== DATAMODEL_NATIVE
)
174 nv
= MIN(nv
, rctl
->rc_dict_entry
->rcd_max_native
);
176 nv
= MIN(nv
, rctl
->rc_dict_entry
->rcd_max_ilp32
);
178 e
->rcep_p
.proc
->p_fno_ctl
= nv
;
183 static rctl_ops_t proc_nofile_ops
= {
191 * process.max-address-space / RLIMIT_VMEM
194 proc_vmem_set(rctl_t
*rctl
, struct proc
*p
, rctl_entity_p_t
*e
, rctl_qty_t nv
)
196 ASSERT(e
->rcep_t
== RCENTITY_PROCESS
);
197 if (p
->p_model
== DATAMODEL_ILP32
)
198 nv
= MIN(nv
, rctl
->rc_dict_entry
->rcd_max_ilp32
);
200 nv
= MIN(nv
, rctl
->rc_dict_entry
->rcd_max_native
);
202 e
->rcep_p
.proc
->p_vmem_ctl
= nv
;
207 static rctl_ops_t proc_vmem_ops
= {
215 * void rctlproc_default_init()
218 * Establish default basic and privileged control values on the init process.
219 * These correspond to the soft and hard limits, respectively.
222 rctlproc_default_init(struct proc
*initp
, rctl_alloc_gp_t
*gp
)
224 struct rlimit64 rlp64
;
227 * RLIMIT_CPU: deny never, sigtoproc(pp, NULL, SIGXCPU).
229 rlp64
.rlim_cur
= rlp64
.rlim_max
= RLIM64_INFINITY
;
230 (void) rctl_rlimit_set(rctlproc_legacy
[RLIMIT_CPU
], initp
, &rlp64
, gp
,
231 RCTL_LOCAL_SIGNAL
, SIGXCPU
, kcred
);
234 * RLIMIT_FSIZE: deny always, sigtoproc(pp, NULL, SIGXFSZ).
236 rlp64
.rlim_cur
= rlp64
.rlim_max
= RLIM64_INFINITY
;
237 (void) rctl_rlimit_set(rctlproc_legacy
[RLIMIT_FSIZE
], initp
, &rlp64
, gp
,
238 RCTL_LOCAL_SIGNAL
| RCTL_LOCAL_DENY
, SIGXFSZ
, kcred
);
241 * RLIMIT_DATA: deny always, no default action.
243 rlp64
.rlim_cur
= rlp64
.rlim_max
= RLIM64_INFINITY
;
244 (void) rctl_rlimit_set(rctlproc_legacy
[RLIMIT_DATA
], initp
, &rlp64
, gp
,
245 RCTL_LOCAL_DENY
, 0, kcred
);
248 * RLIMIT_STACK: deny always, no default action.
250 rlp64
.rlim_cur
= DFLSSIZ
;
251 rlp64
.rlim_max
= MAXSSIZ
;
252 (void) rctl_rlimit_set(rctlproc_legacy
[RLIMIT_STACK
], initp
, &rlp64
, gp
,
253 RCTL_LOCAL_DENY
, 0, kcred
);
256 * RLIMIT_CORE: deny always, no default action.
258 rlp64
.rlim_cur
= rlp64
.rlim_max
= RLIM64_INFINITY
;
259 (void) rctl_rlimit_set(rctlproc_legacy
[RLIMIT_CORE
], initp
, &rlp64
, gp
,
260 RCTL_LOCAL_DENY
, 0, kcred
);
263 * RLIMIT_NOFILE: deny always, no action.
265 rlp64
.rlim_cur
= rlim_fd_cur
;
266 rlp64
.rlim_max
= rlim_fd_max
;
267 (void) rctl_rlimit_set(rctlproc_legacy
[RLIMIT_NOFILE
], initp
, &rlp64
,
268 gp
, RCTL_LOCAL_DENY
, 0, kcred
);
273 rlp64
.rlim_cur
= rlp64
.rlim_max
= RLIM64_INFINITY
;
274 (void) rctl_rlimit_set(rctlproc_legacy
[RLIMIT_VMEM
], initp
, &rlp64
, gp
,
275 RCTL_LOCAL_DENY
, 0, kcred
);
279 * void rctlproc_init()
282 * Register the various resource controls associated with process entities.
283 * The historical rlim_infinity_map and rlim_infinity32_map are now encoded
284 * here as the native and ILP32 infinite values for each resource control.
293 rctlproc_legacy
[RLIMIT_CPU
] = rctl_register("process.max-cpu-time",
294 RCENTITY_PROCESS
, RCTL_GLOBAL_LOWERABLE
| RCTL_GLOBAL_DENY_NEVER
|
295 RCTL_GLOBAL_CPU_TIME
| RCTL_GLOBAL_INFINITE
| RCTL_GLOBAL_SECONDS
,
296 UINT64_MAX
, UINT64_MAX
, &proc_cpu_time_ops
);
297 rctlproc_legacy
[RLIMIT_FSIZE
] = rctl_register("process.max-file-size",
298 RCENTITY_PROCESS
, RCTL_GLOBAL_LOWERABLE
| RCTL_GLOBAL_DENY_ALWAYS
|
299 RCTL_GLOBAL_FILE_SIZE
| RCTL_GLOBAL_BYTES
,
300 MAXOFFSET_T
, MAXOFFSET_T
, &proc_filesize_ops
);
301 rctlproc_legacy
[RLIMIT_DATA
] = rctl_register("process.max-data-size",
302 RCENTITY_PROCESS
, RCTL_GLOBAL_LOWERABLE
| RCTL_GLOBAL_DENY_ALWAYS
|
303 RCTL_GLOBAL_SIGNAL_NEVER
| RCTL_GLOBAL_BYTES
,
304 ULONG_MAX
, UINT32_MAX
, &rctl_default_ops
);
307 rctlproc_legacy
[RLIMIT_STACK
] = rctl_register("process.max-stack-size",
308 RCENTITY_PROCESS
, RCTL_GLOBAL_LOWERABLE
| RCTL_GLOBAL_DENY_ALWAYS
|
309 RCTL_GLOBAL_SIGNAL_NEVER
| RCTL_GLOBAL_BYTES
,
310 LONG_MAX
, INT32_MAX
, &proc_stack_ops
);
312 rctlproc_legacy
[RLIMIT_STACK
] = rctl_register("process.max-stack-size",
313 RCENTITY_PROCESS
, RCTL_GLOBAL_LOWERABLE
| RCTL_GLOBAL_DENY_ALWAYS
|
314 RCTL_GLOBAL_SIGNAL_NEVER
| RCTL_GLOBAL_BYTES
,
315 MAXSSIZ
, USRSTACK32
- PAGESIZE
, &proc_stack_ops
);
318 rctlproc_legacy
[RLIMIT_STACK
] = rctl_register("process.max-stack-size",
319 RCENTITY_PROCESS
, RCTL_GLOBAL_LOWERABLE
| RCTL_GLOBAL_DENY_ALWAYS
|
320 RCTL_GLOBAL_SIGNAL_NEVER
| RCTL_GLOBAL_BYTES
,
321 USRSTACK
- PAGESIZE
, USRSTACK
- PAGESIZE
, &proc_stack_ops
);
323 rctlproc_legacy
[RLIMIT_CORE
] = rctl_register("process.max-core-size",
324 RCENTITY_PROCESS
, RCTL_GLOBAL_LOWERABLE
| RCTL_GLOBAL_DENY_ALWAYS
|
325 RCTL_GLOBAL_SIGNAL_NEVER
| RCTL_GLOBAL_BYTES
,
326 MIN(MAXOFFSET_T
, ULONG_MAX
), UINT32_MAX
, &rctl_default_ops
);
327 rctlproc_legacy
[RLIMIT_NOFILE
] = rctl_register(
328 "process.max-file-descriptor", RCENTITY_PROCESS
,
329 RCTL_GLOBAL_LOWERABLE
| RCTL_GLOBAL_DENY_ALWAYS
|
330 RCTL_GLOBAL_COUNT
, INT32_MAX
, INT32_MAX
, &proc_nofile_ops
);
331 rctlproc_legacy
[RLIMIT_VMEM
] =
332 rctl_register("process.max-address-space", RCENTITY_PROCESS
,
333 RCTL_GLOBAL_LOWERABLE
| RCTL_GLOBAL_DENY_ALWAYS
|
334 RCTL_GLOBAL_SIGNAL_NEVER
| RCTL_GLOBAL_BYTES
,
335 ULONG_MAX
, UINT32_MAX
, &proc_vmem_ops
);
337 rc_process_semmsl
= rctl_register("process.max-sem-nsems",
338 RCENTITY_PROCESS
, RCTL_GLOBAL_DENY_ALWAYS
| RCTL_GLOBAL_COUNT
,
339 SHRT_MAX
, SHRT_MAX
, &rctl_absolute_ops
);
340 rctl_add_legacy_limit("process.max-sem-nsems", "semsys",
341 "seminfo_semmsl", 512, SHRT_MAX
);
343 rc_process_semopm
= rctl_register("process.max-sem-ops",
344 RCENTITY_PROCESS
, RCTL_GLOBAL_DENY_ALWAYS
| RCTL_GLOBAL_COUNT
,
345 INT_MAX
, INT_MAX
, &rctl_absolute_ops
);
346 rctl_add_legacy_limit("process.max-sem-ops", "semsys",
347 "seminfo_semopm", 512, INT_MAX
);
349 rc_process_msgmnb
= rctl_register("process.max-msg-qbytes",
350 RCENTITY_PROCESS
, RCTL_GLOBAL_DENY_ALWAYS
| RCTL_GLOBAL_BYTES
,
351 ULONG_MAX
, ULONG_MAX
, &rctl_absolute_ops
);
352 rctl_add_legacy_limit("process.max-msg-qbytes", "msgsys",
353 "msginfo_msgmnb", 65536, ULONG_MAX
);
355 rc_process_msgtql
= rctl_register("process.max-msg-messages",
356 RCENTITY_PROCESS
, RCTL_GLOBAL_DENY_ALWAYS
| RCTL_GLOBAL_COUNT
,
357 UINT_MAX
, UINT_MAX
, &rctl_absolute_ops
);
358 rctl_add_legacy_limit("process.max-msg-messages", "msgsys",
359 "msginfo_msgtql", 8192, UINT_MAX
);
361 rc_process_portev
= rctl_register("process.max-port-events",
362 RCENTITY_PROCESS
, RCTL_GLOBAL_DENY_ALWAYS
| RCTL_GLOBAL_COUNT
,
363 PORT_MAX_EVENTS
, PORT_MAX_EVENTS
, &rctl_absolute_ops
);
364 rctl_add_default_limit("process.max-port-events", PORT_DEFAULT_EVENTS
,
365 RCPRIV_PRIVILEGED
, RCTL_LOCAL_DENY
);
368 * We set the upper limit to the maximum number of user processes to
369 * make it theoretically possible to deliver all SIGCHILD signals on
370 * child termination, but at least to 8k.
372 rc_process_sigqueue
= rctl_register("process.max-sigqueue-size",
373 RCENTITY_PROCESS
, RCTL_GLOBAL_LOWERABLE
| RCTL_GLOBAL_DENY_ALWAYS
|
374 RCTL_GLOBAL_COUNT
, MAX(v
.v_maxup
, 8192), MAX(v
.v_maxup
, 8192),
376 rctl_add_default_limit("process.max-sigqueue-size",
377 _SIGQUEUE_SIZE_BASIC
, RCPRIV_BASIC
, RCTL_LOCAL_DENY
);
378 rctl_add_default_limit("process.max-sigqueue-size",
379 _SIGQUEUE_SIZE_PRIVILEGED
, RCPRIV_PRIVILEGED
, RCTL_LOCAL_DENY
);
382 * Place minimal set of controls on "sched" process for inheritance by
383 * processes created via newproc().
385 set
= rctl_set_create();
386 gp
= rctl_set_init_prealloc(RCENTITY_PROCESS
);
387 mutex_enter(&curproc
->p_lock
);
388 e
.rcep_p
.proc
= curproc
;
389 e
.rcep_t
= RCENTITY_PROCESS
;
390 curproc
->p_rctls
= rctl_set_init(RCENTITY_PROCESS
, curproc
, &e
,
392 mutex_exit(&curproc
->p_lock
);
393 rctl_prealloc_destroy(gp
);