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