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 2005 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 #include <sys/sysmacros.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/cred_impl.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/user.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/proc.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/acct.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/ipc_impl.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/syscall.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/policy.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/kobj.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/msg.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/devpolicy.h> 50*7c478bd9Sstevel@tonic-gate #include <c2/audit.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/disp.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/zone.h> 55*7c478bd9Sstevel@tonic-gate #include <inet/common.h> 56*7c478bd9Sstevel@tonic-gate #include <inet/optcom.h> 57*7c478bd9Sstevel@tonic-gate #include <sys/sdt.h> 58*7c478bd9Sstevel@tonic-gate #include <sys/mount.h> 59*7c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 60*7c478bd9Sstevel@tonic-gate #include <sys/mntent.h> 61*7c478bd9Sstevel@tonic-gate #include <sys/contract_impl.h> 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate /* 66*7c478bd9Sstevel@tonic-gate * There are two possible layers of privilege routines and two possible 67*7c478bd9Sstevel@tonic-gate * levels of secpolicy. Plus one other we may not be interested in, so 68*7c478bd9Sstevel@tonic-gate * we may need as many as 6 but no more. 69*7c478bd9Sstevel@tonic-gate */ 70*7c478bd9Sstevel@tonic-gate #define MAXPRIVSTACK 6 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate int priv_debug = 0; 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate /* 75*7c478bd9Sstevel@tonic-gate * This file contains the majority of the policy routines. 76*7c478bd9Sstevel@tonic-gate * Since the policy routines are defined by function and not 77*7c478bd9Sstevel@tonic-gate * by privilege, there is quite a bit of duplication of 78*7c478bd9Sstevel@tonic-gate * functions. 79*7c478bd9Sstevel@tonic-gate * 80*7c478bd9Sstevel@tonic-gate * The secpolicy functions must not make asssumptions about 81*7c478bd9Sstevel@tonic-gate * locks held or not held as any lock can be held while they're 82*7c478bd9Sstevel@tonic-gate * being called. 83*7c478bd9Sstevel@tonic-gate * 84*7c478bd9Sstevel@tonic-gate * Credentials are read-only so no special precautions need to 85*7c478bd9Sstevel@tonic-gate * be taken while locking them. 86*7c478bd9Sstevel@tonic-gate * 87*7c478bd9Sstevel@tonic-gate * When a new policy check needs to be added to the system the 88*7c478bd9Sstevel@tonic-gate * following procedure should be followed: 89*7c478bd9Sstevel@tonic-gate * 90*7c478bd9Sstevel@tonic-gate * Pick an appropriate secpolicy_*() function 91*7c478bd9Sstevel@tonic-gate * -> done if one exists. 92*7c478bd9Sstevel@tonic-gate * Create a new secpolicy function, preferably with 93*7c478bd9Sstevel@tonic-gate * a descriptive name using the standard template. 94*7c478bd9Sstevel@tonic-gate * Pick an appropriate privilege for the policy. 95*7c478bd9Sstevel@tonic-gate * If no appropraite privilege exists, define new one 96*7c478bd9Sstevel@tonic-gate * (this should be done with extreme care; in most cases 97*7c478bd9Sstevel@tonic-gate * little is gained by adding another privilege) 98*7c478bd9Sstevel@tonic-gate * 99*7c478bd9Sstevel@tonic-gate * WHY ROOT IS STILL SPECIAL. 100*7c478bd9Sstevel@tonic-gate * 101*7c478bd9Sstevel@tonic-gate * In a number of the policy functions, there are still explicit 102*7c478bd9Sstevel@tonic-gate * checks for uid 0. The rationale behind these is that many root 103*7c478bd9Sstevel@tonic-gate * owned files/objects hold configuration information which can give full 104*7c478bd9Sstevel@tonic-gate * privileges to the user once written to. To prevent escalation 105*7c478bd9Sstevel@tonic-gate * of privilege by allowing just a single privilege to modify root owned 106*7c478bd9Sstevel@tonic-gate * objects, we've added these root specific checks where we considered 107*7c478bd9Sstevel@tonic-gate * them necessary: modifying root owned files, changing uids to 0, etc. 108*7c478bd9Sstevel@tonic-gate * 109*7c478bd9Sstevel@tonic-gate * PRIVILEGE ESCALATION AND ZONES. 110*7c478bd9Sstevel@tonic-gate * 111*7c478bd9Sstevel@tonic-gate * A number of operations potentially allow the caller to achieve 112*7c478bd9Sstevel@tonic-gate * privileges beyond the ones normally required to perform the operation. 113*7c478bd9Sstevel@tonic-gate * For example, if allowed to create a setuid 0 executable, a process can 114*7c478bd9Sstevel@tonic-gate * gain privileges beyond PRIV_FILE_SETID. Zones, however, place 115*7c478bd9Sstevel@tonic-gate * restrictions on the ability to gain privileges beyond those available 116*7c478bd9Sstevel@tonic-gate * within the zone through file and process manipulation. Hence, such 117*7c478bd9Sstevel@tonic-gate * operations require that the caller have an effective set that includes 118*7c478bd9Sstevel@tonic-gate * all privileges available within the current zone, or all privileges 119*7c478bd9Sstevel@tonic-gate * if executing in the global zone. 120*7c478bd9Sstevel@tonic-gate * 121*7c478bd9Sstevel@tonic-gate * This is indicated in the priv_policy* policy checking functions 122*7c478bd9Sstevel@tonic-gate * through a combination of parameters. The "priv" parameter indicates 123*7c478bd9Sstevel@tonic-gate * the privilege that is required, and the "allzone" parameter indicates 124*7c478bd9Sstevel@tonic-gate * whether or not all privileges in the zone are required. In addition, 125*7c478bd9Sstevel@tonic-gate * priv can be set to PRIV_ALL to indicate that all privileges are 126*7c478bd9Sstevel@tonic-gate * required (regardless of zone). There are three scenarios of interest: 127*7c478bd9Sstevel@tonic-gate * (1) operation requires a specific privilege 128*7c478bd9Sstevel@tonic-gate * (2) operation requires a specific privilege, and requires all 129*7c478bd9Sstevel@tonic-gate * privileges available within the zone (or all privileges if in 130*7c478bd9Sstevel@tonic-gate * the global zone) 131*7c478bd9Sstevel@tonic-gate * (3) operation requires all privileges, regardless of zone 132*7c478bd9Sstevel@tonic-gate * 133*7c478bd9Sstevel@tonic-gate * For (1), priv should be set to the specific privilege, and allzone 134*7c478bd9Sstevel@tonic-gate * should be set to B_FALSE. 135*7c478bd9Sstevel@tonic-gate * For (2), priv should be set to the specific privilege, and allzone 136*7c478bd9Sstevel@tonic-gate * should be set to B_TRUE. 137*7c478bd9Sstevel@tonic-gate * For (3), priv should be set to PRIV_ALL, and allzone should be set 138*7c478bd9Sstevel@tonic-gate * to B_FALSE. 139*7c478bd9Sstevel@tonic-gate * 140*7c478bd9Sstevel@tonic-gate */ 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate /* 143*7c478bd9Sstevel@tonic-gate * The privileges are checked against the Effective set for 144*7c478bd9Sstevel@tonic-gate * ordinary processes and checked against the Limit set 145*7c478bd9Sstevel@tonic-gate * for euid 0 processes that haven't manipulated their privilege 146*7c478bd9Sstevel@tonic-gate * sets. 147*7c478bd9Sstevel@tonic-gate */ 148*7c478bd9Sstevel@tonic-gate #define HAS_ALLPRIVS(cr) priv_isfullset(&CR_OEPRIV(cr)) 149*7c478bd9Sstevel@tonic-gate #define ZONEPRIVS(cr) ((cr)->cr_zone->zone_privset) 150*7c478bd9Sstevel@tonic-gate #define HAS_ALLZONEPRIVS(cr) priv_issubset(ZONEPRIVS(cr), &CR_OEPRIV(cr)) 151*7c478bd9Sstevel@tonic-gate #define HAS_PRIVILEGE(cr, pr) ((pr) == PRIV_ALL ? \ 152*7c478bd9Sstevel@tonic-gate HAS_ALLPRIVS(cr) : \ 153*7c478bd9Sstevel@tonic-gate PRIV_ISASSERT(&CR_OEPRIV(cr), pr)) 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate /* 156*7c478bd9Sstevel@tonic-gate * Policy checking functions 157*7c478bd9Sstevel@tonic-gate * 158*7c478bd9Sstevel@tonic-gate * In future, these will migrate to several files when policy 159*7c478bd9Sstevel@tonic-gate * becomes more or less pluggable. 160*7c478bd9Sstevel@tonic-gate * 161*7c478bd9Sstevel@tonic-gate * For now, there's only one policy and this is it. 162*7c478bd9Sstevel@tonic-gate */ 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate /* 165*7c478bd9Sstevel@tonic-gate * Generic policy calls 166*7c478bd9Sstevel@tonic-gate * 167*7c478bd9Sstevel@tonic-gate * The "bottom" functions of policy control 168*7c478bd9Sstevel@tonic-gate */ 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate static char * 171*7c478bd9Sstevel@tonic-gate mprintf(const char *fmt, ...) 172*7c478bd9Sstevel@tonic-gate { 173*7c478bd9Sstevel@tonic-gate va_list args; 174*7c478bd9Sstevel@tonic-gate char *buf; 175*7c478bd9Sstevel@tonic-gate size_t len; 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate va_start(args, fmt); 178*7c478bd9Sstevel@tonic-gate len = vsnprintf(NULL, 0, fmt, args) + 1; 179*7c478bd9Sstevel@tonic-gate va_end(args); 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate buf = kmem_alloc(len, KM_NOSLEEP); 182*7c478bd9Sstevel@tonic-gate 183*7c478bd9Sstevel@tonic-gate if (buf == NULL) 184*7c478bd9Sstevel@tonic-gate return (NULL); 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate va_start(args, fmt); 187*7c478bd9Sstevel@tonic-gate (void) vsnprintf(buf, len, fmt, args); 188*7c478bd9Sstevel@tonic-gate va_end(args); 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate return (buf); 191*7c478bd9Sstevel@tonic-gate } 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate /* 194*7c478bd9Sstevel@tonic-gate * priv_policy_errmsg() 195*7c478bd9Sstevel@tonic-gate * 196*7c478bd9Sstevel@tonic-gate * Generate an error message if privilege debugging is enabled system wide 197*7c478bd9Sstevel@tonic-gate * or for this particular process. 198*7c478bd9Sstevel@tonic-gate */ 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate #define FMTHDR "%s[%d]: missing privilege \"%s\" (euid = %d, syscall = %d)" 201*7c478bd9Sstevel@tonic-gate #define FMTMSG " for \"%s\"" 202*7c478bd9Sstevel@tonic-gate #define FMTFUN " needed at %s+0x%lx" 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate /* The maximum size privilege format: the concatenation of the above */ 205*7c478bd9Sstevel@tonic-gate #define FMTMAX FMTHDR FMTMSG FMTFUN "\n" 206*7c478bd9Sstevel@tonic-gate 207*7c478bd9Sstevel@tonic-gate static void 208*7c478bd9Sstevel@tonic-gate priv_policy_errmsg(const cred_t *cr, int priv, const char *msg) 209*7c478bd9Sstevel@tonic-gate { 210*7c478bd9Sstevel@tonic-gate struct proc *me; 211*7c478bd9Sstevel@tonic-gate pc_t stack[MAXPRIVSTACK]; 212*7c478bd9Sstevel@tonic-gate int depth; 213*7c478bd9Sstevel@tonic-gate int i; 214*7c478bd9Sstevel@tonic-gate char *sym; 215*7c478bd9Sstevel@tonic-gate ulong_t off; 216*7c478bd9Sstevel@tonic-gate const char *pname; 217*7c478bd9Sstevel@tonic-gate 218*7c478bd9Sstevel@tonic-gate char *cmd; 219*7c478bd9Sstevel@tonic-gate char fmt[sizeof (FMTMAX)]; 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate if ((me = curproc) == &p0) 222*7c478bd9Sstevel@tonic-gate return; 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate /* Privileges must be defined */ 225*7c478bd9Sstevel@tonic-gate ASSERT(priv == PRIV_ALL || priv == PRIV_MULTIPLE || 226*7c478bd9Sstevel@tonic-gate priv == PRIV_ALLZONE || priv == PRIV_GLOBAL || 227*7c478bd9Sstevel@tonic-gate priv_getbynum(priv) != NULL); 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate if (priv == PRIV_ALLZONE && INGLOBALZONE(me)) 230*7c478bd9Sstevel@tonic-gate priv = PRIV_ALL; 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate if (curthread->t_pre_sys) 233*7c478bd9Sstevel@tonic-gate ttolwp(curthread)->lwp_badpriv = (short)priv; 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate if (priv_debug == 0 && (CR_FLAGS(cr) & PRIV_DEBUG) == 0) 236*7c478bd9Sstevel@tonic-gate return; 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate (void) strcpy(fmt, FMTHDR); 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate if (me->p_user.u_comm[0]) 241*7c478bd9Sstevel@tonic-gate cmd = &me->p_user.u_comm[0]; 242*7c478bd9Sstevel@tonic-gate else 243*7c478bd9Sstevel@tonic-gate cmd = "priv_policy"; 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate if (msg != NULL && *msg != '\0') { 246*7c478bd9Sstevel@tonic-gate (void) strcat(fmt, FMTMSG); 247*7c478bd9Sstevel@tonic-gate } else { 248*7c478bd9Sstevel@tonic-gate (void) strcat(fmt, "%s"); 249*7c478bd9Sstevel@tonic-gate msg = ""; 250*7c478bd9Sstevel@tonic-gate } 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate sym = NULL; 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate depth = getpcstack(stack, MAXPRIVSTACK); 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate /* 257*7c478bd9Sstevel@tonic-gate * Try to find the first interesting function on the stack. 258*7c478bd9Sstevel@tonic-gate * priv_policy* that's us, so completely uninteresting. 259*7c478bd9Sstevel@tonic-gate * suser(), drv_priv(), secpolicy_* are also called from 260*7c478bd9Sstevel@tonic-gate * too many locations to convey useful information. 261*7c478bd9Sstevel@tonic-gate */ 262*7c478bd9Sstevel@tonic-gate for (i = 0; i < depth; i++) { 263*7c478bd9Sstevel@tonic-gate sym = kobj_getsymname((uintptr_t)stack[i], &off); 264*7c478bd9Sstevel@tonic-gate if (sym != NULL && 265*7c478bd9Sstevel@tonic-gate strstr(sym, "hasprocperm") == 0 && 266*7c478bd9Sstevel@tonic-gate strcmp("suser", sym) != 0 && 267*7c478bd9Sstevel@tonic-gate strcmp("ipcaccess", sym) != 0 && 268*7c478bd9Sstevel@tonic-gate strcmp("drv_priv", sym) != 0 && 269*7c478bd9Sstevel@tonic-gate strncmp("secpolicy_", sym, 10) != 0 && 270*7c478bd9Sstevel@tonic-gate strncmp("priv_policy", sym, 11) != 0) 271*7c478bd9Sstevel@tonic-gate break; 272*7c478bd9Sstevel@tonic-gate } 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate if (sym != NULL) 275*7c478bd9Sstevel@tonic-gate (void) strcat(fmt, FMTFUN); 276*7c478bd9Sstevel@tonic-gate 277*7c478bd9Sstevel@tonic-gate (void) strcat(fmt, "\n"); 278*7c478bd9Sstevel@tonic-gate 279*7c478bd9Sstevel@tonic-gate switch (priv) { 280*7c478bd9Sstevel@tonic-gate case PRIV_ALL: 281*7c478bd9Sstevel@tonic-gate pname = "ALL"; 282*7c478bd9Sstevel@tonic-gate break; 283*7c478bd9Sstevel@tonic-gate case PRIV_MULTIPLE: 284*7c478bd9Sstevel@tonic-gate pname = "MULTIPLE"; 285*7c478bd9Sstevel@tonic-gate break; 286*7c478bd9Sstevel@tonic-gate case PRIV_ALLZONE: 287*7c478bd9Sstevel@tonic-gate pname = "ZONE"; 288*7c478bd9Sstevel@tonic-gate break; 289*7c478bd9Sstevel@tonic-gate case PRIV_GLOBAL: 290*7c478bd9Sstevel@tonic-gate pname = "GLOBAL"; 291*7c478bd9Sstevel@tonic-gate break; 292*7c478bd9Sstevel@tonic-gate default: 293*7c478bd9Sstevel@tonic-gate pname = priv_getbynum(priv); 294*7c478bd9Sstevel@tonic-gate break; 295*7c478bd9Sstevel@tonic-gate } 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate if (CR_FLAGS(cr) & PRIV_DEBUG) { 298*7c478bd9Sstevel@tonic-gate /* Remember last message, just like lwp_badpriv. */ 299*7c478bd9Sstevel@tonic-gate if (curthread->t_pdmsg != NULL) { 300*7c478bd9Sstevel@tonic-gate kmem_free(curthread->t_pdmsg, 301*7c478bd9Sstevel@tonic-gate strlen(curthread->t_pdmsg) + 1); 302*7c478bd9Sstevel@tonic-gate } 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate curthread->t_pdmsg = mprintf(fmt, cmd, me->p_pid, pname, 305*7c478bd9Sstevel@tonic-gate cr->cr_uid, curthread->t_sysnum, msg, sym, off); 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate curthread->t_post_sys = 1; 308*7c478bd9Sstevel@tonic-gate } else { 309*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, fmt, cmd, me->p_pid, pname, cr->cr_uid, 310*7c478bd9Sstevel@tonic-gate curthread->t_sysnum, msg, sym, off); 311*7c478bd9Sstevel@tonic-gate } 312*7c478bd9Sstevel@tonic-gate } 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate /* 315*7c478bd9Sstevel@tonic-gate * Audit failure, log error message. 316*7c478bd9Sstevel@tonic-gate */ 317*7c478bd9Sstevel@tonic-gate static void 318*7c478bd9Sstevel@tonic-gate priv_policy_err(const cred_t *cr, int priv, boolean_t allzone, const char *msg) 319*7c478bd9Sstevel@tonic-gate { 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT 322*7c478bd9Sstevel@tonic-gate if (audit_active) 323*7c478bd9Sstevel@tonic-gate audit_priv(priv, allzone ? ZONEPRIVS(cr) : NULL, 0); 324*7c478bd9Sstevel@tonic-gate #endif 325*7c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone); 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) || 328*7c478bd9Sstevel@tonic-gate curthread->t_pre_sys) { 329*7c478bd9Sstevel@tonic-gate if (allzone && !HAS_ALLZONEPRIVS(cr)) { 330*7c478bd9Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_ALLZONE, msg); 331*7c478bd9Sstevel@tonic-gate } else { 332*7c478bd9Sstevel@tonic-gate ASSERT(!HAS_PRIVILEGE(cr, priv)); 333*7c478bd9Sstevel@tonic-gate priv_policy_errmsg(cr, priv, msg); 334*7c478bd9Sstevel@tonic-gate } 335*7c478bd9Sstevel@tonic-gate } 336*7c478bd9Sstevel@tonic-gate } 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate /* 339*7c478bd9Sstevel@tonic-gate * priv_policy() 340*7c478bd9Sstevel@tonic-gate * return 0 or error. 341*7c478bd9Sstevel@tonic-gate * See block comment above for a description of "priv" and "allzone" usage. 342*7c478bd9Sstevel@tonic-gate */ 343*7c478bd9Sstevel@tonic-gate int 344*7c478bd9Sstevel@tonic-gate priv_policy(const cred_t *cr, int priv, boolean_t allzone, int err, 345*7c478bd9Sstevel@tonic-gate const char *msg) 346*7c478bd9Sstevel@tonic-gate { 347*7c478bd9Sstevel@tonic-gate if (HAS_PRIVILEGE(cr, priv) && (!allzone || HAS_ALLZONEPRIVS(cr))) { 348*7c478bd9Sstevel@tonic-gate if ((allzone || priv == PRIV_ALL || 349*7c478bd9Sstevel@tonic-gate !PRIV_ISASSERT(priv_basic, priv)) && 350*7c478bd9Sstevel@tonic-gate !servicing_interrupt()) { 351*7c478bd9Sstevel@tonic-gate u.u_acflag |= ASU; /* Needed for SVVS */ 352*7c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT 353*7c478bd9Sstevel@tonic-gate if (audit_active) 354*7c478bd9Sstevel@tonic-gate audit_priv(priv, 355*7c478bd9Sstevel@tonic-gate allzone ? ZONEPRIVS(cr) : NULL, 1); 356*7c478bd9Sstevel@tonic-gate #endif 357*7c478bd9Sstevel@tonic-gate } 358*7c478bd9Sstevel@tonic-gate err = 0; 359*7c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone); 360*7c478bd9Sstevel@tonic-gate } else if (!servicing_interrupt()) { 361*7c478bd9Sstevel@tonic-gate /* Failure audited in this procedure */ 362*7c478bd9Sstevel@tonic-gate priv_policy_err(cr, priv, allzone, msg); 363*7c478bd9Sstevel@tonic-gate } 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate return (err); 366*7c478bd9Sstevel@tonic-gate } 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate /* 369*7c478bd9Sstevel@tonic-gate * Return B_TRUE for sufficient privileges, B_FALSE for insufficient privileges. 370*7c478bd9Sstevel@tonic-gate */ 371*7c478bd9Sstevel@tonic-gate boolean_t 372*7c478bd9Sstevel@tonic-gate priv_policy_choice(const cred_t *cr, int priv, boolean_t allzone) 373*7c478bd9Sstevel@tonic-gate { 374*7c478bd9Sstevel@tonic-gate boolean_t res = HAS_PRIVILEGE(cr, priv) && 375*7c478bd9Sstevel@tonic-gate (!allzone || HAS_ALLZONEPRIVS(cr)); 376*7c478bd9Sstevel@tonic-gate 377*7c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT 378*7c478bd9Sstevel@tonic-gate /* Audit success only */ 379*7c478bd9Sstevel@tonic-gate if (res && audit_active && 380*7c478bd9Sstevel@tonic-gate (allzone || priv == PRIV_ALL || !PRIV_ISASSERT(priv_basic, priv)) && 381*7c478bd9Sstevel@tonic-gate !servicing_interrupt()) { 382*7c478bd9Sstevel@tonic-gate audit_priv(priv, allzone ? ZONEPRIVS(cr) : NULL, 1); 383*7c478bd9Sstevel@tonic-gate } 384*7c478bd9Sstevel@tonic-gate #endif 385*7c478bd9Sstevel@tonic-gate if (res) { 386*7c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone); 387*7c478bd9Sstevel@tonic-gate } else { 388*7c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone); 389*7c478bd9Sstevel@tonic-gate } 390*7c478bd9Sstevel@tonic-gate return (res); 391*7c478bd9Sstevel@tonic-gate } 392*7c478bd9Sstevel@tonic-gate 393*7c478bd9Sstevel@tonic-gate /* 394*7c478bd9Sstevel@tonic-gate * Non-auditing variant of priv_policy_choice(). 395*7c478bd9Sstevel@tonic-gate */ 396*7c478bd9Sstevel@tonic-gate boolean_t 397*7c478bd9Sstevel@tonic-gate priv_policy_only(const cred_t *cr, int priv, boolean_t allzone) 398*7c478bd9Sstevel@tonic-gate { 399*7c478bd9Sstevel@tonic-gate boolean_t res = HAS_PRIVILEGE(cr, priv) && 400*7c478bd9Sstevel@tonic-gate (!allzone || HAS_ALLZONEPRIVS(cr)); 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate if (res) { 403*7c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone); 404*7c478bd9Sstevel@tonic-gate } else { 405*7c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone); 406*7c478bd9Sstevel@tonic-gate } 407*7c478bd9Sstevel@tonic-gate return (res); 408*7c478bd9Sstevel@tonic-gate } 409*7c478bd9Sstevel@tonic-gate 410*7c478bd9Sstevel@tonic-gate /* 411*7c478bd9Sstevel@tonic-gate * Check whether all privileges in the required set are present. 412*7c478bd9Sstevel@tonic-gate */ 413*7c478bd9Sstevel@tonic-gate static int 414*7c478bd9Sstevel@tonic-gate secpolicy_require_set(const cred_t *cr, const priv_set_t *req, const char *msg) 415*7c478bd9Sstevel@tonic-gate { 416*7c478bd9Sstevel@tonic-gate int priv; 417*7c478bd9Sstevel@tonic-gate int pfound = -1; 418*7c478bd9Sstevel@tonic-gate priv_set_t pset; 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate if (req == PRIV_FULLSET ? HAS_ALLPRIVS(cr) : priv_issubset(req, 421*7c478bd9Sstevel@tonic-gate &CR_OEPRIV(cr))) { 422*7c478bd9Sstevel@tonic-gate return (0); 423*7c478bd9Sstevel@tonic-gate } 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate if (req == PRIV_FULLSET || priv_isfullset(req)) { 426*7c478bd9Sstevel@tonic-gate priv_policy_err(cr, PRIV_ALL, B_FALSE, msg); 427*7c478bd9Sstevel@tonic-gate return (EACCES); 428*7c478bd9Sstevel@tonic-gate } 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate pset = CR_OEPRIV(cr); /* present privileges */ 431*7c478bd9Sstevel@tonic-gate priv_inverse(&pset); /* all non present privileges */ 432*7c478bd9Sstevel@tonic-gate priv_intersect(req, &pset); /* the actual missing privs */ 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT 435*7c478bd9Sstevel@tonic-gate if (audit_active) 436*7c478bd9Sstevel@tonic-gate audit_priv(PRIV_NONE, &pset, 0); 437*7c478bd9Sstevel@tonic-gate #endif 438*7c478bd9Sstevel@tonic-gate /* 439*7c478bd9Sstevel@tonic-gate * Privilege debugging; special case "one privilege in set". 440*7c478bd9Sstevel@tonic-gate */ 441*7c478bd9Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) || curthread->t_pre_sys) { 442*7c478bd9Sstevel@tonic-gate for (priv = 0; priv < nprivs; priv++) { 443*7c478bd9Sstevel@tonic-gate if (priv_ismember(&pset, priv)) { 444*7c478bd9Sstevel@tonic-gate if (pfound != -1) { 445*7c478bd9Sstevel@tonic-gate /* Multiple missing privs */ 446*7c478bd9Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_MULTIPLE, 447*7c478bd9Sstevel@tonic-gate msg); 448*7c478bd9Sstevel@tonic-gate return (EACCES); 449*7c478bd9Sstevel@tonic-gate } 450*7c478bd9Sstevel@tonic-gate pfound = priv; 451*7c478bd9Sstevel@tonic-gate } 452*7c478bd9Sstevel@tonic-gate } 453*7c478bd9Sstevel@tonic-gate ASSERT(pfound != -1); 454*7c478bd9Sstevel@tonic-gate /* Just the one missing privilege */ 455*7c478bd9Sstevel@tonic-gate priv_policy_errmsg(cr, pfound, msg); 456*7c478bd9Sstevel@tonic-gate } 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate return (EACCES); 459*7c478bd9Sstevel@tonic-gate } 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate /* 462*7c478bd9Sstevel@tonic-gate * Called when an operation requires that the caller be in the 463*7c478bd9Sstevel@tonic-gate * global zone, regardless of privilege. 464*7c478bd9Sstevel@tonic-gate */ 465*7c478bd9Sstevel@tonic-gate static int 466*7c478bd9Sstevel@tonic-gate priv_policy_global(const cred_t *cr) 467*7c478bd9Sstevel@tonic-gate { 468*7c478bd9Sstevel@tonic-gate if (crgetzoneid(cr) == GLOBAL_ZONEID) 469*7c478bd9Sstevel@tonic-gate return (0); /* success */ 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) || 472*7c478bd9Sstevel@tonic-gate curthread->t_pre_sys) { 473*7c478bd9Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_GLOBAL, NULL); 474*7c478bd9Sstevel@tonic-gate } 475*7c478bd9Sstevel@tonic-gate return (EPERM); 476*7c478bd9Sstevel@tonic-gate } 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate /* 479*7c478bd9Sstevel@tonic-gate * Changing process priority 480*7c478bd9Sstevel@tonic-gate */ 481*7c478bd9Sstevel@tonic-gate int 482*7c478bd9Sstevel@tonic-gate secpolicy_setpriority(const cred_t *cr) 483*7c478bd9Sstevel@tonic-gate { 484*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_PRIOCNTL, B_FALSE, EPERM, NULL)); 485*7c478bd9Sstevel@tonic-gate } 486*7c478bd9Sstevel@tonic-gate 487*7c478bd9Sstevel@tonic-gate /* 488*7c478bd9Sstevel@tonic-gate * Binding to a privileged port, port must be specified in host byte 489*7c478bd9Sstevel@tonic-gate * order. 490*7c478bd9Sstevel@tonic-gate */ 491*7c478bd9Sstevel@tonic-gate int 492*7c478bd9Sstevel@tonic-gate secpolicy_net_privaddr(const cred_t *cr, in_port_t port) 493*7c478bd9Sstevel@tonic-gate { 494*7c478bd9Sstevel@tonic-gate /* 495*7c478bd9Sstevel@tonic-gate * NFS ports, these are extra privileged ports, allow bind 496*7c478bd9Sstevel@tonic-gate * only if the SYS_NFS privilege is present. 497*7c478bd9Sstevel@tonic-gate */ 498*7c478bd9Sstevel@tonic-gate if (port == 2049 || port == 4045) 499*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_NFS, B_FALSE, EACCES, 500*7c478bd9Sstevel@tonic-gate "NFS port")); 501*7c478bd9Sstevel@tonic-gate else 502*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_NET_PRIVADDR, B_FALSE, EACCES, 503*7c478bd9Sstevel@tonic-gate NULL)); 504*7c478bd9Sstevel@tonic-gate } 505*7c478bd9Sstevel@tonic-gate 506*7c478bd9Sstevel@tonic-gate /* 507*7c478bd9Sstevel@tonic-gate * Common routine which determines whether a given credential can 508*7c478bd9Sstevel@tonic-gate * act on a given mount. 509*7c478bd9Sstevel@tonic-gate * When called through mount, the parameter needoptcheck is a pointer 510*7c478bd9Sstevel@tonic-gate * to a boolean variable which will be set to either true or false, 511*7c478bd9Sstevel@tonic-gate * depending on whether the mount policy should change the mount options. 512*7c478bd9Sstevel@tonic-gate * In all other cases, needoptcheck should be a NULL pointer. 513*7c478bd9Sstevel@tonic-gate */ 514*7c478bd9Sstevel@tonic-gate static int 515*7c478bd9Sstevel@tonic-gate secpolicy_fs_common(cred_t *cr, vnode_t *mvp, const vfs_t *vfsp, 516*7c478bd9Sstevel@tonic-gate boolean_t *needoptcheck) 517*7c478bd9Sstevel@tonic-gate { 518*7c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 519*7c478bd9Sstevel@tonic-gate boolean_t mounting = needoptcheck != NULL; 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate /* 522*7c478bd9Sstevel@tonic-gate * Short circuit the following cases: 523*7c478bd9Sstevel@tonic-gate * vfsp == NULL or mvp == NULL (pure privilege check) 524*7c478bd9Sstevel@tonic-gate * have all privileges - no further checks required 525*7c478bd9Sstevel@tonic-gate * and no mount options need to be set. 526*7c478bd9Sstevel@tonic-gate */ 527*7c478bd9Sstevel@tonic-gate if (vfsp == NULL || mvp == NULL || HAS_ALLPRIVS(cr)) { 528*7c478bd9Sstevel@tonic-gate if (mounting) 529*7c478bd9Sstevel@tonic-gate *needoptcheck = B_FALSE; 530*7c478bd9Sstevel@tonic-gate 531*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_MOUNT, allzone, EPERM, NULL)); 532*7c478bd9Sstevel@tonic-gate } 533*7c478bd9Sstevel@tonic-gate 534*7c478bd9Sstevel@tonic-gate /* 535*7c478bd9Sstevel@tonic-gate * When operating on an existing mount (either we're not mounting 536*7c478bd9Sstevel@tonic-gate * or we're doing a remount and VFS_REMOUNT will be set), zones 537*7c478bd9Sstevel@tonic-gate * can operate only on mounts established by the zone itself. 538*7c478bd9Sstevel@tonic-gate * When remounting, we're interested in the covered vnode and 539*7c478bd9Sstevel@tonic-gate * not the directory vnode which was passed in. 540*7c478bd9Sstevel@tonic-gate */ 541*7c478bd9Sstevel@tonic-gate if (!mounting || (vfsp->vfs_flag & VFS_REMOUNT) != 0) { 542*7c478bd9Sstevel@tonic-gate zoneid_t zoneid = crgetzoneid(cr); 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate if (zoneid != GLOBAL_ZONEID && 545*7c478bd9Sstevel@tonic-gate vfsp->vfs_zone->zone_id != zoneid) { 546*7c478bd9Sstevel@tonic-gate return (EPERM); 547*7c478bd9Sstevel@tonic-gate } 548*7c478bd9Sstevel@tonic-gate /* 549*7c478bd9Sstevel@tonic-gate * If it's a remount, get the underlying mount point. 550*7c478bd9Sstevel@tonic-gate * This check should really be (vfsp->vfs_flag & VFS_REMOUNT) 551*7c478bd9Sstevel@tonic-gate * but we cannot depend on the VFS_REMOUNT flag being set 552*7c478bd9Sstevel@tonic-gate * correctly if we're not in a mount system call. 553*7c478bd9Sstevel@tonic-gate * But if we get here and we're mounting we're guaranteed 554*7c478bd9Sstevel@tonic-gate * that VFS_REMOUNT is set by the logic above. 555*7c478bd9Sstevel@tonic-gate */ 556*7c478bd9Sstevel@tonic-gate if (mounting) 557*7c478bd9Sstevel@tonic-gate mvp = vfsp->vfs_vnodecovered; 558*7c478bd9Sstevel@tonic-gate } 559*7c478bd9Sstevel@tonic-gate 560*7c478bd9Sstevel@tonic-gate if (mounting) 561*7c478bd9Sstevel@tonic-gate *needoptcheck = B_TRUE; 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate /* 564*7c478bd9Sstevel@tonic-gate * Overlay mounts may hide important stuff; if you can't write to a 565*7c478bd9Sstevel@tonic-gate * mount point but would be able to mount on top of it, you can 566*7c478bd9Sstevel@tonic-gate * escalate your privileges. 567*7c478bd9Sstevel@tonic-gate * So we go about asking the same questions namefs does when it 568*7c478bd9Sstevel@tonic-gate * decides whether you can mount over a file or not but with the 569*7c478bd9Sstevel@tonic-gate * added restriction that you can only mount on top of a regular 570*7c478bd9Sstevel@tonic-gate * file or directory. 571*7c478bd9Sstevel@tonic-gate * If we have all the zone's privileges, we skip all other checks, 572*7c478bd9Sstevel@tonic-gate * or else we may actually get in trouble inside the automounter. 573*7c478bd9Sstevel@tonic-gate */ 574*7c478bd9Sstevel@tonic-gate if ((mvp->v_flag & VROOT) != 0 || 575*7c478bd9Sstevel@tonic-gate (mvp->v_type != VDIR && mvp->v_type != VREG) || 576*7c478bd9Sstevel@tonic-gate HAS_ALLZONEPRIVS(cr)) { 577*7c478bd9Sstevel@tonic-gate allzone = B_TRUE; 578*7c478bd9Sstevel@tonic-gate } else { 579*7c478bd9Sstevel@tonic-gate vattr_t va; 580*7c478bd9Sstevel@tonic-gate int err; 581*7c478bd9Sstevel@tonic-gate 582*7c478bd9Sstevel@tonic-gate va.va_mask = AT_UID|AT_MODE; 583*7c478bd9Sstevel@tonic-gate err = VOP_GETATTR(mvp, &va, 0, cr); 584*7c478bd9Sstevel@tonic-gate if (err != 0) 585*7c478bd9Sstevel@tonic-gate return (err); 586*7c478bd9Sstevel@tonic-gate 587*7c478bd9Sstevel@tonic-gate if ((err = secpolicy_vnode_owner(cr, va.va_uid)) != 0) 588*7c478bd9Sstevel@tonic-gate return (err); 589*7c478bd9Sstevel@tonic-gate 590*7c478bd9Sstevel@tonic-gate if ((va.va_mode & VWRITE) == 0 && 591*7c478bd9Sstevel@tonic-gate secpolicy_vnode_access(cr, mvp, va.va_uid, VWRITE) != 0) { 592*7c478bd9Sstevel@tonic-gate return (EACCES); 593*7c478bd9Sstevel@tonic-gate } 594*7c478bd9Sstevel@tonic-gate } 595*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_MOUNT, allzone, EPERM, NULL)); 596*7c478bd9Sstevel@tonic-gate } 597*7c478bd9Sstevel@tonic-gate 598*7c478bd9Sstevel@tonic-gate int 599*7c478bd9Sstevel@tonic-gate secpolicy_fs_mount(cred_t *cr, vnode_t *mvp, struct vfs *vfsp) 600*7c478bd9Sstevel@tonic-gate { 601*7c478bd9Sstevel@tonic-gate boolean_t needoptchk; 602*7c478bd9Sstevel@tonic-gate int error; 603*7c478bd9Sstevel@tonic-gate 604*7c478bd9Sstevel@tonic-gate error = secpolicy_fs_common(cr, mvp, vfsp, &needoptchk); 605*7c478bd9Sstevel@tonic-gate 606*7c478bd9Sstevel@tonic-gate if (error == 0 && needoptchk) { 607*7c478bd9Sstevel@tonic-gate boolean_t amsuper = HAS_ALLZONEPRIVS(cr); 608*7c478bd9Sstevel@tonic-gate 609*7c478bd9Sstevel@tonic-gate /* 610*7c478bd9Sstevel@tonic-gate * Third check; if we don't have either "nosuid" or 611*7c478bd9Sstevel@tonic-gate * both "nosetuid" and "nodevices", then we add 612*7c478bd9Sstevel@tonic-gate * "nosuid"; this depends on how the current 613*7c478bd9Sstevel@tonic-gate * implementation works (it first checks nosuid). In a 614*7c478bd9Sstevel@tonic-gate * zone, a user with all zone privileges can mount with 615*7c478bd9Sstevel@tonic-gate * "setuid" but never with "devices". 616*7c478bd9Sstevel@tonic-gate */ 617*7c478bd9Sstevel@tonic-gate if (!vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL) && 618*7c478bd9Sstevel@tonic-gate (!vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL) || 619*7c478bd9Sstevel@tonic-gate !vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL))) { 620*7c478bd9Sstevel@tonic-gate if (crgetzoneid(cr) == GLOBAL_ZONEID || !amsuper) 621*7c478bd9Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_NOSUID, NULL, 0); 622*7c478bd9Sstevel@tonic-gate else 623*7c478bd9Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_NODEVICES, NULL, 0); 624*7c478bd9Sstevel@tonic-gate } 625*7c478bd9Sstevel@tonic-gate /* 626*7c478bd9Sstevel@tonic-gate * If we're not the local super user, we set the "restrict" 627*7c478bd9Sstevel@tonic-gate * option to indicate to automountd that this mount should 628*7c478bd9Sstevel@tonic-gate * be handled with care. 629*7c478bd9Sstevel@tonic-gate */ 630*7c478bd9Sstevel@tonic-gate if (!amsuper) 631*7c478bd9Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_RESTRICT, NULL, 0); 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate } 634*7c478bd9Sstevel@tonic-gate return (error); 635*7c478bd9Sstevel@tonic-gate } 636*7c478bd9Sstevel@tonic-gate 637*7c478bd9Sstevel@tonic-gate /* 638*7c478bd9Sstevel@tonic-gate * Does the policy computations for "ownership" of a mount; 639*7c478bd9Sstevel@tonic-gate * here ownership is defined as the ability to "mount" 640*7c478bd9Sstevel@tonic-gate * the filesystem originally. The rootvfs doesn't cover any 641*7c478bd9Sstevel@tonic-gate * vnodes; we attribute its ownership to the rootvp. 642*7c478bd9Sstevel@tonic-gate */ 643*7c478bd9Sstevel@tonic-gate static int 644*7c478bd9Sstevel@tonic-gate secpolicy_fs_owner(cred_t *cr, const struct vfs *vfsp) 645*7c478bd9Sstevel@tonic-gate { 646*7c478bd9Sstevel@tonic-gate vnode_t *mvp; 647*7c478bd9Sstevel@tonic-gate 648*7c478bd9Sstevel@tonic-gate extern vnode_t *rootvp; 649*7c478bd9Sstevel@tonic-gate extern vfs_t *rootvfs; 650*7c478bd9Sstevel@tonic-gate 651*7c478bd9Sstevel@tonic-gate if (vfsp == NULL) 652*7c478bd9Sstevel@tonic-gate mvp = NULL; 653*7c478bd9Sstevel@tonic-gate else if (vfsp == rootvfs) 654*7c478bd9Sstevel@tonic-gate mvp = rootvp; 655*7c478bd9Sstevel@tonic-gate else 656*7c478bd9Sstevel@tonic-gate mvp = vfsp->vfs_vnodecovered; 657*7c478bd9Sstevel@tonic-gate 658*7c478bd9Sstevel@tonic-gate return (secpolicy_fs_common(cr, mvp, vfsp, NULL)); 659*7c478bd9Sstevel@tonic-gate } 660*7c478bd9Sstevel@tonic-gate 661*7c478bd9Sstevel@tonic-gate int 662*7c478bd9Sstevel@tonic-gate secpolicy_fs_unmount(cred_t *cr, struct vfs *vfsp) 663*7c478bd9Sstevel@tonic-gate { 664*7c478bd9Sstevel@tonic-gate return (secpolicy_fs_owner(cr, vfsp)); 665*7c478bd9Sstevel@tonic-gate } 666*7c478bd9Sstevel@tonic-gate 667*7c478bd9Sstevel@tonic-gate /* 668*7c478bd9Sstevel@tonic-gate * Quotas are a resource, but if one has the ability to mount a filesystem, he 669*7c478bd9Sstevel@tonic-gate * should be able to modify quotas on it. 670*7c478bd9Sstevel@tonic-gate */ 671*7c478bd9Sstevel@tonic-gate int 672*7c478bd9Sstevel@tonic-gate secpolicy_fs_quota(const cred_t *cr, const vfs_t *vfsp) 673*7c478bd9Sstevel@tonic-gate { 674*7c478bd9Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 675*7c478bd9Sstevel@tonic-gate } 676*7c478bd9Sstevel@tonic-gate 677*7c478bd9Sstevel@tonic-gate /* 678*7c478bd9Sstevel@tonic-gate * Exceeding minfree: also a per-mount resource constraint. 679*7c478bd9Sstevel@tonic-gate */ 680*7c478bd9Sstevel@tonic-gate int 681*7c478bd9Sstevel@tonic-gate secpolicy_fs_minfree(const cred_t *cr, const vfs_t *vfsp) 682*7c478bd9Sstevel@tonic-gate { 683*7c478bd9Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 684*7c478bd9Sstevel@tonic-gate } 685*7c478bd9Sstevel@tonic-gate 686*7c478bd9Sstevel@tonic-gate int 687*7c478bd9Sstevel@tonic-gate secpolicy_fs_config(const cred_t *cr, const vfs_t *vfsp) 688*7c478bd9Sstevel@tonic-gate { 689*7c478bd9Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 690*7c478bd9Sstevel@tonic-gate } 691*7c478bd9Sstevel@tonic-gate 692*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 693*7c478bd9Sstevel@tonic-gate int 694*7c478bd9Sstevel@tonic-gate secpolicy_fs_linkdir(const cred_t *cr, const vfs_t *vfsp) 695*7c478bd9Sstevel@tonic-gate { 696*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_LINKDIR, B_FALSE, EPERM, NULL)); 697*7c478bd9Sstevel@tonic-gate } 698*7c478bd9Sstevel@tonic-gate 699*7c478bd9Sstevel@tonic-gate /* 700*7c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_access() 701*7c478bd9Sstevel@tonic-gate * 702*7c478bd9Sstevel@tonic-gate * Parameters: Process credential 703*7c478bd9Sstevel@tonic-gate * vnode 704*7c478bd9Sstevel@tonic-gate * uid of owner of vnode 705*7c478bd9Sstevel@tonic-gate * permission bits not granted to the caller when examining 706*7c478bd9Sstevel@tonic-gate * file mode bits (i.e., when a process wants to open a 707*7c478bd9Sstevel@tonic-gate * mode 444 file for VREAD|VWRITE, this function should be 708*7c478bd9Sstevel@tonic-gate * called only with a VWRITE argument). 709*7c478bd9Sstevel@tonic-gate * 710*7c478bd9Sstevel@tonic-gate * Normal: Verifies that cred has the appropriate privileges to 711*7c478bd9Sstevel@tonic-gate * override the mode bits that were denied. 712*7c478bd9Sstevel@tonic-gate * 713*7c478bd9Sstevel@tonic-gate * Override: file_dac_execute - if VEXEC bit was denied and vnode is 714*7c478bd9Sstevel@tonic-gate * not a directory. 715*7c478bd9Sstevel@tonic-gate * file_dac_read - if VREAD bit was denied. 716*7c478bd9Sstevel@tonic-gate * file_dac_search - if VEXEC bit was denied and vnode is 717*7c478bd9Sstevel@tonic-gate * a directory. 718*7c478bd9Sstevel@tonic-gate * file_dac_write - if VWRITE bit was denied. 719*7c478bd9Sstevel@tonic-gate * 720*7c478bd9Sstevel@tonic-gate * Root owned files are special cased to protect system 721*7c478bd9Sstevel@tonic-gate * configuration files and such. 722*7c478bd9Sstevel@tonic-gate * 723*7c478bd9Sstevel@tonic-gate * Output: EACCES - if privilege check fails. 724*7c478bd9Sstevel@tonic-gate */ 725*7c478bd9Sstevel@tonic-gate 726*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 727*7c478bd9Sstevel@tonic-gate int 728*7c478bd9Sstevel@tonic-gate secpolicy_vnode_access(const cred_t *cr, vnode_t *vp, uid_t owner, mode_t mode) 729*7c478bd9Sstevel@tonic-gate { 730*7c478bd9Sstevel@tonic-gate if ((mode & VREAD) && 731*7c478bd9Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_FILE_DAC_READ, B_FALSE, EACCES, NULL) != 0) 732*7c478bd9Sstevel@tonic-gate return (EACCES); 733*7c478bd9Sstevel@tonic-gate 734*7c478bd9Sstevel@tonic-gate if (mode & VWRITE) { 735*7c478bd9Sstevel@tonic-gate boolean_t allzone; 736*7c478bd9Sstevel@tonic-gate 737*7c478bd9Sstevel@tonic-gate if (owner == 0 && cr->cr_uid != 0) 738*7c478bd9Sstevel@tonic-gate allzone = B_TRUE; 739*7c478bd9Sstevel@tonic-gate else 740*7c478bd9Sstevel@tonic-gate allzone = B_FALSE; 741*7c478bd9Sstevel@tonic-gate if (PRIV_POLICY(cr, PRIV_FILE_DAC_WRITE, allzone, EACCES, NULL) 742*7c478bd9Sstevel@tonic-gate != 0) 743*7c478bd9Sstevel@tonic-gate return (EACCES); 744*7c478bd9Sstevel@tonic-gate } 745*7c478bd9Sstevel@tonic-gate 746*7c478bd9Sstevel@tonic-gate if (mode & VEXEC) { 747*7c478bd9Sstevel@tonic-gate /* 748*7c478bd9Sstevel@tonic-gate * Directories use file_dac_search to override the execute bit. 749*7c478bd9Sstevel@tonic-gate */ 750*7c478bd9Sstevel@tonic-gate vtype_t vtype = vp->v_type; 751*7c478bd9Sstevel@tonic-gate 752*7c478bd9Sstevel@tonic-gate if (vtype == VDIR) 753*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_DAC_SEARCH, B_FALSE, 754*7c478bd9Sstevel@tonic-gate EACCES, NULL)); 755*7c478bd9Sstevel@tonic-gate else 756*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_DAC_EXECUTE, B_FALSE, 757*7c478bd9Sstevel@tonic-gate EACCES, NULL)); 758*7c478bd9Sstevel@tonic-gate } 759*7c478bd9Sstevel@tonic-gate return (0); 760*7c478bd9Sstevel@tonic-gate } 761*7c478bd9Sstevel@tonic-gate 762*7c478bd9Sstevel@tonic-gate /* 763*7c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_setid_modify() 764*7c478bd9Sstevel@tonic-gate * 765*7c478bd9Sstevel@tonic-gate * Normal: verify that subject can set the file setid flags. 766*7c478bd9Sstevel@tonic-gate * 767*7c478bd9Sstevel@tonic-gate * Output: EPERM - if not privileged. 768*7c478bd9Sstevel@tonic-gate */ 769*7c478bd9Sstevel@tonic-gate 770*7c478bd9Sstevel@tonic-gate static int 771*7c478bd9Sstevel@tonic-gate secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner) 772*7c478bd9Sstevel@tonic-gate { 773*7c478bd9Sstevel@tonic-gate /* If changing to suid root, must have all zone privs */ 774*7c478bd9Sstevel@tonic-gate boolean_t allzone = B_TRUE; 775*7c478bd9Sstevel@tonic-gate 776*7c478bd9Sstevel@tonic-gate if (owner != 0) { 777*7c478bd9Sstevel@tonic-gate if (owner == cr->cr_uid) 778*7c478bd9Sstevel@tonic-gate return (0); 779*7c478bd9Sstevel@tonic-gate allzone = B_FALSE; 780*7c478bd9Sstevel@tonic-gate } 781*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_SETID, allzone, EPERM, NULL)); 782*7c478bd9Sstevel@tonic-gate } 783*7c478bd9Sstevel@tonic-gate 784*7c478bd9Sstevel@tonic-gate /* 785*7c478bd9Sstevel@tonic-gate * Are we allowed to retain the set-uid/set-gid bits when 786*7c478bd9Sstevel@tonic-gate * changing ownership or when writing to a file? 787*7c478bd9Sstevel@tonic-gate * "issuid" should be true when set-uid; only in that case 788*7c478bd9Sstevel@tonic-gate * root ownership is checked (setgid is assumed). 789*7c478bd9Sstevel@tonic-gate */ 790*7c478bd9Sstevel@tonic-gate int 791*7c478bd9Sstevel@tonic-gate secpolicy_vnode_setid_retain(const cred_t *cred, boolean_t issuidroot) 792*7c478bd9Sstevel@tonic-gate { 793*7c478bd9Sstevel@tonic-gate if (issuidroot && !HAS_ALLZONEPRIVS(cred)) 794*7c478bd9Sstevel@tonic-gate return (EPERM); 795*7c478bd9Sstevel@tonic-gate 796*7c478bd9Sstevel@tonic-gate return (!PRIV_POLICY_CHOICE(cred, PRIV_FILE_SETID, B_FALSE)); 797*7c478bd9Sstevel@tonic-gate } 798*7c478bd9Sstevel@tonic-gate 799*7c478bd9Sstevel@tonic-gate /* 800*7c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_setids_setgids() 801*7c478bd9Sstevel@tonic-gate * 802*7c478bd9Sstevel@tonic-gate * Normal: verify that subject can set the file setgid flag. 803*7c478bd9Sstevel@tonic-gate * 804*7c478bd9Sstevel@tonic-gate * Output: EPERM - if not privileged 805*7c478bd9Sstevel@tonic-gate */ 806*7c478bd9Sstevel@tonic-gate 807*7c478bd9Sstevel@tonic-gate int 808*7c478bd9Sstevel@tonic-gate secpolicy_vnode_setids_setgids(const cred_t *cred, gid_t gid) 809*7c478bd9Sstevel@tonic-gate { 810*7c478bd9Sstevel@tonic-gate if (!groupmember(gid, cred)) 811*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_SETID, B_FALSE, EPERM, 812*7c478bd9Sstevel@tonic-gate NULL)); 813*7c478bd9Sstevel@tonic-gate return (0); 814*7c478bd9Sstevel@tonic-gate } 815*7c478bd9Sstevel@tonic-gate 816*7c478bd9Sstevel@tonic-gate /* 817*7c478bd9Sstevel@tonic-gate * Create a file with a group different than any of the groups allowed: 818*7c478bd9Sstevel@tonic-gate * the group of the directory the file is created in, the effective 819*7c478bd9Sstevel@tonic-gate * group or any of the supplementary groups. 820*7c478bd9Sstevel@tonic-gate */ 821*7c478bd9Sstevel@tonic-gate int 822*7c478bd9Sstevel@tonic-gate secpolicy_vnode_create_gid(const cred_t *cred) 823*7c478bd9Sstevel@tonic-gate { 824*7c478bd9Sstevel@tonic-gate if (HAS_PRIVILEGE(cred, PRIV_FILE_CHOWN)) 825*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_CHOWN, B_FALSE, EPERM, 826*7c478bd9Sstevel@tonic-gate NULL)); 827*7c478bd9Sstevel@tonic-gate else 828*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_CHOWN_SELF, B_FALSE, EPERM, 829*7c478bd9Sstevel@tonic-gate NULL)); 830*7c478bd9Sstevel@tonic-gate } 831*7c478bd9Sstevel@tonic-gate 832*7c478bd9Sstevel@tonic-gate /* 833*7c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_utime_modify() 834*7c478bd9Sstevel@tonic-gate * 835*7c478bd9Sstevel@tonic-gate * Normal: verify that subject can modify the utime on a file. 836*7c478bd9Sstevel@tonic-gate * 837*7c478bd9Sstevel@tonic-gate * Output: EPERM - if access denied. 838*7c478bd9Sstevel@tonic-gate */ 839*7c478bd9Sstevel@tonic-gate 840*7c478bd9Sstevel@tonic-gate static int 841*7c478bd9Sstevel@tonic-gate secpolicy_vnode_utime_modify(const cred_t *cred) 842*7c478bd9Sstevel@tonic-gate { 843*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_OWNER, B_FALSE, EPERM, 844*7c478bd9Sstevel@tonic-gate "modify file times")); 845*7c478bd9Sstevel@tonic-gate } 846*7c478bd9Sstevel@tonic-gate 847*7c478bd9Sstevel@tonic-gate 848*7c478bd9Sstevel@tonic-gate /* 849*7c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_setdac() 850*7c478bd9Sstevel@tonic-gate * 851*7c478bd9Sstevel@tonic-gate * Normal: verify that subject can modify the mode of a file. 852*7c478bd9Sstevel@tonic-gate * allzone privilege needed when modifying root owned object. 853*7c478bd9Sstevel@tonic-gate * 854*7c478bd9Sstevel@tonic-gate * Output: EPERM - if access denied. 855*7c478bd9Sstevel@tonic-gate */ 856*7c478bd9Sstevel@tonic-gate 857*7c478bd9Sstevel@tonic-gate int 858*7c478bd9Sstevel@tonic-gate secpolicy_vnode_setdac(const cred_t *cred, uid_t owner) 859*7c478bd9Sstevel@tonic-gate { 860*7c478bd9Sstevel@tonic-gate if (owner == cred->cr_uid) 861*7c478bd9Sstevel@tonic-gate return (0); 862*7c478bd9Sstevel@tonic-gate 863*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_OWNER, owner == 0, EPERM, NULL)); 864*7c478bd9Sstevel@tonic-gate } 865*7c478bd9Sstevel@tonic-gate /* 866*7c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_stky_modify() 867*7c478bd9Sstevel@tonic-gate * 868*7c478bd9Sstevel@tonic-gate * Normal: verify that subject can make a file a "sticky". 869*7c478bd9Sstevel@tonic-gate * 870*7c478bd9Sstevel@tonic-gate * Output: EPERM - if access denied. 871*7c478bd9Sstevel@tonic-gate */ 872*7c478bd9Sstevel@tonic-gate 873*7c478bd9Sstevel@tonic-gate int 874*7c478bd9Sstevel@tonic-gate secpolicy_vnode_stky_modify(const cred_t *cred) 875*7c478bd9Sstevel@tonic-gate { 876*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_SYS_CONFIG, B_FALSE, EPERM, 877*7c478bd9Sstevel@tonic-gate "set file sticky")); 878*7c478bd9Sstevel@tonic-gate } 879*7c478bd9Sstevel@tonic-gate 880*7c478bd9Sstevel@tonic-gate /* 881*7c478bd9Sstevel@tonic-gate * Policy determines whether we can remove an entry from a directory, 882*7c478bd9Sstevel@tonic-gate * regardless of permission bits. 883*7c478bd9Sstevel@tonic-gate */ 884*7c478bd9Sstevel@tonic-gate int 885*7c478bd9Sstevel@tonic-gate secpolicy_vnode_remove(const cred_t *cr) 886*7c478bd9Sstevel@tonic-gate { 887*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_OWNER, B_FALSE, EACCES, 888*7c478bd9Sstevel@tonic-gate "sticky directory")); 889*7c478bd9Sstevel@tonic-gate } 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate int 892*7c478bd9Sstevel@tonic-gate secpolicy_vnode_owner(const cred_t *cr, uid_t owner) 893*7c478bd9Sstevel@tonic-gate { 894*7c478bd9Sstevel@tonic-gate boolean_t allzone = (owner == 0); 895*7c478bd9Sstevel@tonic-gate 896*7c478bd9Sstevel@tonic-gate if (owner == cr->cr_uid) 897*7c478bd9Sstevel@tonic-gate return (0); 898*7c478bd9Sstevel@tonic-gate 899*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_OWNER, allzone, EPERM, NULL)); 900*7c478bd9Sstevel@tonic-gate } 901*7c478bd9Sstevel@tonic-gate 902*7c478bd9Sstevel@tonic-gate /* 903*7c478bd9Sstevel@tonic-gate * This function checks the policy decisions surrounding the 904*7c478bd9Sstevel@tonic-gate * vop setattr call. 905*7c478bd9Sstevel@tonic-gate * 906*7c478bd9Sstevel@tonic-gate * It should be called after sufficient locks have been established 907*7c478bd9Sstevel@tonic-gate * on the underlying data structures. No concurrent modifications 908*7c478bd9Sstevel@tonic-gate * should be allowed. 909*7c478bd9Sstevel@tonic-gate * 910*7c478bd9Sstevel@tonic-gate * The caller must pass in unlocked version of its vaccess function 911*7c478bd9Sstevel@tonic-gate * this is required because vop_access function should lock the 912*7c478bd9Sstevel@tonic-gate * node for reading. A three argument function should be defined 913*7c478bd9Sstevel@tonic-gate * which accepts the following argument: 914*7c478bd9Sstevel@tonic-gate * A pointer to the internal "node" type (inode *) 915*7c478bd9Sstevel@tonic-gate * vnode access bits (VREAD|VWRITE|VEXEC) 916*7c478bd9Sstevel@tonic-gate * a pointer to the credential 917*7c478bd9Sstevel@tonic-gate * 918*7c478bd9Sstevel@tonic-gate * This function makes the following policy decisions: 919*7c478bd9Sstevel@tonic-gate * 920*7c478bd9Sstevel@tonic-gate * - change permissions 921*7c478bd9Sstevel@tonic-gate * - permission to change file mode if not owner 922*7c478bd9Sstevel@tonic-gate * - permission to add sticky bit to non-directory 923*7c478bd9Sstevel@tonic-gate * - permission to add set-gid bit 924*7c478bd9Sstevel@tonic-gate * 925*7c478bd9Sstevel@tonic-gate * The ovap argument should include AT_MODE|AT_UID|AT_GID. 926*7c478bd9Sstevel@tonic-gate * 927*7c478bd9Sstevel@tonic-gate * If the vap argument does not include AT_MODE, the mode will be copied from 928*7c478bd9Sstevel@tonic-gate * ovap. In certain situations set-uid/set-gid bits need to be removed; 929*7c478bd9Sstevel@tonic-gate * this is done by marking vap->va_mask to include AT_MODE and va_mode 930*7c478bd9Sstevel@tonic-gate * is updated to the newly computed mode. 931*7c478bd9Sstevel@tonic-gate */ 932*7c478bd9Sstevel@tonic-gate 933*7c478bd9Sstevel@tonic-gate int 934*7c478bd9Sstevel@tonic-gate secpolicy_vnode_setattr(cred_t *cr, struct vnode *vp, struct vattr *vap, 935*7c478bd9Sstevel@tonic-gate const struct vattr *ovap, int flags, 936*7c478bd9Sstevel@tonic-gate int unlocked_access(void *, int, cred_t *), 937*7c478bd9Sstevel@tonic-gate void *node) 938*7c478bd9Sstevel@tonic-gate { 939*7c478bd9Sstevel@tonic-gate int mask = vap->va_mask; 940*7c478bd9Sstevel@tonic-gate int error = 0; 941*7c478bd9Sstevel@tonic-gate 942*7c478bd9Sstevel@tonic-gate if (mask & AT_SIZE) { 943*7c478bd9Sstevel@tonic-gate if (vp->v_type == VDIR) { 944*7c478bd9Sstevel@tonic-gate error = EISDIR; 945*7c478bd9Sstevel@tonic-gate goto out; 946*7c478bd9Sstevel@tonic-gate } 947*7c478bd9Sstevel@tonic-gate error = unlocked_access(node, VWRITE, cr); 948*7c478bd9Sstevel@tonic-gate if (error) 949*7c478bd9Sstevel@tonic-gate goto out; 950*7c478bd9Sstevel@tonic-gate } 951*7c478bd9Sstevel@tonic-gate if (mask & AT_MODE) { 952*7c478bd9Sstevel@tonic-gate /* 953*7c478bd9Sstevel@tonic-gate * If not the owner of the file then check privilege 954*7c478bd9Sstevel@tonic-gate * for two things: the privilege to set the mode at all 955*7c478bd9Sstevel@tonic-gate * and, if we're setting setuid, we also need permissions 956*7c478bd9Sstevel@tonic-gate * to add the set-uid bit, if we're not the owner. 957*7c478bd9Sstevel@tonic-gate * In the specific case of creating a set-uid root 958*7c478bd9Sstevel@tonic-gate * file, we need even more permissions. 959*7c478bd9Sstevel@tonic-gate */ 960*7c478bd9Sstevel@tonic-gate if ((error = secpolicy_vnode_setdac(cr, ovap->va_uid)) != 0) 961*7c478bd9Sstevel@tonic-gate goto out; 962*7c478bd9Sstevel@tonic-gate 963*7c478bd9Sstevel@tonic-gate if ((vap->va_mode & S_ISUID) != 0 && 964*7c478bd9Sstevel@tonic-gate (error = secpolicy_vnode_setid_modify(cr, 965*7c478bd9Sstevel@tonic-gate ovap->va_uid)) != 0) { 966*7c478bd9Sstevel@tonic-gate goto out; 967*7c478bd9Sstevel@tonic-gate } 968*7c478bd9Sstevel@tonic-gate 969*7c478bd9Sstevel@tonic-gate /* 970*7c478bd9Sstevel@tonic-gate * Check privilege if attempting to set the 971*7c478bd9Sstevel@tonic-gate * sticky bit on a non-directory. 972*7c478bd9Sstevel@tonic-gate */ 973*7c478bd9Sstevel@tonic-gate if (vp->v_type != VDIR && (vap->va_mode & S_ISVTX) != 0 && 974*7c478bd9Sstevel@tonic-gate secpolicy_vnode_stky_modify(cr) != 0) { 975*7c478bd9Sstevel@tonic-gate vap->va_mode &= ~S_ISVTX; 976*7c478bd9Sstevel@tonic-gate } 977*7c478bd9Sstevel@tonic-gate 978*7c478bd9Sstevel@tonic-gate /* 979*7c478bd9Sstevel@tonic-gate * Check for privilege if attempting to set the 980*7c478bd9Sstevel@tonic-gate * group-id bit. 981*7c478bd9Sstevel@tonic-gate */ 982*7c478bd9Sstevel@tonic-gate if ((vap->va_mode & S_ISGID) != 0 && 983*7c478bd9Sstevel@tonic-gate secpolicy_vnode_setids_setgids(cr, ovap->va_gid) != 0) { 984*7c478bd9Sstevel@tonic-gate vap->va_mode &= ~S_ISGID; 985*7c478bd9Sstevel@tonic-gate } 986*7c478bd9Sstevel@tonic-gate 987*7c478bd9Sstevel@tonic-gate } else 988*7c478bd9Sstevel@tonic-gate vap->va_mode = ovap->va_mode; 989*7c478bd9Sstevel@tonic-gate 990*7c478bd9Sstevel@tonic-gate if (mask & (AT_UID|AT_GID)) { 991*7c478bd9Sstevel@tonic-gate boolean_t checkpriv = B_FALSE; 992*7c478bd9Sstevel@tonic-gate int priv; 993*7c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 994*7c478bd9Sstevel@tonic-gate 995*7c478bd9Sstevel@tonic-gate /* 996*7c478bd9Sstevel@tonic-gate * Chowning files. 997*7c478bd9Sstevel@tonic-gate * 998*7c478bd9Sstevel@tonic-gate * If you are the file owner: 999*7c478bd9Sstevel@tonic-gate * chown to other uid FILE_CHOWN_SELF 1000*7c478bd9Sstevel@tonic-gate * chown to gid (non-member) FILE_CHOWN_SELF 1001*7c478bd9Sstevel@tonic-gate * chown to gid (member) <none> 1002*7c478bd9Sstevel@tonic-gate * 1003*7c478bd9Sstevel@tonic-gate * Instead of PRIV_FILE_CHOWN_SELF, FILE_CHOWN is also 1004*7c478bd9Sstevel@tonic-gate * acceptable but the first one is reported when debugging. 1005*7c478bd9Sstevel@tonic-gate * 1006*7c478bd9Sstevel@tonic-gate * If you are not the file owner: 1007*7c478bd9Sstevel@tonic-gate * chown from root PRIV_FILE_CHOWN + zone 1008*7c478bd9Sstevel@tonic-gate * chown from other to any PRIV_FILE_CHOWN 1009*7c478bd9Sstevel@tonic-gate * 1010*7c478bd9Sstevel@tonic-gate */ 1011*7c478bd9Sstevel@tonic-gate if (cr->cr_uid != ovap->va_uid) { 1012*7c478bd9Sstevel@tonic-gate checkpriv = B_TRUE; 1013*7c478bd9Sstevel@tonic-gate allzone = (ovap->va_uid == 0); 1014*7c478bd9Sstevel@tonic-gate priv = PRIV_FILE_CHOWN; 1015*7c478bd9Sstevel@tonic-gate } else { 1016*7c478bd9Sstevel@tonic-gate if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || 1017*7c478bd9Sstevel@tonic-gate ((mask & AT_GID) && vap->va_gid != ovap->va_gid && 1018*7c478bd9Sstevel@tonic-gate !groupmember(vap->va_gid, cr))) { 1019*7c478bd9Sstevel@tonic-gate checkpriv = B_TRUE; 1020*7c478bd9Sstevel@tonic-gate priv = HAS_PRIVILEGE(cr, PRIV_FILE_CHOWN) ? 1021*7c478bd9Sstevel@tonic-gate PRIV_FILE_CHOWN : PRIV_FILE_CHOWN_SELF; 1022*7c478bd9Sstevel@tonic-gate } 1023*7c478bd9Sstevel@tonic-gate } 1024*7c478bd9Sstevel@tonic-gate /* 1025*7c478bd9Sstevel@tonic-gate * If necessary, check privilege to see if update can be done. 1026*7c478bd9Sstevel@tonic-gate */ 1027*7c478bd9Sstevel@tonic-gate if (checkpriv && 1028*7c478bd9Sstevel@tonic-gate (error = PRIV_POLICY(cr, priv, allzone, EPERM, NULL)) 1029*7c478bd9Sstevel@tonic-gate != 0) { 1030*7c478bd9Sstevel@tonic-gate goto out; 1031*7c478bd9Sstevel@tonic-gate } 1032*7c478bd9Sstevel@tonic-gate 1033*7c478bd9Sstevel@tonic-gate /* 1034*7c478bd9Sstevel@tonic-gate * If the file has either the set UID or set GID bits 1035*7c478bd9Sstevel@tonic-gate * set and the caller can set the bits, then leave them. 1036*7c478bd9Sstevel@tonic-gate */ 1037*7c478bd9Sstevel@tonic-gate if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0 && 1038*7c478bd9Sstevel@tonic-gate secpolicy_vnode_setid_retain(cr, 1039*7c478bd9Sstevel@tonic-gate (vap->va_mode & S_ISUID) != 0 && 1040*7c478bd9Sstevel@tonic-gate (mask & AT_UID) != 0 && vap->va_uid == 0) != 0) { 1041*7c478bd9Sstevel@tonic-gate /* Copied from ovap above if AT_MODE not specified */ 1042*7c478bd9Sstevel@tonic-gate vap->va_mask |= AT_MODE; 1043*7c478bd9Sstevel@tonic-gate vap->va_mode &= ~(S_ISUID|S_ISGID); 1044*7c478bd9Sstevel@tonic-gate } 1045*7c478bd9Sstevel@tonic-gate } 1046*7c478bd9Sstevel@tonic-gate if (mask & (AT_ATIME|AT_MTIME)) { 1047*7c478bd9Sstevel@tonic-gate /* 1048*7c478bd9Sstevel@tonic-gate * If not the file owner and not otherwise privileged, 1049*7c478bd9Sstevel@tonic-gate * always return an error when setting the 1050*7c478bd9Sstevel@tonic-gate * time other than the current (ATTR_UTIME flag set). 1051*7c478bd9Sstevel@tonic-gate * If setting the current time (ATTR_UTIME not set) then 1052*7c478bd9Sstevel@tonic-gate * unlocked_access will check permissions according to policy. 1053*7c478bd9Sstevel@tonic-gate */ 1054*7c478bd9Sstevel@tonic-gate if (cr->cr_uid != ovap->va_uid) { 1055*7c478bd9Sstevel@tonic-gate if (flags & ATTR_UTIME) 1056*7c478bd9Sstevel@tonic-gate error = secpolicy_vnode_utime_modify(cr); 1057*7c478bd9Sstevel@tonic-gate else { 1058*7c478bd9Sstevel@tonic-gate error = unlocked_access(node, VWRITE, cr); 1059*7c478bd9Sstevel@tonic-gate if (error == EACCES && 1060*7c478bd9Sstevel@tonic-gate secpolicy_vnode_utime_modify(cr) == 0) 1061*7c478bd9Sstevel@tonic-gate error = 0; 1062*7c478bd9Sstevel@tonic-gate } 1063*7c478bd9Sstevel@tonic-gate if (error) 1064*7c478bd9Sstevel@tonic-gate goto out; 1065*7c478bd9Sstevel@tonic-gate } 1066*7c478bd9Sstevel@tonic-gate } 1067*7c478bd9Sstevel@tonic-gate out: 1068*7c478bd9Sstevel@tonic-gate return (error); 1069*7c478bd9Sstevel@tonic-gate } 1070*7c478bd9Sstevel@tonic-gate 1071*7c478bd9Sstevel@tonic-gate /* 1072*7c478bd9Sstevel@tonic-gate * Name: secpolicy_pcfs_modify_bootpartition() 1073*7c478bd9Sstevel@tonic-gate * 1074*7c478bd9Sstevel@tonic-gate * Normal: verify that subject can modify a pcfs boot partition. 1075*7c478bd9Sstevel@tonic-gate * 1076*7c478bd9Sstevel@tonic-gate * Output: EACCES - if privilege check failed. 1077*7c478bd9Sstevel@tonic-gate */ 1078*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1079*7c478bd9Sstevel@tonic-gate int 1080*7c478bd9Sstevel@tonic-gate secpolicy_pcfs_modify_bootpartition(const cred_t *cred) 1081*7c478bd9Sstevel@tonic-gate { 1082*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_ALL, B_FALSE, EACCES, 1083*7c478bd9Sstevel@tonic-gate "modify pcfs boot partition")); 1084*7c478bd9Sstevel@tonic-gate } 1085*7c478bd9Sstevel@tonic-gate 1086*7c478bd9Sstevel@tonic-gate /* 1087*7c478bd9Sstevel@tonic-gate * System V IPC routines 1088*7c478bd9Sstevel@tonic-gate */ 1089*7c478bd9Sstevel@tonic-gate int 1090*7c478bd9Sstevel@tonic-gate secpolicy_ipc_owner(const cred_t *cr, const struct kipc_perm *ip) 1091*7c478bd9Sstevel@tonic-gate { 1092*7c478bd9Sstevel@tonic-gate if (crgetzoneid(cr) != ip->ipc_zoneid || 1093*7c478bd9Sstevel@tonic-gate (cr->cr_uid != ip->ipc_uid && cr->cr_uid != ip->ipc_cuid)) { 1094*7c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 1095*7c478bd9Sstevel@tonic-gate if (ip->ipc_uid == 0 || ip->ipc_cuid == 0) 1096*7c478bd9Sstevel@tonic-gate allzone = B_TRUE; 1097*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_OWNER, allzone, EPERM, NULL)); 1098*7c478bd9Sstevel@tonic-gate } 1099*7c478bd9Sstevel@tonic-gate return (0); 1100*7c478bd9Sstevel@tonic-gate } 1101*7c478bd9Sstevel@tonic-gate 1102*7c478bd9Sstevel@tonic-gate int 1103*7c478bd9Sstevel@tonic-gate secpolicy_ipc_config(const cred_t *cr) 1104*7c478bd9Sstevel@tonic-gate { 1105*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_IPC_CONFIG, B_FALSE, EPERM, NULL)); 1106*7c478bd9Sstevel@tonic-gate } 1107*7c478bd9Sstevel@tonic-gate 1108*7c478bd9Sstevel@tonic-gate int 1109*7c478bd9Sstevel@tonic-gate secpolicy_ipc_access(const cred_t *cr, const struct kipc_perm *ip, mode_t mode) 1110*7c478bd9Sstevel@tonic-gate { 1111*7c478bd9Sstevel@tonic-gate 1112*7c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 1113*7c478bd9Sstevel@tonic-gate 1114*7c478bd9Sstevel@tonic-gate ASSERT((mode & (MSG_R|MSG_W)) != 0); 1115*7c478bd9Sstevel@tonic-gate 1116*7c478bd9Sstevel@tonic-gate if ((mode & MSG_R) && 1117*7c478bd9Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_IPC_DAC_READ, allzone, EACCES, NULL) != 0) 1118*7c478bd9Sstevel@tonic-gate return (EACCES); 1119*7c478bd9Sstevel@tonic-gate 1120*7c478bd9Sstevel@tonic-gate if (mode & MSG_W) { 1121*7c478bd9Sstevel@tonic-gate if (cr->cr_uid != 0 && (ip->ipc_uid == 0 || ip->ipc_cuid == 0)) 1122*7c478bd9Sstevel@tonic-gate allzone = B_TRUE; 1123*7c478bd9Sstevel@tonic-gate 1124*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_DAC_WRITE, allzone, EACCES, 1125*7c478bd9Sstevel@tonic-gate NULL)); 1126*7c478bd9Sstevel@tonic-gate } 1127*7c478bd9Sstevel@tonic-gate return (0); 1128*7c478bd9Sstevel@tonic-gate } 1129*7c478bd9Sstevel@tonic-gate 1130*7c478bd9Sstevel@tonic-gate int 1131*7c478bd9Sstevel@tonic-gate secpolicy_rsm_access(const cred_t *cr, uid_t owner, mode_t mode) 1132*7c478bd9Sstevel@tonic-gate { 1133*7c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 1134*7c478bd9Sstevel@tonic-gate 1135*7c478bd9Sstevel@tonic-gate ASSERT((mode & (MSG_R|MSG_W)) != 0); 1136*7c478bd9Sstevel@tonic-gate 1137*7c478bd9Sstevel@tonic-gate if ((mode & MSG_R) && 1138*7c478bd9Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_IPC_DAC_READ, allzone, EACCES, NULL) != 0) 1139*7c478bd9Sstevel@tonic-gate return (EACCES); 1140*7c478bd9Sstevel@tonic-gate 1141*7c478bd9Sstevel@tonic-gate if (mode & MSG_W) { 1142*7c478bd9Sstevel@tonic-gate if (cr->cr_uid != 0 && owner == 0) 1143*7c478bd9Sstevel@tonic-gate allzone = B_TRUE; 1144*7c478bd9Sstevel@tonic-gate 1145*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_DAC_WRITE, allzone, EACCES, 1146*7c478bd9Sstevel@tonic-gate NULL)); 1147*7c478bd9Sstevel@tonic-gate } 1148*7c478bd9Sstevel@tonic-gate return (0); 1149*7c478bd9Sstevel@tonic-gate } 1150*7c478bd9Sstevel@tonic-gate 1151*7c478bd9Sstevel@tonic-gate /* 1152*7c478bd9Sstevel@tonic-gate * Audit configuration. 1153*7c478bd9Sstevel@tonic-gate */ 1154*7c478bd9Sstevel@tonic-gate int 1155*7c478bd9Sstevel@tonic-gate secpolicy_audit_config(const cred_t *cr) 1156*7c478bd9Sstevel@tonic-gate { 1157*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_AUDIT, B_FALSE, EPERM, NULL)); 1158*7c478bd9Sstevel@tonic-gate } 1159*7c478bd9Sstevel@tonic-gate 1160*7c478bd9Sstevel@tonic-gate /* 1161*7c478bd9Sstevel@tonic-gate * Audit record generation. 1162*7c478bd9Sstevel@tonic-gate */ 1163*7c478bd9Sstevel@tonic-gate int 1164*7c478bd9Sstevel@tonic-gate secpolicy_audit_modify(const cred_t *cr) 1165*7c478bd9Sstevel@tonic-gate { 1166*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_AUDIT, B_FALSE, EPERM, NULL)); 1167*7c478bd9Sstevel@tonic-gate } 1168*7c478bd9Sstevel@tonic-gate 1169*7c478bd9Sstevel@tonic-gate /* 1170*7c478bd9Sstevel@tonic-gate * Get audit attributes. 1171*7c478bd9Sstevel@tonic-gate * Either PRIV_SYS_AUDIT or PRIV_PROC_AUDIT required; report the 1172*7c478bd9Sstevel@tonic-gate * "Least" of the two privileges on error. 1173*7c478bd9Sstevel@tonic-gate */ 1174*7c478bd9Sstevel@tonic-gate int 1175*7c478bd9Sstevel@tonic-gate secpolicy_audit_getattr(const cred_t *cr) 1176*7c478bd9Sstevel@tonic-gate { 1177*7c478bd9Sstevel@tonic-gate if (!PRIV_POLICY_ONLY(cr, PRIV_SYS_AUDIT, B_FALSE)) { 1178*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_AUDIT, B_FALSE, EPERM, 1179*7c478bd9Sstevel@tonic-gate NULL)); 1180*7c478bd9Sstevel@tonic-gate } else { 1181*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_AUDIT, B_FALSE, EPERM, NULL)); 1182*7c478bd9Sstevel@tonic-gate } 1183*7c478bd9Sstevel@tonic-gate } 1184*7c478bd9Sstevel@tonic-gate 1185*7c478bd9Sstevel@tonic-gate 1186*7c478bd9Sstevel@tonic-gate /* 1187*7c478bd9Sstevel@tonic-gate * Locking physical memory 1188*7c478bd9Sstevel@tonic-gate */ 1189*7c478bd9Sstevel@tonic-gate int 1190*7c478bd9Sstevel@tonic-gate secpolicy_lock_memory(const cred_t *cr) 1191*7c478bd9Sstevel@tonic-gate { 1192*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_LOCK_MEMORY, B_FALSE, EPERM, NULL)); 1193*7c478bd9Sstevel@tonic-gate } 1194*7c478bd9Sstevel@tonic-gate 1195*7c478bd9Sstevel@tonic-gate /* 1196*7c478bd9Sstevel@tonic-gate * Accounting (both acct(2) and exacct). 1197*7c478bd9Sstevel@tonic-gate */ 1198*7c478bd9Sstevel@tonic-gate int 1199*7c478bd9Sstevel@tonic-gate secpolicy_acct(const cred_t *cr) 1200*7c478bd9Sstevel@tonic-gate { 1201*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ACCT, B_FALSE, EPERM, NULL)); 1202*7c478bd9Sstevel@tonic-gate } 1203*7c478bd9Sstevel@tonic-gate 1204*7c478bd9Sstevel@tonic-gate /* 1205*7c478bd9Sstevel@tonic-gate * Is this process privileged to change its uids at will? 1206*7c478bd9Sstevel@tonic-gate * Uid 0 is still considered "special" and having the SETID 1207*7c478bd9Sstevel@tonic-gate * privilege is not sufficient to get uid 0. 1208*7c478bd9Sstevel@tonic-gate * Files are owned by root, so the privilege would give 1209*7c478bd9Sstevel@tonic-gate * full access and euid 0 is still effective. 1210*7c478bd9Sstevel@tonic-gate * 1211*7c478bd9Sstevel@tonic-gate * If you have the privilege and euid 0 only then do you 1212*7c478bd9Sstevel@tonic-gate * get the powers of root wrt uid 0. 1213*7c478bd9Sstevel@tonic-gate * 1214*7c478bd9Sstevel@tonic-gate * For gid manipulations, this is should be called with an 1215*7c478bd9Sstevel@tonic-gate * uid of -1. 1216*7c478bd9Sstevel@tonic-gate * 1217*7c478bd9Sstevel@tonic-gate */ 1218*7c478bd9Sstevel@tonic-gate int 1219*7c478bd9Sstevel@tonic-gate secpolicy_allow_setid(const cred_t *cr, uid_t newuid, boolean_t checkonly) 1220*7c478bd9Sstevel@tonic-gate { 1221*7c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 1222*7c478bd9Sstevel@tonic-gate 1223*7c478bd9Sstevel@tonic-gate if (newuid == 0 && cr->cr_uid != 0 && cr->cr_suid != 0 && 1224*7c478bd9Sstevel@tonic-gate cr->cr_ruid != 0) { 1225*7c478bd9Sstevel@tonic-gate allzone = B_TRUE; 1226*7c478bd9Sstevel@tonic-gate } 1227*7c478bd9Sstevel@tonic-gate 1228*7c478bd9Sstevel@tonic-gate return (checkonly ? !PRIV_POLICY_ONLY(cr, PRIV_PROC_SETID, allzone) : 1229*7c478bd9Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_PROC_SETID, allzone, EPERM, NULL)); 1230*7c478bd9Sstevel@tonic-gate } 1231*7c478bd9Sstevel@tonic-gate 1232*7c478bd9Sstevel@tonic-gate 1233*7c478bd9Sstevel@tonic-gate /* 1234*7c478bd9Sstevel@tonic-gate * Acting on a different process: if the mode is for writing, 1235*7c478bd9Sstevel@tonic-gate * the restrictions are more severe. This is called after 1236*7c478bd9Sstevel@tonic-gate * we've verified that the uids do not match. 1237*7c478bd9Sstevel@tonic-gate */ 1238*7c478bd9Sstevel@tonic-gate int 1239*7c478bd9Sstevel@tonic-gate secpolicy_proc_owner(const cred_t *scr, const cred_t *tcr, int mode) 1240*7c478bd9Sstevel@tonic-gate { 1241*7c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 1242*7c478bd9Sstevel@tonic-gate 1243*7c478bd9Sstevel@tonic-gate if ((mode & VWRITE) && scr->cr_uid != 0 && 1244*7c478bd9Sstevel@tonic-gate (tcr->cr_uid == 0 || tcr->cr_ruid == 0 || tcr->cr_suid == 0)) 1245*7c478bd9Sstevel@tonic-gate allzone = B_TRUE; 1246*7c478bd9Sstevel@tonic-gate 1247*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, allzone, EPERM, NULL)); 1248*7c478bd9Sstevel@tonic-gate } 1249*7c478bd9Sstevel@tonic-gate 1250*7c478bd9Sstevel@tonic-gate int 1251*7c478bd9Sstevel@tonic-gate secpolicy_proc_access(const cred_t *scr) 1252*7c478bd9Sstevel@tonic-gate { 1253*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, B_FALSE, EACCES, NULL)); 1254*7c478bd9Sstevel@tonic-gate } 1255*7c478bd9Sstevel@tonic-gate 1256*7c478bd9Sstevel@tonic-gate int 1257*7c478bd9Sstevel@tonic-gate secpolicy_proc_excl_open(const cred_t *scr) 1258*7c478bd9Sstevel@tonic-gate { 1259*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, B_FALSE, EBUSY, NULL)); 1260*7c478bd9Sstevel@tonic-gate } 1261*7c478bd9Sstevel@tonic-gate 1262*7c478bd9Sstevel@tonic-gate int 1263*7c478bd9Sstevel@tonic-gate secpolicy_proc_zone(const cred_t *scr) 1264*7c478bd9Sstevel@tonic-gate { 1265*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_ZONE, B_FALSE, EPERM, NULL)); 1266*7c478bd9Sstevel@tonic-gate } 1267*7c478bd9Sstevel@tonic-gate 1268*7c478bd9Sstevel@tonic-gate /* 1269*7c478bd9Sstevel@tonic-gate * Destroying the system 1270*7c478bd9Sstevel@tonic-gate */ 1271*7c478bd9Sstevel@tonic-gate 1272*7c478bd9Sstevel@tonic-gate int 1273*7c478bd9Sstevel@tonic-gate secpolicy_kmdb(const cred_t *scr) 1274*7c478bd9Sstevel@tonic-gate { 1275*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); 1276*7c478bd9Sstevel@tonic-gate } 1277*7c478bd9Sstevel@tonic-gate 1278*7c478bd9Sstevel@tonic-gate /* 1279*7c478bd9Sstevel@tonic-gate * Processor sets, cpu configuration, resource pools. 1280*7c478bd9Sstevel@tonic-gate */ 1281*7c478bd9Sstevel@tonic-gate int 1282*7c478bd9Sstevel@tonic-gate secpolicy_pset(const cred_t *cr) 1283*7c478bd9Sstevel@tonic-gate { 1284*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 1285*7c478bd9Sstevel@tonic-gate } 1286*7c478bd9Sstevel@tonic-gate 1287*7c478bd9Sstevel@tonic-gate int 1288*7c478bd9Sstevel@tonic-gate secpolicy_ponline(const cred_t *cr) 1289*7c478bd9Sstevel@tonic-gate { 1290*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 1291*7c478bd9Sstevel@tonic-gate } 1292*7c478bd9Sstevel@tonic-gate 1293*7c478bd9Sstevel@tonic-gate int 1294*7c478bd9Sstevel@tonic-gate secpolicy_pool(const cred_t *cr) 1295*7c478bd9Sstevel@tonic-gate { 1296*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 1297*7c478bd9Sstevel@tonic-gate } 1298*7c478bd9Sstevel@tonic-gate 1299*7c478bd9Sstevel@tonic-gate int 1300*7c478bd9Sstevel@tonic-gate secpolicy_blacklist(const cred_t *cr) 1301*7c478bd9Sstevel@tonic-gate { 1302*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 1303*7c478bd9Sstevel@tonic-gate } 1304*7c478bd9Sstevel@tonic-gate 1305*7c478bd9Sstevel@tonic-gate /* 1306*7c478bd9Sstevel@tonic-gate * Catch all system configuration. 1307*7c478bd9Sstevel@tonic-gate */ 1308*7c478bd9Sstevel@tonic-gate int 1309*7c478bd9Sstevel@tonic-gate secpolicy_sys_config(const cred_t *cr, boolean_t checkonly) 1310*7c478bd9Sstevel@tonic-gate { 1311*7c478bd9Sstevel@tonic-gate if (checkonly) { 1312*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_CONFIG, B_FALSE) ? 0 : 1313*7c478bd9Sstevel@tonic-gate EPERM); 1314*7c478bd9Sstevel@tonic-gate } else { 1315*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 1316*7c478bd9Sstevel@tonic-gate } 1317*7c478bd9Sstevel@tonic-gate } 1318*7c478bd9Sstevel@tonic-gate 1319*7c478bd9Sstevel@tonic-gate /* 1320*7c478bd9Sstevel@tonic-gate * Zone administration (halt, reboot, etc.) from within zone. 1321*7c478bd9Sstevel@tonic-gate */ 1322*7c478bd9Sstevel@tonic-gate int 1323*7c478bd9Sstevel@tonic-gate secpolicy_zone_admin(const cred_t *cr, boolean_t checkonly) 1324*7c478bd9Sstevel@tonic-gate { 1325*7c478bd9Sstevel@tonic-gate if (checkonly) { 1326*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_ADMIN, B_FALSE) ? 0 : 1327*7c478bd9Sstevel@tonic-gate EPERM); 1328*7c478bd9Sstevel@tonic-gate } else { 1329*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, 1330*7c478bd9Sstevel@tonic-gate NULL)); 1331*7c478bd9Sstevel@tonic-gate } 1332*7c478bd9Sstevel@tonic-gate } 1333*7c478bd9Sstevel@tonic-gate 1334*7c478bd9Sstevel@tonic-gate /* 1335*7c478bd9Sstevel@tonic-gate * Zone configuration (create, halt, enter). 1336*7c478bd9Sstevel@tonic-gate */ 1337*7c478bd9Sstevel@tonic-gate int 1338*7c478bd9Sstevel@tonic-gate secpolicy_zone_config(const cred_t *cr) 1339*7c478bd9Sstevel@tonic-gate { 1340*7c478bd9Sstevel@tonic-gate /* 1341*7c478bd9Sstevel@tonic-gate * Require all privileges to avoid possibility of privilege 1342*7c478bd9Sstevel@tonic-gate * escalation. 1343*7c478bd9Sstevel@tonic-gate */ 1344*7c478bd9Sstevel@tonic-gate return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); 1345*7c478bd9Sstevel@tonic-gate } 1346*7c478bd9Sstevel@tonic-gate 1347*7c478bd9Sstevel@tonic-gate /* 1348*7c478bd9Sstevel@tonic-gate * Various other system configuration calls 1349*7c478bd9Sstevel@tonic-gate */ 1350*7c478bd9Sstevel@tonic-gate int 1351*7c478bd9Sstevel@tonic-gate secpolicy_coreadm(const cred_t *cr) 1352*7c478bd9Sstevel@tonic-gate { 1353*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, NULL)); 1354*7c478bd9Sstevel@tonic-gate } 1355*7c478bd9Sstevel@tonic-gate 1356*7c478bd9Sstevel@tonic-gate int 1357*7c478bd9Sstevel@tonic-gate secpolicy_systeminfo(const cred_t *cr) 1358*7c478bd9Sstevel@tonic-gate { 1359*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, NULL)); 1360*7c478bd9Sstevel@tonic-gate } 1361*7c478bd9Sstevel@tonic-gate 1362*7c478bd9Sstevel@tonic-gate int 1363*7c478bd9Sstevel@tonic-gate secpolicy_dispadm(const cred_t *cr) 1364*7c478bd9Sstevel@tonic-gate { 1365*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 1366*7c478bd9Sstevel@tonic-gate } 1367*7c478bd9Sstevel@tonic-gate 1368*7c478bd9Sstevel@tonic-gate int 1369*7c478bd9Sstevel@tonic-gate secpolicy_settime(const cred_t *cr) 1370*7c478bd9Sstevel@tonic-gate { 1371*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_TIME, B_FALSE, EPERM, NULL)); 1372*7c478bd9Sstevel@tonic-gate } 1373*7c478bd9Sstevel@tonic-gate 1374*7c478bd9Sstevel@tonic-gate /* 1375*7c478bd9Sstevel@tonic-gate * For realtime users: high resolution clock. 1376*7c478bd9Sstevel@tonic-gate */ 1377*7c478bd9Sstevel@tonic-gate int 1378*7c478bd9Sstevel@tonic-gate secpolicy_clock_highres(const cred_t *cr) 1379*7c478bd9Sstevel@tonic-gate { 1380*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_CLOCK_HIGHRES, B_FALSE, EPERM, 1381*7c478bd9Sstevel@tonic-gate NULL)); 1382*7c478bd9Sstevel@tonic-gate } 1383*7c478bd9Sstevel@tonic-gate 1384*7c478bd9Sstevel@tonic-gate /* 1385*7c478bd9Sstevel@tonic-gate * drv_priv() is documented as callable from interrupt context, not that 1386*7c478bd9Sstevel@tonic-gate * anyone ever does, but still. No debugging or auditing can be done when 1387*7c478bd9Sstevel@tonic-gate * it is called from interrupt context. 1388*7c478bd9Sstevel@tonic-gate * returns 0 on succes, EPERM on failure. 1389*7c478bd9Sstevel@tonic-gate */ 1390*7c478bd9Sstevel@tonic-gate int 1391*7c478bd9Sstevel@tonic-gate drv_priv(cred_t *cr) 1392*7c478bd9Sstevel@tonic-gate { 1393*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 1394*7c478bd9Sstevel@tonic-gate } 1395*7c478bd9Sstevel@tonic-gate 1396*7c478bd9Sstevel@tonic-gate int 1397*7c478bd9Sstevel@tonic-gate secpolicy_sys_devices(const cred_t *cr) 1398*7c478bd9Sstevel@tonic-gate { 1399*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 1400*7c478bd9Sstevel@tonic-gate } 1401*7c478bd9Sstevel@tonic-gate 1402*7c478bd9Sstevel@tonic-gate int 1403*7c478bd9Sstevel@tonic-gate secpolicy_excl_open(const cred_t *cr) 1404*7c478bd9Sstevel@tonic-gate { 1405*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EBUSY, NULL)); 1406*7c478bd9Sstevel@tonic-gate } 1407*7c478bd9Sstevel@tonic-gate 1408*7c478bd9Sstevel@tonic-gate int 1409*7c478bd9Sstevel@tonic-gate secpolicy_rctlsys(const cred_t *cr, boolean_t is_zone_rctl) 1410*7c478bd9Sstevel@tonic-gate { 1411*7c478bd9Sstevel@tonic-gate /* zone.* rctls can only be set from the global zone */ 1412*7c478bd9Sstevel@tonic-gate if (is_zone_rctl && priv_policy_global(cr) != 0) 1413*7c478bd9Sstevel@tonic-gate return (EPERM); 1414*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 1415*7c478bd9Sstevel@tonic-gate } 1416*7c478bd9Sstevel@tonic-gate 1417*7c478bd9Sstevel@tonic-gate int 1418*7c478bd9Sstevel@tonic-gate secpolicy_resource(const cred_t *cr) 1419*7c478bd9Sstevel@tonic-gate { 1420*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 1421*7c478bd9Sstevel@tonic-gate } 1422*7c478bd9Sstevel@tonic-gate 1423*7c478bd9Sstevel@tonic-gate /* 1424*7c478bd9Sstevel@tonic-gate * Processes with a real uid of 0 escape any form of accounting, much 1425*7c478bd9Sstevel@tonic-gate * like before. 1426*7c478bd9Sstevel@tonic-gate */ 1427*7c478bd9Sstevel@tonic-gate int 1428*7c478bd9Sstevel@tonic-gate secpolicy_newproc(const cred_t *cr) 1429*7c478bd9Sstevel@tonic-gate { 1430*7c478bd9Sstevel@tonic-gate if (cr->cr_ruid == 0) 1431*7c478bd9Sstevel@tonic-gate return (0); 1432*7c478bd9Sstevel@tonic-gate 1433*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 1434*7c478bd9Sstevel@tonic-gate } 1435*7c478bd9Sstevel@tonic-gate 1436*7c478bd9Sstevel@tonic-gate /* 1437*7c478bd9Sstevel@tonic-gate * Networking 1438*7c478bd9Sstevel@tonic-gate */ 1439*7c478bd9Sstevel@tonic-gate int 1440*7c478bd9Sstevel@tonic-gate secpolicy_net_rawaccess(const cred_t *cr) 1441*7c478bd9Sstevel@tonic-gate { 1442*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_NET_RAWACCESS, B_FALSE, EACCES, NULL)); 1443*7c478bd9Sstevel@tonic-gate } 1444*7c478bd9Sstevel@tonic-gate 1445*7c478bd9Sstevel@tonic-gate /* 1446*7c478bd9Sstevel@tonic-gate * Need this privilege for accessing the ICMP device 1447*7c478bd9Sstevel@tonic-gate */ 1448*7c478bd9Sstevel@tonic-gate int 1449*7c478bd9Sstevel@tonic-gate secpolicy_net_icmpaccess(const cred_t *cr) 1450*7c478bd9Sstevel@tonic-gate { 1451*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_NET_ICMPACCESS, B_FALSE, EACCES, NULL)); 1452*7c478bd9Sstevel@tonic-gate } 1453*7c478bd9Sstevel@tonic-gate 1454*7c478bd9Sstevel@tonic-gate /* 1455*7c478bd9Sstevel@tonic-gate * There are a few rare cases where the kernel generates ioctls() from 1456*7c478bd9Sstevel@tonic-gate * interrupt context with a credential of kcred rather than NULL. 1457*7c478bd9Sstevel@tonic-gate * In those cases, we take the safe and cheap test. 1458*7c478bd9Sstevel@tonic-gate */ 1459*7c478bd9Sstevel@tonic-gate int 1460*7c478bd9Sstevel@tonic-gate secpolicy_net_config(const cred_t *cr, boolean_t checkonly) 1461*7c478bd9Sstevel@tonic-gate { 1462*7c478bd9Sstevel@tonic-gate if (checkonly) { 1463*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE) ? 1464*7c478bd9Sstevel@tonic-gate 0 : EPERM); 1465*7c478bd9Sstevel@tonic-gate } else { 1466*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_NET_CONFIG, B_FALSE, EPERM, 1467*7c478bd9Sstevel@tonic-gate NULL)); 1468*7c478bd9Sstevel@tonic-gate } 1469*7c478bd9Sstevel@tonic-gate } 1470*7c478bd9Sstevel@tonic-gate 1471*7c478bd9Sstevel@tonic-gate 1472*7c478bd9Sstevel@tonic-gate /* 1473*7c478bd9Sstevel@tonic-gate * Map network pseudo privileges to actual privileges. 1474*7c478bd9Sstevel@tonic-gate * So we don't need to recompile IP when we change the privileges. 1475*7c478bd9Sstevel@tonic-gate */ 1476*7c478bd9Sstevel@tonic-gate int 1477*7c478bd9Sstevel@tonic-gate secpolicy_net(const cred_t *cr, int netpriv, boolean_t checkonly) 1478*7c478bd9Sstevel@tonic-gate { 1479*7c478bd9Sstevel@tonic-gate int priv = PRIV_ALL; 1480*7c478bd9Sstevel@tonic-gate 1481*7c478bd9Sstevel@tonic-gate switch (netpriv) { 1482*7c478bd9Sstevel@tonic-gate case OP_CONFIG: 1483*7c478bd9Sstevel@tonic-gate priv = PRIV_SYS_NET_CONFIG; 1484*7c478bd9Sstevel@tonic-gate break; 1485*7c478bd9Sstevel@tonic-gate case OP_RAW: 1486*7c478bd9Sstevel@tonic-gate priv = PRIV_NET_RAWACCESS; 1487*7c478bd9Sstevel@tonic-gate break; 1488*7c478bd9Sstevel@tonic-gate case OP_PRIVPORT: 1489*7c478bd9Sstevel@tonic-gate priv = PRIV_NET_PRIVADDR; 1490*7c478bd9Sstevel@tonic-gate break; 1491*7c478bd9Sstevel@tonic-gate } 1492*7c478bd9Sstevel@tonic-gate ASSERT(priv != PRIV_ALL); 1493*7c478bd9Sstevel@tonic-gate if (checkonly) 1494*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, priv, B_FALSE) ? 0 : EPERM); 1495*7c478bd9Sstevel@tonic-gate else 1496*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, priv, B_FALSE, EPERM, NULL)); 1497*7c478bd9Sstevel@tonic-gate } 1498*7c478bd9Sstevel@tonic-gate 1499*7c478bd9Sstevel@tonic-gate /* 1500*7c478bd9Sstevel@tonic-gate * Checks for operations that are either client-only or are used by 1501*7c478bd9Sstevel@tonic-gate * both clients and servers. 1502*7c478bd9Sstevel@tonic-gate */ 1503*7c478bd9Sstevel@tonic-gate int 1504*7c478bd9Sstevel@tonic-gate secpolicy_nfs(const cred_t *cr) 1505*7c478bd9Sstevel@tonic-gate { 1506*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_NFS, B_FALSE, EPERM, NULL)); 1507*7c478bd9Sstevel@tonic-gate } 1508*7c478bd9Sstevel@tonic-gate 1509*7c478bd9Sstevel@tonic-gate /* 1510*7c478bd9Sstevel@tonic-gate * Special case for opening rpcmod: have NFS privileges or network 1511*7c478bd9Sstevel@tonic-gate * config privileges. 1512*7c478bd9Sstevel@tonic-gate */ 1513*7c478bd9Sstevel@tonic-gate int 1514*7c478bd9Sstevel@tonic-gate secpolicy_rpcmod_open(const cred_t *cr) 1515*7c478bd9Sstevel@tonic-gate { 1516*7c478bd9Sstevel@tonic-gate if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NFS, B_FALSE)) 1517*7c478bd9Sstevel@tonic-gate return (secpolicy_nfs(cr)); 1518*7c478bd9Sstevel@tonic-gate else 1519*7c478bd9Sstevel@tonic-gate return (secpolicy_net_config(cr, NULL)); 1520*7c478bd9Sstevel@tonic-gate } 1521*7c478bd9Sstevel@tonic-gate 1522*7c478bd9Sstevel@tonic-gate int 1523*7c478bd9Sstevel@tonic-gate secpolicy_chroot(const cred_t *cr) 1524*7c478bd9Sstevel@tonic-gate { 1525*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_CHROOT, B_FALSE, EPERM, NULL)); 1526*7c478bd9Sstevel@tonic-gate } 1527*7c478bd9Sstevel@tonic-gate 1528*7c478bd9Sstevel@tonic-gate int 1529*7c478bd9Sstevel@tonic-gate secpolicy_tasksys(const cred_t *cr) 1530*7c478bd9Sstevel@tonic-gate { 1531*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_TASKID, B_FALSE, EPERM, NULL)); 1532*7c478bd9Sstevel@tonic-gate } 1533*7c478bd9Sstevel@tonic-gate 1534*7c478bd9Sstevel@tonic-gate /* 1535*7c478bd9Sstevel@tonic-gate * Basic privilege checks. 1536*7c478bd9Sstevel@tonic-gate */ 1537*7c478bd9Sstevel@tonic-gate int 1538*7c478bd9Sstevel@tonic-gate secpolicy_basic_exec(const cred_t *cr) 1539*7c478bd9Sstevel@tonic-gate { 1540*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_EXEC, B_FALSE, EPERM, NULL)); 1541*7c478bd9Sstevel@tonic-gate } 1542*7c478bd9Sstevel@tonic-gate 1543*7c478bd9Sstevel@tonic-gate int 1544*7c478bd9Sstevel@tonic-gate secpolicy_basic_fork(const cred_t *cr) 1545*7c478bd9Sstevel@tonic-gate { 1546*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_FORK, B_FALSE, EPERM, NULL)); 1547*7c478bd9Sstevel@tonic-gate } 1548*7c478bd9Sstevel@tonic-gate 1549*7c478bd9Sstevel@tonic-gate int 1550*7c478bd9Sstevel@tonic-gate secpolicy_basic_proc(const cred_t *cr) 1551*7c478bd9Sstevel@tonic-gate { 1552*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_SESSION, B_FALSE, EPERM, NULL)); 1553*7c478bd9Sstevel@tonic-gate } 1554*7c478bd9Sstevel@tonic-gate 1555*7c478bd9Sstevel@tonic-gate /* 1556*7c478bd9Sstevel@tonic-gate * Slightly complicated because we don't want to trigger the policy too 1557*7c478bd9Sstevel@tonic-gate * often. First we shortcircuit access to "self" (tp == sp) or if 1558*7c478bd9Sstevel@tonic-gate * we don't have the privilege but if we have permission 1559*7c478bd9Sstevel@tonic-gate * just return (0) and we don't flag the privilege as needed. 1560*7c478bd9Sstevel@tonic-gate * Else, we test for the privilege because we either have it or need it. 1561*7c478bd9Sstevel@tonic-gate */ 1562*7c478bd9Sstevel@tonic-gate int 1563*7c478bd9Sstevel@tonic-gate secpolicy_basic_procinfo(const cred_t *cr, proc_t *tp, proc_t *sp) 1564*7c478bd9Sstevel@tonic-gate { 1565*7c478bd9Sstevel@tonic-gate if (tp == sp || 1566*7c478bd9Sstevel@tonic-gate !HAS_PRIVILEGE(cr, PRIV_PROC_INFO) && prochasprocperm(tp, sp, cr)) { 1567*7c478bd9Sstevel@tonic-gate return (0); 1568*7c478bd9Sstevel@tonic-gate } else { 1569*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_INFO, B_FALSE, EPERM, NULL)); 1570*7c478bd9Sstevel@tonic-gate } 1571*7c478bd9Sstevel@tonic-gate } 1572*7c478bd9Sstevel@tonic-gate 1573*7c478bd9Sstevel@tonic-gate int 1574*7c478bd9Sstevel@tonic-gate secpolicy_basic_link(const cred_t *cr) 1575*7c478bd9Sstevel@tonic-gate { 1576*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_LINK_ANY, B_FALSE, EPERM, NULL)); 1577*7c478bd9Sstevel@tonic-gate } 1578*7c478bd9Sstevel@tonic-gate 1579*7c478bd9Sstevel@tonic-gate /* 1580*7c478bd9Sstevel@tonic-gate * Additional device protection. 1581*7c478bd9Sstevel@tonic-gate * 1582*7c478bd9Sstevel@tonic-gate * Traditionally, a device has specific permissions on the node in 1583*7c478bd9Sstevel@tonic-gate * the filesystem which govern which devices can be opened by what 1584*7c478bd9Sstevel@tonic-gate * processes. In certain cases, it is desirable to add extra 1585*7c478bd9Sstevel@tonic-gate * restrictions, as writing to certain devices is identical to 1586*7c478bd9Sstevel@tonic-gate * having a complete run of the system. 1587*7c478bd9Sstevel@tonic-gate * 1588*7c478bd9Sstevel@tonic-gate * This mechanism is called the device policy. 1589*7c478bd9Sstevel@tonic-gate * 1590*7c478bd9Sstevel@tonic-gate * When a device is opened, its policy entry is looked up in the 1591*7c478bd9Sstevel@tonic-gate * policy cache and checked. 1592*7c478bd9Sstevel@tonic-gate */ 1593*7c478bd9Sstevel@tonic-gate int 1594*7c478bd9Sstevel@tonic-gate secpolicy_spec_open(const cred_t *cr, struct vnode *vp, int oflag) 1595*7c478bd9Sstevel@tonic-gate { 1596*7c478bd9Sstevel@tonic-gate devplcy_t *plcy; 1597*7c478bd9Sstevel@tonic-gate int err; 1598*7c478bd9Sstevel@tonic-gate struct snode *csp = VTOS(common_specvp(vp)); 1599*7c478bd9Sstevel@tonic-gate 1600*7c478bd9Sstevel@tonic-gate mutex_enter(&csp->s_lock); 1601*7c478bd9Sstevel@tonic-gate 1602*7c478bd9Sstevel@tonic-gate if (csp->s_plcy == NULL || csp->s_plcy->dp_gen != devplcy_gen) { 1603*7c478bd9Sstevel@tonic-gate plcy = devpolicy_find(vp); 1604*7c478bd9Sstevel@tonic-gate if (csp->s_plcy) 1605*7c478bd9Sstevel@tonic-gate dpfree(csp->s_plcy); 1606*7c478bd9Sstevel@tonic-gate csp->s_plcy = plcy; 1607*7c478bd9Sstevel@tonic-gate ASSERT(plcy != NULL); 1608*7c478bd9Sstevel@tonic-gate } else 1609*7c478bd9Sstevel@tonic-gate plcy = csp->s_plcy; 1610*7c478bd9Sstevel@tonic-gate 1611*7c478bd9Sstevel@tonic-gate if (plcy == nullpolicy) { 1612*7c478bd9Sstevel@tonic-gate mutex_exit(&csp->s_lock); 1613*7c478bd9Sstevel@tonic-gate return (0); 1614*7c478bd9Sstevel@tonic-gate } 1615*7c478bd9Sstevel@tonic-gate 1616*7c478bd9Sstevel@tonic-gate dphold(plcy); 1617*7c478bd9Sstevel@tonic-gate 1618*7c478bd9Sstevel@tonic-gate mutex_exit(&csp->s_lock); 1619*7c478bd9Sstevel@tonic-gate 1620*7c478bd9Sstevel@tonic-gate err = secpolicy_require_set(cr, 1621*7c478bd9Sstevel@tonic-gate (oflag & FWRITE) ? &plcy->dp_wrp : &plcy->dp_rdp, "devpolicy"); 1622*7c478bd9Sstevel@tonic-gate dpfree(plcy); 1623*7c478bd9Sstevel@tonic-gate 1624*7c478bd9Sstevel@tonic-gate return (err); 1625*7c478bd9Sstevel@tonic-gate } 1626*7c478bd9Sstevel@tonic-gate 1627*7c478bd9Sstevel@tonic-gate int 1628*7c478bd9Sstevel@tonic-gate secpolicy_modctl(const cred_t *cr, int cmd) 1629*7c478bd9Sstevel@tonic-gate { 1630*7c478bd9Sstevel@tonic-gate switch (cmd) { 1631*7c478bd9Sstevel@tonic-gate case MODINFO: 1632*7c478bd9Sstevel@tonic-gate case MODGETPATH: 1633*7c478bd9Sstevel@tonic-gate case MODGETPATHLEN: 1634*7c478bd9Sstevel@tonic-gate case MODGETFBNAME: 1635*7c478bd9Sstevel@tonic-gate case MODGETNAME: 1636*7c478bd9Sstevel@tonic-gate case MODGETDEVPOLICY: 1637*7c478bd9Sstevel@tonic-gate case MODGETDEVPOLICYBYNAME: 1638*7c478bd9Sstevel@tonic-gate case MODGETMAJBIND: 1639*7c478bd9Sstevel@tonic-gate /* Unprivileged */ 1640*7c478bd9Sstevel@tonic-gate return (0); 1641*7c478bd9Sstevel@tonic-gate case MODLOAD: 1642*7c478bd9Sstevel@tonic-gate case MODSETDEVPOLICY: 1643*7c478bd9Sstevel@tonic-gate return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); 1644*7c478bd9Sstevel@tonic-gate default: 1645*7c478bd9Sstevel@tonic-gate return (secpolicy_sys_config(cr, B_FALSE)); 1646*7c478bd9Sstevel@tonic-gate } 1647*7c478bd9Sstevel@tonic-gate } 1648*7c478bd9Sstevel@tonic-gate 1649*7c478bd9Sstevel@tonic-gate int 1650*7c478bd9Sstevel@tonic-gate secpolicy_console(const cred_t *cr) 1651*7c478bd9Sstevel@tonic-gate { 1652*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 1653*7c478bd9Sstevel@tonic-gate } 1654*7c478bd9Sstevel@tonic-gate 1655*7c478bd9Sstevel@tonic-gate int 1656*7c478bd9Sstevel@tonic-gate secpolicy_power_mgmt(const cred_t *cr) 1657*7c478bd9Sstevel@tonic-gate { 1658*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 1659*7c478bd9Sstevel@tonic-gate } 1660*7c478bd9Sstevel@tonic-gate 1661*7c478bd9Sstevel@tonic-gate /* 1662*7c478bd9Sstevel@tonic-gate * Simulate terminal input; another escalation of privileges avenue. 1663*7c478bd9Sstevel@tonic-gate */ 1664*7c478bd9Sstevel@tonic-gate 1665*7c478bd9Sstevel@tonic-gate int 1666*7c478bd9Sstevel@tonic-gate secpolicy_sti(const cred_t *cr) 1667*7c478bd9Sstevel@tonic-gate { 1668*7c478bd9Sstevel@tonic-gate return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); 1669*7c478bd9Sstevel@tonic-gate } 1670*7c478bd9Sstevel@tonic-gate 1671*7c478bd9Sstevel@tonic-gate int 1672*7c478bd9Sstevel@tonic-gate secpolicy_swapctl(const cred_t *cr) 1673*7c478bd9Sstevel@tonic-gate { 1674*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 1675*7c478bd9Sstevel@tonic-gate } 1676*7c478bd9Sstevel@tonic-gate 1677*7c478bd9Sstevel@tonic-gate int 1678*7c478bd9Sstevel@tonic-gate secpolicy_cpc_cpu(const cred_t *cr) 1679*7c478bd9Sstevel@tonic-gate { 1680*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CPC_CPU, B_FALSE, EACCES, NULL)); 1681*7c478bd9Sstevel@tonic-gate } 1682*7c478bd9Sstevel@tonic-gate 1683*7c478bd9Sstevel@tonic-gate /* 1684*7c478bd9Sstevel@tonic-gate * secpolicy_contract_observer 1685*7c478bd9Sstevel@tonic-gate * 1686*7c478bd9Sstevel@tonic-gate * Determine if the subject may observe a specific contract's events. 1687*7c478bd9Sstevel@tonic-gate */ 1688*7c478bd9Sstevel@tonic-gate int 1689*7c478bd9Sstevel@tonic-gate secpolicy_contract_observer(const cred_t *cr, struct contract *ct) 1690*7c478bd9Sstevel@tonic-gate { 1691*7c478bd9Sstevel@tonic-gate if (contract_owned(ct, cr, B_FALSE)) 1692*7c478bd9Sstevel@tonic-gate return (0); 1693*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CONTRACT_OBSERVER, B_FALSE, EPERM, NULL)); 1694*7c478bd9Sstevel@tonic-gate } 1695*7c478bd9Sstevel@tonic-gate 1696*7c478bd9Sstevel@tonic-gate /* 1697*7c478bd9Sstevel@tonic-gate * secpolicy_contract_observer_choice 1698*7c478bd9Sstevel@tonic-gate * 1699*7c478bd9Sstevel@tonic-gate * Determine if the subject may observe any contract's events. Just 1700*7c478bd9Sstevel@tonic-gate * tests privilege and audits on success. 1701*7c478bd9Sstevel@tonic-gate */ 1702*7c478bd9Sstevel@tonic-gate boolean_t 1703*7c478bd9Sstevel@tonic-gate secpolicy_contract_observer_choice(const cred_t *cr) 1704*7c478bd9Sstevel@tonic-gate { 1705*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY_CHOICE(cr, PRIV_CONTRACT_OBSERVER, B_FALSE)); 1706*7c478bd9Sstevel@tonic-gate } 1707*7c478bd9Sstevel@tonic-gate 1708*7c478bd9Sstevel@tonic-gate /* 1709*7c478bd9Sstevel@tonic-gate * secpolicy_contract_event 1710*7c478bd9Sstevel@tonic-gate * 1711*7c478bd9Sstevel@tonic-gate * Determine if the subject may request critical contract events or 1712*7c478bd9Sstevel@tonic-gate * reliable contract event delivery. 1713*7c478bd9Sstevel@tonic-gate */ 1714*7c478bd9Sstevel@tonic-gate int 1715*7c478bd9Sstevel@tonic-gate secpolicy_contract_event(const cred_t *cr) 1716*7c478bd9Sstevel@tonic-gate { 1717*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CONTRACT_EVENT, B_FALSE, EPERM, NULL)); 1718*7c478bd9Sstevel@tonic-gate } 1719*7c478bd9Sstevel@tonic-gate 1720*7c478bd9Sstevel@tonic-gate /* 1721*7c478bd9Sstevel@tonic-gate * secpolicy_contract_event_choice 1722*7c478bd9Sstevel@tonic-gate * 1723*7c478bd9Sstevel@tonic-gate * Determine if the subject may retain contract events in its critical 1724*7c478bd9Sstevel@tonic-gate * set when a change in other terms would normally require a change in 1725*7c478bd9Sstevel@tonic-gate * the critical set. Just tests privilege and audits on success. 1726*7c478bd9Sstevel@tonic-gate */ 1727*7c478bd9Sstevel@tonic-gate boolean_t 1728*7c478bd9Sstevel@tonic-gate secpolicy_contract_event_choice(const cred_t *cr) 1729*7c478bd9Sstevel@tonic-gate { 1730*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY_CHOICE(cr, PRIV_CONTRACT_EVENT, B_FALSE)); 1731*7c478bd9Sstevel@tonic-gate } 1732*7c478bd9Sstevel@tonic-gate 1733*7c478bd9Sstevel@tonic-gate /* 1734*7c478bd9Sstevel@tonic-gate * Name: secpolicy_gart_access 1735*7c478bd9Sstevel@tonic-gate * 1736*7c478bd9Sstevel@tonic-gate * Normal: Verify if the subject has sufficient priveleges to make ioctls 1737*7c478bd9Sstevel@tonic-gate * to agpgart device 1738*7c478bd9Sstevel@tonic-gate * 1739*7c478bd9Sstevel@tonic-gate * Output: EPERM - if not privileged 1740*7c478bd9Sstevel@tonic-gate * 1741*7c478bd9Sstevel@tonic-gate */ 1742*7c478bd9Sstevel@tonic-gate int 1743*7c478bd9Sstevel@tonic-gate secpolicy_gart_access(const cred_t *cr) 1744*7c478bd9Sstevel@tonic-gate { 1745*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_GART_ACCESS, B_FALSE, EPERM, NULL)); 1746*7c478bd9Sstevel@tonic-gate } 1747*7c478bd9Sstevel@tonic-gate 1748*7c478bd9Sstevel@tonic-gate /* 1749*7c478bd9Sstevel@tonic-gate * Name: secpolicy_gart_map 1750*7c478bd9Sstevel@tonic-gate * 1751*7c478bd9Sstevel@tonic-gate * Normal: Verify if the subject has sufficient privelegs to map aperture 1752*7c478bd9Sstevel@tonic-gate * range through agpgart driver 1753*7c478bd9Sstevel@tonic-gate * 1754*7c478bd9Sstevel@tonic-gate * Output: EPERM - if not privileged 1755*7c478bd9Sstevel@tonic-gate * 1756*7c478bd9Sstevel@tonic-gate */ 1757*7c478bd9Sstevel@tonic-gate int 1758*7c478bd9Sstevel@tonic-gate secpolicy_gart_map(const cred_t *cr) 1759*7c478bd9Sstevel@tonic-gate { 1760*7c478bd9Sstevel@tonic-gate if (PRIV_POLICY(cr, PRIV_GART_ACCESS, B_FALSE, EPERM, NULL)) { 1761*7c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_GART_MAP, B_FALSE, EPERM, NULL)); 1762*7c478bd9Sstevel@tonic-gate } 1763*7c478bd9Sstevel@tonic-gate return (0); 1764*7c478bd9Sstevel@tonic-gate } 1765