10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <sys/types.h> 300Sstevel@tonic-gate #include <sys/sysmacros.h> 310Sstevel@tonic-gate #include <sys/param.h> 320Sstevel@tonic-gate #include <sys/systm.h> 330Sstevel@tonic-gate #include <sys/cred_impl.h> 340Sstevel@tonic-gate #include <sys/vnode.h> 350Sstevel@tonic-gate #include <sys/vfs.h> 360Sstevel@tonic-gate #include <sys/stat.h> 370Sstevel@tonic-gate #include <sys/errno.h> 380Sstevel@tonic-gate #include <sys/kmem.h> 390Sstevel@tonic-gate #include <sys/user.h> 400Sstevel@tonic-gate #include <sys/proc.h> 410Sstevel@tonic-gate #include <sys/acct.h> 420Sstevel@tonic-gate #include <sys/ipc_impl.h> 430Sstevel@tonic-gate #include <sys/syscall.h> 440Sstevel@tonic-gate #include <sys/cmn_err.h> 450Sstevel@tonic-gate #include <sys/debug.h> 460Sstevel@tonic-gate #include <sys/policy.h> 470Sstevel@tonic-gate #include <sys/kobj.h> 480Sstevel@tonic-gate #include <sys/msg.h> 490Sstevel@tonic-gate #include <sys/devpolicy.h> 500Sstevel@tonic-gate #include <c2/audit.h> 510Sstevel@tonic-gate #include <sys/varargs.h> 520Sstevel@tonic-gate #include <sys/modctl.h> 530Sstevel@tonic-gate #include <sys/disp.h> 540Sstevel@tonic-gate #include <sys/zone.h> 550Sstevel@tonic-gate #include <inet/common.h> 560Sstevel@tonic-gate #include <inet/optcom.h> 570Sstevel@tonic-gate #include <sys/sdt.h> 580Sstevel@tonic-gate #include <sys/mount.h> 590Sstevel@tonic-gate #include <sys/vfs.h> 600Sstevel@tonic-gate #include <sys/mntent.h> 610Sstevel@tonic-gate #include <sys/contract_impl.h> 620Sstevel@tonic-gate 630Sstevel@tonic-gate #include <sys/sunddi.h> 640Sstevel@tonic-gate 650Sstevel@tonic-gate /* 660Sstevel@tonic-gate * There are two possible layers of privilege routines and two possible 670Sstevel@tonic-gate * levels of secpolicy. Plus one other we may not be interested in, so 680Sstevel@tonic-gate * we may need as many as 6 but no more. 690Sstevel@tonic-gate */ 700Sstevel@tonic-gate #define MAXPRIVSTACK 6 710Sstevel@tonic-gate 720Sstevel@tonic-gate int priv_debug = 0; 730Sstevel@tonic-gate 740Sstevel@tonic-gate /* 750Sstevel@tonic-gate * This file contains the majority of the policy routines. 760Sstevel@tonic-gate * Since the policy routines are defined by function and not 770Sstevel@tonic-gate * by privilege, there is quite a bit of duplication of 780Sstevel@tonic-gate * functions. 790Sstevel@tonic-gate * 800Sstevel@tonic-gate * The secpolicy functions must not make asssumptions about 810Sstevel@tonic-gate * locks held or not held as any lock can be held while they're 820Sstevel@tonic-gate * being called. 830Sstevel@tonic-gate * 840Sstevel@tonic-gate * Credentials are read-only so no special precautions need to 850Sstevel@tonic-gate * be taken while locking them. 860Sstevel@tonic-gate * 870Sstevel@tonic-gate * When a new policy check needs to be added to the system the 880Sstevel@tonic-gate * following procedure should be followed: 890Sstevel@tonic-gate * 900Sstevel@tonic-gate * Pick an appropriate secpolicy_*() function 910Sstevel@tonic-gate * -> done if one exists. 920Sstevel@tonic-gate * Create a new secpolicy function, preferably with 930Sstevel@tonic-gate * a descriptive name using the standard template. 940Sstevel@tonic-gate * Pick an appropriate privilege for the policy. 950Sstevel@tonic-gate * If no appropraite privilege exists, define new one 960Sstevel@tonic-gate * (this should be done with extreme care; in most cases 970Sstevel@tonic-gate * little is gained by adding another privilege) 980Sstevel@tonic-gate * 990Sstevel@tonic-gate * WHY ROOT IS STILL SPECIAL. 1000Sstevel@tonic-gate * 1010Sstevel@tonic-gate * In a number of the policy functions, there are still explicit 1020Sstevel@tonic-gate * checks for uid 0. The rationale behind these is that many root 1030Sstevel@tonic-gate * owned files/objects hold configuration information which can give full 1040Sstevel@tonic-gate * privileges to the user once written to. To prevent escalation 1050Sstevel@tonic-gate * of privilege by allowing just a single privilege to modify root owned 1060Sstevel@tonic-gate * objects, we've added these root specific checks where we considered 1070Sstevel@tonic-gate * them necessary: modifying root owned files, changing uids to 0, etc. 1080Sstevel@tonic-gate * 1090Sstevel@tonic-gate * PRIVILEGE ESCALATION AND ZONES. 1100Sstevel@tonic-gate * 1110Sstevel@tonic-gate * A number of operations potentially allow the caller to achieve 1120Sstevel@tonic-gate * privileges beyond the ones normally required to perform the operation. 1130Sstevel@tonic-gate * For example, if allowed to create a setuid 0 executable, a process can 1140Sstevel@tonic-gate * gain privileges beyond PRIV_FILE_SETID. Zones, however, place 1150Sstevel@tonic-gate * restrictions on the ability to gain privileges beyond those available 1160Sstevel@tonic-gate * within the zone through file and process manipulation. Hence, such 1170Sstevel@tonic-gate * operations require that the caller have an effective set that includes 1180Sstevel@tonic-gate * all privileges available within the current zone, or all privileges 1190Sstevel@tonic-gate * if executing in the global zone. 1200Sstevel@tonic-gate * 1210Sstevel@tonic-gate * This is indicated in the priv_policy* policy checking functions 1220Sstevel@tonic-gate * through a combination of parameters. The "priv" parameter indicates 1230Sstevel@tonic-gate * the privilege that is required, and the "allzone" parameter indicates 1240Sstevel@tonic-gate * whether or not all privileges in the zone are required. In addition, 1250Sstevel@tonic-gate * priv can be set to PRIV_ALL to indicate that all privileges are 1260Sstevel@tonic-gate * required (regardless of zone). There are three scenarios of interest: 1270Sstevel@tonic-gate * (1) operation requires a specific privilege 1280Sstevel@tonic-gate * (2) operation requires a specific privilege, and requires all 1290Sstevel@tonic-gate * privileges available within the zone (or all privileges if in 1300Sstevel@tonic-gate * the global zone) 1310Sstevel@tonic-gate * (3) operation requires all privileges, regardless of zone 1320Sstevel@tonic-gate * 1330Sstevel@tonic-gate * For (1), priv should be set to the specific privilege, and allzone 1340Sstevel@tonic-gate * should be set to B_FALSE. 1350Sstevel@tonic-gate * For (2), priv should be set to the specific privilege, and allzone 1360Sstevel@tonic-gate * should be set to B_TRUE. 1370Sstevel@tonic-gate * For (3), priv should be set to PRIV_ALL, and allzone should be set 1380Sstevel@tonic-gate * to B_FALSE. 1390Sstevel@tonic-gate * 1400Sstevel@tonic-gate */ 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate /* 1430Sstevel@tonic-gate * The privileges are checked against the Effective set for 1440Sstevel@tonic-gate * ordinary processes and checked against the Limit set 1450Sstevel@tonic-gate * for euid 0 processes that haven't manipulated their privilege 1460Sstevel@tonic-gate * sets. 1470Sstevel@tonic-gate */ 1480Sstevel@tonic-gate #define HAS_ALLPRIVS(cr) priv_isfullset(&CR_OEPRIV(cr)) 1490Sstevel@tonic-gate #define ZONEPRIVS(cr) ((cr)->cr_zone->zone_privset) 1500Sstevel@tonic-gate #define HAS_ALLZONEPRIVS(cr) priv_issubset(ZONEPRIVS(cr), &CR_OEPRIV(cr)) 1510Sstevel@tonic-gate #define HAS_PRIVILEGE(cr, pr) ((pr) == PRIV_ALL ? \ 1520Sstevel@tonic-gate HAS_ALLPRIVS(cr) : \ 1530Sstevel@tonic-gate PRIV_ISASSERT(&CR_OEPRIV(cr), pr)) 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate /* 1560Sstevel@tonic-gate * Policy checking functions 1570Sstevel@tonic-gate * 1580Sstevel@tonic-gate * In future, these will migrate to several files when policy 1590Sstevel@tonic-gate * becomes more or less pluggable. 1600Sstevel@tonic-gate * 1610Sstevel@tonic-gate * For now, there's only one policy and this is it. 1620Sstevel@tonic-gate */ 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate /* 1650Sstevel@tonic-gate * Generic policy calls 1660Sstevel@tonic-gate * 1670Sstevel@tonic-gate * The "bottom" functions of policy control 1680Sstevel@tonic-gate */ 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate static char * 1710Sstevel@tonic-gate mprintf(const char *fmt, ...) 1720Sstevel@tonic-gate { 1730Sstevel@tonic-gate va_list args; 1740Sstevel@tonic-gate char *buf; 1750Sstevel@tonic-gate size_t len; 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate va_start(args, fmt); 1780Sstevel@tonic-gate len = vsnprintf(NULL, 0, fmt, args) + 1; 1790Sstevel@tonic-gate va_end(args); 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate buf = kmem_alloc(len, KM_NOSLEEP); 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate if (buf == NULL) 1840Sstevel@tonic-gate return (NULL); 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate va_start(args, fmt); 1870Sstevel@tonic-gate (void) vsnprintf(buf, len, fmt, args); 1880Sstevel@tonic-gate va_end(args); 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate return (buf); 1910Sstevel@tonic-gate } 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate /* 1940Sstevel@tonic-gate * priv_policy_errmsg() 1950Sstevel@tonic-gate * 1960Sstevel@tonic-gate * Generate an error message if privilege debugging is enabled system wide 1970Sstevel@tonic-gate * or for this particular process. 1980Sstevel@tonic-gate */ 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate #define FMTHDR "%s[%d]: missing privilege \"%s\" (euid = %d, syscall = %d)" 2010Sstevel@tonic-gate #define FMTMSG " for \"%s\"" 2020Sstevel@tonic-gate #define FMTFUN " needed at %s+0x%lx" 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate /* The maximum size privilege format: the concatenation of the above */ 2050Sstevel@tonic-gate #define FMTMAX FMTHDR FMTMSG FMTFUN "\n" 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate static void 2080Sstevel@tonic-gate priv_policy_errmsg(const cred_t *cr, int priv, const char *msg) 2090Sstevel@tonic-gate { 2100Sstevel@tonic-gate struct proc *me; 2110Sstevel@tonic-gate pc_t stack[MAXPRIVSTACK]; 2120Sstevel@tonic-gate int depth; 2130Sstevel@tonic-gate int i; 2140Sstevel@tonic-gate char *sym; 2150Sstevel@tonic-gate ulong_t off; 2160Sstevel@tonic-gate const char *pname; 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate char *cmd; 2190Sstevel@tonic-gate char fmt[sizeof (FMTMAX)]; 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate if ((me = curproc) == &p0) 2220Sstevel@tonic-gate return; 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate /* Privileges must be defined */ 2250Sstevel@tonic-gate ASSERT(priv == PRIV_ALL || priv == PRIV_MULTIPLE || 2260Sstevel@tonic-gate priv == PRIV_ALLZONE || priv == PRIV_GLOBAL || 2270Sstevel@tonic-gate priv_getbynum(priv) != NULL); 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate if (priv == PRIV_ALLZONE && INGLOBALZONE(me)) 2300Sstevel@tonic-gate priv = PRIV_ALL; 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate if (curthread->t_pre_sys) 2330Sstevel@tonic-gate ttolwp(curthread)->lwp_badpriv = (short)priv; 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate if (priv_debug == 0 && (CR_FLAGS(cr) & PRIV_DEBUG) == 0) 2360Sstevel@tonic-gate return; 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate (void) strcpy(fmt, FMTHDR); 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate if (me->p_user.u_comm[0]) 2410Sstevel@tonic-gate cmd = &me->p_user.u_comm[0]; 2420Sstevel@tonic-gate else 2430Sstevel@tonic-gate cmd = "priv_policy"; 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate if (msg != NULL && *msg != '\0') { 2460Sstevel@tonic-gate (void) strcat(fmt, FMTMSG); 2470Sstevel@tonic-gate } else { 2480Sstevel@tonic-gate (void) strcat(fmt, "%s"); 2490Sstevel@tonic-gate msg = ""; 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate sym = NULL; 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate depth = getpcstack(stack, MAXPRIVSTACK); 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate /* 2570Sstevel@tonic-gate * Try to find the first interesting function on the stack. 2580Sstevel@tonic-gate * priv_policy* that's us, so completely uninteresting. 2590Sstevel@tonic-gate * suser(), drv_priv(), secpolicy_* are also called from 2600Sstevel@tonic-gate * too many locations to convey useful information. 2610Sstevel@tonic-gate */ 2620Sstevel@tonic-gate for (i = 0; i < depth; i++) { 2630Sstevel@tonic-gate sym = kobj_getsymname((uintptr_t)stack[i], &off); 2640Sstevel@tonic-gate if (sym != NULL && 2650Sstevel@tonic-gate strstr(sym, "hasprocperm") == 0 && 2660Sstevel@tonic-gate strcmp("suser", sym) != 0 && 2670Sstevel@tonic-gate strcmp("ipcaccess", sym) != 0 && 2680Sstevel@tonic-gate strcmp("drv_priv", sym) != 0 && 2690Sstevel@tonic-gate strncmp("secpolicy_", sym, 10) != 0 && 2700Sstevel@tonic-gate strncmp("priv_policy", sym, 11) != 0) 2710Sstevel@tonic-gate break; 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate if (sym != NULL) 2750Sstevel@tonic-gate (void) strcat(fmt, FMTFUN); 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate (void) strcat(fmt, "\n"); 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate switch (priv) { 2800Sstevel@tonic-gate case PRIV_ALL: 2810Sstevel@tonic-gate pname = "ALL"; 2820Sstevel@tonic-gate break; 2830Sstevel@tonic-gate case PRIV_MULTIPLE: 2840Sstevel@tonic-gate pname = "MULTIPLE"; 2850Sstevel@tonic-gate break; 2860Sstevel@tonic-gate case PRIV_ALLZONE: 2870Sstevel@tonic-gate pname = "ZONE"; 2880Sstevel@tonic-gate break; 2890Sstevel@tonic-gate case PRIV_GLOBAL: 2900Sstevel@tonic-gate pname = "GLOBAL"; 2910Sstevel@tonic-gate break; 2920Sstevel@tonic-gate default: 2930Sstevel@tonic-gate pname = priv_getbynum(priv); 2940Sstevel@tonic-gate break; 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate if (CR_FLAGS(cr) & PRIV_DEBUG) { 2980Sstevel@tonic-gate /* Remember last message, just like lwp_badpriv. */ 2990Sstevel@tonic-gate if (curthread->t_pdmsg != NULL) { 3000Sstevel@tonic-gate kmem_free(curthread->t_pdmsg, 3010Sstevel@tonic-gate strlen(curthread->t_pdmsg) + 1); 3020Sstevel@tonic-gate } 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate curthread->t_pdmsg = mprintf(fmt, cmd, me->p_pid, pname, 3050Sstevel@tonic-gate cr->cr_uid, curthread->t_sysnum, msg, sym, off); 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate curthread->t_post_sys = 1; 3080Sstevel@tonic-gate } else { 3090Sstevel@tonic-gate cmn_err(CE_NOTE, fmt, cmd, me->p_pid, pname, cr->cr_uid, 3100Sstevel@tonic-gate curthread->t_sysnum, msg, sym, off); 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate } 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate /* 3150Sstevel@tonic-gate * Audit failure, log error message. 3160Sstevel@tonic-gate */ 3170Sstevel@tonic-gate static void 3180Sstevel@tonic-gate priv_policy_err(const cred_t *cr, int priv, boolean_t allzone, const char *msg) 3190Sstevel@tonic-gate { 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate #ifdef C2_AUDIT 3220Sstevel@tonic-gate if (audit_active) 3230Sstevel@tonic-gate audit_priv(priv, allzone ? ZONEPRIVS(cr) : NULL, 0); 3240Sstevel@tonic-gate #endif 3250Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone); 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) || 3280Sstevel@tonic-gate curthread->t_pre_sys) { 3290Sstevel@tonic-gate if (allzone && !HAS_ALLZONEPRIVS(cr)) { 3300Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_ALLZONE, msg); 3310Sstevel@tonic-gate } else { 3320Sstevel@tonic-gate ASSERT(!HAS_PRIVILEGE(cr, priv)); 3330Sstevel@tonic-gate priv_policy_errmsg(cr, priv, msg); 3340Sstevel@tonic-gate } 3350Sstevel@tonic-gate } 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate /* 3390Sstevel@tonic-gate * priv_policy() 3400Sstevel@tonic-gate * return 0 or error. 3410Sstevel@tonic-gate * See block comment above for a description of "priv" and "allzone" usage. 3420Sstevel@tonic-gate */ 3430Sstevel@tonic-gate int 3440Sstevel@tonic-gate priv_policy(const cred_t *cr, int priv, boolean_t allzone, int err, 3450Sstevel@tonic-gate const char *msg) 3460Sstevel@tonic-gate { 3470Sstevel@tonic-gate if (HAS_PRIVILEGE(cr, priv) && (!allzone || HAS_ALLZONEPRIVS(cr))) { 3480Sstevel@tonic-gate if ((allzone || priv == PRIV_ALL || 3490Sstevel@tonic-gate !PRIV_ISASSERT(priv_basic, priv)) && 3500Sstevel@tonic-gate !servicing_interrupt()) { 3510Sstevel@tonic-gate u.u_acflag |= ASU; /* Needed for SVVS */ 3520Sstevel@tonic-gate #ifdef C2_AUDIT 3530Sstevel@tonic-gate if (audit_active) 3540Sstevel@tonic-gate audit_priv(priv, 3550Sstevel@tonic-gate allzone ? ZONEPRIVS(cr) : NULL, 1); 3560Sstevel@tonic-gate #endif 3570Sstevel@tonic-gate } 3580Sstevel@tonic-gate err = 0; 3590Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone); 3600Sstevel@tonic-gate } else if (!servicing_interrupt()) { 3610Sstevel@tonic-gate /* Failure audited in this procedure */ 3620Sstevel@tonic-gate priv_policy_err(cr, priv, allzone, msg); 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate return (err); 3660Sstevel@tonic-gate } 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate /* 3690Sstevel@tonic-gate * Return B_TRUE for sufficient privileges, B_FALSE for insufficient privileges. 3700Sstevel@tonic-gate */ 3710Sstevel@tonic-gate boolean_t 3720Sstevel@tonic-gate priv_policy_choice(const cred_t *cr, int priv, boolean_t allzone) 3730Sstevel@tonic-gate { 3740Sstevel@tonic-gate boolean_t res = HAS_PRIVILEGE(cr, priv) && 3750Sstevel@tonic-gate (!allzone || HAS_ALLZONEPRIVS(cr)); 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate #ifdef C2_AUDIT 3780Sstevel@tonic-gate /* Audit success only */ 3790Sstevel@tonic-gate if (res && audit_active && 3800Sstevel@tonic-gate (allzone || priv == PRIV_ALL || !PRIV_ISASSERT(priv_basic, priv)) && 3810Sstevel@tonic-gate !servicing_interrupt()) { 3820Sstevel@tonic-gate audit_priv(priv, allzone ? ZONEPRIVS(cr) : NULL, 1); 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate #endif 3850Sstevel@tonic-gate if (res) { 3860Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone); 3870Sstevel@tonic-gate } else { 3880Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone); 3890Sstevel@tonic-gate } 3900Sstevel@tonic-gate return (res); 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate /* 3940Sstevel@tonic-gate * Non-auditing variant of priv_policy_choice(). 3950Sstevel@tonic-gate */ 3960Sstevel@tonic-gate boolean_t 3970Sstevel@tonic-gate priv_policy_only(const cred_t *cr, int priv, boolean_t allzone) 3980Sstevel@tonic-gate { 3990Sstevel@tonic-gate boolean_t res = HAS_PRIVILEGE(cr, priv) && 4000Sstevel@tonic-gate (!allzone || HAS_ALLZONEPRIVS(cr)); 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate if (res) { 4030Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone); 4040Sstevel@tonic-gate } else { 4050Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone); 4060Sstevel@tonic-gate } 4070Sstevel@tonic-gate return (res); 4080Sstevel@tonic-gate } 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate /* 4110Sstevel@tonic-gate * Check whether all privileges in the required set are present. 4120Sstevel@tonic-gate */ 4130Sstevel@tonic-gate static int 4140Sstevel@tonic-gate secpolicy_require_set(const cred_t *cr, const priv_set_t *req, const char *msg) 4150Sstevel@tonic-gate { 4160Sstevel@tonic-gate int priv; 4170Sstevel@tonic-gate int pfound = -1; 4180Sstevel@tonic-gate priv_set_t pset; 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate if (req == PRIV_FULLSET ? HAS_ALLPRIVS(cr) : priv_issubset(req, 4210Sstevel@tonic-gate &CR_OEPRIV(cr))) { 4220Sstevel@tonic-gate return (0); 4230Sstevel@tonic-gate } 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate if (req == PRIV_FULLSET || priv_isfullset(req)) { 4260Sstevel@tonic-gate priv_policy_err(cr, PRIV_ALL, B_FALSE, msg); 4270Sstevel@tonic-gate return (EACCES); 4280Sstevel@tonic-gate } 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate pset = CR_OEPRIV(cr); /* present privileges */ 4310Sstevel@tonic-gate priv_inverse(&pset); /* all non present privileges */ 4320Sstevel@tonic-gate priv_intersect(req, &pset); /* the actual missing privs */ 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate #ifdef C2_AUDIT 4350Sstevel@tonic-gate if (audit_active) 4360Sstevel@tonic-gate audit_priv(PRIV_NONE, &pset, 0); 4370Sstevel@tonic-gate #endif 4380Sstevel@tonic-gate /* 4390Sstevel@tonic-gate * Privilege debugging; special case "one privilege in set". 4400Sstevel@tonic-gate */ 4410Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) || curthread->t_pre_sys) { 4420Sstevel@tonic-gate for (priv = 0; priv < nprivs; priv++) { 4430Sstevel@tonic-gate if (priv_ismember(&pset, priv)) { 4440Sstevel@tonic-gate if (pfound != -1) { 4450Sstevel@tonic-gate /* Multiple missing privs */ 4460Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_MULTIPLE, 4470Sstevel@tonic-gate msg); 4480Sstevel@tonic-gate return (EACCES); 4490Sstevel@tonic-gate } 4500Sstevel@tonic-gate pfound = priv; 4510Sstevel@tonic-gate } 4520Sstevel@tonic-gate } 4530Sstevel@tonic-gate ASSERT(pfound != -1); 4540Sstevel@tonic-gate /* Just the one missing privilege */ 4550Sstevel@tonic-gate priv_policy_errmsg(cr, pfound, msg); 4560Sstevel@tonic-gate } 4570Sstevel@tonic-gate 4580Sstevel@tonic-gate return (EACCES); 4590Sstevel@tonic-gate } 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate /* 4620Sstevel@tonic-gate * Called when an operation requires that the caller be in the 4630Sstevel@tonic-gate * global zone, regardless of privilege. 4640Sstevel@tonic-gate */ 4650Sstevel@tonic-gate static int 4660Sstevel@tonic-gate priv_policy_global(const cred_t *cr) 4670Sstevel@tonic-gate { 4680Sstevel@tonic-gate if (crgetzoneid(cr) == GLOBAL_ZONEID) 4690Sstevel@tonic-gate return (0); /* success */ 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) || 4720Sstevel@tonic-gate curthread->t_pre_sys) { 4730Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_GLOBAL, NULL); 4740Sstevel@tonic-gate } 4750Sstevel@tonic-gate return (EPERM); 4760Sstevel@tonic-gate } 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate /* 4790Sstevel@tonic-gate * Changing process priority 4800Sstevel@tonic-gate */ 4810Sstevel@tonic-gate int 4820Sstevel@tonic-gate secpolicy_setpriority(const cred_t *cr) 4830Sstevel@tonic-gate { 4840Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_PRIOCNTL, B_FALSE, EPERM, NULL)); 4850Sstevel@tonic-gate } 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate /* 4880Sstevel@tonic-gate * Binding to a privileged port, port must be specified in host byte 4890Sstevel@tonic-gate * order. 4900Sstevel@tonic-gate */ 4910Sstevel@tonic-gate int 4920Sstevel@tonic-gate secpolicy_net_privaddr(const cred_t *cr, in_port_t port) 4930Sstevel@tonic-gate { 4940Sstevel@tonic-gate /* 4950Sstevel@tonic-gate * NFS ports, these are extra privileged ports, allow bind 4960Sstevel@tonic-gate * only if the SYS_NFS privilege is present. 4970Sstevel@tonic-gate */ 4980Sstevel@tonic-gate if (port == 2049 || port == 4045) 4990Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_NFS, B_FALSE, EACCES, 5000Sstevel@tonic-gate "NFS port")); 5010Sstevel@tonic-gate else 5020Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_NET_PRIVADDR, B_FALSE, EACCES, 5030Sstevel@tonic-gate NULL)); 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate /* 5070Sstevel@tonic-gate * Common routine which determines whether a given credential can 5080Sstevel@tonic-gate * act on a given mount. 5090Sstevel@tonic-gate * When called through mount, the parameter needoptcheck is a pointer 5100Sstevel@tonic-gate * to a boolean variable which will be set to either true or false, 5110Sstevel@tonic-gate * depending on whether the mount policy should change the mount options. 5120Sstevel@tonic-gate * In all other cases, needoptcheck should be a NULL pointer. 5130Sstevel@tonic-gate */ 5140Sstevel@tonic-gate static int 5150Sstevel@tonic-gate secpolicy_fs_common(cred_t *cr, vnode_t *mvp, const vfs_t *vfsp, 5160Sstevel@tonic-gate boolean_t *needoptcheck) 5170Sstevel@tonic-gate { 5180Sstevel@tonic-gate boolean_t allzone = B_FALSE; 5190Sstevel@tonic-gate boolean_t mounting = needoptcheck != NULL; 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate /* 5220Sstevel@tonic-gate * Short circuit the following cases: 5230Sstevel@tonic-gate * vfsp == NULL or mvp == NULL (pure privilege check) 5240Sstevel@tonic-gate * have all privileges - no further checks required 5250Sstevel@tonic-gate * and no mount options need to be set. 5260Sstevel@tonic-gate */ 5270Sstevel@tonic-gate if (vfsp == NULL || mvp == NULL || HAS_ALLPRIVS(cr)) { 5280Sstevel@tonic-gate if (mounting) 5290Sstevel@tonic-gate *needoptcheck = B_FALSE; 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_MOUNT, allzone, EPERM, NULL)); 5320Sstevel@tonic-gate } 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate /* 5350Sstevel@tonic-gate * When operating on an existing mount (either we're not mounting 5360Sstevel@tonic-gate * or we're doing a remount and VFS_REMOUNT will be set), zones 5370Sstevel@tonic-gate * can operate only on mounts established by the zone itself. 5380Sstevel@tonic-gate */ 5390Sstevel@tonic-gate if (!mounting || (vfsp->vfs_flag & VFS_REMOUNT) != 0) { 5400Sstevel@tonic-gate zoneid_t zoneid = crgetzoneid(cr); 5410Sstevel@tonic-gate 5420Sstevel@tonic-gate if (zoneid != GLOBAL_ZONEID && 5430Sstevel@tonic-gate vfsp->vfs_zone->zone_id != zoneid) { 5440Sstevel@tonic-gate return (EPERM); 5450Sstevel@tonic-gate } 5460Sstevel@tonic-gate } 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate if (mounting) 5490Sstevel@tonic-gate *needoptcheck = B_TRUE; 5500Sstevel@tonic-gate 5510Sstevel@tonic-gate /* 5520Sstevel@tonic-gate * Overlay mounts may hide important stuff; if you can't write to a 5530Sstevel@tonic-gate * mount point but would be able to mount on top of it, you can 5540Sstevel@tonic-gate * escalate your privileges. 5550Sstevel@tonic-gate * So we go about asking the same questions namefs does when it 5560Sstevel@tonic-gate * decides whether you can mount over a file or not but with the 5570Sstevel@tonic-gate * added restriction that you can only mount on top of a regular 5580Sstevel@tonic-gate * file or directory. 5590Sstevel@tonic-gate * If we have all the zone's privileges, we skip all other checks, 5600Sstevel@tonic-gate * or else we may actually get in trouble inside the automounter. 5610Sstevel@tonic-gate */ 5620Sstevel@tonic-gate if ((mvp->v_flag & VROOT) != 0 || 5630Sstevel@tonic-gate (mvp->v_type != VDIR && mvp->v_type != VREG) || 5640Sstevel@tonic-gate HAS_ALLZONEPRIVS(cr)) { 5650Sstevel@tonic-gate allzone = B_TRUE; 5660Sstevel@tonic-gate } else { 5670Sstevel@tonic-gate vattr_t va; 5680Sstevel@tonic-gate int err; 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate va.va_mask = AT_UID|AT_MODE; 5710Sstevel@tonic-gate err = VOP_GETATTR(mvp, &va, 0, cr); 5720Sstevel@tonic-gate if (err != 0) 5730Sstevel@tonic-gate return (err); 5740Sstevel@tonic-gate 5750Sstevel@tonic-gate if ((err = secpolicy_vnode_owner(cr, va.va_uid)) != 0) 5760Sstevel@tonic-gate return (err); 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate if ((va.va_mode & VWRITE) == 0 && 5790Sstevel@tonic-gate secpolicy_vnode_access(cr, mvp, va.va_uid, VWRITE) != 0) { 5800Sstevel@tonic-gate return (EACCES); 5810Sstevel@tonic-gate } 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_MOUNT, allzone, EPERM, NULL)); 5840Sstevel@tonic-gate } 5850Sstevel@tonic-gate 586*148Scasper extern vnode_t *rootvp; 587*148Scasper extern vfs_t *rootvfs; 588*148Scasper 5890Sstevel@tonic-gate int 5900Sstevel@tonic-gate secpolicy_fs_mount(cred_t *cr, vnode_t *mvp, struct vfs *vfsp) 5910Sstevel@tonic-gate { 5920Sstevel@tonic-gate boolean_t needoptchk; 5930Sstevel@tonic-gate int error; 5940Sstevel@tonic-gate 595*148Scasper /* 596*148Scasper * If it's a remount, get the underlying mount point, 597*148Scasper * except for the root where we use the rootvp. 598*148Scasper */ 599*148Scasper if ((vfsp->vfs_flag & VFS_REMOUNT) != 0) { 600*148Scasper if (vfsp == rootvfs) 601*148Scasper mvp = rootvp; 602*148Scasper else 603*148Scasper mvp = vfsp->vfs_vnodecovered; 604*148Scasper } 605*148Scasper 6060Sstevel@tonic-gate error = secpolicy_fs_common(cr, mvp, vfsp, &needoptchk); 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate if (error == 0 && needoptchk) { 6090Sstevel@tonic-gate boolean_t amsuper = HAS_ALLZONEPRIVS(cr); 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate /* 6120Sstevel@tonic-gate * Third check; if we don't have either "nosuid" or 6130Sstevel@tonic-gate * both "nosetuid" and "nodevices", then we add 6140Sstevel@tonic-gate * "nosuid"; this depends on how the current 6150Sstevel@tonic-gate * implementation works (it first checks nosuid). In a 6160Sstevel@tonic-gate * zone, a user with all zone privileges can mount with 6170Sstevel@tonic-gate * "setuid" but never with "devices". 6180Sstevel@tonic-gate */ 6190Sstevel@tonic-gate if (!vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL) && 6200Sstevel@tonic-gate (!vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL) || 6210Sstevel@tonic-gate !vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL))) { 6220Sstevel@tonic-gate if (crgetzoneid(cr) == GLOBAL_ZONEID || !amsuper) 6230Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_NOSUID, NULL, 0); 6240Sstevel@tonic-gate else 6250Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_NODEVICES, NULL, 0); 6260Sstevel@tonic-gate } 6270Sstevel@tonic-gate /* 6280Sstevel@tonic-gate * If we're not the local super user, we set the "restrict" 6290Sstevel@tonic-gate * option to indicate to automountd that this mount should 6300Sstevel@tonic-gate * be handled with care. 6310Sstevel@tonic-gate */ 6320Sstevel@tonic-gate if (!amsuper) 6330Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_RESTRICT, NULL, 0); 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate } 6360Sstevel@tonic-gate return (error); 6370Sstevel@tonic-gate } 6380Sstevel@tonic-gate 6390Sstevel@tonic-gate /* 6400Sstevel@tonic-gate * Does the policy computations for "ownership" of a mount; 6410Sstevel@tonic-gate * here ownership is defined as the ability to "mount" 6420Sstevel@tonic-gate * the filesystem originally. The rootvfs doesn't cover any 6430Sstevel@tonic-gate * vnodes; we attribute its ownership to the rootvp. 6440Sstevel@tonic-gate */ 6450Sstevel@tonic-gate static int 6460Sstevel@tonic-gate secpolicy_fs_owner(cred_t *cr, const struct vfs *vfsp) 6470Sstevel@tonic-gate { 6480Sstevel@tonic-gate vnode_t *mvp; 6490Sstevel@tonic-gate 6500Sstevel@tonic-gate if (vfsp == NULL) 6510Sstevel@tonic-gate mvp = NULL; 6520Sstevel@tonic-gate else if (vfsp == rootvfs) 6530Sstevel@tonic-gate mvp = rootvp; 6540Sstevel@tonic-gate else 6550Sstevel@tonic-gate mvp = vfsp->vfs_vnodecovered; 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate return (secpolicy_fs_common(cr, mvp, vfsp, NULL)); 6580Sstevel@tonic-gate } 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate int 6610Sstevel@tonic-gate secpolicy_fs_unmount(cred_t *cr, struct vfs *vfsp) 6620Sstevel@tonic-gate { 6630Sstevel@tonic-gate return (secpolicy_fs_owner(cr, vfsp)); 6640Sstevel@tonic-gate } 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate /* 6670Sstevel@tonic-gate * Quotas are a resource, but if one has the ability to mount a filesystem, he 6680Sstevel@tonic-gate * should be able to modify quotas on it. 6690Sstevel@tonic-gate */ 6700Sstevel@tonic-gate int 6710Sstevel@tonic-gate secpolicy_fs_quota(const cred_t *cr, const vfs_t *vfsp) 6720Sstevel@tonic-gate { 6730Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 6740Sstevel@tonic-gate } 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate /* 6770Sstevel@tonic-gate * Exceeding minfree: also a per-mount resource constraint. 6780Sstevel@tonic-gate */ 6790Sstevel@tonic-gate int 6800Sstevel@tonic-gate secpolicy_fs_minfree(const cred_t *cr, const vfs_t *vfsp) 6810Sstevel@tonic-gate { 6820Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 6830Sstevel@tonic-gate } 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate int 6860Sstevel@tonic-gate secpolicy_fs_config(const cred_t *cr, const vfs_t *vfsp) 6870Sstevel@tonic-gate { 6880Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 6890Sstevel@tonic-gate } 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate /* ARGSUSED */ 6920Sstevel@tonic-gate int 6930Sstevel@tonic-gate secpolicy_fs_linkdir(const cred_t *cr, const vfs_t *vfsp) 6940Sstevel@tonic-gate { 6950Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_LINKDIR, B_FALSE, EPERM, NULL)); 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate /* 6990Sstevel@tonic-gate * Name: secpolicy_vnode_access() 7000Sstevel@tonic-gate * 7010Sstevel@tonic-gate * Parameters: Process credential 7020Sstevel@tonic-gate * vnode 7030Sstevel@tonic-gate * uid of owner of vnode 7040Sstevel@tonic-gate * permission bits not granted to the caller when examining 7050Sstevel@tonic-gate * file mode bits (i.e., when a process wants to open a 7060Sstevel@tonic-gate * mode 444 file for VREAD|VWRITE, this function should be 7070Sstevel@tonic-gate * called only with a VWRITE argument). 7080Sstevel@tonic-gate * 7090Sstevel@tonic-gate * Normal: Verifies that cred has the appropriate privileges to 7100Sstevel@tonic-gate * override the mode bits that were denied. 7110Sstevel@tonic-gate * 7120Sstevel@tonic-gate * Override: file_dac_execute - if VEXEC bit was denied and vnode is 7130Sstevel@tonic-gate * not a directory. 7140Sstevel@tonic-gate * file_dac_read - if VREAD bit was denied. 7150Sstevel@tonic-gate * file_dac_search - if VEXEC bit was denied and vnode is 7160Sstevel@tonic-gate * a directory. 7170Sstevel@tonic-gate * file_dac_write - if VWRITE bit was denied. 7180Sstevel@tonic-gate * 7190Sstevel@tonic-gate * Root owned files are special cased to protect system 7200Sstevel@tonic-gate * configuration files and such. 7210Sstevel@tonic-gate * 7220Sstevel@tonic-gate * Output: EACCES - if privilege check fails. 7230Sstevel@tonic-gate */ 7240Sstevel@tonic-gate 7250Sstevel@tonic-gate /* ARGSUSED */ 7260Sstevel@tonic-gate int 7270Sstevel@tonic-gate secpolicy_vnode_access(const cred_t *cr, vnode_t *vp, uid_t owner, mode_t mode) 7280Sstevel@tonic-gate { 7290Sstevel@tonic-gate if ((mode & VREAD) && 7300Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_FILE_DAC_READ, B_FALSE, EACCES, NULL) != 0) 7310Sstevel@tonic-gate return (EACCES); 7320Sstevel@tonic-gate 7330Sstevel@tonic-gate if (mode & VWRITE) { 7340Sstevel@tonic-gate boolean_t allzone; 7350Sstevel@tonic-gate 7360Sstevel@tonic-gate if (owner == 0 && cr->cr_uid != 0) 7370Sstevel@tonic-gate allzone = B_TRUE; 7380Sstevel@tonic-gate else 7390Sstevel@tonic-gate allzone = B_FALSE; 7400Sstevel@tonic-gate if (PRIV_POLICY(cr, PRIV_FILE_DAC_WRITE, allzone, EACCES, NULL) 7410Sstevel@tonic-gate != 0) 7420Sstevel@tonic-gate return (EACCES); 7430Sstevel@tonic-gate } 7440Sstevel@tonic-gate 7450Sstevel@tonic-gate if (mode & VEXEC) { 7460Sstevel@tonic-gate /* 7470Sstevel@tonic-gate * Directories use file_dac_search to override the execute bit. 7480Sstevel@tonic-gate */ 7490Sstevel@tonic-gate vtype_t vtype = vp->v_type; 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate if (vtype == VDIR) 7520Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_DAC_SEARCH, B_FALSE, 7530Sstevel@tonic-gate EACCES, NULL)); 7540Sstevel@tonic-gate else 7550Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_DAC_EXECUTE, B_FALSE, 7560Sstevel@tonic-gate EACCES, NULL)); 7570Sstevel@tonic-gate } 7580Sstevel@tonic-gate return (0); 7590Sstevel@tonic-gate } 7600Sstevel@tonic-gate 7610Sstevel@tonic-gate /* 7620Sstevel@tonic-gate * Name: secpolicy_vnode_setid_modify() 7630Sstevel@tonic-gate * 7640Sstevel@tonic-gate * Normal: verify that subject can set the file setid flags. 7650Sstevel@tonic-gate * 7660Sstevel@tonic-gate * Output: EPERM - if not privileged. 7670Sstevel@tonic-gate */ 7680Sstevel@tonic-gate 7690Sstevel@tonic-gate static int 7700Sstevel@tonic-gate secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner) 7710Sstevel@tonic-gate { 7720Sstevel@tonic-gate /* If changing to suid root, must have all zone privs */ 7730Sstevel@tonic-gate boolean_t allzone = B_TRUE; 7740Sstevel@tonic-gate 7750Sstevel@tonic-gate if (owner != 0) { 7760Sstevel@tonic-gate if (owner == cr->cr_uid) 7770Sstevel@tonic-gate return (0); 7780Sstevel@tonic-gate allzone = B_FALSE; 7790Sstevel@tonic-gate } 7800Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_SETID, allzone, EPERM, NULL)); 7810Sstevel@tonic-gate } 7820Sstevel@tonic-gate 7830Sstevel@tonic-gate /* 7840Sstevel@tonic-gate * Are we allowed to retain the set-uid/set-gid bits when 7850Sstevel@tonic-gate * changing ownership or when writing to a file? 7860Sstevel@tonic-gate * "issuid" should be true when set-uid; only in that case 7870Sstevel@tonic-gate * root ownership is checked (setgid is assumed). 7880Sstevel@tonic-gate */ 7890Sstevel@tonic-gate int 7900Sstevel@tonic-gate secpolicy_vnode_setid_retain(const cred_t *cred, boolean_t issuidroot) 7910Sstevel@tonic-gate { 7920Sstevel@tonic-gate if (issuidroot && !HAS_ALLZONEPRIVS(cred)) 7930Sstevel@tonic-gate return (EPERM); 7940Sstevel@tonic-gate 7950Sstevel@tonic-gate return (!PRIV_POLICY_CHOICE(cred, PRIV_FILE_SETID, B_FALSE)); 7960Sstevel@tonic-gate } 7970Sstevel@tonic-gate 7980Sstevel@tonic-gate /* 7990Sstevel@tonic-gate * Name: secpolicy_vnode_setids_setgids() 8000Sstevel@tonic-gate * 8010Sstevel@tonic-gate * Normal: verify that subject can set the file setgid flag. 8020Sstevel@tonic-gate * 8030Sstevel@tonic-gate * Output: EPERM - if not privileged 8040Sstevel@tonic-gate */ 8050Sstevel@tonic-gate 8060Sstevel@tonic-gate int 8070Sstevel@tonic-gate secpolicy_vnode_setids_setgids(const cred_t *cred, gid_t gid) 8080Sstevel@tonic-gate { 8090Sstevel@tonic-gate if (!groupmember(gid, cred)) 8100Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_SETID, B_FALSE, EPERM, 8110Sstevel@tonic-gate NULL)); 8120Sstevel@tonic-gate return (0); 8130Sstevel@tonic-gate } 8140Sstevel@tonic-gate 8150Sstevel@tonic-gate /* 8160Sstevel@tonic-gate * Create a file with a group different than any of the groups allowed: 8170Sstevel@tonic-gate * the group of the directory the file is created in, the effective 8180Sstevel@tonic-gate * group or any of the supplementary groups. 8190Sstevel@tonic-gate */ 8200Sstevel@tonic-gate int 8210Sstevel@tonic-gate secpolicy_vnode_create_gid(const cred_t *cred) 8220Sstevel@tonic-gate { 8230Sstevel@tonic-gate if (HAS_PRIVILEGE(cred, PRIV_FILE_CHOWN)) 8240Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_CHOWN, B_FALSE, EPERM, 8250Sstevel@tonic-gate NULL)); 8260Sstevel@tonic-gate else 8270Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_CHOWN_SELF, B_FALSE, EPERM, 8280Sstevel@tonic-gate NULL)); 8290Sstevel@tonic-gate } 8300Sstevel@tonic-gate 8310Sstevel@tonic-gate /* 8320Sstevel@tonic-gate * Name: secpolicy_vnode_utime_modify() 8330Sstevel@tonic-gate * 8340Sstevel@tonic-gate * Normal: verify that subject can modify the utime on a file. 8350Sstevel@tonic-gate * 8360Sstevel@tonic-gate * Output: EPERM - if access denied. 8370Sstevel@tonic-gate */ 8380Sstevel@tonic-gate 8390Sstevel@tonic-gate static int 8400Sstevel@tonic-gate secpolicy_vnode_utime_modify(const cred_t *cred) 8410Sstevel@tonic-gate { 8420Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_OWNER, B_FALSE, EPERM, 8430Sstevel@tonic-gate "modify file times")); 8440Sstevel@tonic-gate } 8450Sstevel@tonic-gate 8460Sstevel@tonic-gate 8470Sstevel@tonic-gate /* 8480Sstevel@tonic-gate * Name: secpolicy_vnode_setdac() 8490Sstevel@tonic-gate * 8500Sstevel@tonic-gate * Normal: verify that subject can modify the mode of a file. 8510Sstevel@tonic-gate * allzone privilege needed when modifying root owned object. 8520Sstevel@tonic-gate * 8530Sstevel@tonic-gate * Output: EPERM - if access denied. 8540Sstevel@tonic-gate */ 8550Sstevel@tonic-gate 8560Sstevel@tonic-gate int 8570Sstevel@tonic-gate secpolicy_vnode_setdac(const cred_t *cred, uid_t owner) 8580Sstevel@tonic-gate { 8590Sstevel@tonic-gate if (owner == cred->cr_uid) 8600Sstevel@tonic-gate return (0); 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_OWNER, owner == 0, EPERM, NULL)); 8630Sstevel@tonic-gate } 8640Sstevel@tonic-gate /* 8650Sstevel@tonic-gate * Name: secpolicy_vnode_stky_modify() 8660Sstevel@tonic-gate * 8670Sstevel@tonic-gate * Normal: verify that subject can make a file a "sticky". 8680Sstevel@tonic-gate * 8690Sstevel@tonic-gate * Output: EPERM - if access denied. 8700Sstevel@tonic-gate */ 8710Sstevel@tonic-gate 8720Sstevel@tonic-gate int 8730Sstevel@tonic-gate secpolicy_vnode_stky_modify(const cred_t *cred) 8740Sstevel@tonic-gate { 8750Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_SYS_CONFIG, B_FALSE, EPERM, 8760Sstevel@tonic-gate "set file sticky")); 8770Sstevel@tonic-gate } 8780Sstevel@tonic-gate 8790Sstevel@tonic-gate /* 8800Sstevel@tonic-gate * Policy determines whether we can remove an entry from a directory, 8810Sstevel@tonic-gate * regardless of permission bits. 8820Sstevel@tonic-gate */ 8830Sstevel@tonic-gate int 8840Sstevel@tonic-gate secpolicy_vnode_remove(const cred_t *cr) 8850Sstevel@tonic-gate { 8860Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_OWNER, B_FALSE, EACCES, 8870Sstevel@tonic-gate "sticky directory")); 8880Sstevel@tonic-gate } 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate int 8910Sstevel@tonic-gate secpolicy_vnode_owner(const cred_t *cr, uid_t owner) 8920Sstevel@tonic-gate { 8930Sstevel@tonic-gate boolean_t allzone = (owner == 0); 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate if (owner == cr->cr_uid) 8960Sstevel@tonic-gate return (0); 8970Sstevel@tonic-gate 8980Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_OWNER, allzone, EPERM, NULL)); 8990Sstevel@tonic-gate } 9000Sstevel@tonic-gate 9010Sstevel@tonic-gate /* 9020Sstevel@tonic-gate * This function checks the policy decisions surrounding the 9030Sstevel@tonic-gate * vop setattr call. 9040Sstevel@tonic-gate * 9050Sstevel@tonic-gate * It should be called after sufficient locks have been established 9060Sstevel@tonic-gate * on the underlying data structures. No concurrent modifications 9070Sstevel@tonic-gate * should be allowed. 9080Sstevel@tonic-gate * 9090Sstevel@tonic-gate * The caller must pass in unlocked version of its vaccess function 9100Sstevel@tonic-gate * this is required because vop_access function should lock the 9110Sstevel@tonic-gate * node for reading. A three argument function should be defined 9120Sstevel@tonic-gate * which accepts the following argument: 9130Sstevel@tonic-gate * A pointer to the internal "node" type (inode *) 9140Sstevel@tonic-gate * vnode access bits (VREAD|VWRITE|VEXEC) 9150Sstevel@tonic-gate * a pointer to the credential 9160Sstevel@tonic-gate * 9170Sstevel@tonic-gate * This function makes the following policy decisions: 9180Sstevel@tonic-gate * 9190Sstevel@tonic-gate * - change permissions 9200Sstevel@tonic-gate * - permission to change file mode if not owner 9210Sstevel@tonic-gate * - permission to add sticky bit to non-directory 9220Sstevel@tonic-gate * - permission to add set-gid bit 9230Sstevel@tonic-gate * 9240Sstevel@tonic-gate * The ovap argument should include AT_MODE|AT_UID|AT_GID. 9250Sstevel@tonic-gate * 9260Sstevel@tonic-gate * If the vap argument does not include AT_MODE, the mode will be copied from 9270Sstevel@tonic-gate * ovap. In certain situations set-uid/set-gid bits need to be removed; 9280Sstevel@tonic-gate * this is done by marking vap->va_mask to include AT_MODE and va_mode 9290Sstevel@tonic-gate * is updated to the newly computed mode. 9300Sstevel@tonic-gate */ 9310Sstevel@tonic-gate 9320Sstevel@tonic-gate int 9330Sstevel@tonic-gate secpolicy_vnode_setattr(cred_t *cr, struct vnode *vp, struct vattr *vap, 9340Sstevel@tonic-gate const struct vattr *ovap, int flags, 9350Sstevel@tonic-gate int unlocked_access(void *, int, cred_t *), 9360Sstevel@tonic-gate void *node) 9370Sstevel@tonic-gate { 9380Sstevel@tonic-gate int mask = vap->va_mask; 9390Sstevel@tonic-gate int error = 0; 9400Sstevel@tonic-gate 9410Sstevel@tonic-gate if (mask & AT_SIZE) { 9420Sstevel@tonic-gate if (vp->v_type == VDIR) { 9430Sstevel@tonic-gate error = EISDIR; 9440Sstevel@tonic-gate goto out; 9450Sstevel@tonic-gate } 9460Sstevel@tonic-gate error = unlocked_access(node, VWRITE, cr); 9470Sstevel@tonic-gate if (error) 9480Sstevel@tonic-gate goto out; 9490Sstevel@tonic-gate } 9500Sstevel@tonic-gate if (mask & AT_MODE) { 9510Sstevel@tonic-gate /* 9520Sstevel@tonic-gate * If not the owner of the file then check privilege 9530Sstevel@tonic-gate * for two things: the privilege to set the mode at all 9540Sstevel@tonic-gate * and, if we're setting setuid, we also need permissions 9550Sstevel@tonic-gate * to add the set-uid bit, if we're not the owner. 9560Sstevel@tonic-gate * In the specific case of creating a set-uid root 9570Sstevel@tonic-gate * file, we need even more permissions. 9580Sstevel@tonic-gate */ 9590Sstevel@tonic-gate if ((error = secpolicy_vnode_setdac(cr, ovap->va_uid)) != 0) 9600Sstevel@tonic-gate goto out; 9610Sstevel@tonic-gate 9620Sstevel@tonic-gate if ((vap->va_mode & S_ISUID) != 0 && 9630Sstevel@tonic-gate (error = secpolicy_vnode_setid_modify(cr, 9640Sstevel@tonic-gate ovap->va_uid)) != 0) { 9650Sstevel@tonic-gate goto out; 9660Sstevel@tonic-gate } 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate /* 9690Sstevel@tonic-gate * Check privilege if attempting to set the 9700Sstevel@tonic-gate * sticky bit on a non-directory. 9710Sstevel@tonic-gate */ 9720Sstevel@tonic-gate if (vp->v_type != VDIR && (vap->va_mode & S_ISVTX) != 0 && 9730Sstevel@tonic-gate secpolicy_vnode_stky_modify(cr) != 0) { 9740Sstevel@tonic-gate vap->va_mode &= ~S_ISVTX; 9750Sstevel@tonic-gate } 9760Sstevel@tonic-gate 9770Sstevel@tonic-gate /* 9780Sstevel@tonic-gate * Check for privilege if attempting to set the 9790Sstevel@tonic-gate * group-id bit. 9800Sstevel@tonic-gate */ 9810Sstevel@tonic-gate if ((vap->va_mode & S_ISGID) != 0 && 9820Sstevel@tonic-gate secpolicy_vnode_setids_setgids(cr, ovap->va_gid) != 0) { 9830Sstevel@tonic-gate vap->va_mode &= ~S_ISGID; 9840Sstevel@tonic-gate } 9850Sstevel@tonic-gate 9860Sstevel@tonic-gate } else 9870Sstevel@tonic-gate vap->va_mode = ovap->va_mode; 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate if (mask & (AT_UID|AT_GID)) { 9900Sstevel@tonic-gate boolean_t checkpriv = B_FALSE; 9910Sstevel@tonic-gate int priv; 9920Sstevel@tonic-gate boolean_t allzone = B_FALSE; 9930Sstevel@tonic-gate 9940Sstevel@tonic-gate /* 9950Sstevel@tonic-gate * Chowning files. 9960Sstevel@tonic-gate * 9970Sstevel@tonic-gate * If you are the file owner: 9980Sstevel@tonic-gate * chown to other uid FILE_CHOWN_SELF 9990Sstevel@tonic-gate * chown to gid (non-member) FILE_CHOWN_SELF 10000Sstevel@tonic-gate * chown to gid (member) <none> 10010Sstevel@tonic-gate * 10020Sstevel@tonic-gate * Instead of PRIV_FILE_CHOWN_SELF, FILE_CHOWN is also 10030Sstevel@tonic-gate * acceptable but the first one is reported when debugging. 10040Sstevel@tonic-gate * 10050Sstevel@tonic-gate * If you are not the file owner: 10060Sstevel@tonic-gate * chown from root PRIV_FILE_CHOWN + zone 10070Sstevel@tonic-gate * chown from other to any PRIV_FILE_CHOWN 10080Sstevel@tonic-gate * 10090Sstevel@tonic-gate */ 10100Sstevel@tonic-gate if (cr->cr_uid != ovap->va_uid) { 10110Sstevel@tonic-gate checkpriv = B_TRUE; 10120Sstevel@tonic-gate allzone = (ovap->va_uid == 0); 10130Sstevel@tonic-gate priv = PRIV_FILE_CHOWN; 10140Sstevel@tonic-gate } else { 10150Sstevel@tonic-gate if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || 10160Sstevel@tonic-gate ((mask & AT_GID) && vap->va_gid != ovap->va_gid && 10170Sstevel@tonic-gate !groupmember(vap->va_gid, cr))) { 10180Sstevel@tonic-gate checkpriv = B_TRUE; 10190Sstevel@tonic-gate priv = HAS_PRIVILEGE(cr, PRIV_FILE_CHOWN) ? 10200Sstevel@tonic-gate PRIV_FILE_CHOWN : PRIV_FILE_CHOWN_SELF; 10210Sstevel@tonic-gate } 10220Sstevel@tonic-gate } 10230Sstevel@tonic-gate /* 10240Sstevel@tonic-gate * If necessary, check privilege to see if update can be done. 10250Sstevel@tonic-gate */ 10260Sstevel@tonic-gate if (checkpriv && 10270Sstevel@tonic-gate (error = PRIV_POLICY(cr, priv, allzone, EPERM, NULL)) 10280Sstevel@tonic-gate != 0) { 10290Sstevel@tonic-gate goto out; 10300Sstevel@tonic-gate } 10310Sstevel@tonic-gate 10320Sstevel@tonic-gate /* 10330Sstevel@tonic-gate * If the file has either the set UID or set GID bits 10340Sstevel@tonic-gate * set and the caller can set the bits, then leave them. 10350Sstevel@tonic-gate */ 10360Sstevel@tonic-gate if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0 && 10370Sstevel@tonic-gate secpolicy_vnode_setid_retain(cr, 10380Sstevel@tonic-gate (vap->va_mode & S_ISUID) != 0 && 10390Sstevel@tonic-gate (mask & AT_UID) != 0 && vap->va_uid == 0) != 0) { 10400Sstevel@tonic-gate /* Copied from ovap above if AT_MODE not specified */ 10410Sstevel@tonic-gate vap->va_mask |= AT_MODE; 10420Sstevel@tonic-gate vap->va_mode &= ~(S_ISUID|S_ISGID); 10430Sstevel@tonic-gate } 10440Sstevel@tonic-gate } 10450Sstevel@tonic-gate if (mask & (AT_ATIME|AT_MTIME)) { 10460Sstevel@tonic-gate /* 10470Sstevel@tonic-gate * If not the file owner and not otherwise privileged, 10480Sstevel@tonic-gate * always return an error when setting the 10490Sstevel@tonic-gate * time other than the current (ATTR_UTIME flag set). 10500Sstevel@tonic-gate * If setting the current time (ATTR_UTIME not set) then 10510Sstevel@tonic-gate * unlocked_access will check permissions according to policy. 10520Sstevel@tonic-gate */ 10530Sstevel@tonic-gate if (cr->cr_uid != ovap->va_uid) { 10540Sstevel@tonic-gate if (flags & ATTR_UTIME) 10550Sstevel@tonic-gate error = secpolicy_vnode_utime_modify(cr); 10560Sstevel@tonic-gate else { 10570Sstevel@tonic-gate error = unlocked_access(node, VWRITE, cr); 10580Sstevel@tonic-gate if (error == EACCES && 10590Sstevel@tonic-gate secpolicy_vnode_utime_modify(cr) == 0) 10600Sstevel@tonic-gate error = 0; 10610Sstevel@tonic-gate } 10620Sstevel@tonic-gate if (error) 10630Sstevel@tonic-gate goto out; 10640Sstevel@tonic-gate } 10650Sstevel@tonic-gate } 10660Sstevel@tonic-gate out: 10670Sstevel@tonic-gate return (error); 10680Sstevel@tonic-gate } 10690Sstevel@tonic-gate 10700Sstevel@tonic-gate /* 10710Sstevel@tonic-gate * Name: secpolicy_pcfs_modify_bootpartition() 10720Sstevel@tonic-gate * 10730Sstevel@tonic-gate * Normal: verify that subject can modify a pcfs boot partition. 10740Sstevel@tonic-gate * 10750Sstevel@tonic-gate * Output: EACCES - if privilege check failed. 10760Sstevel@tonic-gate */ 10770Sstevel@tonic-gate /*ARGSUSED*/ 10780Sstevel@tonic-gate int 10790Sstevel@tonic-gate secpolicy_pcfs_modify_bootpartition(const cred_t *cred) 10800Sstevel@tonic-gate { 10810Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_ALL, B_FALSE, EACCES, 10820Sstevel@tonic-gate "modify pcfs boot partition")); 10830Sstevel@tonic-gate } 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate /* 10860Sstevel@tonic-gate * System V IPC routines 10870Sstevel@tonic-gate */ 10880Sstevel@tonic-gate int 10890Sstevel@tonic-gate secpolicy_ipc_owner(const cred_t *cr, const struct kipc_perm *ip) 10900Sstevel@tonic-gate { 10910Sstevel@tonic-gate if (crgetzoneid(cr) != ip->ipc_zoneid || 10920Sstevel@tonic-gate (cr->cr_uid != ip->ipc_uid && cr->cr_uid != ip->ipc_cuid)) { 10930Sstevel@tonic-gate boolean_t allzone = B_FALSE; 10940Sstevel@tonic-gate if (ip->ipc_uid == 0 || ip->ipc_cuid == 0) 10950Sstevel@tonic-gate allzone = B_TRUE; 10960Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_OWNER, allzone, EPERM, NULL)); 10970Sstevel@tonic-gate } 10980Sstevel@tonic-gate return (0); 10990Sstevel@tonic-gate } 11000Sstevel@tonic-gate 11010Sstevel@tonic-gate int 11020Sstevel@tonic-gate secpolicy_ipc_config(const cred_t *cr) 11030Sstevel@tonic-gate { 11040Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_IPC_CONFIG, B_FALSE, EPERM, NULL)); 11050Sstevel@tonic-gate } 11060Sstevel@tonic-gate 11070Sstevel@tonic-gate int 11080Sstevel@tonic-gate secpolicy_ipc_access(const cred_t *cr, const struct kipc_perm *ip, mode_t mode) 11090Sstevel@tonic-gate { 11100Sstevel@tonic-gate 11110Sstevel@tonic-gate boolean_t allzone = B_FALSE; 11120Sstevel@tonic-gate 11130Sstevel@tonic-gate ASSERT((mode & (MSG_R|MSG_W)) != 0); 11140Sstevel@tonic-gate 11150Sstevel@tonic-gate if ((mode & MSG_R) && 11160Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_IPC_DAC_READ, allzone, EACCES, NULL) != 0) 11170Sstevel@tonic-gate return (EACCES); 11180Sstevel@tonic-gate 11190Sstevel@tonic-gate if (mode & MSG_W) { 11200Sstevel@tonic-gate if (cr->cr_uid != 0 && (ip->ipc_uid == 0 || ip->ipc_cuid == 0)) 11210Sstevel@tonic-gate allzone = B_TRUE; 11220Sstevel@tonic-gate 11230Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_DAC_WRITE, allzone, EACCES, 11240Sstevel@tonic-gate NULL)); 11250Sstevel@tonic-gate } 11260Sstevel@tonic-gate return (0); 11270Sstevel@tonic-gate } 11280Sstevel@tonic-gate 11290Sstevel@tonic-gate int 11300Sstevel@tonic-gate secpolicy_rsm_access(const cred_t *cr, uid_t owner, mode_t mode) 11310Sstevel@tonic-gate { 11320Sstevel@tonic-gate boolean_t allzone = B_FALSE; 11330Sstevel@tonic-gate 11340Sstevel@tonic-gate ASSERT((mode & (MSG_R|MSG_W)) != 0); 11350Sstevel@tonic-gate 11360Sstevel@tonic-gate if ((mode & MSG_R) && 11370Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_IPC_DAC_READ, allzone, EACCES, NULL) != 0) 11380Sstevel@tonic-gate return (EACCES); 11390Sstevel@tonic-gate 11400Sstevel@tonic-gate if (mode & MSG_W) { 11410Sstevel@tonic-gate if (cr->cr_uid != 0 && owner == 0) 11420Sstevel@tonic-gate allzone = B_TRUE; 11430Sstevel@tonic-gate 11440Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_DAC_WRITE, allzone, EACCES, 11450Sstevel@tonic-gate NULL)); 11460Sstevel@tonic-gate } 11470Sstevel@tonic-gate return (0); 11480Sstevel@tonic-gate } 11490Sstevel@tonic-gate 11500Sstevel@tonic-gate /* 11510Sstevel@tonic-gate * Audit configuration. 11520Sstevel@tonic-gate */ 11530Sstevel@tonic-gate int 11540Sstevel@tonic-gate secpolicy_audit_config(const cred_t *cr) 11550Sstevel@tonic-gate { 11560Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_AUDIT, B_FALSE, EPERM, NULL)); 11570Sstevel@tonic-gate } 11580Sstevel@tonic-gate 11590Sstevel@tonic-gate /* 11600Sstevel@tonic-gate * Audit record generation. 11610Sstevel@tonic-gate */ 11620Sstevel@tonic-gate int 11630Sstevel@tonic-gate secpolicy_audit_modify(const cred_t *cr) 11640Sstevel@tonic-gate { 11650Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_AUDIT, B_FALSE, EPERM, NULL)); 11660Sstevel@tonic-gate } 11670Sstevel@tonic-gate 11680Sstevel@tonic-gate /* 11690Sstevel@tonic-gate * Get audit attributes. 11700Sstevel@tonic-gate * Either PRIV_SYS_AUDIT or PRIV_PROC_AUDIT required; report the 11710Sstevel@tonic-gate * "Least" of the two privileges on error. 11720Sstevel@tonic-gate */ 11730Sstevel@tonic-gate int 11740Sstevel@tonic-gate secpolicy_audit_getattr(const cred_t *cr) 11750Sstevel@tonic-gate { 11760Sstevel@tonic-gate if (!PRIV_POLICY_ONLY(cr, PRIV_SYS_AUDIT, B_FALSE)) { 11770Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_AUDIT, B_FALSE, EPERM, 11780Sstevel@tonic-gate NULL)); 11790Sstevel@tonic-gate } else { 11800Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_AUDIT, B_FALSE, EPERM, NULL)); 11810Sstevel@tonic-gate } 11820Sstevel@tonic-gate } 11830Sstevel@tonic-gate 11840Sstevel@tonic-gate 11850Sstevel@tonic-gate /* 11860Sstevel@tonic-gate * Locking physical memory 11870Sstevel@tonic-gate */ 11880Sstevel@tonic-gate int 11890Sstevel@tonic-gate secpolicy_lock_memory(const cred_t *cr) 11900Sstevel@tonic-gate { 11910Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_LOCK_MEMORY, B_FALSE, EPERM, NULL)); 11920Sstevel@tonic-gate } 11930Sstevel@tonic-gate 11940Sstevel@tonic-gate /* 11950Sstevel@tonic-gate * Accounting (both acct(2) and exacct). 11960Sstevel@tonic-gate */ 11970Sstevel@tonic-gate int 11980Sstevel@tonic-gate secpolicy_acct(const cred_t *cr) 11990Sstevel@tonic-gate { 12000Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ACCT, B_FALSE, EPERM, NULL)); 12010Sstevel@tonic-gate } 12020Sstevel@tonic-gate 12030Sstevel@tonic-gate /* 12040Sstevel@tonic-gate * Is this process privileged to change its uids at will? 12050Sstevel@tonic-gate * Uid 0 is still considered "special" and having the SETID 12060Sstevel@tonic-gate * privilege is not sufficient to get uid 0. 12070Sstevel@tonic-gate * Files are owned by root, so the privilege would give 12080Sstevel@tonic-gate * full access and euid 0 is still effective. 12090Sstevel@tonic-gate * 12100Sstevel@tonic-gate * If you have the privilege and euid 0 only then do you 12110Sstevel@tonic-gate * get the powers of root wrt uid 0. 12120Sstevel@tonic-gate * 12130Sstevel@tonic-gate * For gid manipulations, this is should be called with an 12140Sstevel@tonic-gate * uid of -1. 12150Sstevel@tonic-gate * 12160Sstevel@tonic-gate */ 12170Sstevel@tonic-gate int 12180Sstevel@tonic-gate secpolicy_allow_setid(const cred_t *cr, uid_t newuid, boolean_t checkonly) 12190Sstevel@tonic-gate { 12200Sstevel@tonic-gate boolean_t allzone = B_FALSE; 12210Sstevel@tonic-gate 12220Sstevel@tonic-gate if (newuid == 0 && cr->cr_uid != 0 && cr->cr_suid != 0 && 12230Sstevel@tonic-gate cr->cr_ruid != 0) { 12240Sstevel@tonic-gate allzone = B_TRUE; 12250Sstevel@tonic-gate } 12260Sstevel@tonic-gate 12270Sstevel@tonic-gate return (checkonly ? !PRIV_POLICY_ONLY(cr, PRIV_PROC_SETID, allzone) : 12280Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_PROC_SETID, allzone, EPERM, NULL)); 12290Sstevel@tonic-gate } 12300Sstevel@tonic-gate 12310Sstevel@tonic-gate 12320Sstevel@tonic-gate /* 12330Sstevel@tonic-gate * Acting on a different process: if the mode is for writing, 12340Sstevel@tonic-gate * the restrictions are more severe. This is called after 12350Sstevel@tonic-gate * we've verified that the uids do not match. 12360Sstevel@tonic-gate */ 12370Sstevel@tonic-gate int 12380Sstevel@tonic-gate secpolicy_proc_owner(const cred_t *scr, const cred_t *tcr, int mode) 12390Sstevel@tonic-gate { 12400Sstevel@tonic-gate boolean_t allzone = B_FALSE; 12410Sstevel@tonic-gate 12420Sstevel@tonic-gate if ((mode & VWRITE) && scr->cr_uid != 0 && 12430Sstevel@tonic-gate (tcr->cr_uid == 0 || tcr->cr_ruid == 0 || tcr->cr_suid == 0)) 12440Sstevel@tonic-gate allzone = B_TRUE; 12450Sstevel@tonic-gate 12460Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, allzone, EPERM, NULL)); 12470Sstevel@tonic-gate } 12480Sstevel@tonic-gate 12490Sstevel@tonic-gate int 12500Sstevel@tonic-gate secpolicy_proc_access(const cred_t *scr) 12510Sstevel@tonic-gate { 12520Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, B_FALSE, EACCES, NULL)); 12530Sstevel@tonic-gate } 12540Sstevel@tonic-gate 12550Sstevel@tonic-gate int 12560Sstevel@tonic-gate secpolicy_proc_excl_open(const cred_t *scr) 12570Sstevel@tonic-gate { 12580Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, B_FALSE, EBUSY, NULL)); 12590Sstevel@tonic-gate } 12600Sstevel@tonic-gate 12610Sstevel@tonic-gate int 12620Sstevel@tonic-gate secpolicy_proc_zone(const cred_t *scr) 12630Sstevel@tonic-gate { 12640Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_ZONE, B_FALSE, EPERM, NULL)); 12650Sstevel@tonic-gate } 12660Sstevel@tonic-gate 12670Sstevel@tonic-gate /* 12680Sstevel@tonic-gate * Destroying the system 12690Sstevel@tonic-gate */ 12700Sstevel@tonic-gate 12710Sstevel@tonic-gate int 12720Sstevel@tonic-gate secpolicy_kmdb(const cred_t *scr) 12730Sstevel@tonic-gate { 12740Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); 12750Sstevel@tonic-gate } 12760Sstevel@tonic-gate 12770Sstevel@tonic-gate /* 12780Sstevel@tonic-gate * Processor sets, cpu configuration, resource pools. 12790Sstevel@tonic-gate */ 12800Sstevel@tonic-gate int 12810Sstevel@tonic-gate secpolicy_pset(const cred_t *cr) 12820Sstevel@tonic-gate { 12830Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 12840Sstevel@tonic-gate } 12850Sstevel@tonic-gate 12860Sstevel@tonic-gate int 12870Sstevel@tonic-gate secpolicy_ponline(const cred_t *cr) 12880Sstevel@tonic-gate { 12890Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 12900Sstevel@tonic-gate } 12910Sstevel@tonic-gate 12920Sstevel@tonic-gate int 12930Sstevel@tonic-gate secpolicy_pool(const cred_t *cr) 12940Sstevel@tonic-gate { 12950Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 12960Sstevel@tonic-gate } 12970Sstevel@tonic-gate 12980Sstevel@tonic-gate int 12990Sstevel@tonic-gate secpolicy_blacklist(const cred_t *cr) 13000Sstevel@tonic-gate { 13010Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 13020Sstevel@tonic-gate } 13030Sstevel@tonic-gate 13040Sstevel@tonic-gate /* 13050Sstevel@tonic-gate * Catch all system configuration. 13060Sstevel@tonic-gate */ 13070Sstevel@tonic-gate int 13080Sstevel@tonic-gate secpolicy_sys_config(const cred_t *cr, boolean_t checkonly) 13090Sstevel@tonic-gate { 13100Sstevel@tonic-gate if (checkonly) { 13110Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_CONFIG, B_FALSE) ? 0 : 13120Sstevel@tonic-gate EPERM); 13130Sstevel@tonic-gate } else { 13140Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 13150Sstevel@tonic-gate } 13160Sstevel@tonic-gate } 13170Sstevel@tonic-gate 13180Sstevel@tonic-gate /* 13190Sstevel@tonic-gate * Zone administration (halt, reboot, etc.) from within zone. 13200Sstevel@tonic-gate */ 13210Sstevel@tonic-gate int 13220Sstevel@tonic-gate secpolicy_zone_admin(const cred_t *cr, boolean_t checkonly) 13230Sstevel@tonic-gate { 13240Sstevel@tonic-gate if (checkonly) { 13250Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_ADMIN, B_FALSE) ? 0 : 13260Sstevel@tonic-gate EPERM); 13270Sstevel@tonic-gate } else { 13280Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, 13290Sstevel@tonic-gate NULL)); 13300Sstevel@tonic-gate } 13310Sstevel@tonic-gate } 13320Sstevel@tonic-gate 13330Sstevel@tonic-gate /* 13340Sstevel@tonic-gate * Zone configuration (create, halt, enter). 13350Sstevel@tonic-gate */ 13360Sstevel@tonic-gate int 13370Sstevel@tonic-gate secpolicy_zone_config(const cred_t *cr) 13380Sstevel@tonic-gate { 13390Sstevel@tonic-gate /* 13400Sstevel@tonic-gate * Require all privileges to avoid possibility of privilege 13410Sstevel@tonic-gate * escalation. 13420Sstevel@tonic-gate */ 13430Sstevel@tonic-gate return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); 13440Sstevel@tonic-gate } 13450Sstevel@tonic-gate 13460Sstevel@tonic-gate /* 13470Sstevel@tonic-gate * Various other system configuration calls 13480Sstevel@tonic-gate */ 13490Sstevel@tonic-gate int 13500Sstevel@tonic-gate secpolicy_coreadm(const cred_t *cr) 13510Sstevel@tonic-gate { 13520Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, NULL)); 13530Sstevel@tonic-gate } 13540Sstevel@tonic-gate 13550Sstevel@tonic-gate int 13560Sstevel@tonic-gate secpolicy_systeminfo(const cred_t *cr) 13570Sstevel@tonic-gate { 13580Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, NULL)); 13590Sstevel@tonic-gate } 13600Sstevel@tonic-gate 13610Sstevel@tonic-gate int 13620Sstevel@tonic-gate secpolicy_dispadm(const cred_t *cr) 13630Sstevel@tonic-gate { 13640Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 13650Sstevel@tonic-gate } 13660Sstevel@tonic-gate 13670Sstevel@tonic-gate int 13680Sstevel@tonic-gate secpolicy_settime(const cred_t *cr) 13690Sstevel@tonic-gate { 13700Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_TIME, B_FALSE, EPERM, NULL)); 13710Sstevel@tonic-gate } 13720Sstevel@tonic-gate 13730Sstevel@tonic-gate /* 13740Sstevel@tonic-gate * For realtime users: high resolution clock. 13750Sstevel@tonic-gate */ 13760Sstevel@tonic-gate int 13770Sstevel@tonic-gate secpolicy_clock_highres(const cred_t *cr) 13780Sstevel@tonic-gate { 13790Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_CLOCK_HIGHRES, B_FALSE, EPERM, 13800Sstevel@tonic-gate NULL)); 13810Sstevel@tonic-gate } 13820Sstevel@tonic-gate 13830Sstevel@tonic-gate /* 13840Sstevel@tonic-gate * drv_priv() is documented as callable from interrupt context, not that 13850Sstevel@tonic-gate * anyone ever does, but still. No debugging or auditing can be done when 13860Sstevel@tonic-gate * it is called from interrupt context. 13870Sstevel@tonic-gate * returns 0 on succes, EPERM on failure. 13880Sstevel@tonic-gate */ 13890Sstevel@tonic-gate int 13900Sstevel@tonic-gate drv_priv(cred_t *cr) 13910Sstevel@tonic-gate { 13920Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 13930Sstevel@tonic-gate } 13940Sstevel@tonic-gate 13950Sstevel@tonic-gate int 13960Sstevel@tonic-gate secpolicy_sys_devices(const cred_t *cr) 13970Sstevel@tonic-gate { 13980Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 13990Sstevel@tonic-gate } 14000Sstevel@tonic-gate 14010Sstevel@tonic-gate int 14020Sstevel@tonic-gate secpolicy_excl_open(const cred_t *cr) 14030Sstevel@tonic-gate { 14040Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EBUSY, NULL)); 14050Sstevel@tonic-gate } 14060Sstevel@tonic-gate 14070Sstevel@tonic-gate int 14080Sstevel@tonic-gate secpolicy_rctlsys(const cred_t *cr, boolean_t is_zone_rctl) 14090Sstevel@tonic-gate { 14100Sstevel@tonic-gate /* zone.* rctls can only be set from the global zone */ 14110Sstevel@tonic-gate if (is_zone_rctl && priv_policy_global(cr) != 0) 14120Sstevel@tonic-gate return (EPERM); 14130Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 14140Sstevel@tonic-gate } 14150Sstevel@tonic-gate 14160Sstevel@tonic-gate int 14170Sstevel@tonic-gate secpolicy_resource(const cred_t *cr) 14180Sstevel@tonic-gate { 14190Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 14200Sstevel@tonic-gate } 14210Sstevel@tonic-gate 14220Sstevel@tonic-gate /* 14230Sstevel@tonic-gate * Processes with a real uid of 0 escape any form of accounting, much 14240Sstevel@tonic-gate * like before. 14250Sstevel@tonic-gate */ 14260Sstevel@tonic-gate int 14270Sstevel@tonic-gate secpolicy_newproc(const cred_t *cr) 14280Sstevel@tonic-gate { 14290Sstevel@tonic-gate if (cr->cr_ruid == 0) 14300Sstevel@tonic-gate return (0); 14310Sstevel@tonic-gate 14320Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 14330Sstevel@tonic-gate } 14340Sstevel@tonic-gate 14350Sstevel@tonic-gate /* 14360Sstevel@tonic-gate * Networking 14370Sstevel@tonic-gate */ 14380Sstevel@tonic-gate int 14390Sstevel@tonic-gate secpolicy_net_rawaccess(const cred_t *cr) 14400Sstevel@tonic-gate { 14410Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_NET_RAWACCESS, B_FALSE, EACCES, NULL)); 14420Sstevel@tonic-gate } 14430Sstevel@tonic-gate 14440Sstevel@tonic-gate /* 14450Sstevel@tonic-gate * Need this privilege for accessing the ICMP device 14460Sstevel@tonic-gate */ 14470Sstevel@tonic-gate int 14480Sstevel@tonic-gate secpolicy_net_icmpaccess(const cred_t *cr) 14490Sstevel@tonic-gate { 14500Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_NET_ICMPACCESS, B_FALSE, EACCES, NULL)); 14510Sstevel@tonic-gate } 14520Sstevel@tonic-gate 14530Sstevel@tonic-gate /* 14540Sstevel@tonic-gate * There are a few rare cases where the kernel generates ioctls() from 14550Sstevel@tonic-gate * interrupt context with a credential of kcred rather than NULL. 14560Sstevel@tonic-gate * In those cases, we take the safe and cheap test. 14570Sstevel@tonic-gate */ 14580Sstevel@tonic-gate int 14590Sstevel@tonic-gate secpolicy_net_config(const cred_t *cr, boolean_t checkonly) 14600Sstevel@tonic-gate { 14610Sstevel@tonic-gate if (checkonly) { 14620Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE) ? 14630Sstevel@tonic-gate 0 : EPERM); 14640Sstevel@tonic-gate } else { 14650Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_NET_CONFIG, B_FALSE, EPERM, 14660Sstevel@tonic-gate NULL)); 14670Sstevel@tonic-gate } 14680Sstevel@tonic-gate } 14690Sstevel@tonic-gate 14700Sstevel@tonic-gate 14710Sstevel@tonic-gate /* 14720Sstevel@tonic-gate * Map network pseudo privileges to actual privileges. 14730Sstevel@tonic-gate * So we don't need to recompile IP when we change the privileges. 14740Sstevel@tonic-gate */ 14750Sstevel@tonic-gate int 14760Sstevel@tonic-gate secpolicy_net(const cred_t *cr, int netpriv, boolean_t checkonly) 14770Sstevel@tonic-gate { 14780Sstevel@tonic-gate int priv = PRIV_ALL; 14790Sstevel@tonic-gate 14800Sstevel@tonic-gate switch (netpriv) { 14810Sstevel@tonic-gate case OP_CONFIG: 14820Sstevel@tonic-gate priv = PRIV_SYS_NET_CONFIG; 14830Sstevel@tonic-gate break; 14840Sstevel@tonic-gate case OP_RAW: 14850Sstevel@tonic-gate priv = PRIV_NET_RAWACCESS; 14860Sstevel@tonic-gate break; 14870Sstevel@tonic-gate case OP_PRIVPORT: 14880Sstevel@tonic-gate priv = PRIV_NET_PRIVADDR; 14890Sstevel@tonic-gate break; 14900Sstevel@tonic-gate } 14910Sstevel@tonic-gate ASSERT(priv != PRIV_ALL); 14920Sstevel@tonic-gate if (checkonly) 14930Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, priv, B_FALSE) ? 0 : EPERM); 14940Sstevel@tonic-gate else 14950Sstevel@tonic-gate return (PRIV_POLICY(cr, priv, B_FALSE, EPERM, NULL)); 14960Sstevel@tonic-gate } 14970Sstevel@tonic-gate 14980Sstevel@tonic-gate /* 14990Sstevel@tonic-gate * Checks for operations that are either client-only or are used by 15000Sstevel@tonic-gate * both clients and servers. 15010Sstevel@tonic-gate */ 15020Sstevel@tonic-gate int 15030Sstevel@tonic-gate secpolicy_nfs(const cred_t *cr) 15040Sstevel@tonic-gate { 15050Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_NFS, B_FALSE, EPERM, NULL)); 15060Sstevel@tonic-gate } 15070Sstevel@tonic-gate 15080Sstevel@tonic-gate /* 15090Sstevel@tonic-gate * Special case for opening rpcmod: have NFS privileges or network 15100Sstevel@tonic-gate * config privileges. 15110Sstevel@tonic-gate */ 15120Sstevel@tonic-gate int 15130Sstevel@tonic-gate secpolicy_rpcmod_open(const cred_t *cr) 15140Sstevel@tonic-gate { 15150Sstevel@tonic-gate if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NFS, B_FALSE)) 15160Sstevel@tonic-gate return (secpolicy_nfs(cr)); 15170Sstevel@tonic-gate else 15180Sstevel@tonic-gate return (secpolicy_net_config(cr, NULL)); 15190Sstevel@tonic-gate } 15200Sstevel@tonic-gate 15210Sstevel@tonic-gate int 15220Sstevel@tonic-gate secpolicy_chroot(const cred_t *cr) 15230Sstevel@tonic-gate { 15240Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_CHROOT, B_FALSE, EPERM, NULL)); 15250Sstevel@tonic-gate } 15260Sstevel@tonic-gate 15270Sstevel@tonic-gate int 15280Sstevel@tonic-gate secpolicy_tasksys(const cred_t *cr) 15290Sstevel@tonic-gate { 15300Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_TASKID, B_FALSE, EPERM, NULL)); 15310Sstevel@tonic-gate } 15320Sstevel@tonic-gate 15330Sstevel@tonic-gate /* 15340Sstevel@tonic-gate * Basic privilege checks. 15350Sstevel@tonic-gate */ 15360Sstevel@tonic-gate int 15370Sstevel@tonic-gate secpolicy_basic_exec(const cred_t *cr) 15380Sstevel@tonic-gate { 15390Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_EXEC, B_FALSE, EPERM, NULL)); 15400Sstevel@tonic-gate } 15410Sstevel@tonic-gate 15420Sstevel@tonic-gate int 15430Sstevel@tonic-gate secpolicy_basic_fork(const cred_t *cr) 15440Sstevel@tonic-gate { 15450Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_FORK, B_FALSE, EPERM, NULL)); 15460Sstevel@tonic-gate } 15470Sstevel@tonic-gate 15480Sstevel@tonic-gate int 15490Sstevel@tonic-gate secpolicy_basic_proc(const cred_t *cr) 15500Sstevel@tonic-gate { 15510Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_SESSION, B_FALSE, EPERM, NULL)); 15520Sstevel@tonic-gate } 15530Sstevel@tonic-gate 15540Sstevel@tonic-gate /* 15550Sstevel@tonic-gate * Slightly complicated because we don't want to trigger the policy too 15560Sstevel@tonic-gate * often. First we shortcircuit access to "self" (tp == sp) or if 15570Sstevel@tonic-gate * we don't have the privilege but if we have permission 15580Sstevel@tonic-gate * just return (0) and we don't flag the privilege as needed. 15590Sstevel@tonic-gate * Else, we test for the privilege because we either have it or need it. 15600Sstevel@tonic-gate */ 15610Sstevel@tonic-gate int 15620Sstevel@tonic-gate secpolicy_basic_procinfo(const cred_t *cr, proc_t *tp, proc_t *sp) 15630Sstevel@tonic-gate { 15640Sstevel@tonic-gate if (tp == sp || 15650Sstevel@tonic-gate !HAS_PRIVILEGE(cr, PRIV_PROC_INFO) && prochasprocperm(tp, sp, cr)) { 15660Sstevel@tonic-gate return (0); 15670Sstevel@tonic-gate } else { 15680Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_INFO, B_FALSE, EPERM, NULL)); 15690Sstevel@tonic-gate } 15700Sstevel@tonic-gate } 15710Sstevel@tonic-gate 15720Sstevel@tonic-gate int 15730Sstevel@tonic-gate secpolicy_basic_link(const cred_t *cr) 15740Sstevel@tonic-gate { 15750Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_LINK_ANY, B_FALSE, EPERM, NULL)); 15760Sstevel@tonic-gate } 15770Sstevel@tonic-gate 15780Sstevel@tonic-gate /* 15790Sstevel@tonic-gate * Additional device protection. 15800Sstevel@tonic-gate * 15810Sstevel@tonic-gate * Traditionally, a device has specific permissions on the node in 15820Sstevel@tonic-gate * the filesystem which govern which devices can be opened by what 15830Sstevel@tonic-gate * processes. In certain cases, it is desirable to add extra 15840Sstevel@tonic-gate * restrictions, as writing to certain devices is identical to 15850Sstevel@tonic-gate * having a complete run of the system. 15860Sstevel@tonic-gate * 15870Sstevel@tonic-gate * This mechanism is called the device policy. 15880Sstevel@tonic-gate * 15890Sstevel@tonic-gate * When a device is opened, its policy entry is looked up in the 15900Sstevel@tonic-gate * policy cache and checked. 15910Sstevel@tonic-gate */ 15920Sstevel@tonic-gate int 15930Sstevel@tonic-gate secpolicy_spec_open(const cred_t *cr, struct vnode *vp, int oflag) 15940Sstevel@tonic-gate { 15950Sstevel@tonic-gate devplcy_t *plcy; 15960Sstevel@tonic-gate int err; 15970Sstevel@tonic-gate struct snode *csp = VTOS(common_specvp(vp)); 15980Sstevel@tonic-gate 15990Sstevel@tonic-gate mutex_enter(&csp->s_lock); 16000Sstevel@tonic-gate 16010Sstevel@tonic-gate if (csp->s_plcy == NULL || csp->s_plcy->dp_gen != devplcy_gen) { 16020Sstevel@tonic-gate plcy = devpolicy_find(vp); 16030Sstevel@tonic-gate if (csp->s_plcy) 16040Sstevel@tonic-gate dpfree(csp->s_plcy); 16050Sstevel@tonic-gate csp->s_plcy = plcy; 16060Sstevel@tonic-gate ASSERT(plcy != NULL); 16070Sstevel@tonic-gate } else 16080Sstevel@tonic-gate plcy = csp->s_plcy; 16090Sstevel@tonic-gate 16100Sstevel@tonic-gate if (plcy == nullpolicy) { 16110Sstevel@tonic-gate mutex_exit(&csp->s_lock); 16120Sstevel@tonic-gate return (0); 16130Sstevel@tonic-gate } 16140Sstevel@tonic-gate 16150Sstevel@tonic-gate dphold(plcy); 16160Sstevel@tonic-gate 16170Sstevel@tonic-gate mutex_exit(&csp->s_lock); 16180Sstevel@tonic-gate 16190Sstevel@tonic-gate err = secpolicy_require_set(cr, 16200Sstevel@tonic-gate (oflag & FWRITE) ? &plcy->dp_wrp : &plcy->dp_rdp, "devpolicy"); 16210Sstevel@tonic-gate dpfree(plcy); 16220Sstevel@tonic-gate 16230Sstevel@tonic-gate return (err); 16240Sstevel@tonic-gate } 16250Sstevel@tonic-gate 16260Sstevel@tonic-gate int 16270Sstevel@tonic-gate secpolicy_modctl(const cred_t *cr, int cmd) 16280Sstevel@tonic-gate { 16290Sstevel@tonic-gate switch (cmd) { 16300Sstevel@tonic-gate case MODINFO: 16310Sstevel@tonic-gate case MODGETPATH: 16320Sstevel@tonic-gate case MODGETPATHLEN: 16330Sstevel@tonic-gate case MODGETFBNAME: 16340Sstevel@tonic-gate case MODGETNAME: 16350Sstevel@tonic-gate case MODGETDEVPOLICY: 16360Sstevel@tonic-gate case MODGETDEVPOLICYBYNAME: 16370Sstevel@tonic-gate case MODGETMAJBIND: 16380Sstevel@tonic-gate /* Unprivileged */ 16390Sstevel@tonic-gate return (0); 16400Sstevel@tonic-gate case MODLOAD: 16410Sstevel@tonic-gate case MODSETDEVPOLICY: 16420Sstevel@tonic-gate return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); 16430Sstevel@tonic-gate default: 16440Sstevel@tonic-gate return (secpolicy_sys_config(cr, B_FALSE)); 16450Sstevel@tonic-gate } 16460Sstevel@tonic-gate } 16470Sstevel@tonic-gate 16480Sstevel@tonic-gate int 16490Sstevel@tonic-gate secpolicy_console(const cred_t *cr) 16500Sstevel@tonic-gate { 16510Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 16520Sstevel@tonic-gate } 16530Sstevel@tonic-gate 16540Sstevel@tonic-gate int 16550Sstevel@tonic-gate secpolicy_power_mgmt(const cred_t *cr) 16560Sstevel@tonic-gate { 16570Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 16580Sstevel@tonic-gate } 16590Sstevel@tonic-gate 16600Sstevel@tonic-gate /* 16610Sstevel@tonic-gate * Simulate terminal input; another escalation of privileges avenue. 16620Sstevel@tonic-gate */ 16630Sstevel@tonic-gate 16640Sstevel@tonic-gate int 16650Sstevel@tonic-gate secpolicy_sti(const cred_t *cr) 16660Sstevel@tonic-gate { 16670Sstevel@tonic-gate return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); 16680Sstevel@tonic-gate } 16690Sstevel@tonic-gate 16700Sstevel@tonic-gate int 16710Sstevel@tonic-gate secpolicy_swapctl(const cred_t *cr) 16720Sstevel@tonic-gate { 16730Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 16740Sstevel@tonic-gate } 16750Sstevel@tonic-gate 16760Sstevel@tonic-gate int 16770Sstevel@tonic-gate secpolicy_cpc_cpu(const cred_t *cr) 16780Sstevel@tonic-gate { 16790Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CPC_CPU, B_FALSE, EACCES, NULL)); 16800Sstevel@tonic-gate } 16810Sstevel@tonic-gate 16820Sstevel@tonic-gate /* 16830Sstevel@tonic-gate * secpolicy_contract_observer 16840Sstevel@tonic-gate * 16850Sstevel@tonic-gate * Determine if the subject may observe a specific contract's events. 16860Sstevel@tonic-gate */ 16870Sstevel@tonic-gate int 16880Sstevel@tonic-gate secpolicy_contract_observer(const cred_t *cr, struct contract *ct) 16890Sstevel@tonic-gate { 16900Sstevel@tonic-gate if (contract_owned(ct, cr, B_FALSE)) 16910Sstevel@tonic-gate return (0); 16920Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CONTRACT_OBSERVER, B_FALSE, EPERM, NULL)); 16930Sstevel@tonic-gate } 16940Sstevel@tonic-gate 16950Sstevel@tonic-gate /* 16960Sstevel@tonic-gate * secpolicy_contract_observer_choice 16970Sstevel@tonic-gate * 16980Sstevel@tonic-gate * Determine if the subject may observe any contract's events. Just 16990Sstevel@tonic-gate * tests privilege and audits on success. 17000Sstevel@tonic-gate */ 17010Sstevel@tonic-gate boolean_t 17020Sstevel@tonic-gate secpolicy_contract_observer_choice(const cred_t *cr) 17030Sstevel@tonic-gate { 17040Sstevel@tonic-gate return (PRIV_POLICY_CHOICE(cr, PRIV_CONTRACT_OBSERVER, B_FALSE)); 17050Sstevel@tonic-gate } 17060Sstevel@tonic-gate 17070Sstevel@tonic-gate /* 17080Sstevel@tonic-gate * secpolicy_contract_event 17090Sstevel@tonic-gate * 17100Sstevel@tonic-gate * Determine if the subject may request critical contract events or 17110Sstevel@tonic-gate * reliable contract event delivery. 17120Sstevel@tonic-gate */ 17130Sstevel@tonic-gate int 17140Sstevel@tonic-gate secpolicy_contract_event(const cred_t *cr) 17150Sstevel@tonic-gate { 17160Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CONTRACT_EVENT, B_FALSE, EPERM, NULL)); 17170Sstevel@tonic-gate } 17180Sstevel@tonic-gate 17190Sstevel@tonic-gate /* 17200Sstevel@tonic-gate * secpolicy_contract_event_choice 17210Sstevel@tonic-gate * 17220Sstevel@tonic-gate * Determine if the subject may retain contract events in its critical 17230Sstevel@tonic-gate * set when a change in other terms would normally require a change in 17240Sstevel@tonic-gate * the critical set. Just tests privilege and audits on success. 17250Sstevel@tonic-gate */ 17260Sstevel@tonic-gate boolean_t 17270Sstevel@tonic-gate secpolicy_contract_event_choice(const cred_t *cr) 17280Sstevel@tonic-gate { 17290Sstevel@tonic-gate return (PRIV_POLICY_CHOICE(cr, PRIV_CONTRACT_EVENT, B_FALSE)); 17300Sstevel@tonic-gate } 17310Sstevel@tonic-gate 17320Sstevel@tonic-gate /* 17330Sstevel@tonic-gate * Name: secpolicy_gart_access 17340Sstevel@tonic-gate * 17350Sstevel@tonic-gate * Normal: Verify if the subject has sufficient priveleges to make ioctls 17360Sstevel@tonic-gate * to agpgart device 17370Sstevel@tonic-gate * 17380Sstevel@tonic-gate * Output: EPERM - if not privileged 17390Sstevel@tonic-gate * 17400Sstevel@tonic-gate */ 17410Sstevel@tonic-gate int 17420Sstevel@tonic-gate secpolicy_gart_access(const cred_t *cr) 17430Sstevel@tonic-gate { 17440Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_GART_ACCESS, B_FALSE, EPERM, NULL)); 17450Sstevel@tonic-gate } 17460Sstevel@tonic-gate 17470Sstevel@tonic-gate /* 17480Sstevel@tonic-gate * Name: secpolicy_gart_map 17490Sstevel@tonic-gate * 17500Sstevel@tonic-gate * Normal: Verify if the subject has sufficient privelegs to map aperture 17510Sstevel@tonic-gate * range through agpgart driver 17520Sstevel@tonic-gate * 17530Sstevel@tonic-gate * Output: EPERM - if not privileged 17540Sstevel@tonic-gate * 17550Sstevel@tonic-gate */ 17560Sstevel@tonic-gate int 17570Sstevel@tonic-gate secpolicy_gart_map(const cred_t *cr) 17580Sstevel@tonic-gate { 17590Sstevel@tonic-gate if (PRIV_POLICY(cr, PRIV_GART_ACCESS, B_FALSE, EPERM, NULL)) { 17600Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_GART_MAP, B_FALSE, EPERM, NULL)); 17610Sstevel@tonic-gate } 17620Sstevel@tonic-gate return (0); 17630Sstevel@tonic-gate } 1764