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 #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/cred.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/rctl.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/rctl_impl.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/strlog.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/syslog.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/policy.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/proc.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/task.h> 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate /* 45*7c478bd9Sstevel@tonic-gate * setrctl(2), getrctl(2), and private rctlsys(2*) system calls 46*7c478bd9Sstevel@tonic-gate * 47*7c478bd9Sstevel@tonic-gate * Resource control block (rctlblk_ptr_t, rctl_opaque_t) 48*7c478bd9Sstevel@tonic-gate * The resource control system call interfaces present the resource control 49*7c478bd9Sstevel@tonic-gate * values and flags via the resource control block abstraction, made manifest 50*7c478bd9Sstevel@tonic-gate * via an opaque data type with strict type definitions. Keeping the formal 51*7c478bd9Sstevel@tonic-gate * definitions in the rcontrol block allows us to be clever in the kernel, 52*7c478bd9Sstevel@tonic-gate * combining attributes where appropriate in the current implementation while 53*7c478bd9Sstevel@tonic-gate * preserving binary compatibility in the face of implementation changes. 54*7c478bd9Sstevel@tonic-gate */ 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate #define RBX_TO_BLK 0x1 57*7c478bd9Sstevel@tonic-gate #define RBX_FROM_BLK 0x2 58*7c478bd9Sstevel@tonic-gate #define RBX_VAL 0x4 59*7c478bd9Sstevel@tonic-gate #define RBX_CTL 0x8 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate static void 62*7c478bd9Sstevel@tonic-gate rctlsys_rblk_xfrm(rctl_opaque_t *blk, rctl_dict_entry_t *rde, 63*7c478bd9Sstevel@tonic-gate rctl_val_t *val, int flags) 64*7c478bd9Sstevel@tonic-gate { 65*7c478bd9Sstevel@tonic-gate if (flags & RBX_FROM_BLK) { 66*7c478bd9Sstevel@tonic-gate if (flags & RBX_VAL) { 67*7c478bd9Sstevel@tonic-gate /* 68*7c478bd9Sstevel@tonic-gate * Firing time cannot be set. 69*7c478bd9Sstevel@tonic-gate */ 70*7c478bd9Sstevel@tonic-gate val->rcv_privilege = blk->rcq_privilege; 71*7c478bd9Sstevel@tonic-gate val->rcv_value = blk->rcq_value; 72*7c478bd9Sstevel@tonic-gate val->rcv_flagaction = blk->rcq_local_flagaction; 73*7c478bd9Sstevel@tonic-gate val->rcv_action_signal = blk->rcq_local_signal; 74*7c478bd9Sstevel@tonic-gate val->rcv_action_recip_pid = 75*7c478bd9Sstevel@tonic-gate blk->rcq_local_recipient_pid; 76*7c478bd9Sstevel@tonic-gate } 77*7c478bd9Sstevel@tonic-gate if (flags & RBX_CTL) { 78*7c478bd9Sstevel@tonic-gate rde->rcd_flagaction = blk->rcq_global_flagaction; 79*7c478bd9Sstevel@tonic-gate rde->rcd_syslog_level = blk->rcq_global_syslog_level; 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate /* 82*7c478bd9Sstevel@tonic-gate * Because the strlog() interface supports fewer options 83*7c478bd9Sstevel@tonic-gate * than are made available via the syslog() interface to 84*7c478bd9Sstevel@tonic-gate * userland, we map the syslog level down to a smaller 85*7c478bd9Sstevel@tonic-gate * set of distinct logging behaviours. 86*7c478bd9Sstevel@tonic-gate */ 87*7c478bd9Sstevel@tonic-gate rde->rcd_strlog_flags = 0; 88*7c478bd9Sstevel@tonic-gate switch (blk->rcq_global_syslog_level) { 89*7c478bd9Sstevel@tonic-gate case LOG_EMERG: 90*7c478bd9Sstevel@tonic-gate case LOG_ALERT: 91*7c478bd9Sstevel@tonic-gate case LOG_CRIT: 92*7c478bd9Sstevel@tonic-gate rde->rcd_strlog_flags |= SL_CONSOLE; 93*7c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 94*7c478bd9Sstevel@tonic-gate case LOG_ERR: 95*7c478bd9Sstevel@tonic-gate rde->rcd_strlog_flags |= SL_ERROR; 96*7c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 97*7c478bd9Sstevel@tonic-gate case LOG_WARNING: 98*7c478bd9Sstevel@tonic-gate rde->rcd_strlog_flags |= SL_WARN; 99*7c478bd9Sstevel@tonic-gate break; 100*7c478bd9Sstevel@tonic-gate case LOG_NOTICE: 101*7c478bd9Sstevel@tonic-gate rde->rcd_strlog_flags |= SL_CONSOLE; 102*7c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 103*7c478bd9Sstevel@tonic-gate case LOG_INFO: /* informational */ 104*7c478bd9Sstevel@tonic-gate case LOG_DEBUG: /* debug-level messages */ 105*7c478bd9Sstevel@tonic-gate default: 106*7c478bd9Sstevel@tonic-gate rde->rcd_strlog_flags |= SL_NOTE; 107*7c478bd9Sstevel@tonic-gate break; 108*7c478bd9Sstevel@tonic-gate } 109*7c478bd9Sstevel@tonic-gate } 110*7c478bd9Sstevel@tonic-gate } else { 111*7c478bd9Sstevel@tonic-gate bzero(blk, sizeof (rctl_opaque_t)); 112*7c478bd9Sstevel@tonic-gate if (flags & RBX_VAL) { 113*7c478bd9Sstevel@tonic-gate blk->rcq_privilege = val->rcv_privilege; 114*7c478bd9Sstevel@tonic-gate blk->rcq_value = val->rcv_value; 115*7c478bd9Sstevel@tonic-gate blk->rcq_enforced_value = rctl_model_value(rde, 116*7c478bd9Sstevel@tonic-gate curproc, val->rcv_value); 117*7c478bd9Sstevel@tonic-gate blk->rcq_local_flagaction = val->rcv_flagaction; 118*7c478bd9Sstevel@tonic-gate blk->rcq_local_signal = val->rcv_action_signal; 119*7c478bd9Sstevel@tonic-gate blk->rcq_firing_time = val->rcv_firing_time; 120*7c478bd9Sstevel@tonic-gate blk->rcq_local_recipient_pid = 121*7c478bd9Sstevel@tonic-gate val->rcv_action_recip_pid; 122*7c478bd9Sstevel@tonic-gate } 123*7c478bd9Sstevel@tonic-gate if (flags & RBX_CTL) { 124*7c478bd9Sstevel@tonic-gate blk->rcq_global_flagaction = rde->rcd_flagaction; 125*7c478bd9Sstevel@tonic-gate blk->rcq_global_syslog_level = rde->rcd_syslog_level; 126*7c478bd9Sstevel@tonic-gate } 127*7c478bd9Sstevel@tonic-gate } 128*7c478bd9Sstevel@tonic-gate } 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate /* 131*7c478bd9Sstevel@tonic-gate * int rctl_invalid_value(rctl_dict_entry_t *, rctl_val_t *) 132*7c478bd9Sstevel@tonic-gate * 133*7c478bd9Sstevel@tonic-gate * Overview 134*7c478bd9Sstevel@tonic-gate * Perform basic validation of proposed new resource control value against the 135*7c478bd9Sstevel@tonic-gate * global properties set on the control. Any system call operation presented 136*7c478bd9Sstevel@tonic-gate * with an invalid resource control value should return -1 and set errno to 137*7c478bd9Sstevel@tonic-gate * EINVAL. 138*7c478bd9Sstevel@tonic-gate * 139*7c478bd9Sstevel@tonic-gate * Return values 140*7c478bd9Sstevel@tonic-gate * 0 if valid, 1 if invalid. 141*7c478bd9Sstevel@tonic-gate * 142*7c478bd9Sstevel@tonic-gate * Caller's context 143*7c478bd9Sstevel@tonic-gate * No restriction on context. 144*7c478bd9Sstevel@tonic-gate */ 145*7c478bd9Sstevel@tonic-gate int 146*7c478bd9Sstevel@tonic-gate rctl_invalid_value(rctl_dict_entry_t *rde, rctl_val_t *rval) 147*7c478bd9Sstevel@tonic-gate { 148*7c478bd9Sstevel@tonic-gate rctl_val_t *sys_rval; 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate if (rval->rcv_privilege != RCPRIV_BASIC && 151*7c478bd9Sstevel@tonic-gate rval->rcv_privilege != RCPRIV_PRIVILEGED && 152*7c478bd9Sstevel@tonic-gate rval->rcv_privilege != RCPRIV_SYSTEM) 153*7c478bd9Sstevel@tonic-gate return (1); 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate if (rval->rcv_flagaction & ~RCTL_LOCAL_MASK) 156*7c478bd9Sstevel@tonic-gate return (1); 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate if (rval->rcv_privilege == RCPRIV_BASIC && 159*7c478bd9Sstevel@tonic-gate (rde->rcd_flagaction & RCTL_GLOBAL_NOBASIC) != 0) 160*7c478bd9Sstevel@tonic-gate return (1); 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate if ((rval->rcv_flagaction & RCTL_LOCAL_DENY) == 0 && 163*7c478bd9Sstevel@tonic-gate (rde->rcd_flagaction & RCTL_GLOBAL_DENY_ALWAYS) != 0) 164*7c478bd9Sstevel@tonic-gate return (1); 165*7c478bd9Sstevel@tonic-gate 166*7c478bd9Sstevel@tonic-gate if ((rval->rcv_flagaction & RCTL_LOCAL_DENY) && 167*7c478bd9Sstevel@tonic-gate (rde->rcd_flagaction & RCTL_GLOBAL_DENY_NEVER)) 168*7c478bd9Sstevel@tonic-gate return (1); 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate if ((rval->rcv_flagaction & RCTL_LOCAL_SIGNAL) && 171*7c478bd9Sstevel@tonic-gate (rde->rcd_flagaction & RCTL_GLOBAL_SIGNAL_NEVER)) 172*7c478bd9Sstevel@tonic-gate return (1); 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate if ((rval->rcv_flagaction & RCTL_LOCAL_SIGNAL) && 175*7c478bd9Sstevel@tonic-gate rval->rcv_action_signal == 0) 176*7c478bd9Sstevel@tonic-gate return (1); 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate if (rval->rcv_action_signal == SIGXCPU && 179*7c478bd9Sstevel@tonic-gate (rde->rcd_flagaction & RCTL_GLOBAL_CPU_TIME) == 0) 180*7c478bd9Sstevel@tonic-gate return (1); 181*7c478bd9Sstevel@tonic-gate else if (rval->rcv_action_signal == SIGXFSZ && 182*7c478bd9Sstevel@tonic-gate (rde->rcd_flagaction & RCTL_GLOBAL_FILE_SIZE) == 0) 183*7c478bd9Sstevel@tonic-gate return (1); 184*7c478bd9Sstevel@tonic-gate else if (rval->rcv_action_signal != SIGHUP && 185*7c478bd9Sstevel@tonic-gate rval->rcv_action_signal != SIGABRT && 186*7c478bd9Sstevel@tonic-gate rval->rcv_action_signal != SIGKILL && 187*7c478bd9Sstevel@tonic-gate rval->rcv_action_signal != SIGTERM && 188*7c478bd9Sstevel@tonic-gate rval->rcv_action_signal != SIGSTOP && 189*7c478bd9Sstevel@tonic-gate rval->rcv_action_signal != SIGXCPU && 190*7c478bd9Sstevel@tonic-gate rval->rcv_action_signal != SIGXFSZ && 191*7c478bd9Sstevel@tonic-gate rval->rcv_action_signal != SIGXRES && 192*7c478bd9Sstevel@tonic-gate rval->rcv_action_signal != 0) /* That is, no signal is ok. */ 193*7c478bd9Sstevel@tonic-gate return (1); 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate sys_rval = rde->rcd_default_value; 196*7c478bd9Sstevel@tonic-gate while (sys_rval->rcv_privilege != RCPRIV_SYSTEM) 197*7c478bd9Sstevel@tonic-gate sys_rval = sys_rval->rcv_next; 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate if (rval->rcv_value > sys_rval->rcv_value) 200*7c478bd9Sstevel@tonic-gate return (1); 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate return (0); 203*7c478bd9Sstevel@tonic-gate } 204*7c478bd9Sstevel@tonic-gate 205*7c478bd9Sstevel@tonic-gate /* 206*7c478bd9Sstevel@tonic-gate * static long rctlsys_get(char *name, rctl_opaque_t *old_rblk, 207*7c478bd9Sstevel@tonic-gate * rctl_opaque_t *new_rblk, int flags) 208*7c478bd9Sstevel@tonic-gate * 209*7c478bd9Sstevel@tonic-gate * Overview 210*7c478bd9Sstevel@tonic-gate * rctlsys_get() is the implementation of the core logic of getrctl(2), the 211*7c478bd9Sstevel@tonic-gate * public system call for fetching resource control values. Two mutually 212*7c478bd9Sstevel@tonic-gate * exclusive flag values are supported: RCTL_FIRST and RCTL_NEXT. When 213*7c478bd9Sstevel@tonic-gate * RCTL_FIRST is presented, the value of old_rblk is ignored, and the first 214*7c478bd9Sstevel@tonic-gate * value in the resource control value sequence for the named control is 215*7c478bd9Sstevel@tonic-gate * transformed and placed in the user memory location at new_rblk. In the 216*7c478bd9Sstevel@tonic-gate * RCTL_NEXT case, the value of old_rblk is examined, and the next value in 217*7c478bd9Sstevel@tonic-gate * the sequence is transformed and placed at new_rblk. 218*7c478bd9Sstevel@tonic-gate */ 219*7c478bd9Sstevel@tonic-gate static long 220*7c478bd9Sstevel@tonic-gate rctlsys_get(char *name, rctl_opaque_t *old_rblk, rctl_opaque_t *new_rblk, 221*7c478bd9Sstevel@tonic-gate int flags) 222*7c478bd9Sstevel@tonic-gate { 223*7c478bd9Sstevel@tonic-gate rctl_val_t *nval; 224*7c478bd9Sstevel@tonic-gate rctl_opaque_t *nblk; 225*7c478bd9Sstevel@tonic-gate rctl_hndl_t hndl; 226*7c478bd9Sstevel@tonic-gate char *kname; 227*7c478bd9Sstevel@tonic-gate size_t klen; 228*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t *krde; 229*7c478bd9Sstevel@tonic-gate int ret; 230*7c478bd9Sstevel@tonic-gate int action = flags & (~RCTLSYS_ACTION_MASK); 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate if (flags & (~RCTLSYS_MASK)) 233*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate if (action != RCTL_FIRST && action != RCTL_NEXT && 236*7c478bd9Sstevel@tonic-gate action != RCTL_USAGE) 237*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate if (new_rblk == NULL || name == NULL) 240*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate kname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 243*7c478bd9Sstevel@tonic-gate krde = kmem_alloc(sizeof (rctl_dict_entry_t), KM_SLEEP); 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate if (copyinstr(name, kname, MAXPATHLEN, &klen) != 0) { 246*7c478bd9Sstevel@tonic-gate kmem_free(kname, MAXPATHLEN); 247*7c478bd9Sstevel@tonic-gate kmem_free(krde, sizeof (rctl_dict_entry_t)); 248*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 249*7c478bd9Sstevel@tonic-gate } 250*7c478bd9Sstevel@tonic-gate 251*7c478bd9Sstevel@tonic-gate if ((hndl = rctl_hndl_lookup(kname)) == -1) { 252*7c478bd9Sstevel@tonic-gate kmem_free(kname, MAXPATHLEN); 253*7c478bd9Sstevel@tonic-gate kmem_free(krde, sizeof (rctl_dict_entry_t)); 254*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 255*7c478bd9Sstevel@tonic-gate } 256*7c478bd9Sstevel@tonic-gate 257*7c478bd9Sstevel@tonic-gate if (rctl_global_get(kname, krde) == -1) { 258*7c478bd9Sstevel@tonic-gate kmem_free(kname, MAXPATHLEN); 259*7c478bd9Sstevel@tonic-gate kmem_free(krde, sizeof (rctl_dict_entry_t)); 260*7c478bd9Sstevel@tonic-gate return (set_errno(ESRCH)); 261*7c478bd9Sstevel@tonic-gate } 262*7c478bd9Sstevel@tonic-gate 263*7c478bd9Sstevel@tonic-gate kmem_free(kname, MAXPATHLEN); 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate nval = kmem_cache_alloc(rctl_val_cache, KM_SLEEP); 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate if (action == RCTL_USAGE) { 268*7c478bd9Sstevel@tonic-gate kmem_cache_free(rctl_val_cache, nval); 269*7c478bd9Sstevel@tonic-gate kmem_free(krde, sizeof (rctl_dict_entry_t)); 270*7c478bd9Sstevel@tonic-gate return (set_errno(ENOTSUP)); 271*7c478bd9Sstevel@tonic-gate } else if (action == RCTL_FIRST) { 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate mutex_enter(&curproc->p_lock); 274*7c478bd9Sstevel@tonic-gate if (ret = rctl_local_get(hndl, NULL, nval, curproc)) { 275*7c478bd9Sstevel@tonic-gate mutex_exit(&curproc->p_lock); 276*7c478bd9Sstevel@tonic-gate kmem_cache_free(rctl_val_cache, nval); 277*7c478bd9Sstevel@tonic-gate kmem_free(krde, sizeof (rctl_dict_entry_t)); 278*7c478bd9Sstevel@tonic-gate return (set_errno(ret)); 279*7c478bd9Sstevel@tonic-gate } 280*7c478bd9Sstevel@tonic-gate mutex_exit(&curproc->p_lock); 281*7c478bd9Sstevel@tonic-gate } else { 282*7c478bd9Sstevel@tonic-gate /* 283*7c478bd9Sstevel@tonic-gate * RCTL_NEXT 284*7c478bd9Sstevel@tonic-gate */ 285*7c478bd9Sstevel@tonic-gate rctl_val_t *oval; 286*7c478bd9Sstevel@tonic-gate rctl_opaque_t *oblk; 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate oblk = kmem_alloc(sizeof (rctl_opaque_t), KM_SLEEP); 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate if (copyin(old_rblk, oblk, sizeof (rctl_opaque_t)) == -1) { 291*7c478bd9Sstevel@tonic-gate kmem_cache_free(rctl_val_cache, nval); 292*7c478bd9Sstevel@tonic-gate kmem_free(oblk, sizeof (rctl_opaque_t)); 293*7c478bd9Sstevel@tonic-gate kmem_free(krde, sizeof (rctl_dict_entry_t)); 294*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 295*7c478bd9Sstevel@tonic-gate } 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate oval = kmem_cache_alloc(rctl_val_cache, KM_SLEEP); 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate rctlsys_rblk_xfrm(oblk, NULL, oval, RBX_FROM_BLK | RBX_VAL); 300*7c478bd9Sstevel@tonic-gate mutex_enter(&curproc->p_lock); 301*7c478bd9Sstevel@tonic-gate ret = rctl_local_get(hndl, oval, nval, curproc); 302*7c478bd9Sstevel@tonic-gate mutex_exit(&curproc->p_lock); 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate kmem_cache_free(rctl_val_cache, oval); 305*7c478bd9Sstevel@tonic-gate kmem_free(oblk, sizeof (rctl_opaque_t)); 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate if (ret != 0) { 308*7c478bd9Sstevel@tonic-gate kmem_cache_free(rctl_val_cache, nval); 309*7c478bd9Sstevel@tonic-gate kmem_free(krde, sizeof (rctl_dict_entry_t)); 310*7c478bd9Sstevel@tonic-gate return (set_errno(ret)); 311*7c478bd9Sstevel@tonic-gate } 312*7c478bd9Sstevel@tonic-gate } 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate nblk = kmem_alloc(sizeof (rctl_opaque_t), KM_SLEEP); 315*7c478bd9Sstevel@tonic-gate 316*7c478bd9Sstevel@tonic-gate rctlsys_rblk_xfrm(nblk, krde, nval, RBX_TO_BLK | RBX_VAL | RBX_CTL); 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate kmem_free(krde, sizeof (rctl_dict_entry_t)); 319*7c478bd9Sstevel@tonic-gate kmem_cache_free(rctl_val_cache, nval); 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate if (copyout(nblk, new_rblk, sizeof (rctl_opaque_t)) == -1) { 322*7c478bd9Sstevel@tonic-gate kmem_free(nblk, sizeof (rctl_opaque_t)); 323*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 324*7c478bd9Sstevel@tonic-gate } 325*7c478bd9Sstevel@tonic-gate 326*7c478bd9Sstevel@tonic-gate kmem_free(nblk, sizeof (rctl_opaque_t)); 327*7c478bd9Sstevel@tonic-gate 328*7c478bd9Sstevel@tonic-gate return (0); 329*7c478bd9Sstevel@tonic-gate } 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate /* 332*7c478bd9Sstevel@tonic-gate * static long rctlsys_set(char *name, rctl_opaque_t *old_rblk, 333*7c478bd9Sstevel@tonic-gate * rctl_opaque_t *new_rblk, int flags) 334*7c478bd9Sstevel@tonic-gate * 335*7c478bd9Sstevel@tonic-gate * Overview 336*7c478bd9Sstevel@tonic-gate * rctlsys_set() is the implementation of the core login of setrctl(2), which 337*7c478bd9Sstevel@tonic-gate * allows the establishment of resource control values. Flags may take on any 338*7c478bd9Sstevel@tonic-gate * of three exclusive values: RCTL_INSERT, RCTL_DELETE, and RCTL_REPLACE. 339*7c478bd9Sstevel@tonic-gate * RCTL_INSERT ignores old_rblk and inserts the value in the appropriate 340*7c478bd9Sstevel@tonic-gate * position in the ordered sequence of resource control values. RCTL_DELETE 341*7c478bd9Sstevel@tonic-gate * ignores old_rblk and deletes the first resource control value matching 342*7c478bd9Sstevel@tonic-gate * (value, priority) in the given resource block. If no matching value is 343*7c478bd9Sstevel@tonic-gate * found, -1 is returned and errno is set to ENOENT. Finally, in the case of 344*7c478bd9Sstevel@tonic-gate * RCTL_REPLACE, old_rblk is used to match (value, priority); the matching 345*7c478bd9Sstevel@tonic-gate * resource control value in the sequence is replaced with the contents of 346*7c478bd9Sstevel@tonic-gate * new_rblk. Again, if no match is found, -1 is returned and errno is set to 347*7c478bd9Sstevel@tonic-gate * ENOENT. 348*7c478bd9Sstevel@tonic-gate * 349*7c478bd9Sstevel@tonic-gate * rctlsys_set() causes a cursor test, which can reactivate resource controls 350*7c478bd9Sstevel@tonic-gate * that have previously fired. 351*7c478bd9Sstevel@tonic-gate */ 352*7c478bd9Sstevel@tonic-gate static long 353*7c478bd9Sstevel@tonic-gate rctlsys_set(char *name, rctl_opaque_t *old_rblk, rctl_opaque_t *new_rblk, 354*7c478bd9Sstevel@tonic-gate int flags) 355*7c478bd9Sstevel@tonic-gate { 356*7c478bd9Sstevel@tonic-gate rctl_val_t *nval; 357*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t *rde; 358*7c478bd9Sstevel@tonic-gate rctl_opaque_t *nblk; 359*7c478bd9Sstevel@tonic-gate rctl_hndl_t hndl; 360*7c478bd9Sstevel@tonic-gate char *kname; 361*7c478bd9Sstevel@tonic-gate size_t klen; 362*7c478bd9Sstevel@tonic-gate long ret = 0; 363*7c478bd9Sstevel@tonic-gate proc_t *pp = NULL; 364*7c478bd9Sstevel@tonic-gate pid_t pid; 365*7c478bd9Sstevel@tonic-gate int action = flags & (~RCTLSYS_ACTION_MASK); 366*7c478bd9Sstevel@tonic-gate rctl_val_t *oval; 367*7c478bd9Sstevel@tonic-gate rctl_val_t *rval1; 368*7c478bd9Sstevel@tonic-gate rctl_val_t *rval2; 369*7c478bd9Sstevel@tonic-gate rctl_val_t *tval; 370*7c478bd9Sstevel@tonic-gate rctl_opaque_t *oblk; 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate if (flags & (~RCTLSYS_MASK)) 373*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate if (action != RCTL_INSERT && 376*7c478bd9Sstevel@tonic-gate action != RCTL_DELETE && 377*7c478bd9Sstevel@tonic-gate action != RCTL_REPLACE) 378*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 379*7c478bd9Sstevel@tonic-gate 380*7c478bd9Sstevel@tonic-gate if (new_rblk == NULL || name == NULL) 381*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate kname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 384*7c478bd9Sstevel@tonic-gate if (copyinstr(name, kname, MAXPATHLEN, &klen) != 0) { 385*7c478bd9Sstevel@tonic-gate kmem_free(kname, MAXPATHLEN); 386*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 387*7c478bd9Sstevel@tonic-gate } 388*7c478bd9Sstevel@tonic-gate 389*7c478bd9Sstevel@tonic-gate if ((hndl = rctl_hndl_lookup(kname)) == -1) { 390*7c478bd9Sstevel@tonic-gate kmem_free(kname, MAXPATHLEN); 391*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 392*7c478bd9Sstevel@tonic-gate } 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate kmem_free(kname, MAXPATHLEN); 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate rde = rctl_dict_lookup_hndl(hndl); 397*7c478bd9Sstevel@tonic-gate 398*7c478bd9Sstevel@tonic-gate nblk = kmem_alloc(sizeof (rctl_opaque_t), KM_SLEEP); 399*7c478bd9Sstevel@tonic-gate 400*7c478bd9Sstevel@tonic-gate if (copyin(new_rblk, nblk, sizeof (rctl_opaque_t)) == -1) { 401*7c478bd9Sstevel@tonic-gate kmem_free(nblk, sizeof (rctl_opaque_t)); 402*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 403*7c478bd9Sstevel@tonic-gate } 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate nval = kmem_cache_alloc(rctl_val_cache, KM_SLEEP); 406*7c478bd9Sstevel@tonic-gate 407*7c478bd9Sstevel@tonic-gate rctlsys_rblk_xfrm(nblk, NULL, nval, RBX_FROM_BLK | RBX_VAL); 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate if (rctl_invalid_value(rde, nval)) { 410*7c478bd9Sstevel@tonic-gate kmem_free(nblk, sizeof (rctl_opaque_t)); 411*7c478bd9Sstevel@tonic-gate kmem_cache_free(rctl_val_cache, nval); 412*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 413*7c478bd9Sstevel@tonic-gate } 414*7c478bd9Sstevel@tonic-gate 415*7c478bd9Sstevel@tonic-gate /* allocate what we might need before potentially grabbing p_lock */ 416*7c478bd9Sstevel@tonic-gate oblk = kmem_alloc(sizeof (rctl_opaque_t), KM_SLEEP); 417*7c478bd9Sstevel@tonic-gate oval = kmem_cache_alloc(rctl_val_cache, KM_SLEEP); 418*7c478bd9Sstevel@tonic-gate rval1 = kmem_cache_alloc(rctl_val_cache, KM_SLEEP); 419*7c478bd9Sstevel@tonic-gate rval2 = kmem_cache_alloc(rctl_val_cache, KM_SLEEP); 420*7c478bd9Sstevel@tonic-gate 421*7c478bd9Sstevel@tonic-gate if (nval->rcv_privilege == RCPRIV_BASIC) { 422*7c478bd9Sstevel@tonic-gate if (flags & RCTL_USE_RECIPIENT_PID) { 423*7c478bd9Sstevel@tonic-gate pid = nval->rcv_action_recip_pid; 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate /* case for manipulating rctl values on other procs */ 426*7c478bd9Sstevel@tonic-gate if (pid != curproc->p_pid) { 427*7c478bd9Sstevel@tonic-gate /* cannot be other pid on process rctls */ 428*7c478bd9Sstevel@tonic-gate if (rde->rcd_entity == RCENTITY_PROCESS) { 429*7c478bd9Sstevel@tonic-gate ret = set_errno(EINVAL); 430*7c478bd9Sstevel@tonic-gate goto rctlsys_out; 431*7c478bd9Sstevel@tonic-gate } 432*7c478bd9Sstevel@tonic-gate /* 433*7c478bd9Sstevel@tonic-gate * must have privilege to manipulate controls 434*7c478bd9Sstevel@tonic-gate * on other processes 435*7c478bd9Sstevel@tonic-gate */ 436*7c478bd9Sstevel@tonic-gate if (secpolicy_rctlsys(CRED(), B_FALSE) != 0) { 437*7c478bd9Sstevel@tonic-gate ret = set_errno(EACCES); 438*7c478bd9Sstevel@tonic-gate goto rctlsys_out; 439*7c478bd9Sstevel@tonic-gate } 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate pid = nval->rcv_action_recip_pid; 442*7c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 443*7c478bd9Sstevel@tonic-gate pp = prfind(pid); 444*7c478bd9Sstevel@tonic-gate if (!pp) { 445*7c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 446*7c478bd9Sstevel@tonic-gate ret = set_errno(ESRCH); 447*7c478bd9Sstevel@tonic-gate goto rctlsys_out; 448*7c478bd9Sstevel@tonic-gate } 449*7c478bd9Sstevel@tonic-gate 450*7c478bd9Sstevel@tonic-gate /* 451*7c478bd9Sstevel@tonic-gate * idle or zombie procs have either not yet 452*7c478bd9Sstevel@tonic-gate * set up their rctls or have already done 453*7c478bd9Sstevel@tonic-gate * their rctl_set_tearoff's. 454*7c478bd9Sstevel@tonic-gate */ 455*7c478bd9Sstevel@tonic-gate if (pp->p_stat == SZOMB || 456*7c478bd9Sstevel@tonic-gate pp->p_stat == SIDL) { 457*7c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 458*7c478bd9Sstevel@tonic-gate ret = set_errno(ESRCH); 459*7c478bd9Sstevel@tonic-gate goto rctlsys_out; 460*7c478bd9Sstevel@tonic-gate } 461*7c478bd9Sstevel@tonic-gate 462*7c478bd9Sstevel@tonic-gate /* 463*7c478bd9Sstevel@tonic-gate * hold this pp's p_lock to ensure that 464*7c478bd9Sstevel@tonic-gate * it does not do it's rctl_set_tearoff 465*7c478bd9Sstevel@tonic-gate * If we did not do this, we could 466*7c478bd9Sstevel@tonic-gate * potentially add rctls to the entity 467*7c478bd9Sstevel@tonic-gate * with a recipient that is a process 468*7c478bd9Sstevel@tonic-gate * that has exited. 469*7c478bd9Sstevel@tonic-gate */ 470*7c478bd9Sstevel@tonic-gate mutex_enter(&pp->p_lock); 471*7c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate /* 474*7c478bd9Sstevel@tonic-gate * We know that curproc's task, project, 475*7c478bd9Sstevel@tonic-gate * and zone pointers will not change 476*7c478bd9Sstevel@tonic-gate * because functions that change them 477*7c478bd9Sstevel@tonic-gate * call holdlwps(SHOLDFORK1) first. 478*7c478bd9Sstevel@tonic-gate */ 479*7c478bd9Sstevel@tonic-gate 480*7c478bd9Sstevel@tonic-gate /* 481*7c478bd9Sstevel@tonic-gate * verify that the found pp is in the 482*7c478bd9Sstevel@tonic-gate * current task. If it is, then it 483*7c478bd9Sstevel@tonic-gate * is also within the current project 484*7c478bd9Sstevel@tonic-gate * and zone. 485*7c478bd9Sstevel@tonic-gate */ 486*7c478bd9Sstevel@tonic-gate if (rde->rcd_entity == RCENTITY_TASK && 487*7c478bd9Sstevel@tonic-gate pp->p_task != curproc->p_task) { 488*7c478bd9Sstevel@tonic-gate ret = set_errno(ESRCH); 489*7c478bd9Sstevel@tonic-gate goto rctlsys_out; 490*7c478bd9Sstevel@tonic-gate } 491*7c478bd9Sstevel@tonic-gate 492*7c478bd9Sstevel@tonic-gate ASSERT(pp->p_task->tk_proj == 493*7c478bd9Sstevel@tonic-gate curproc->p_task->tk_proj); 494*7c478bd9Sstevel@tonic-gate ASSERT(pp->p_zone == curproc->p_zone); 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate 497*7c478bd9Sstevel@tonic-gate nval->rcv_action_recipient = pp; 498*7c478bd9Sstevel@tonic-gate nval->rcv_action_recip_pid = pid; 499*7c478bd9Sstevel@tonic-gate 500*7c478bd9Sstevel@tonic-gate } else { 501*7c478bd9Sstevel@tonic-gate /* for manipulating rctl values on this proc */ 502*7c478bd9Sstevel@tonic-gate mutex_enter(&curproc->p_lock); 503*7c478bd9Sstevel@tonic-gate pp = curproc; 504*7c478bd9Sstevel@tonic-gate nval->rcv_action_recipient = curproc; 505*7c478bd9Sstevel@tonic-gate nval->rcv_action_recip_pid = curproc->p_pid; 506*7c478bd9Sstevel@tonic-gate } 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate } else { 509*7c478bd9Sstevel@tonic-gate /* RCTL_USE_RECIPIENT_PID not set, use this proc */ 510*7c478bd9Sstevel@tonic-gate mutex_enter(&curproc->p_lock); 511*7c478bd9Sstevel@tonic-gate pp = curproc; 512*7c478bd9Sstevel@tonic-gate nval->rcv_action_recipient = curproc; 513*7c478bd9Sstevel@tonic-gate nval->rcv_action_recip_pid = curproc->p_pid; 514*7c478bd9Sstevel@tonic-gate } 515*7c478bd9Sstevel@tonic-gate 516*7c478bd9Sstevel@tonic-gate } else { 517*7c478bd9Sstevel@tonic-gate /* privileged controls have no recipient pid */ 518*7c478bd9Sstevel@tonic-gate mutex_enter(&curproc->p_lock); 519*7c478bd9Sstevel@tonic-gate pp = curproc; 520*7c478bd9Sstevel@tonic-gate nval->rcv_action_recipient = NULL; 521*7c478bd9Sstevel@tonic-gate nval->rcv_action_recip_pid = -1; 522*7c478bd9Sstevel@tonic-gate } 523*7c478bd9Sstevel@tonic-gate 524*7c478bd9Sstevel@tonic-gate nval->rcv_firing_time = 0; 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate if (action == RCTL_REPLACE) { 527*7c478bd9Sstevel@tonic-gate 528*7c478bd9Sstevel@tonic-gate if (copyin(old_rblk, oblk, sizeof (rctl_opaque_t)) == -1) { 529*7c478bd9Sstevel@tonic-gate ret = set_errno(EFAULT); 530*7c478bd9Sstevel@tonic-gate goto rctlsys_out; 531*7c478bd9Sstevel@tonic-gate } 532*7c478bd9Sstevel@tonic-gate 533*7c478bd9Sstevel@tonic-gate rctlsys_rblk_xfrm(oblk, NULL, oval, RBX_FROM_BLK | RBX_VAL); 534*7c478bd9Sstevel@tonic-gate 535*7c478bd9Sstevel@tonic-gate if (rctl_invalid_value(rde, oval)) { 536*7c478bd9Sstevel@tonic-gate ret = set_errno(EINVAL); 537*7c478bd9Sstevel@tonic-gate goto rctlsys_out; 538*7c478bd9Sstevel@tonic-gate } 539*7c478bd9Sstevel@tonic-gate 540*7c478bd9Sstevel@tonic-gate if (oval->rcv_privilege == RCPRIV_BASIC) { 541*7c478bd9Sstevel@tonic-gate if (!(flags & RCTL_USE_RECIPIENT_PID)) { 542*7c478bd9Sstevel@tonic-gate oval->rcv_action_recipient = curproc; 543*7c478bd9Sstevel@tonic-gate oval->rcv_action_recip_pid = curproc->p_pid; 544*7c478bd9Sstevel@tonic-gate } 545*7c478bd9Sstevel@tonic-gate } else { 546*7c478bd9Sstevel@tonic-gate oval->rcv_action_recipient = NULL; 547*7c478bd9Sstevel@tonic-gate oval->rcv_action_recip_pid = -1; 548*7c478bd9Sstevel@tonic-gate } 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate /* 551*7c478bd9Sstevel@tonic-gate * Find the real value we're attempting to replace on the 552*7c478bd9Sstevel@tonic-gate * sequence, rather than trusting the one delivered from 553*7c478bd9Sstevel@tonic-gate * userland. 554*7c478bd9Sstevel@tonic-gate */ 555*7c478bd9Sstevel@tonic-gate if (ret = rctl_local_get(hndl, NULL, rval1, pp)) { 556*7c478bd9Sstevel@tonic-gate (void) set_errno(ret); 557*7c478bd9Sstevel@tonic-gate goto rctlsys_out; 558*7c478bd9Sstevel@tonic-gate } 559*7c478bd9Sstevel@tonic-gate 560*7c478bd9Sstevel@tonic-gate do { 561*7c478bd9Sstevel@tonic-gate if (rval1->rcv_privilege == RCPRIV_SYSTEM || 562*7c478bd9Sstevel@tonic-gate rctl_val_cmp(oval, rval1, 0) == 0) 563*7c478bd9Sstevel@tonic-gate break; 564*7c478bd9Sstevel@tonic-gate 565*7c478bd9Sstevel@tonic-gate tval = rval1; 566*7c478bd9Sstevel@tonic-gate rval1 = rval2; 567*7c478bd9Sstevel@tonic-gate rval2 = tval; 568*7c478bd9Sstevel@tonic-gate } while (rctl_local_get(hndl, rval2, rval1, pp) == 0); 569*7c478bd9Sstevel@tonic-gate 570*7c478bd9Sstevel@tonic-gate if (rval1->rcv_privilege == RCPRIV_SYSTEM) { 571*7c478bd9Sstevel@tonic-gate if (rctl_val_cmp(oval, rval1, 1) == 0) 572*7c478bd9Sstevel@tonic-gate ret = set_errno(EPERM); 573*7c478bd9Sstevel@tonic-gate else 574*7c478bd9Sstevel@tonic-gate ret = set_errno(ESRCH); 575*7c478bd9Sstevel@tonic-gate 576*7c478bd9Sstevel@tonic-gate goto rctlsys_out; 577*7c478bd9Sstevel@tonic-gate } 578*7c478bd9Sstevel@tonic-gate 579*7c478bd9Sstevel@tonic-gate bcopy(rval1, oval, sizeof (rctl_val_t)); 580*7c478bd9Sstevel@tonic-gate 581*7c478bd9Sstevel@tonic-gate /* 582*7c478bd9Sstevel@tonic-gate * System controls are immutable. 583*7c478bd9Sstevel@tonic-gate */ 584*7c478bd9Sstevel@tonic-gate if (nval->rcv_privilege == RCPRIV_SYSTEM) { 585*7c478bd9Sstevel@tonic-gate ret = set_errno(EPERM); 586*7c478bd9Sstevel@tonic-gate goto rctlsys_out; 587*7c478bd9Sstevel@tonic-gate } 588*7c478bd9Sstevel@tonic-gate 589*7c478bd9Sstevel@tonic-gate /* 590*7c478bd9Sstevel@tonic-gate * Only privileged processes in the global zone can modify 591*7c478bd9Sstevel@tonic-gate * privileged rctls of type RCENTITY_ZONE; replacing privileged 592*7c478bd9Sstevel@tonic-gate * controls with basic ones are not allowed either. Lowering a 593*7c478bd9Sstevel@tonic-gate * lowerable one might be OK for privileged processes in a 594*7c478bd9Sstevel@tonic-gate * non-global zone, but lowerable rctls probably don't make 595*7c478bd9Sstevel@tonic-gate * sense for zones (hence, not modifiable from within a zone). 596*7c478bd9Sstevel@tonic-gate */ 597*7c478bd9Sstevel@tonic-gate if (rde->rcd_entity == RCENTITY_ZONE && 598*7c478bd9Sstevel@tonic-gate (nval->rcv_privilege == RCPRIV_PRIVILEGED || 599*7c478bd9Sstevel@tonic-gate oval->rcv_privilege == RCPRIV_PRIVILEGED) && 600*7c478bd9Sstevel@tonic-gate secpolicy_rctlsys(CRED(), B_TRUE) != 0) { 601*7c478bd9Sstevel@tonic-gate ret = set_errno(EACCES); 602*7c478bd9Sstevel@tonic-gate goto rctlsys_out; 603*7c478bd9Sstevel@tonic-gate } 604*7c478bd9Sstevel@tonic-gate 605*7c478bd9Sstevel@tonic-gate /* 606*7c478bd9Sstevel@tonic-gate * Must be privileged to replace a privileged control with 607*7c478bd9Sstevel@tonic-gate * a basic one. 608*7c478bd9Sstevel@tonic-gate */ 609*7c478bd9Sstevel@tonic-gate if (oval->rcv_privilege == RCPRIV_PRIVILEGED && 610*7c478bd9Sstevel@tonic-gate nval->rcv_privilege != RCPRIV_PRIVILEGED && 611*7c478bd9Sstevel@tonic-gate secpolicy_rctlsys(CRED(), B_FALSE) != 0) { 612*7c478bd9Sstevel@tonic-gate ret = set_errno(EACCES); 613*7c478bd9Sstevel@tonic-gate goto rctlsys_out; 614*7c478bd9Sstevel@tonic-gate } 615*7c478bd9Sstevel@tonic-gate 616*7c478bd9Sstevel@tonic-gate /* 617*7c478bd9Sstevel@tonic-gate * Must have lowerable global property for non-privileged 618*7c478bd9Sstevel@tonic-gate * to lower the value of a privileged control; otherwise must 619*7c478bd9Sstevel@tonic-gate * have sufficient privileges to modify privileged controls 620*7c478bd9Sstevel@tonic-gate * at all. 621*7c478bd9Sstevel@tonic-gate */ 622*7c478bd9Sstevel@tonic-gate if (oval->rcv_privilege == RCPRIV_PRIVILEGED && 623*7c478bd9Sstevel@tonic-gate nval->rcv_privilege == RCPRIV_PRIVILEGED && 624*7c478bd9Sstevel@tonic-gate ((((rde->rcd_flagaction & RCTL_GLOBAL_LOWERABLE) == 0) || 625*7c478bd9Sstevel@tonic-gate oval->rcv_flagaction != nval->rcv_flagaction || 626*7c478bd9Sstevel@tonic-gate oval->rcv_action_signal != nval->rcv_action_signal || 627*7c478bd9Sstevel@tonic-gate oval->rcv_value < nval->rcv_value)) && 628*7c478bd9Sstevel@tonic-gate secpolicy_rctlsys(CRED(), B_FALSE) != 0) { 629*7c478bd9Sstevel@tonic-gate ret = set_errno(EACCES); 630*7c478bd9Sstevel@tonic-gate goto rctlsys_out; 631*7c478bd9Sstevel@tonic-gate } 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate if (ret = rctl_local_replace(hndl, oval, nval, pp)) { 634*7c478bd9Sstevel@tonic-gate (void) set_errno(ret); 635*7c478bd9Sstevel@tonic-gate goto rctlsys_out; 636*7c478bd9Sstevel@tonic-gate } 637*7c478bd9Sstevel@tonic-gate 638*7c478bd9Sstevel@tonic-gate /* ensure that nval is not freed */ 639*7c478bd9Sstevel@tonic-gate nval = NULL; 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate } else if (action == RCTL_INSERT) { 642*7c478bd9Sstevel@tonic-gate /* 643*7c478bd9Sstevel@tonic-gate * System controls are immutable. 644*7c478bd9Sstevel@tonic-gate */ 645*7c478bd9Sstevel@tonic-gate if (nval->rcv_privilege == RCPRIV_SYSTEM) { 646*7c478bd9Sstevel@tonic-gate ret = set_errno(EPERM); 647*7c478bd9Sstevel@tonic-gate goto rctlsys_out; 648*7c478bd9Sstevel@tonic-gate } 649*7c478bd9Sstevel@tonic-gate 650*7c478bd9Sstevel@tonic-gate /* 651*7c478bd9Sstevel@tonic-gate * Only privileged processes in the global zone may add 652*7c478bd9Sstevel@tonic-gate * privileged zone.* rctls. Only privileged processes 653*7c478bd9Sstevel@tonic-gate * may add other privileged rctls. 654*7c478bd9Sstevel@tonic-gate */ 655*7c478bd9Sstevel@tonic-gate if (nval->rcv_privilege == RCPRIV_PRIVILEGED) { 656*7c478bd9Sstevel@tonic-gate if ((rde->rcd_entity == RCENTITY_ZONE && 657*7c478bd9Sstevel@tonic-gate secpolicy_rctlsys(CRED(), B_TRUE) != 0) || 658*7c478bd9Sstevel@tonic-gate (rde->rcd_entity != RCENTITY_ZONE && 659*7c478bd9Sstevel@tonic-gate secpolicy_rctlsys(CRED(), B_FALSE) != 0)) { 660*7c478bd9Sstevel@tonic-gate ret = set_errno(EACCES); 661*7c478bd9Sstevel@tonic-gate goto rctlsys_out; 662*7c478bd9Sstevel@tonic-gate } 663*7c478bd9Sstevel@tonic-gate } 664*7c478bd9Sstevel@tonic-gate 665*7c478bd9Sstevel@tonic-gate /* 666*7c478bd9Sstevel@tonic-gate * Only one basic control is allowed per rctl. 667*7c478bd9Sstevel@tonic-gate * If a basic control is being inserted, delete 668*7c478bd9Sstevel@tonic-gate * any other basic control. 669*7c478bd9Sstevel@tonic-gate */ 670*7c478bd9Sstevel@tonic-gate if ((nval->rcv_privilege == RCPRIV_BASIC) && 671*7c478bd9Sstevel@tonic-gate (rctl_local_get(hndl, NULL, rval1, pp) == 0)) { 672*7c478bd9Sstevel@tonic-gate do { 673*7c478bd9Sstevel@tonic-gate if (rval1->rcv_privilege == RCPRIV_BASIC && 674*7c478bd9Sstevel@tonic-gate rval1->rcv_action_recipient == curproc) { 675*7c478bd9Sstevel@tonic-gate (void) rctl_local_delete(hndl, rval1, 676*7c478bd9Sstevel@tonic-gate pp); 677*7c478bd9Sstevel@tonic-gate if (rctl_local_get(hndl, NULL, rval1, 678*7c478bd9Sstevel@tonic-gate pp) != 0) 679*7c478bd9Sstevel@tonic-gate break; 680*7c478bd9Sstevel@tonic-gate } 681*7c478bd9Sstevel@tonic-gate 682*7c478bd9Sstevel@tonic-gate tval = rval1; 683*7c478bd9Sstevel@tonic-gate rval1 = rval2; 684*7c478bd9Sstevel@tonic-gate rval2 = tval; 685*7c478bd9Sstevel@tonic-gate } while (rctl_local_get(hndl, rval2, rval1, pp) 686*7c478bd9Sstevel@tonic-gate == 0); 687*7c478bd9Sstevel@tonic-gate } 688*7c478bd9Sstevel@tonic-gate 689*7c478bd9Sstevel@tonic-gate 690*7c478bd9Sstevel@tonic-gate if (ret = rctl_local_insert(hndl, nval, pp)) { 691*7c478bd9Sstevel@tonic-gate (void) set_errno(ret); 692*7c478bd9Sstevel@tonic-gate goto rctlsys_out; 693*7c478bd9Sstevel@tonic-gate } 694*7c478bd9Sstevel@tonic-gate 695*7c478bd9Sstevel@tonic-gate /* ensure that nval is not freed */ 696*7c478bd9Sstevel@tonic-gate nval = NULL; 697*7c478bd9Sstevel@tonic-gate 698*7c478bd9Sstevel@tonic-gate } else { 699*7c478bd9Sstevel@tonic-gate /* 700*7c478bd9Sstevel@tonic-gate * RCTL_DELETE 701*7c478bd9Sstevel@tonic-gate */ 702*7c478bd9Sstevel@tonic-gate if (nval->rcv_privilege == RCPRIV_SYSTEM) { 703*7c478bd9Sstevel@tonic-gate ret = set_errno(EPERM); 704*7c478bd9Sstevel@tonic-gate goto rctlsys_out; 705*7c478bd9Sstevel@tonic-gate } 706*7c478bd9Sstevel@tonic-gate 707*7c478bd9Sstevel@tonic-gate if (nval->rcv_privilege == RCPRIV_PRIVILEGED) { 708*7c478bd9Sstevel@tonic-gate if ((rde->rcd_entity == RCENTITY_ZONE && 709*7c478bd9Sstevel@tonic-gate secpolicy_rctlsys(CRED(), B_TRUE) != 0) || 710*7c478bd9Sstevel@tonic-gate (rde->rcd_entity != RCENTITY_ZONE && 711*7c478bd9Sstevel@tonic-gate secpolicy_rctlsys(CRED(), B_FALSE) != 0)) { 712*7c478bd9Sstevel@tonic-gate ret = set_errno(EACCES); 713*7c478bd9Sstevel@tonic-gate goto rctlsys_out; 714*7c478bd9Sstevel@tonic-gate } 715*7c478bd9Sstevel@tonic-gate } 716*7c478bd9Sstevel@tonic-gate 717*7c478bd9Sstevel@tonic-gate if (ret = rctl_local_delete(hndl, nval, pp)) { 718*7c478bd9Sstevel@tonic-gate (void) set_errno(ret); 719*7c478bd9Sstevel@tonic-gate goto rctlsys_out; 720*7c478bd9Sstevel@tonic-gate } 721*7c478bd9Sstevel@tonic-gate } 722*7c478bd9Sstevel@tonic-gate 723*7c478bd9Sstevel@tonic-gate rctlsys_out: 724*7c478bd9Sstevel@tonic-gate 725*7c478bd9Sstevel@tonic-gate if (pp) 726*7c478bd9Sstevel@tonic-gate mutex_exit(&pp->p_lock); 727*7c478bd9Sstevel@tonic-gate 728*7c478bd9Sstevel@tonic-gate kmem_free(nblk, sizeof (rctl_opaque_t)); 729*7c478bd9Sstevel@tonic-gate kmem_free(oblk, sizeof (rctl_opaque_t)); 730*7c478bd9Sstevel@tonic-gate 731*7c478bd9Sstevel@tonic-gate /* only free nval if we did not rctl_local_insert it */ 732*7c478bd9Sstevel@tonic-gate if (nval) 733*7c478bd9Sstevel@tonic-gate kmem_cache_free(rctl_val_cache, nval); 734*7c478bd9Sstevel@tonic-gate 735*7c478bd9Sstevel@tonic-gate kmem_cache_free(rctl_val_cache, oval); 736*7c478bd9Sstevel@tonic-gate kmem_cache_free(rctl_val_cache, rval1); 737*7c478bd9Sstevel@tonic-gate kmem_cache_free(rctl_val_cache, rval2); 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate return (ret); 740*7c478bd9Sstevel@tonic-gate } 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate static long 743*7c478bd9Sstevel@tonic-gate rctlsys_lst(char *ubuf, size_t ubufsz) 744*7c478bd9Sstevel@tonic-gate { 745*7c478bd9Sstevel@tonic-gate char *kbuf; 746*7c478bd9Sstevel@tonic-gate size_t kbufsz; 747*7c478bd9Sstevel@tonic-gate 748*7c478bd9Sstevel@tonic-gate kbufsz = rctl_build_name_buf(&kbuf); 749*7c478bd9Sstevel@tonic-gate 750*7c478bd9Sstevel@tonic-gate if (kbufsz <= ubufsz && 751*7c478bd9Sstevel@tonic-gate copyout(kbuf, ubuf, kbufsz) != 0) { 752*7c478bd9Sstevel@tonic-gate kmem_free(kbuf, kbufsz); 753*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 754*7c478bd9Sstevel@tonic-gate } 755*7c478bd9Sstevel@tonic-gate 756*7c478bd9Sstevel@tonic-gate kmem_free(kbuf, kbufsz); 757*7c478bd9Sstevel@tonic-gate 758*7c478bd9Sstevel@tonic-gate return (kbufsz); 759*7c478bd9Sstevel@tonic-gate } 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate static long 762*7c478bd9Sstevel@tonic-gate rctlsys_ctl(char *name, rctl_opaque_t *rblk, int flags) 763*7c478bd9Sstevel@tonic-gate { 764*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t *krde; 765*7c478bd9Sstevel@tonic-gate rctl_opaque_t *krblk; 766*7c478bd9Sstevel@tonic-gate char *kname; 767*7c478bd9Sstevel@tonic-gate size_t klen; 768*7c478bd9Sstevel@tonic-gate 769*7c478bd9Sstevel@tonic-gate kname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 770*7c478bd9Sstevel@tonic-gate 771*7c478bd9Sstevel@tonic-gate if (name == NULL || copyinstr(name, kname, MAXPATHLEN, &klen) != 0) { 772*7c478bd9Sstevel@tonic-gate kmem_free(kname, MAXPATHLEN); 773*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 774*7c478bd9Sstevel@tonic-gate } 775*7c478bd9Sstevel@tonic-gate 776*7c478bd9Sstevel@tonic-gate switch (flags) { 777*7c478bd9Sstevel@tonic-gate case RCTLCTL_GET: 778*7c478bd9Sstevel@tonic-gate krde = kmem_alloc(sizeof (rctl_dict_entry_t), KM_SLEEP); 779*7c478bd9Sstevel@tonic-gate krblk = kmem_zalloc(sizeof (rctl_opaque_t), KM_SLEEP); 780*7c478bd9Sstevel@tonic-gate 781*7c478bd9Sstevel@tonic-gate if (rctl_global_get(kname, krde) == -1) { 782*7c478bd9Sstevel@tonic-gate kmem_free(krde, sizeof (rctl_dict_entry_t)); 783*7c478bd9Sstevel@tonic-gate kmem_free(krblk, sizeof (rctl_opaque_t)); 784*7c478bd9Sstevel@tonic-gate kmem_free(kname, MAXPATHLEN); 785*7c478bd9Sstevel@tonic-gate return (set_errno(ESRCH)); 786*7c478bd9Sstevel@tonic-gate } 787*7c478bd9Sstevel@tonic-gate 788*7c478bd9Sstevel@tonic-gate rctlsys_rblk_xfrm(krblk, krde, NULL, RBX_TO_BLK | RBX_CTL); 789*7c478bd9Sstevel@tonic-gate 790*7c478bd9Sstevel@tonic-gate if (copyout(krblk, rblk, sizeof (rctl_opaque_t)) != 0) { 791*7c478bd9Sstevel@tonic-gate kmem_free(krde, sizeof (rctl_dict_entry_t)); 792*7c478bd9Sstevel@tonic-gate kmem_free(krblk, sizeof (rctl_opaque_t)); 793*7c478bd9Sstevel@tonic-gate kmem_free(kname, MAXPATHLEN); 794*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 795*7c478bd9Sstevel@tonic-gate } 796*7c478bd9Sstevel@tonic-gate 797*7c478bd9Sstevel@tonic-gate kmem_free(krde, sizeof (rctl_dict_entry_t)); 798*7c478bd9Sstevel@tonic-gate kmem_free(krblk, sizeof (rctl_opaque_t)); 799*7c478bd9Sstevel@tonic-gate kmem_free(kname, MAXPATHLEN); 800*7c478bd9Sstevel@tonic-gate break; 801*7c478bd9Sstevel@tonic-gate case RCTLCTL_SET: 802*7c478bd9Sstevel@tonic-gate if (secpolicy_rctlsys(CRED(), B_TRUE) != 0) { 803*7c478bd9Sstevel@tonic-gate kmem_free(kname, MAXPATHLEN); 804*7c478bd9Sstevel@tonic-gate return (set_errno(EPERM)); 805*7c478bd9Sstevel@tonic-gate } 806*7c478bd9Sstevel@tonic-gate 807*7c478bd9Sstevel@tonic-gate krde = kmem_alloc(sizeof (rctl_dict_entry_t), KM_SLEEP); 808*7c478bd9Sstevel@tonic-gate krblk = kmem_zalloc(sizeof (rctl_opaque_t), KM_SLEEP); 809*7c478bd9Sstevel@tonic-gate 810*7c478bd9Sstevel@tonic-gate if (rctl_global_get(kname, krde) == -1) { 811*7c478bd9Sstevel@tonic-gate kmem_free(krde, sizeof (rctl_dict_entry_t)); 812*7c478bd9Sstevel@tonic-gate kmem_free(krblk, sizeof (rctl_opaque_t)); 813*7c478bd9Sstevel@tonic-gate kmem_free(kname, MAXPATHLEN); 814*7c478bd9Sstevel@tonic-gate return (set_errno(ESRCH)); 815*7c478bd9Sstevel@tonic-gate } 816*7c478bd9Sstevel@tonic-gate 817*7c478bd9Sstevel@tonic-gate if (copyin(rblk, krblk, sizeof (rctl_opaque_t)) != 0) { 818*7c478bd9Sstevel@tonic-gate kmem_free(krde, sizeof (rctl_dict_entry_t)); 819*7c478bd9Sstevel@tonic-gate kmem_free(krblk, sizeof (rctl_opaque_t)); 820*7c478bd9Sstevel@tonic-gate kmem_free(kname, MAXPATHLEN); 821*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 822*7c478bd9Sstevel@tonic-gate } 823*7c478bd9Sstevel@tonic-gate 824*7c478bd9Sstevel@tonic-gate rctlsys_rblk_xfrm(krblk, krde, NULL, RBX_FROM_BLK | RBX_CTL); 825*7c478bd9Sstevel@tonic-gate 826*7c478bd9Sstevel@tonic-gate if (rctl_global_set(kname, krde) == -1) { 827*7c478bd9Sstevel@tonic-gate kmem_free(krde, sizeof (rctl_dict_entry_t)); 828*7c478bd9Sstevel@tonic-gate kmem_free(krblk, sizeof (rctl_opaque_t)); 829*7c478bd9Sstevel@tonic-gate kmem_free(kname, MAXPATHLEN); 830*7c478bd9Sstevel@tonic-gate return (set_errno(ESRCH)); 831*7c478bd9Sstevel@tonic-gate } 832*7c478bd9Sstevel@tonic-gate 833*7c478bd9Sstevel@tonic-gate kmem_free(krde, sizeof (rctl_dict_entry_t)); 834*7c478bd9Sstevel@tonic-gate kmem_free(krblk, sizeof (rctl_opaque_t)); 835*7c478bd9Sstevel@tonic-gate kmem_free(kname, MAXPATHLEN); 836*7c478bd9Sstevel@tonic-gate 837*7c478bd9Sstevel@tonic-gate break; 838*7c478bd9Sstevel@tonic-gate default: 839*7c478bd9Sstevel@tonic-gate kmem_free(kname, MAXPATHLEN); 840*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 841*7c478bd9Sstevel@tonic-gate } 842*7c478bd9Sstevel@tonic-gate 843*7c478bd9Sstevel@tonic-gate return (0); 844*7c478bd9Sstevel@tonic-gate } 845*7c478bd9Sstevel@tonic-gate 846*7c478bd9Sstevel@tonic-gate long 847*7c478bd9Sstevel@tonic-gate rctlsys(int code, char *name, void *obuf, void *nbuf, size_t obufsz, int flags) 848*7c478bd9Sstevel@tonic-gate { 849*7c478bd9Sstevel@tonic-gate switch (code) { 850*7c478bd9Sstevel@tonic-gate case 0: 851*7c478bd9Sstevel@tonic-gate return (rctlsys_get(name, obuf, nbuf, flags)); 852*7c478bd9Sstevel@tonic-gate 853*7c478bd9Sstevel@tonic-gate case 1: 854*7c478bd9Sstevel@tonic-gate return (rctlsys_set(name, obuf, nbuf, flags)); 855*7c478bd9Sstevel@tonic-gate 856*7c478bd9Sstevel@tonic-gate case 2: 857*7c478bd9Sstevel@tonic-gate /* 858*7c478bd9Sstevel@tonic-gate * Private call for rctl_walk(3C). 859*7c478bd9Sstevel@tonic-gate */ 860*7c478bd9Sstevel@tonic-gate return (rctlsys_lst(obuf, obufsz)); 861*7c478bd9Sstevel@tonic-gate 862*7c478bd9Sstevel@tonic-gate case 3: 863*7c478bd9Sstevel@tonic-gate /* 864*7c478bd9Sstevel@tonic-gate * Private code for rctladm(1M): "rctlctl". 865*7c478bd9Sstevel@tonic-gate */ 866*7c478bd9Sstevel@tonic-gate return (rctlsys_ctl(name, obuf, flags)); 867*7c478bd9Sstevel@tonic-gate 868*7c478bd9Sstevel@tonic-gate default: 869*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 870*7c478bd9Sstevel@tonic-gate } 871*7c478bd9Sstevel@tonic-gate } 872