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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <sys/types.h>
27 #include <sys/cmn_err.h>
28 #include <sys/sysmacros.h>
29 #include <sys/proc.h>
30 #include <sys/rctl.h>
31 #include <sys/rctl_impl.h>
32 #include <sys/port_kernel.h>
33 #include <sys/signal.h>
34 #include <sys/var.h>
35
36 #include <sys/vmparam.h>
37 #include <sys/machparam.h>
38
39 /*
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.
45 */
46
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 */
56 };
57 int rctlproc_signals[RLIM_NLIMITS] = {
58 SIGXCPU, /* RLIMIT_CPU */
59 SIGXFSZ, /* RLIMIT_FSIZE */
60 0, 0, 0, 0, 0 /* remainder do not signal */
61 };
62
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;
69
70 /*
71 * process.max-cpu-time / RLIMIT_CPU
72 */
73 /*ARGSUSED*/
74 static int
proc_cpu_time_test(struct rctl * rctl,struct proc * p,rctl_entity_p_t * e,rctl_val_t * rval,rctl_qty_t inc,uint_t flags)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)
77 {
78 return (inc >= rval->rcv_value);
79 }
80
81 static rctl_ops_t proc_cpu_time_ops = {
82 rcop_no_action,
83 rcop_no_usage,
84 rcop_no_set,
85 proc_cpu_time_test
86 };
87
88 /*
89 * process.max-file-size / RLIMIT_FSIZE
90 */
91 static int
proc_filesize_set(rctl_t * rctl,struct proc * p,rctl_entity_p_t * e,rctl_qty_t nv)92 proc_filesize_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e,
93 rctl_qty_t nv)
94 {
95 if (p->p_model == DATAMODEL_NATIVE)
96 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_native);
97 else
98 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_ilp32);
99
100 ASSERT(e->rcep_t == RCENTITY_PROCESS);
101 e->rcep_p.proc->p_fsz_ctl = nv;
102
103 return (0);
104 }
105
106 static rctl_ops_t proc_filesize_ops = {
107 rcop_no_action,
108 rcop_no_usage,
109 proc_filesize_set,
110 rcop_no_test
111 };
112
113 /*
114 * process.max-data / RLIMIT_DATA
115 */
116
117 /*
118 * process.max-stack-size / RLIMIT_STACK
119 */
120 static int
proc_stack_set(rctl_t * rctl,struct proc * p,rctl_entity_p_t * e,rctl_qty_t nv)121 proc_stack_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e,
122 rctl_qty_t nv)
123 {
124 klwp_t *lwp = ttolwp(curthread);
125
126 if (p->p_model == DATAMODEL_NATIVE)
127 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_native);
128 else
129 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_ilp32);
130
131 /*
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.
138 *
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
145 * process model.
146 */
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;
152 }
153
154 e->rcep_p.proc->p_stk_ctl = nv;
155
156 return (0);
157 }
158
159 static rctl_ops_t proc_stack_ops = {
160 rcop_no_action,
161 rcop_no_usage,
162 proc_stack_set,
163 rcop_no_test
164 };
165
166 /*
167 * process.max-file-descriptors / RLIMIT_NOFILE
168 */
169 static int
proc_nofile_set(rctl_t * rctl,struct proc * p,rctl_entity_p_t * e,rctl_qty_t nv)170 proc_nofile_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e, rctl_qty_t nv)
171 {
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);
175 else
176 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_ilp32);
177
178 e->rcep_p.proc->p_fno_ctl = nv;
179
180 return (0);
181 }
182
183 static rctl_ops_t proc_nofile_ops = {
184 rcop_no_action,
185 rcop_no_usage,
186 proc_nofile_set,
187 rcop_absolute_test
188 };
189
190 /*
191 * process.max-address-space / RLIMIT_VMEM
192 */
193 static int
proc_vmem_set(rctl_t * rctl,struct proc * p,rctl_entity_p_t * e,rctl_qty_t nv)194 proc_vmem_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e, rctl_qty_t nv)
195 {
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);
199 else
200 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_native);
201
202 e->rcep_p.proc->p_vmem_ctl = nv;
203
204 return (0);
205 }
206
207 static rctl_ops_t proc_vmem_ops = {
208 rcop_no_action,
209 rcop_no_usage,
210 proc_vmem_set,
211 rcop_no_test
212 };
213
214 /*
215 * void rctlproc_default_init()
216 *
217 * Overview
218 * Establish default basic and privileged control values on the init process.
219 * These correspond to the soft and hard limits, respectively.
220 */
221 void
rctlproc_default_init(struct proc * initp,rctl_alloc_gp_t * gp)222 rctlproc_default_init(struct proc *initp, rctl_alloc_gp_t *gp)
223 {
224 struct rlimit64 rlp64;
225
226 /*
227 * RLIMIT_CPU: deny never, sigtoproc(pp, NULL, SIGXCPU).
228 */
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);
232
233 /*
234 * RLIMIT_FSIZE: deny always, sigtoproc(pp, NULL, SIGXFSZ).
235 */
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);
239
240 /*
241 * RLIMIT_DATA: deny always, no default action.
242 */
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);
246
247 /*
248 * RLIMIT_STACK: deny always, no default action.
249 */
250 #ifdef __sparc
251 rlp64.rlim_cur = DFLSSIZ;
252 rlp64.rlim_max = LONG_MAX;
253 #else
254 rlp64.rlim_cur = DFLSSIZ;
255 rlp64.rlim_max = MAXSSIZ;
256 #endif
257 (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_STACK], initp, &rlp64, gp,
258 RCTL_LOCAL_DENY, 0, kcred);
259
260 /*
261 * RLIMIT_CORE: deny always, no default action.
262 */
263 rlp64.rlim_cur = rlp64.rlim_max = RLIM64_INFINITY;
264 (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_CORE], initp, &rlp64, gp,
265 RCTL_LOCAL_DENY, 0, kcred);
266
267 /*
268 * RLIMIT_NOFILE: deny always, no action.
269 */
270 rlp64.rlim_cur = rlim_fd_cur;
271 rlp64.rlim_max = rlim_fd_max;
272 (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_NOFILE], initp, &rlp64,
273 gp, RCTL_LOCAL_DENY, 0, kcred);
274
275 /*
276 * RLIMIT_VMEM
277 */
278 rlp64.rlim_cur = rlp64.rlim_max = RLIM64_INFINITY;
279 (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_VMEM], initp, &rlp64, gp,
280 RCTL_LOCAL_DENY, 0, kcred);
281 }
282
283 /*
284 * void rctlproc_init()
285 *
286 * Overview
287 * Register the various resource controls associated with process entities.
288 * The historical rlim_infinity_map and rlim_infinity32_map are now encoded
289 * here as the native and ILP32 infinite values for each resource control.
290 */
291 void
rctlproc_init(void)292 rctlproc_init(void)
293 {
294 rctl_set_t *set;
295 rctl_alloc_gp_t *gp;
296 rctl_entity_p_t e;
297
298 rctlproc_legacy[RLIMIT_CPU] = rctl_register("process.max-cpu-time",
299 RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_NEVER |
300 RCTL_GLOBAL_CPU_TIME | RCTL_GLOBAL_INFINITE | RCTL_GLOBAL_SECONDS,
301 UINT64_MAX, UINT64_MAX, &proc_cpu_time_ops);
302 rctlproc_legacy[RLIMIT_FSIZE] = rctl_register("process.max-file-size",
303 RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
304 RCTL_GLOBAL_FILE_SIZE | RCTL_GLOBAL_BYTES,
305 MAXOFFSET_T, MAXOFFSET_T, &proc_filesize_ops);
306 rctlproc_legacy[RLIMIT_DATA] = rctl_register("process.max-data-size",
307 RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
308 RCTL_GLOBAL_SIGNAL_NEVER | RCTL_GLOBAL_BYTES,
309 ULONG_MAX, UINT32_MAX, &rctl_default_ops);
310 #ifdef _LP64
311 #ifdef __sparc
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 LONG_MAX, INT32_MAX, &proc_stack_ops);
316 #else /* __sparc */
317 rctlproc_legacy[RLIMIT_STACK] = rctl_register("process.max-stack-size",
318 RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
319 RCTL_GLOBAL_SIGNAL_NEVER | RCTL_GLOBAL_BYTES,
320 MAXSSIZ, USRSTACK32 - PAGESIZE, &proc_stack_ops);
321 #endif /* __sparc */
322 #else /* _LP64 */
323 rctlproc_legacy[RLIMIT_STACK] = rctl_register("process.max-stack-size",
324 RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
325 RCTL_GLOBAL_SIGNAL_NEVER | RCTL_GLOBAL_BYTES,
326 USRSTACK - PAGESIZE, USRSTACK - PAGESIZE, &proc_stack_ops);
327 #endif
328 rctlproc_legacy[RLIMIT_CORE] = rctl_register("process.max-core-size",
329 RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
330 RCTL_GLOBAL_SIGNAL_NEVER | RCTL_GLOBAL_BYTES,
331 MIN(MAXOFFSET_T, ULONG_MAX), UINT32_MAX, &rctl_default_ops);
332 rctlproc_legacy[RLIMIT_NOFILE] = rctl_register(
333 "process.max-file-descriptor", RCENTITY_PROCESS,
334 RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
335 RCTL_GLOBAL_COUNT, INT32_MAX, INT32_MAX, &proc_nofile_ops);
336 rctlproc_legacy[RLIMIT_VMEM] =
337 rctl_register("process.max-address-space", RCENTITY_PROCESS,
338 RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
339 RCTL_GLOBAL_SIGNAL_NEVER | RCTL_GLOBAL_BYTES,
340 ULONG_MAX, UINT32_MAX, &proc_vmem_ops);
341
342 rc_process_semmsl = rctl_register("process.max-sem-nsems",
343 RCENTITY_PROCESS, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_COUNT,
344 SHRT_MAX, SHRT_MAX, &rctl_absolute_ops);
345 rctl_add_legacy_limit("process.max-sem-nsems", "semsys",
346 "seminfo_semmsl", 512, SHRT_MAX);
347
348 rc_process_semopm = rctl_register("process.max-sem-ops",
349 RCENTITY_PROCESS, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_COUNT,
350 INT_MAX, INT_MAX, &rctl_absolute_ops);
351 rctl_add_legacy_limit("process.max-sem-ops", "semsys",
352 "seminfo_semopm", 512, INT_MAX);
353
354 rc_process_msgmnb = rctl_register("process.max-msg-qbytes",
355 RCENTITY_PROCESS, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_BYTES,
356 ULONG_MAX, ULONG_MAX, &rctl_absolute_ops);
357 rctl_add_legacy_limit("process.max-msg-qbytes", "msgsys",
358 "msginfo_msgmnb", 65536, ULONG_MAX);
359
360 rc_process_msgtql = rctl_register("process.max-msg-messages",
361 RCENTITY_PROCESS, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_COUNT,
362 UINT_MAX, UINT_MAX, &rctl_absolute_ops);
363 rctl_add_legacy_limit("process.max-msg-messages", "msgsys",
364 "msginfo_msgtql", 8192, UINT_MAX);
365
366 rc_process_portev = rctl_register("process.max-port-events",
367 RCENTITY_PROCESS, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_COUNT,
368 PORT_MAX_EVENTS, PORT_MAX_EVENTS, &rctl_absolute_ops);
369 rctl_add_default_limit("process.max-port-events", PORT_DEFAULT_EVENTS,
370 RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
371
372 /*
373 * We set the upper limit to the maximum number of user processes to
374 * make it theoretically possible to deliver all SIGCHILD signals on
375 * child termination, but at least to 8k.
376 */
377 rc_process_sigqueue = rctl_register("process.max-sigqueue-size",
378 RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
379 RCTL_GLOBAL_COUNT, MAX(v.v_maxup, 8192), MAX(v.v_maxup, 8192),
380 &rctl_absolute_ops);
381 rctl_add_default_limit("process.max-sigqueue-size",
382 _SIGQUEUE_SIZE_BASIC, RCPRIV_BASIC, RCTL_LOCAL_DENY);
383 rctl_add_default_limit("process.max-sigqueue-size",
384 _SIGQUEUE_SIZE_PRIVILEGED, RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
385
386 /*
387 * Place minimal set of controls on "sched" process for inheritance by
388 * processes created via newproc().
389 */
390 set = rctl_set_create();
391 gp = rctl_set_init_prealloc(RCENTITY_PROCESS);
392 mutex_enter(&curproc->p_lock);
393 e.rcep_p.proc = curproc;
394 e.rcep_t = RCENTITY_PROCESS;
395 curproc->p_rctls = rctl_set_init(RCENTITY_PROCESS, curproc, &e,
396 set, gp);
397 mutex_exit(&curproc->p_lock);
398 rctl_prealloc_destroy(gp);
399 }
400