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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
28 #include <sys/cmn_err.h>
30 #include <sys/errno.h>
32 #include <sys/rctl_impl.h>
33 #include <sys/strlog.h>
34 #include <sys/syslog.h>
35 #include <sys/sysmacros.h>
36 #include <sys/systm.h>
37 #include <sys/policy.h>
42 * setrctl(2), getrctl(2), and private rctlsys(2*) system calls
44 * Resource control block (rctlblk_ptr_t, rctl_opaque_t)
45 * The resource control system call interfaces present the resource control
46 * values and flags via the resource control block abstraction, made manifest
47 * via an opaque data type with strict type definitions. Keeping the formal
48 * definitions in the rcontrol block allows us to be clever in the kernel,
49 * combining attributes where appropriate in the current implementation while
50 * preserving binary compatibility in the face of implementation changes.
53 #define RBX_TO_BLK 0x1
54 #define RBX_FROM_BLK 0x2
59 rctlsys_rblk_xfrm(rctl_opaque_t
*blk
, rctl_dict_entry_t
*rde
,
60 rctl_val_t
*val
, int flags
)
62 if (flags
& RBX_FROM_BLK
) {
63 if (flags
& RBX_VAL
) {
65 * Firing time cannot be set.
67 val
->rcv_privilege
= blk
->rcq_privilege
;
68 val
->rcv_value
= blk
->rcq_value
;
69 val
->rcv_flagaction
= blk
->rcq_local_flagaction
;
70 val
->rcv_action_signal
= blk
->rcq_local_signal
;
71 val
->rcv_action_recip_pid
=
72 blk
->rcq_local_recipient_pid
;
74 if (flags
& RBX_CTL
) {
75 rde
->rcd_flagaction
= blk
->rcq_global_flagaction
;
76 rde
->rcd_syslog_level
= blk
->rcq_global_syslog_level
;
79 * Because the strlog() interface supports fewer options
80 * than are made available via the syslog() interface to
81 * userland, we map the syslog level down to a smaller
82 * set of distinct logging behaviours.
84 rde
->rcd_strlog_flags
= 0;
85 switch (blk
->rcq_global_syslog_level
) {
89 rde
->rcd_strlog_flags
|= SL_CONSOLE
;
92 rde
->rcd_strlog_flags
|= SL_ERROR
;
95 rde
->rcd_strlog_flags
|= SL_WARN
;
98 rde
->rcd_strlog_flags
|= SL_CONSOLE
;
100 case LOG_INFO
: /* informational */
101 case LOG_DEBUG
: /* debug-level messages */
103 rde
->rcd_strlog_flags
|= SL_NOTE
;
108 bzero(blk
, sizeof (rctl_opaque_t
));
109 if (flags
& RBX_VAL
) {
110 blk
->rcq_privilege
= val
->rcv_privilege
;
111 blk
->rcq_value
= val
->rcv_value
;
112 blk
->rcq_enforced_value
= rctl_model_value(rde
,
113 curproc
, val
->rcv_value
);
114 blk
->rcq_local_flagaction
= val
->rcv_flagaction
;
115 blk
->rcq_local_signal
= val
->rcv_action_signal
;
116 blk
->rcq_firing_time
= val
->rcv_firing_time
;
117 blk
->rcq_local_recipient_pid
=
118 val
->rcv_action_recip_pid
;
120 if (flags
& RBX_CTL
) {
121 blk
->rcq_global_flagaction
= rde
->rcd_flagaction
;
122 blk
->rcq_global_syslog_level
= rde
->rcd_syslog_level
;
128 * int rctl_invalid_value(rctl_dict_entry_t *, rctl_val_t *)
131 * Perform basic validation of proposed new resource control value against the
132 * global properties set on the control. Any system call operation presented
133 * with an invalid resource control value should return -1 and set errno to
137 * 0 if valid, 1 if invalid.
140 * No restriction on context.
143 rctl_invalid_value(rctl_dict_entry_t
*rde
, rctl_val_t
*rval
)
145 rctl_val_t
*sys_rval
;
147 if (rval
->rcv_privilege
!= RCPRIV_BASIC
&&
148 rval
->rcv_privilege
!= RCPRIV_PRIVILEGED
&&
149 rval
->rcv_privilege
!= RCPRIV_SYSTEM
)
152 if (rval
->rcv_flagaction
& ~RCTL_LOCAL_MASK
)
155 if (rval
->rcv_privilege
== RCPRIV_BASIC
&&
156 (rde
->rcd_flagaction
& RCTL_GLOBAL_NOBASIC
) != 0)
159 if ((rval
->rcv_flagaction
& RCTL_LOCAL_DENY
) == 0 &&
160 (rde
->rcd_flagaction
& RCTL_GLOBAL_DENY_ALWAYS
) != 0)
163 if ((rval
->rcv_flagaction
& RCTL_LOCAL_DENY
) &&
164 (rde
->rcd_flagaction
& RCTL_GLOBAL_DENY_NEVER
))
167 if ((rval
->rcv_flagaction
& RCTL_LOCAL_SIGNAL
) &&
168 (rde
->rcd_flagaction
& RCTL_GLOBAL_SIGNAL_NEVER
))
171 if ((rval
->rcv_flagaction
& RCTL_LOCAL_SIGNAL
) &&
172 rval
->rcv_action_signal
== 0)
175 if (rval
->rcv_action_signal
== SIGXCPU
&&
176 (rde
->rcd_flagaction
& RCTL_GLOBAL_CPU_TIME
) == 0)
178 else if (rval
->rcv_action_signal
== SIGXFSZ
&&
179 (rde
->rcd_flagaction
& RCTL_GLOBAL_FILE_SIZE
) == 0)
181 else if (rval
->rcv_action_signal
!= SIGHUP
&&
182 rval
->rcv_action_signal
!= SIGABRT
&&
183 rval
->rcv_action_signal
!= SIGKILL
&&
184 rval
->rcv_action_signal
!= SIGTERM
&&
185 rval
->rcv_action_signal
!= SIGSTOP
&&
186 rval
->rcv_action_signal
!= SIGXCPU
&&
187 rval
->rcv_action_signal
!= SIGXFSZ
&&
188 rval
->rcv_action_signal
!= SIGXRES
&&
189 rval
->rcv_action_signal
!= 0) /* That is, no signal is ok. */
192 sys_rval
= rde
->rcd_default_value
;
193 while (sys_rval
->rcv_privilege
!= RCPRIV_SYSTEM
)
194 sys_rval
= sys_rval
->rcv_next
;
196 if (rval
->rcv_value
> sys_rval
->rcv_value
)
203 * static long rctlsys_get(char *name, rctl_opaque_t *old_rblk,
204 * rctl_opaque_t *new_rblk, int flags)
207 * rctlsys_get() is the implementation of the core logic of getrctl(2), the
208 * public system call for fetching resource control values. Three mutually
209 * exclusive flag values are supported: RCTL_USAGE, RCTL_FIRST and RCTL_NEXT.
210 * When RCTL_USAGE is presented, the current usage for the resource control
211 * is returned in new_blk if the resource control provides an implementation
212 * of the usage operation. When RCTL_FIRST is presented, the value of
213 * old_rblk is ignored, and the first value in the resource control value
214 * sequence for the named control is transformed and placed in the user
215 * memory location at new_rblk. In the RCTL_NEXT case, the value of old_rblk
216 * is examined, and the next value in the sequence is transformed and placed
220 rctlsys_get(char *name
, rctl_opaque_t
*old_rblk
, rctl_opaque_t
*new_rblk
,
228 rctl_dict_entry_t
*krde
;
230 int action
= flags
& (~RCTLSYS_ACTION_MASK
);
232 if (flags
& (~RCTLSYS_MASK
))
233 return (set_errno(EINVAL
));
235 if (action
!= RCTL_FIRST
&& action
!= RCTL_NEXT
&&
236 action
!= RCTL_USAGE
)
237 return (set_errno(EINVAL
));
239 if (new_rblk
== NULL
|| name
== NULL
)
240 return (set_errno(EFAULT
));
242 kname
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
243 krde
= kmem_alloc(sizeof (rctl_dict_entry_t
), KM_SLEEP
);
245 if (copyinstr(name
, kname
, MAXPATHLEN
, &klen
) != 0) {
246 kmem_free(kname
, MAXPATHLEN
);
247 kmem_free(krde
, sizeof (rctl_dict_entry_t
));
248 return (set_errno(EFAULT
));
251 if ((hndl
= rctl_hndl_lookup(kname
)) == -1) {
252 kmem_free(kname
, MAXPATHLEN
);
253 kmem_free(krde
, sizeof (rctl_dict_entry_t
));
254 return (set_errno(EINVAL
));
257 if (rctl_global_get(kname
, krde
) == -1) {
258 kmem_free(kname
, MAXPATHLEN
);
259 kmem_free(krde
, sizeof (rctl_dict_entry_t
));
260 return (set_errno(ESRCH
));
263 kmem_free(kname
, MAXPATHLEN
);
265 if (action
!= RCTL_USAGE
)
266 nval
= kmem_cache_alloc(rctl_val_cache
, KM_SLEEP
);
268 if (action
== RCTL_USAGE
) {
273 mutex_enter(&curproc
->p_lock
);
274 if ((rset
= rctl_entity_obtain_rset(krde
, curproc
)) == NULL
) {
275 mutex_exit(&curproc
->p_lock
);
276 kmem_free(krde
, sizeof (rctl_dict_entry_t
));
277 return (set_errno(ESRCH
));
279 mutex_enter(&rset
->rcs_lock
);
280 if (rctl_set_find(rset
, hndl
, &rctl
) == -1) {
281 mutex_exit(&rset
->rcs_lock
);
282 mutex_exit(&curproc
->p_lock
);
283 kmem_free(krde
, sizeof (rctl_dict_entry_t
));
284 return (set_errno(ESRCH
));
286 if (RCTLOP_NO_USAGE(rctl
)) {
287 mutex_exit(&rset
->rcs_lock
);
288 mutex_exit(&curproc
->p_lock
);
289 kmem_free(krde
, sizeof (rctl_dict_entry_t
));
290 return (set_errno(ENOTSUP
));
292 usage
= RCTLOP_GET_USAGE(rctl
, curproc
);
293 mutex_exit(&rset
->rcs_lock
);
294 mutex_exit(&curproc
->p_lock
);
296 nblk
= kmem_zalloc(sizeof (rctl_opaque_t
), KM_SLEEP
);
297 nblk
->rcq_value
= usage
;
299 ret
= copyout(nblk
, new_rblk
, sizeof (rctl_opaque_t
));
300 kmem_free(nblk
, sizeof (rctl_opaque_t
));
301 kmem_free(krde
, sizeof (rctl_dict_entry_t
));
302 return (ret
== 0 ? 0 : set_errno(EFAULT
));
303 } else if (action
== RCTL_FIRST
) {
305 mutex_enter(&curproc
->p_lock
);
306 if (ret
= rctl_local_get(hndl
, NULL
, nval
, curproc
)) {
307 mutex_exit(&curproc
->p_lock
);
308 kmem_cache_free(rctl_val_cache
, nval
);
309 kmem_free(krde
, sizeof (rctl_dict_entry_t
));
310 return (set_errno(ret
));
312 mutex_exit(&curproc
->p_lock
);
320 oblk
= kmem_alloc(sizeof (rctl_opaque_t
), KM_SLEEP
);
322 if (copyin(old_rblk
, oblk
, sizeof (rctl_opaque_t
)) == -1) {
323 kmem_cache_free(rctl_val_cache
, nval
);
324 kmem_free(oblk
, sizeof (rctl_opaque_t
));
325 kmem_free(krde
, sizeof (rctl_dict_entry_t
));
326 return (set_errno(EFAULT
));
329 oval
= kmem_cache_alloc(rctl_val_cache
, KM_SLEEP
);
331 rctlsys_rblk_xfrm(oblk
, NULL
, oval
, RBX_FROM_BLK
| RBX_VAL
);
332 mutex_enter(&curproc
->p_lock
);
333 ret
= rctl_local_get(hndl
, oval
, nval
, curproc
);
334 mutex_exit(&curproc
->p_lock
);
336 kmem_cache_free(rctl_val_cache
, oval
);
337 kmem_free(oblk
, sizeof (rctl_opaque_t
));
340 kmem_cache_free(rctl_val_cache
, nval
);
341 kmem_free(krde
, sizeof (rctl_dict_entry_t
));
342 return (set_errno(ret
));
346 nblk
= kmem_alloc(sizeof (rctl_opaque_t
), KM_SLEEP
);
348 rctlsys_rblk_xfrm(nblk
, krde
, nval
, RBX_TO_BLK
| RBX_VAL
| RBX_CTL
);
350 kmem_free(krde
, sizeof (rctl_dict_entry_t
));
351 kmem_cache_free(rctl_val_cache
, nval
);
353 if (copyout(nblk
, new_rblk
, sizeof (rctl_opaque_t
)) == -1) {
354 kmem_free(nblk
, sizeof (rctl_opaque_t
));
355 return (set_errno(EFAULT
));
358 kmem_free(nblk
, sizeof (rctl_opaque_t
));
364 * static long rctlsys_set(char *name, rctl_opaque_t *old_rblk,
365 * rctl_opaque_t *new_rblk, int flags)
368 * rctlsys_set() is the implementation of the core login of setrctl(2), which
369 * allows the establishment of resource control values. Flags may take on any
370 * of three exclusive values: RCTL_INSERT, RCTL_DELETE, and RCTL_REPLACE.
371 * RCTL_INSERT ignores old_rblk and inserts the value in the appropriate
372 * position in the ordered sequence of resource control values. RCTL_DELETE
373 * ignores old_rblk and deletes the first resource control value matching
374 * (value, priority) in the given resource block. If no matching value is
375 * found, -1 is returned and errno is set to ENOENT. Finally, in the case of
376 * RCTL_REPLACE, old_rblk is used to match (value, priority); the matching
377 * resource control value in the sequence is replaced with the contents of
378 * new_rblk. Again, if no match is found, -1 is returned and errno is set to
381 * rctlsys_set() causes a cursor test, which can reactivate resource controls
382 * that have previously fired.
385 rctlsys_set(char *name
, rctl_opaque_t
*old_rblk
, rctl_opaque_t
*new_rblk
,
389 rctl_dict_entry_t
*rde
;
397 int action
= flags
& (~RCTLSYS_ACTION_MASK
);
404 if (flags
& (~RCTLSYS_MASK
))
405 return (set_errno(EINVAL
));
407 if (action
!= RCTL_INSERT
&&
408 action
!= RCTL_DELETE
&&
409 action
!= RCTL_REPLACE
)
410 return (set_errno(EINVAL
));
412 if (new_rblk
== NULL
|| name
== NULL
)
413 return (set_errno(EFAULT
));
415 kname
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
416 if (copyinstr(name
, kname
, MAXPATHLEN
, &klen
) != 0) {
417 kmem_free(kname
, MAXPATHLEN
);
418 return (set_errno(EFAULT
));
421 if ((hndl
= rctl_hndl_lookup(kname
)) == -1) {
422 kmem_free(kname
, MAXPATHLEN
);
423 return (set_errno(EINVAL
));
426 kmem_free(kname
, MAXPATHLEN
);
428 rde
= rctl_dict_lookup_hndl(hndl
);
430 nblk
= kmem_alloc(sizeof (rctl_opaque_t
), KM_SLEEP
);
432 if (copyin(new_rblk
, nblk
, sizeof (rctl_opaque_t
)) == -1) {
433 kmem_free(nblk
, sizeof (rctl_opaque_t
));
434 return (set_errno(EFAULT
));
437 nval
= kmem_cache_alloc(rctl_val_cache
, KM_SLEEP
);
439 rctlsys_rblk_xfrm(nblk
, NULL
, nval
, RBX_FROM_BLK
| RBX_VAL
);
441 if (rctl_invalid_value(rde
, nval
)) {
442 kmem_free(nblk
, sizeof (rctl_opaque_t
));
443 kmem_cache_free(rctl_val_cache
, nval
);
444 return (set_errno(EINVAL
));
447 /* allocate what we might need before potentially grabbing p_lock */
448 oblk
= kmem_alloc(sizeof (rctl_opaque_t
), KM_SLEEP
);
449 oval
= kmem_cache_alloc(rctl_val_cache
, KM_SLEEP
);
450 rval1
= kmem_cache_alloc(rctl_val_cache
, KM_SLEEP
);
451 rval2
= kmem_cache_alloc(rctl_val_cache
, KM_SLEEP
);
453 if (nval
->rcv_privilege
== RCPRIV_BASIC
) {
454 if (flags
& RCTL_USE_RECIPIENT_PID
) {
455 pid
= nval
->rcv_action_recip_pid
;
457 /* case for manipulating rctl values on other procs */
458 if (pid
!= curproc
->p_pid
) {
459 /* cannot be other pid on process rctls */
460 if (rde
->rcd_entity
== RCENTITY_PROCESS
) {
461 ret
= set_errno(EINVAL
);
465 * must have privilege to manipulate controls
468 if (secpolicy_rctlsys(CRED(), B_FALSE
) != 0) {
469 ret
= set_errno(EACCES
);
473 pid
= nval
->rcv_action_recip_pid
;
474 mutex_enter(&pidlock
);
477 mutex_exit(&pidlock
);
478 ret
= set_errno(ESRCH
);
483 * idle or zombie procs have either not yet
484 * set up their rctls or have already done
485 * their rctl_set_tearoff's.
487 if (pp
->p_stat
== SZOMB
||
488 pp
->p_stat
== SIDL
) {
489 mutex_exit(&pidlock
);
490 ret
= set_errno(ESRCH
);
495 * hold this pp's p_lock to ensure that
496 * it does not do it's rctl_set_tearoff
497 * If we did not do this, we could
498 * potentially add rctls to the entity
499 * with a recipient that is a process
502 mutex_enter(&pp
->p_lock
);
503 mutex_exit(&pidlock
);
506 * We know that curproc's task, project,
507 * and zone pointers will not change
508 * because functions that change them
509 * call holdlwps(SHOLDFORK1) first.
513 * verify that the found pp is in the
514 * current task. If it is, then it
515 * is also within the current project
518 if (rde
->rcd_entity
== RCENTITY_TASK
&&
519 pp
->p_task
!= curproc
->p_task
) {
520 ret
= set_errno(ESRCH
);
524 ASSERT(pp
->p_task
->tk_proj
==
525 curproc
->p_task
->tk_proj
);
526 ASSERT(pp
->p_zone
== curproc
->p_zone
);
529 nval
->rcv_action_recipient
= pp
;
530 nval
->rcv_action_recip_pid
= pid
;
533 /* for manipulating rctl values on this proc */
534 mutex_enter(&curproc
->p_lock
);
536 nval
->rcv_action_recipient
= curproc
;
537 nval
->rcv_action_recip_pid
= curproc
->p_pid
;
541 /* RCTL_USE_RECIPIENT_PID not set, use this proc */
542 mutex_enter(&curproc
->p_lock
);
544 nval
->rcv_action_recipient
= curproc
;
545 nval
->rcv_action_recip_pid
= curproc
->p_pid
;
549 /* privileged controls have no recipient pid */
550 mutex_enter(&curproc
->p_lock
);
552 nval
->rcv_action_recipient
= NULL
;
553 nval
->rcv_action_recip_pid
= -1;
556 nval
->rcv_firing_time
= 0;
558 if (action
== RCTL_REPLACE
) {
560 if (copyin(old_rblk
, oblk
, sizeof (rctl_opaque_t
)) == -1) {
561 ret
= set_errno(EFAULT
);
565 rctlsys_rblk_xfrm(oblk
, NULL
, oval
, RBX_FROM_BLK
| RBX_VAL
);
567 if (rctl_invalid_value(rde
, oval
)) {
568 ret
= set_errno(EINVAL
);
572 if (oval
->rcv_privilege
== RCPRIV_BASIC
) {
573 if (!(flags
& RCTL_USE_RECIPIENT_PID
)) {
574 oval
->rcv_action_recipient
= curproc
;
575 oval
->rcv_action_recip_pid
= curproc
->p_pid
;
578 oval
->rcv_action_recipient
= NULL
;
579 oval
->rcv_action_recip_pid
= -1;
583 * Find the real value we're attempting to replace on the
584 * sequence, rather than trusting the one delivered from
587 if (ret
= rctl_local_get(hndl
, NULL
, rval1
, pp
)) {
588 (void) set_errno(ret
);
593 if (rval1
->rcv_privilege
== RCPRIV_SYSTEM
||
594 rctl_val_cmp(oval
, rval1
, 0) == 0)
600 } while (rctl_local_get(hndl
, rval2
, rval1
, pp
) == 0);
602 if (rval1
->rcv_privilege
== RCPRIV_SYSTEM
) {
603 if (rctl_val_cmp(oval
, rval1
, 1) == 0)
604 ret
= set_errno(EPERM
);
606 ret
= set_errno(ESRCH
);
611 bcopy(rval1
, oval
, sizeof (rctl_val_t
));
614 * System controls are immutable.
616 if (nval
->rcv_privilege
== RCPRIV_SYSTEM
) {
617 ret
= set_errno(EPERM
);
622 * Only privileged processes in the global zone can modify
623 * privileged rctls of type RCENTITY_ZONE; replacing privileged
624 * controls with basic ones are not allowed either. Lowering a
625 * lowerable one might be OK for privileged processes in a
626 * non-global zone, but lowerable rctls probably don't make
627 * sense for zones (hence, not modifiable from within a zone).
629 if (rde
->rcd_entity
== RCENTITY_ZONE
&&
630 (nval
->rcv_privilege
== RCPRIV_PRIVILEGED
||
631 oval
->rcv_privilege
== RCPRIV_PRIVILEGED
) &&
632 secpolicy_rctlsys(CRED(), B_TRUE
) != 0) {
633 ret
= set_errno(EACCES
);
638 * Must be privileged to replace a privileged control with
641 if (oval
->rcv_privilege
== RCPRIV_PRIVILEGED
&&
642 nval
->rcv_privilege
!= RCPRIV_PRIVILEGED
&&
643 secpolicy_rctlsys(CRED(), B_FALSE
) != 0) {
644 ret
= set_errno(EACCES
);
649 * Must have lowerable global property for non-privileged
650 * to lower the value of a privileged control; otherwise must
651 * have sufficient privileges to modify privileged controls
654 if (oval
->rcv_privilege
== RCPRIV_PRIVILEGED
&&
655 nval
->rcv_privilege
== RCPRIV_PRIVILEGED
&&
656 ((((rde
->rcd_flagaction
& RCTL_GLOBAL_LOWERABLE
) == 0) ||
657 oval
->rcv_flagaction
!= nval
->rcv_flagaction
||
658 oval
->rcv_action_signal
!= nval
->rcv_action_signal
||
659 oval
->rcv_value
< nval
->rcv_value
)) &&
660 secpolicy_rctlsys(CRED(), B_FALSE
) != 0) {
661 ret
= set_errno(EACCES
);
665 if (ret
= rctl_local_replace(hndl
, oval
, nval
, pp
)) {
666 (void) set_errno(ret
);
670 /* ensure that nval is not freed */
673 } else if (action
== RCTL_INSERT
) {
675 * System controls are immutable.
677 if (nval
->rcv_privilege
== RCPRIV_SYSTEM
) {
678 ret
= set_errno(EPERM
);
683 * Only privileged processes in the global zone may add
684 * privileged zone.* rctls. Only privileged processes
685 * may add other privileged rctls.
687 if (nval
->rcv_privilege
== RCPRIV_PRIVILEGED
) {
688 if ((rde
->rcd_entity
== RCENTITY_ZONE
&&
689 secpolicy_rctlsys(CRED(), B_TRUE
) != 0) ||
690 (rde
->rcd_entity
!= RCENTITY_ZONE
&&
691 secpolicy_rctlsys(CRED(), B_FALSE
) != 0)) {
692 ret
= set_errno(EACCES
);
698 * Only one basic control is allowed per rctl.
699 * If a basic control is being inserted, delete
700 * any other basic control.
702 if ((nval
->rcv_privilege
== RCPRIV_BASIC
) &&
703 (rctl_local_get(hndl
, NULL
, rval1
, pp
) == 0)) {
705 if (rval1
->rcv_privilege
== RCPRIV_BASIC
&&
706 rval1
->rcv_action_recipient
== curproc
) {
707 (void) rctl_local_delete(hndl
, rval1
,
709 if (rctl_local_get(hndl
, NULL
, rval1
,
717 } while (rctl_local_get(hndl
, rval2
, rval1
, pp
)
722 if (ret
= rctl_local_insert(hndl
, nval
, pp
)) {
723 (void) set_errno(ret
);
727 /* ensure that nval is not freed */
734 if (nval
->rcv_privilege
== RCPRIV_SYSTEM
) {
735 ret
= set_errno(EPERM
);
739 if (nval
->rcv_privilege
== RCPRIV_PRIVILEGED
) {
740 if ((rde
->rcd_entity
== RCENTITY_ZONE
&&
741 secpolicy_rctlsys(CRED(), B_TRUE
) != 0) ||
742 (rde
->rcd_entity
!= RCENTITY_ZONE
&&
743 secpolicy_rctlsys(CRED(), B_FALSE
) != 0)) {
744 ret
= set_errno(EACCES
);
749 if (ret
= rctl_local_delete(hndl
, nval
, pp
)) {
750 (void) set_errno(ret
);
758 mutex_exit(&pp
->p_lock
);
760 kmem_free(nblk
, sizeof (rctl_opaque_t
));
761 kmem_free(oblk
, sizeof (rctl_opaque_t
));
763 /* only free nval if we did not rctl_local_insert it */
765 kmem_cache_free(rctl_val_cache
, nval
);
767 kmem_cache_free(rctl_val_cache
, oval
);
768 kmem_cache_free(rctl_val_cache
, rval1
);
769 kmem_cache_free(rctl_val_cache
, rval2
);
775 rctlsys_lst(char *ubuf
, size_t ubufsz
)
780 kbufsz
= rctl_build_name_buf(&kbuf
);
782 if (kbufsz
<= ubufsz
&&
783 copyout(kbuf
, ubuf
, kbufsz
) != 0) {
784 kmem_free(kbuf
, kbufsz
);
785 return (set_errno(EFAULT
));
788 kmem_free(kbuf
, kbufsz
);
794 rctlsys_ctl(char *name
, rctl_opaque_t
*rblk
, int flags
)
796 rctl_dict_entry_t
*krde
;
797 rctl_opaque_t
*krblk
;
801 kname
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
803 if (name
== NULL
|| copyinstr(name
, kname
, MAXPATHLEN
, &klen
) != 0) {
804 kmem_free(kname
, MAXPATHLEN
);
805 return (set_errno(EFAULT
));
810 krde
= kmem_alloc(sizeof (rctl_dict_entry_t
), KM_SLEEP
);
811 krblk
= kmem_zalloc(sizeof (rctl_opaque_t
), KM_SLEEP
);
813 if (rctl_global_get(kname
, krde
) == -1) {
814 kmem_free(krde
, sizeof (rctl_dict_entry_t
));
815 kmem_free(krblk
, sizeof (rctl_opaque_t
));
816 kmem_free(kname
, MAXPATHLEN
);
817 return (set_errno(ESRCH
));
820 rctlsys_rblk_xfrm(krblk
, krde
, NULL
, RBX_TO_BLK
| RBX_CTL
);
822 if (copyout(krblk
, rblk
, sizeof (rctl_opaque_t
)) != 0) {
823 kmem_free(krde
, sizeof (rctl_dict_entry_t
));
824 kmem_free(krblk
, sizeof (rctl_opaque_t
));
825 kmem_free(kname
, MAXPATHLEN
);
826 return (set_errno(EFAULT
));
829 kmem_free(krde
, sizeof (rctl_dict_entry_t
));
830 kmem_free(krblk
, sizeof (rctl_opaque_t
));
831 kmem_free(kname
, MAXPATHLEN
);
834 if (secpolicy_rctlsys(CRED(), B_TRUE
) != 0) {
835 kmem_free(kname
, MAXPATHLEN
);
836 return (set_errno(EPERM
));
839 krde
= kmem_alloc(sizeof (rctl_dict_entry_t
), KM_SLEEP
);
840 krblk
= kmem_zalloc(sizeof (rctl_opaque_t
), KM_SLEEP
);
842 if (rctl_global_get(kname
, krde
) == -1) {
843 kmem_free(krde
, sizeof (rctl_dict_entry_t
));
844 kmem_free(krblk
, sizeof (rctl_opaque_t
));
845 kmem_free(kname
, MAXPATHLEN
);
846 return (set_errno(ESRCH
));
849 if (copyin(rblk
, krblk
, sizeof (rctl_opaque_t
)) != 0) {
850 kmem_free(krde
, sizeof (rctl_dict_entry_t
));
851 kmem_free(krblk
, sizeof (rctl_opaque_t
));
852 kmem_free(kname
, MAXPATHLEN
);
853 return (set_errno(EFAULT
));
856 rctlsys_rblk_xfrm(krblk
, krde
, NULL
, RBX_FROM_BLK
| RBX_CTL
);
858 if (rctl_global_set(kname
, krde
) == -1) {
859 kmem_free(krde
, sizeof (rctl_dict_entry_t
));
860 kmem_free(krblk
, sizeof (rctl_opaque_t
));
861 kmem_free(kname
, MAXPATHLEN
);
862 return (set_errno(ESRCH
));
865 kmem_free(krde
, sizeof (rctl_dict_entry_t
));
866 kmem_free(krblk
, sizeof (rctl_opaque_t
));
867 kmem_free(kname
, MAXPATHLEN
);
871 kmem_free(kname
, MAXPATHLEN
);
872 return (set_errno(EINVAL
));
879 * The arbitrary maximum number of rctl_opaque_t that we can pass to
882 #define RCTL_PROJSET_MAXSIZE 1024
885 rctlsys_projset(char *name
, rctl_opaque_t
*rblk
, size_t size
, int flags
)
887 rctl_dict_entry_t
*krde
;
888 rctl_opaque_t
*krblk
;
892 rctl_val_t
*new_values
= NULL
;
893 rctl_val_t
*alloc_values
= NULL
;
895 rctl_val_t
*alloc_val
;
899 kname
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
901 if (name
== NULL
|| copyinstr(name
, kname
, MAXPATHLEN
, &klen
) != 0) {
902 kmem_free(kname
, MAXPATHLEN
);
903 return (set_errno(EFAULT
));
906 if (size
> RCTL_PROJSET_MAXSIZE
) {
907 kmem_free(kname
, MAXPATHLEN
);
908 return (set_errno(EINVAL
));
911 if ((hndl
= rctl_hndl_lookup(kname
)) == -1) {
912 kmem_free(kname
, MAXPATHLEN
);
913 return (set_errno(EINVAL
));
916 krde
= rctl_dict_lookup_hndl(hndl
);
918 /* If not a project entity then exit */
919 if ((krde
->rcd_entity
!= RCENTITY_PROJECT
) || (size
<= 0)) {
920 kmem_free(kname
, MAXPATHLEN
);
921 return (set_errno(EINVAL
));
924 if (secpolicy_rctlsys(CRED(), B_FALSE
) != 0) {
925 kmem_free(kname
, MAXPATHLEN
);
926 return (set_errno(EPERM
));
929 /* Allocate an array large enough for all resource control blocks */
930 krblk
= kmem_zalloc(sizeof (rctl_opaque_t
) * size
, KM_SLEEP
);
932 if (copyin(rblk
, krblk
, sizeof (rctl_opaque_t
) * size
) == 0) {
934 for (count
= 0; (count
< size
) && (error
== 0); count
++) {
935 new_val
= kmem_cache_alloc(rctl_val_cache
, KM_SLEEP
);
936 alloc_val
= kmem_cache_alloc(rctl_val_cache
, KM_SLEEP
);
938 rctlsys_rblk_xfrm(&krblk
[count
], NULL
, new_val
,
939 RBX_FROM_BLK
| RBX_VAL
);
942 * Project entity resource control values should always
945 if (new_val
->rcv_privilege
!= RCPRIV_PRIVILEGED
) {
946 kmem_cache_free(rctl_val_cache
, new_val
);
947 kmem_cache_free(rctl_val_cache
, alloc_val
);
950 } else if (rctl_invalid_value(krde
, new_val
) == 0) {
953 * This is a project entity; we do not set
954 * rcv_action_recipient or rcv_action_recip_pid
956 new_val
->rcv_action_recipient
= NULL
;
957 new_val
->rcv_action_recip_pid
= -1;
958 new_val
->rcv_flagaction
|= RCTL_LOCAL_PROJDB
;
959 new_val
->rcv_firing_time
= 0;
961 new_val
->rcv_prev
= NULL
;
962 new_val
->rcv_next
= new_values
;
963 new_values
= new_val
;
966 * alloc_val is left largely uninitialized, it
967 * is a pre-allocated rctl_val_t which is used
968 * later in rctl_local_replace_all() /
969 * rctl_local_insert_all().
971 alloc_val
->rcv_prev
= NULL
;
972 alloc_val
->rcv_next
= alloc_values
;
973 alloc_values
= alloc_val
;
975 kmem_cache_free(rctl_val_cache
, new_val
);
976 kmem_cache_free(rctl_val_cache
, alloc_val
);
986 kmem_free(krblk
, sizeof (rctl_opaque_t
) * size
);
987 kmem_free(kname
, MAXPATHLEN
);
991 * We will have the same number of items in the alloc_values
992 * linked list, as we have in new_values. However, we remain
993 * cautious, and teardown the linked lists individually.
995 while (new_values
!= NULL
) {
996 new_val
= new_values
;
997 new_values
= new_values
->rcv_next
;
998 kmem_cache_free(rctl_val_cache
, new_val
);
1001 while (alloc_values
!= NULL
) {
1002 alloc_val
= alloc_values
;
1003 alloc_values
= alloc_values
->rcv_next
;
1004 kmem_cache_free(rctl_val_cache
, alloc_val
);
1007 return (set_errno(error
));
1011 * We take the p_lock here to maintain consistency with other functions
1012 * - rctlsys_get() and rctlsys_set()
1014 mutex_enter(&curproc
->p_lock
);
1015 if (flags
& TASK_PROJ_PURGE
) {
1016 (void) rctl_local_replace_all(hndl
, new_values
, alloc_values
,
1019 (void) rctl_local_insert_all(hndl
, new_values
, alloc_values
,
1022 mutex_exit(&curproc
->p_lock
);
1028 rctlsys(int code
, char *name
, void *obuf
, void *nbuf
, size_t obufsz
, int flags
)
1032 return (rctlsys_get(name
, obuf
, nbuf
, flags
));
1035 return (rctlsys_set(name
, obuf
, nbuf
, flags
));
1039 * Private call for rctl_walk(3C).
1041 return (rctlsys_lst(obuf
, obufsz
));
1045 * Private code for rctladm(8): "rctlctl".
1047 return (rctlsys_ctl(name
, obuf
, flags
));
1050 * Private code for setproject(3PROJECT).
1052 return (rctlsys_projset(name
, nbuf
, obufsz
, flags
));
1055 return (set_errno(EINVAL
));