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 51544Seschrock * Common Development and Distribution License (the "License"). 61544Seschrock * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*11537SCasper.Dik@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <sys/types.h> 270Sstevel@tonic-gate #include <sys/sysmacros.h> 280Sstevel@tonic-gate #include <sys/param.h> 290Sstevel@tonic-gate #include <sys/systm.h> 300Sstevel@tonic-gate #include <sys/cred_impl.h> 310Sstevel@tonic-gate #include <sys/vnode.h> 320Sstevel@tonic-gate #include <sys/vfs.h> 330Sstevel@tonic-gate #include <sys/stat.h> 340Sstevel@tonic-gate #include <sys/errno.h> 350Sstevel@tonic-gate #include <sys/kmem.h> 360Sstevel@tonic-gate #include <sys/user.h> 370Sstevel@tonic-gate #include <sys/proc.h> 380Sstevel@tonic-gate #include <sys/acct.h> 390Sstevel@tonic-gate #include <sys/ipc_impl.h> 400Sstevel@tonic-gate #include <sys/cmn_err.h> 410Sstevel@tonic-gate #include <sys/debug.h> 420Sstevel@tonic-gate #include <sys/policy.h> 430Sstevel@tonic-gate #include <sys/kobj.h> 440Sstevel@tonic-gate #include <sys/msg.h> 450Sstevel@tonic-gate #include <sys/devpolicy.h> 460Sstevel@tonic-gate #include <c2/audit.h> 470Sstevel@tonic-gate #include <sys/varargs.h> 486134Scasper #include <sys/klpd.h> 490Sstevel@tonic-gate #include <sys/modctl.h> 500Sstevel@tonic-gate #include <sys/disp.h> 510Sstevel@tonic-gate #include <sys/zone.h> 520Sstevel@tonic-gate #include <inet/optcom.h> 530Sstevel@tonic-gate #include <sys/sdt.h> 540Sstevel@tonic-gate #include <sys/vfs.h> 550Sstevel@tonic-gate #include <sys/mntent.h> 560Sstevel@tonic-gate #include <sys/contract_impl.h> 578275SEric Cheng #include <sys/dld_ioc.h> 580Sstevel@tonic-gate 590Sstevel@tonic-gate /* 600Sstevel@tonic-gate * There are two possible layers of privilege routines and two possible 610Sstevel@tonic-gate * levels of secpolicy. Plus one other we may not be interested in, so 620Sstevel@tonic-gate * we may need as many as 6 but no more. 630Sstevel@tonic-gate */ 640Sstevel@tonic-gate #define MAXPRIVSTACK 6 650Sstevel@tonic-gate 66*11537SCasper.Dik@Sun.COM #ifdef DEBUG 67*11537SCasper.Dik@Sun.COM int priv_debug = 1; 68*11537SCasper.Dik@Sun.COM #else 690Sstevel@tonic-gate int priv_debug = 0; 70*11537SCasper.Dik@Sun.COM #endif 71*11537SCasper.Dik@Sun.COM int priv_basic_test = -1; 720Sstevel@tonic-gate 730Sstevel@tonic-gate /* 740Sstevel@tonic-gate * This file contains the majority of the policy routines. 750Sstevel@tonic-gate * Since the policy routines are defined by function and not 760Sstevel@tonic-gate * by privilege, there is quite a bit of duplication of 770Sstevel@tonic-gate * functions. 780Sstevel@tonic-gate * 795331Samw * The secpolicy functions must not make assumptions about 800Sstevel@tonic-gate * locks held or not held as any lock can be held while they're 810Sstevel@tonic-gate * being called. 820Sstevel@tonic-gate * 830Sstevel@tonic-gate * Credentials are read-only so no special precautions need to 840Sstevel@tonic-gate * be taken while locking them. 850Sstevel@tonic-gate * 860Sstevel@tonic-gate * When a new policy check needs to be added to the system the 870Sstevel@tonic-gate * following procedure should be followed: 880Sstevel@tonic-gate * 890Sstevel@tonic-gate * Pick an appropriate secpolicy_*() function 900Sstevel@tonic-gate * -> done if one exists. 910Sstevel@tonic-gate * Create a new secpolicy function, preferably with 920Sstevel@tonic-gate * a descriptive name using the standard template. 930Sstevel@tonic-gate * Pick an appropriate privilege for the policy. 940Sstevel@tonic-gate * If no appropraite privilege exists, define new one 950Sstevel@tonic-gate * (this should be done with extreme care; in most cases 960Sstevel@tonic-gate * little is gained by adding another privilege) 970Sstevel@tonic-gate * 980Sstevel@tonic-gate * WHY ROOT IS STILL SPECIAL. 990Sstevel@tonic-gate * 1000Sstevel@tonic-gate * In a number of the policy functions, there are still explicit 1010Sstevel@tonic-gate * checks for uid 0. The rationale behind these is that many root 1020Sstevel@tonic-gate * owned files/objects hold configuration information which can give full 1030Sstevel@tonic-gate * privileges to the user once written to. To prevent escalation 1040Sstevel@tonic-gate * of privilege by allowing just a single privilege to modify root owned 1050Sstevel@tonic-gate * objects, we've added these root specific checks where we considered 1060Sstevel@tonic-gate * them necessary: modifying root owned files, changing uids to 0, etc. 1070Sstevel@tonic-gate * 1080Sstevel@tonic-gate * PRIVILEGE ESCALATION AND ZONES. 1090Sstevel@tonic-gate * 1100Sstevel@tonic-gate * A number of operations potentially allow the caller to achieve 1110Sstevel@tonic-gate * privileges beyond the ones normally required to perform the operation. 1120Sstevel@tonic-gate * For example, if allowed to create a setuid 0 executable, a process can 1130Sstevel@tonic-gate * gain privileges beyond PRIV_FILE_SETID. Zones, however, place 1140Sstevel@tonic-gate * restrictions on the ability to gain privileges beyond those available 1150Sstevel@tonic-gate * within the zone through file and process manipulation. Hence, such 1160Sstevel@tonic-gate * operations require that the caller have an effective set that includes 1170Sstevel@tonic-gate * all privileges available within the current zone, or all privileges 1180Sstevel@tonic-gate * if executing in the global zone. 1190Sstevel@tonic-gate * 1200Sstevel@tonic-gate * This is indicated in the priv_policy* policy checking functions 1210Sstevel@tonic-gate * through a combination of parameters. The "priv" parameter indicates 1220Sstevel@tonic-gate * the privilege that is required, and the "allzone" parameter indicates 1230Sstevel@tonic-gate * whether or not all privileges in the zone are required. In addition, 1240Sstevel@tonic-gate * priv can be set to PRIV_ALL to indicate that all privileges are 1250Sstevel@tonic-gate * required (regardless of zone). There are three scenarios of interest: 1260Sstevel@tonic-gate * (1) operation requires a specific privilege 1270Sstevel@tonic-gate * (2) operation requires a specific privilege, and requires all 1280Sstevel@tonic-gate * privileges available within the zone (or all privileges if in 1290Sstevel@tonic-gate * the global zone) 1300Sstevel@tonic-gate * (3) operation requires all privileges, regardless of zone 1310Sstevel@tonic-gate * 1320Sstevel@tonic-gate * For (1), priv should be set to the specific privilege, and allzone 1330Sstevel@tonic-gate * should be set to B_FALSE. 1340Sstevel@tonic-gate * For (2), priv should be set to the specific privilege, and allzone 1350Sstevel@tonic-gate * should be set to B_TRUE. 1360Sstevel@tonic-gate * For (3), priv should be set to PRIV_ALL, and allzone should be set 1370Sstevel@tonic-gate * to B_FALSE. 1380Sstevel@tonic-gate * 1390Sstevel@tonic-gate */ 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate /* 1420Sstevel@tonic-gate * The privileges are checked against the Effective set for 1430Sstevel@tonic-gate * ordinary processes and checked against the Limit set 1440Sstevel@tonic-gate * for euid 0 processes that haven't manipulated their privilege 1450Sstevel@tonic-gate * sets. 1460Sstevel@tonic-gate */ 1470Sstevel@tonic-gate #define HAS_ALLPRIVS(cr) priv_isfullset(&CR_OEPRIV(cr)) 1480Sstevel@tonic-gate #define ZONEPRIVS(cr) ((cr)->cr_zone->zone_privset) 1490Sstevel@tonic-gate #define HAS_ALLZONEPRIVS(cr) priv_issubset(ZONEPRIVS(cr), &CR_OEPRIV(cr)) 1500Sstevel@tonic-gate #define HAS_PRIVILEGE(cr, pr) ((pr) == PRIV_ALL ? \ 1510Sstevel@tonic-gate HAS_ALLPRIVS(cr) : \ 1520Sstevel@tonic-gate PRIV_ISASSERT(&CR_OEPRIV(cr), pr)) 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate /* 1556134Scasper * Policy checking functions. 1560Sstevel@tonic-gate * 1576134Scasper * All of the system's policy should be implemented here. 1580Sstevel@tonic-gate */ 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate /* 1616134Scasper * Private functions which take an additional va_list argument to 1626134Scasper * implement an object specific policy override. 1636134Scasper */ 1646134Scasper static int priv_policy_ap(const cred_t *, int, boolean_t, int, 1656134Scasper const char *, va_list); 1666134Scasper static int priv_policy_va(const cred_t *, int, boolean_t, int, 1676134Scasper const char *, ...); 1686134Scasper 1696134Scasper /* 1700Sstevel@tonic-gate * Generic policy calls 1710Sstevel@tonic-gate * 1720Sstevel@tonic-gate * The "bottom" functions of policy control 1730Sstevel@tonic-gate */ 1740Sstevel@tonic-gate static char * 1750Sstevel@tonic-gate mprintf(const char *fmt, ...) 1760Sstevel@tonic-gate { 1770Sstevel@tonic-gate va_list args; 1780Sstevel@tonic-gate char *buf; 1790Sstevel@tonic-gate size_t len; 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate va_start(args, fmt); 1820Sstevel@tonic-gate len = vsnprintf(NULL, 0, fmt, args) + 1; 1830Sstevel@tonic-gate va_end(args); 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate buf = kmem_alloc(len, KM_NOSLEEP); 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate if (buf == NULL) 1880Sstevel@tonic-gate return (NULL); 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate va_start(args, fmt); 1910Sstevel@tonic-gate (void) vsnprintf(buf, len, fmt, args); 1920Sstevel@tonic-gate va_end(args); 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate return (buf); 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate /* 1980Sstevel@tonic-gate * priv_policy_errmsg() 1990Sstevel@tonic-gate * 2000Sstevel@tonic-gate * Generate an error message if privilege debugging is enabled system wide 2010Sstevel@tonic-gate * or for this particular process. 2020Sstevel@tonic-gate */ 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate #define FMTHDR "%s[%d]: missing privilege \"%s\" (euid = %d, syscall = %d)" 2050Sstevel@tonic-gate #define FMTMSG " for \"%s\"" 2060Sstevel@tonic-gate #define FMTFUN " needed at %s+0x%lx" 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate /* The maximum size privilege format: the concatenation of the above */ 2090Sstevel@tonic-gate #define FMTMAX FMTHDR FMTMSG FMTFUN "\n" 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate static void 2120Sstevel@tonic-gate priv_policy_errmsg(const cred_t *cr, int priv, const char *msg) 2130Sstevel@tonic-gate { 2140Sstevel@tonic-gate struct proc *me; 2150Sstevel@tonic-gate pc_t stack[MAXPRIVSTACK]; 2160Sstevel@tonic-gate int depth; 2170Sstevel@tonic-gate int i; 2180Sstevel@tonic-gate char *sym; 2190Sstevel@tonic-gate ulong_t off; 2200Sstevel@tonic-gate const char *pname; 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate char *cmd; 2230Sstevel@tonic-gate char fmt[sizeof (FMTMAX)]; 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate if ((me = curproc) == &p0) 2260Sstevel@tonic-gate return; 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate /* Privileges must be defined */ 2290Sstevel@tonic-gate ASSERT(priv == PRIV_ALL || priv == PRIV_MULTIPLE || 2300Sstevel@tonic-gate priv == PRIV_ALLZONE || priv == PRIV_GLOBAL || 2310Sstevel@tonic-gate priv_getbynum(priv) != NULL); 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate if (priv == PRIV_ALLZONE && INGLOBALZONE(me)) 2340Sstevel@tonic-gate priv = PRIV_ALL; 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate if (curthread->t_pre_sys) 2370Sstevel@tonic-gate ttolwp(curthread)->lwp_badpriv = (short)priv; 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate if (priv_debug == 0 && (CR_FLAGS(cr) & PRIV_DEBUG) == 0) 2400Sstevel@tonic-gate return; 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate (void) strcpy(fmt, FMTHDR); 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate if (me->p_user.u_comm[0]) 2450Sstevel@tonic-gate cmd = &me->p_user.u_comm[0]; 2460Sstevel@tonic-gate else 2470Sstevel@tonic-gate cmd = "priv_policy"; 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate if (msg != NULL && *msg != '\0') { 2500Sstevel@tonic-gate (void) strcat(fmt, FMTMSG); 2510Sstevel@tonic-gate } else { 2520Sstevel@tonic-gate (void) strcat(fmt, "%s"); 2530Sstevel@tonic-gate msg = ""; 2540Sstevel@tonic-gate } 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate sym = NULL; 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate depth = getpcstack(stack, MAXPRIVSTACK); 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate /* 2610Sstevel@tonic-gate * Try to find the first interesting function on the stack. 2620Sstevel@tonic-gate * priv_policy* that's us, so completely uninteresting. 2630Sstevel@tonic-gate * suser(), drv_priv(), secpolicy_* are also called from 2640Sstevel@tonic-gate * too many locations to convey useful information. 2650Sstevel@tonic-gate */ 2660Sstevel@tonic-gate for (i = 0; i < depth; i++) { 2670Sstevel@tonic-gate sym = kobj_getsymname((uintptr_t)stack[i], &off); 2680Sstevel@tonic-gate if (sym != NULL && 2690Sstevel@tonic-gate strstr(sym, "hasprocperm") == 0 && 2700Sstevel@tonic-gate strcmp("suser", sym) != 0 && 2710Sstevel@tonic-gate strcmp("ipcaccess", sym) != 0 && 2720Sstevel@tonic-gate strcmp("drv_priv", sym) != 0 && 2730Sstevel@tonic-gate strncmp("secpolicy_", sym, 10) != 0 && 2740Sstevel@tonic-gate strncmp("priv_policy", sym, 11) != 0) 2750Sstevel@tonic-gate break; 2760Sstevel@tonic-gate } 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate if (sym != NULL) 2790Sstevel@tonic-gate (void) strcat(fmt, FMTFUN); 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate (void) strcat(fmt, "\n"); 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate switch (priv) { 2840Sstevel@tonic-gate case PRIV_ALL: 2850Sstevel@tonic-gate pname = "ALL"; 2860Sstevel@tonic-gate break; 2870Sstevel@tonic-gate case PRIV_MULTIPLE: 2880Sstevel@tonic-gate pname = "MULTIPLE"; 2890Sstevel@tonic-gate break; 2900Sstevel@tonic-gate case PRIV_ALLZONE: 2910Sstevel@tonic-gate pname = "ZONE"; 2920Sstevel@tonic-gate break; 2930Sstevel@tonic-gate case PRIV_GLOBAL: 2940Sstevel@tonic-gate pname = "GLOBAL"; 2950Sstevel@tonic-gate break; 2960Sstevel@tonic-gate default: 2970Sstevel@tonic-gate pname = priv_getbynum(priv); 2980Sstevel@tonic-gate break; 2990Sstevel@tonic-gate } 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate if (CR_FLAGS(cr) & PRIV_DEBUG) { 3020Sstevel@tonic-gate /* Remember last message, just like lwp_badpriv. */ 3030Sstevel@tonic-gate if (curthread->t_pdmsg != NULL) { 3040Sstevel@tonic-gate kmem_free(curthread->t_pdmsg, 3050Sstevel@tonic-gate strlen(curthread->t_pdmsg) + 1); 3060Sstevel@tonic-gate } 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate curthread->t_pdmsg = mprintf(fmt, cmd, me->p_pid, pname, 3094543Smarks cr->cr_uid, curthread->t_sysnum, msg, sym, off); 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate curthread->t_post_sys = 1; 3126134Scasper } 3136134Scasper if (priv_debug) { 3140Sstevel@tonic-gate cmn_err(CE_NOTE, fmt, cmd, me->p_pid, pname, cr->cr_uid, 3150Sstevel@tonic-gate curthread->t_sysnum, msg, sym, off); 3160Sstevel@tonic-gate } 3170Sstevel@tonic-gate } 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate /* 3206134Scasper * Override the policy, if appropriate. Return 0 if the external 3216134Scasper * policy engine approves. 3226134Scasper */ 3236134Scasper static int 3246134Scasper priv_policy_override(const cred_t *cr, int priv, boolean_t allzone, va_list ap) 3256134Scasper { 3266134Scasper priv_set_t set; 3276134Scasper int ret; 3286134Scasper 3296134Scasper if (!(CR_FLAGS(cr) & PRIV_XPOLICY)) 3306134Scasper return (-1); 3316134Scasper 3326134Scasper if (priv == PRIV_ALL) { 3336134Scasper priv_fillset(&set); 3346134Scasper } else if (allzone) { 3356134Scasper set = *ZONEPRIVS(cr); 3366134Scasper } else { 3376134Scasper priv_emptyset(&set); 3386134Scasper priv_addset(&set, priv); 3396134Scasper } 3406134Scasper ret = klpd_call(cr, &set, ap); 3416134Scasper return (ret); 3426134Scasper } 3436134Scasper 3446134Scasper static int 3456134Scasper priv_policy_override_set(const cred_t *cr, const priv_set_t *req, ...) 3466134Scasper { 3476134Scasper va_list ap; 3486134Scasper 3496134Scasper if (CR_FLAGS(cr) & PRIV_XPOLICY) { 3506134Scasper va_start(ap, req); 3516134Scasper return (klpd_call(cr, req, ap)); 3526134Scasper } 3536134Scasper return (-1); 3546134Scasper } 3556134Scasper 3566134Scasper /* 3570Sstevel@tonic-gate * Audit failure, log error message. 3580Sstevel@tonic-gate */ 3590Sstevel@tonic-gate static void 3600Sstevel@tonic-gate priv_policy_err(const cred_t *cr, int priv, boolean_t allzone, const char *msg) 3610Sstevel@tonic-gate { 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate if (audit_active) 3640Sstevel@tonic-gate audit_priv(priv, allzone ? ZONEPRIVS(cr) : NULL, 0); 3650Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone); 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) || 3680Sstevel@tonic-gate curthread->t_pre_sys) { 3690Sstevel@tonic-gate if (allzone && !HAS_ALLZONEPRIVS(cr)) { 3700Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_ALLZONE, msg); 3710Sstevel@tonic-gate } else { 3720Sstevel@tonic-gate ASSERT(!HAS_PRIVILEGE(cr, priv)); 3730Sstevel@tonic-gate priv_policy_errmsg(cr, priv, msg); 3740Sstevel@tonic-gate } 3750Sstevel@tonic-gate } 3760Sstevel@tonic-gate } 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate /* 3796134Scasper * priv_policy_ap() 3800Sstevel@tonic-gate * return 0 or error. 3810Sstevel@tonic-gate * See block comment above for a description of "priv" and "allzone" usage. 3820Sstevel@tonic-gate */ 3836134Scasper static int 3846134Scasper priv_policy_ap(const cred_t *cr, int priv, boolean_t allzone, int err, 3856134Scasper const char *msg, va_list ap) 3860Sstevel@tonic-gate { 3876134Scasper if ((HAS_PRIVILEGE(cr, priv) && (!allzone || HAS_ALLZONEPRIVS(cr))) || 3886134Scasper (!servicing_interrupt() && 3896134Scasper priv_policy_override(cr, priv, allzone, ap) == 0)) { 3900Sstevel@tonic-gate if ((allzone || priv == PRIV_ALL || 3910Sstevel@tonic-gate !PRIV_ISASSERT(priv_basic, priv)) && 3920Sstevel@tonic-gate !servicing_interrupt()) { 3933446Smrj PTOU(curproc)->u_acflag |= ASU; /* Needed for SVVS */ 3940Sstevel@tonic-gate if (audit_active) 3950Sstevel@tonic-gate audit_priv(priv, 3960Sstevel@tonic-gate allzone ? ZONEPRIVS(cr) : NULL, 1); 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate err = 0; 3990Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone); 4000Sstevel@tonic-gate } else if (!servicing_interrupt()) { 4010Sstevel@tonic-gate /* Failure audited in this procedure */ 4020Sstevel@tonic-gate priv_policy_err(cr, priv, allzone, msg); 4030Sstevel@tonic-gate } 4046134Scasper return (err); 4056134Scasper } 4060Sstevel@tonic-gate 4076134Scasper int 4086134Scasper priv_policy_va(const cred_t *cr, int priv, boolean_t allzone, int err, 4096134Scasper const char *msg, ...) 4106134Scasper { 4116134Scasper int ret; 4126134Scasper va_list ap; 4136134Scasper 4146134Scasper va_start(ap, msg); 4156134Scasper ret = priv_policy_ap(cr, priv, allzone, err, msg, ap); 4166134Scasper va_end(ap); 4176134Scasper 4186134Scasper return (ret); 4196134Scasper } 4206134Scasper 4216134Scasper int 4226134Scasper priv_policy(const cred_t *cr, int priv, boolean_t allzone, int err, 4236134Scasper const char *msg) 4246134Scasper { 4256134Scasper return (priv_policy_va(cr, priv, allzone, err, msg, KLPDARG_NOMORE)); 4260Sstevel@tonic-gate } 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate /* 4290Sstevel@tonic-gate * Return B_TRUE for sufficient privileges, B_FALSE for insufficient privileges. 4300Sstevel@tonic-gate */ 4310Sstevel@tonic-gate boolean_t 4320Sstevel@tonic-gate priv_policy_choice(const cred_t *cr, int priv, boolean_t allzone) 4330Sstevel@tonic-gate { 4340Sstevel@tonic-gate boolean_t res = HAS_PRIVILEGE(cr, priv) && 4350Sstevel@tonic-gate (!allzone || HAS_ALLZONEPRIVS(cr)); 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate /* Audit success only */ 4380Sstevel@tonic-gate if (res && audit_active && 4390Sstevel@tonic-gate (allzone || priv == PRIV_ALL || !PRIV_ISASSERT(priv_basic, priv)) && 4400Sstevel@tonic-gate !servicing_interrupt()) { 4410Sstevel@tonic-gate audit_priv(priv, allzone ? ZONEPRIVS(cr) : NULL, 1); 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate if (res) { 4440Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone); 4450Sstevel@tonic-gate } else { 4460Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone); 4470Sstevel@tonic-gate } 4480Sstevel@tonic-gate return (res); 4490Sstevel@tonic-gate } 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate /* 4520Sstevel@tonic-gate * Non-auditing variant of priv_policy_choice(). 4530Sstevel@tonic-gate */ 4540Sstevel@tonic-gate boolean_t 4550Sstevel@tonic-gate priv_policy_only(const cred_t *cr, int priv, boolean_t allzone) 4560Sstevel@tonic-gate { 4570Sstevel@tonic-gate boolean_t res = HAS_PRIVILEGE(cr, priv) && 4580Sstevel@tonic-gate (!allzone || HAS_ALLZONEPRIVS(cr)); 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate if (res) { 4610Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone); 4620Sstevel@tonic-gate } else { 4630Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone); 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate return (res); 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate 4680Sstevel@tonic-gate /* 4690Sstevel@tonic-gate * Check whether all privileges in the required set are present. 4700Sstevel@tonic-gate */ 4710Sstevel@tonic-gate static int 4720Sstevel@tonic-gate secpolicy_require_set(const cred_t *cr, const priv_set_t *req, const char *msg) 4730Sstevel@tonic-gate { 4740Sstevel@tonic-gate int priv; 4750Sstevel@tonic-gate int pfound = -1; 4760Sstevel@tonic-gate priv_set_t pset; 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate if (req == PRIV_FULLSET ? HAS_ALLPRIVS(cr) : priv_issubset(req, 4794543Smarks &CR_OEPRIV(cr))) { 4800Sstevel@tonic-gate return (0); 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate 4836134Scasper if (priv_policy_override_set(cr, req, KLPDARG_NOMORE) == 0) 4846134Scasper return (0); 4856134Scasper 4860Sstevel@tonic-gate if (req == PRIV_FULLSET || priv_isfullset(req)) { 4870Sstevel@tonic-gate priv_policy_err(cr, PRIV_ALL, B_FALSE, msg); 4880Sstevel@tonic-gate return (EACCES); 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate pset = CR_OEPRIV(cr); /* present privileges */ 4920Sstevel@tonic-gate priv_inverse(&pset); /* all non present privileges */ 4930Sstevel@tonic-gate priv_intersect(req, &pset); /* the actual missing privs */ 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate if (audit_active) 4960Sstevel@tonic-gate audit_priv(PRIV_NONE, &pset, 0); 4970Sstevel@tonic-gate /* 4980Sstevel@tonic-gate * Privilege debugging; special case "one privilege in set". 4990Sstevel@tonic-gate */ 5000Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) || curthread->t_pre_sys) { 5010Sstevel@tonic-gate for (priv = 0; priv < nprivs; priv++) { 5020Sstevel@tonic-gate if (priv_ismember(&pset, priv)) { 5030Sstevel@tonic-gate if (pfound != -1) { 5040Sstevel@tonic-gate /* Multiple missing privs */ 5050Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_MULTIPLE, 5064543Smarks msg); 5070Sstevel@tonic-gate return (EACCES); 5080Sstevel@tonic-gate } 5090Sstevel@tonic-gate pfound = priv; 5100Sstevel@tonic-gate } 5110Sstevel@tonic-gate } 5120Sstevel@tonic-gate ASSERT(pfound != -1); 5130Sstevel@tonic-gate /* Just the one missing privilege */ 5140Sstevel@tonic-gate priv_policy_errmsg(cr, pfound, msg); 5150Sstevel@tonic-gate } 5160Sstevel@tonic-gate 5170Sstevel@tonic-gate return (EACCES); 5180Sstevel@tonic-gate } 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate /* 5210Sstevel@tonic-gate * Called when an operation requires that the caller be in the 5220Sstevel@tonic-gate * global zone, regardless of privilege. 5230Sstevel@tonic-gate */ 5240Sstevel@tonic-gate static int 5250Sstevel@tonic-gate priv_policy_global(const cred_t *cr) 5260Sstevel@tonic-gate { 5270Sstevel@tonic-gate if (crgetzoneid(cr) == GLOBAL_ZONEID) 5280Sstevel@tonic-gate return (0); /* success */ 5290Sstevel@tonic-gate 5300Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) || 5310Sstevel@tonic-gate curthread->t_pre_sys) { 5320Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_GLOBAL, NULL); 5330Sstevel@tonic-gate } 5340Sstevel@tonic-gate return (EPERM); 5350Sstevel@tonic-gate } 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate /* 5380Sstevel@tonic-gate * Changing process priority 5390Sstevel@tonic-gate */ 5400Sstevel@tonic-gate int 5410Sstevel@tonic-gate secpolicy_setpriority(const cred_t *cr) 5420Sstevel@tonic-gate { 5430Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_PRIOCNTL, B_FALSE, EPERM, NULL)); 5440Sstevel@tonic-gate } 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate /* 5470Sstevel@tonic-gate * Binding to a privileged port, port must be specified in host byte 5480Sstevel@tonic-gate * order. 5490Sstevel@tonic-gate */ 5500Sstevel@tonic-gate int 5516134Scasper secpolicy_net_privaddr(const cred_t *cr, in_port_t port, int proto) 5520Sstevel@tonic-gate { 5535331Samw char *reason; 5545331Samw int priv; 5555331Samw 5565331Samw switch (port) { 5575331Samw case 137: 5585331Samw case 138: 5595331Samw case 139: 5605331Samw case 445: 5615331Samw /* 5625331Samw * NBT and SMB ports, these are extra privileged ports, 5635331Samw * allow bind only if the SYS_SMB privilege is present. 5645331Samw */ 5655331Samw priv = PRIV_SYS_SMB; 5665331Samw reason = "NBT or SMB port"; 5675331Samw break; 5685331Samw 5695331Samw case 2049: 5705331Samw case 4045: 5715331Samw /* 5725331Samw * NFS ports, these are extra privileged ports, allow bind 5735331Samw * only if the SYS_NFS privilege is present. 5745331Samw */ 5755331Samw priv = PRIV_SYS_NFS; 5765331Samw reason = "NFS port"; 5775331Samw break; 5785331Samw 5795331Samw default: 5805331Samw priv = PRIV_NET_PRIVADDR; 5815331Samw reason = NULL; 5825331Samw break; 5835331Samw 5845331Samw } 5855331Samw 5866134Scasper return (priv_policy_va(cr, priv, B_FALSE, EACCES, reason, 5876134Scasper KLPDARG_PORT, (int)proto, (int)port, KLPDARG_NOMORE)); 5880Sstevel@tonic-gate } 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate /* 5911676Sjpk * Binding to a multilevel port on a trusted (labeled) system. 5921676Sjpk */ 5931676Sjpk int 5941676Sjpk secpolicy_net_bindmlp(const cred_t *cr) 5951676Sjpk { 5966134Scasper return (PRIV_POLICY(cr, PRIV_NET_BINDMLP, B_FALSE, EACCES, NULL)); 5971676Sjpk } 5981676Sjpk 5991676Sjpk /* 6001676Sjpk * Allow a communication between a zone and an unlabeled host when their 6011676Sjpk * labels don't match. 6021676Sjpk */ 6031676Sjpk int 6041676Sjpk secpolicy_net_mac_aware(const cred_t *cr) 6051676Sjpk { 6066134Scasper return (PRIV_POLICY(cr, PRIV_NET_MAC_AWARE, B_FALSE, EACCES, NULL)); 6071676Sjpk } 6081676Sjpk 6091676Sjpk /* 61010934Ssommerfeld@sun.com * Allow a privileged process to transmit traffic without explicit labels 61110934Ssommerfeld@sun.com */ 61210934Ssommerfeld@sun.com int 61310934Ssommerfeld@sun.com secpolicy_net_mac_implicit(const cred_t *cr) 61410934Ssommerfeld@sun.com { 61510934Ssommerfeld@sun.com return (PRIV_POLICY(cr, PRIV_NET_MAC_IMPLICIT, B_FALSE, EACCES, NULL)); 61610934Ssommerfeld@sun.com } 61710934Ssommerfeld@sun.com 61810934Ssommerfeld@sun.com /* 6190Sstevel@tonic-gate * Common routine which determines whether a given credential can 6200Sstevel@tonic-gate * act on a given mount. 6210Sstevel@tonic-gate * When called through mount, the parameter needoptcheck is a pointer 6220Sstevel@tonic-gate * to a boolean variable which will be set to either true or false, 6230Sstevel@tonic-gate * depending on whether the mount policy should change the mount options. 6240Sstevel@tonic-gate * In all other cases, needoptcheck should be a NULL pointer. 6250Sstevel@tonic-gate */ 6260Sstevel@tonic-gate static int 6270Sstevel@tonic-gate secpolicy_fs_common(cred_t *cr, vnode_t *mvp, const vfs_t *vfsp, 6280Sstevel@tonic-gate boolean_t *needoptcheck) 6290Sstevel@tonic-gate { 6300Sstevel@tonic-gate boolean_t allzone = B_FALSE; 6310Sstevel@tonic-gate boolean_t mounting = needoptcheck != NULL; 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate /* 6340Sstevel@tonic-gate * Short circuit the following cases: 6350Sstevel@tonic-gate * vfsp == NULL or mvp == NULL (pure privilege check) 6360Sstevel@tonic-gate * have all privileges - no further checks required 6370Sstevel@tonic-gate * and no mount options need to be set. 6380Sstevel@tonic-gate */ 6390Sstevel@tonic-gate if (vfsp == NULL || mvp == NULL || HAS_ALLPRIVS(cr)) { 6400Sstevel@tonic-gate if (mounting) 6410Sstevel@tonic-gate *needoptcheck = B_FALSE; 6420Sstevel@tonic-gate 6436134Scasper return (priv_policy_va(cr, PRIV_SYS_MOUNT, allzone, EPERM, 6446134Scasper NULL, KLPDARG_VNODE, mvp, (char *)NULL, KLPDARG_NOMORE)); 6450Sstevel@tonic-gate } 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate /* 6480Sstevel@tonic-gate * When operating on an existing mount (either we're not mounting 6490Sstevel@tonic-gate * or we're doing a remount and VFS_REMOUNT will be set), zones 6500Sstevel@tonic-gate * can operate only on mounts established by the zone itself. 6510Sstevel@tonic-gate */ 6520Sstevel@tonic-gate if (!mounting || (vfsp->vfs_flag & VFS_REMOUNT) != 0) { 6530Sstevel@tonic-gate zoneid_t zoneid = crgetzoneid(cr); 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate if (zoneid != GLOBAL_ZONEID && 6560Sstevel@tonic-gate vfsp->vfs_zone->zone_id != zoneid) { 6570Sstevel@tonic-gate return (EPERM); 6580Sstevel@tonic-gate } 6590Sstevel@tonic-gate } 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate if (mounting) 6620Sstevel@tonic-gate *needoptcheck = B_TRUE; 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate /* 6650Sstevel@tonic-gate * Overlay mounts may hide important stuff; if you can't write to a 6660Sstevel@tonic-gate * mount point but would be able to mount on top of it, you can 6670Sstevel@tonic-gate * escalate your privileges. 6680Sstevel@tonic-gate * So we go about asking the same questions namefs does when it 6690Sstevel@tonic-gate * decides whether you can mount over a file or not but with the 6700Sstevel@tonic-gate * added restriction that you can only mount on top of a regular 6710Sstevel@tonic-gate * file or directory. 6720Sstevel@tonic-gate * If we have all the zone's privileges, we skip all other checks, 6730Sstevel@tonic-gate * or else we may actually get in trouble inside the automounter. 6740Sstevel@tonic-gate */ 6750Sstevel@tonic-gate if ((mvp->v_flag & VROOT) != 0 || 6760Sstevel@tonic-gate (mvp->v_type != VDIR && mvp->v_type != VREG) || 6770Sstevel@tonic-gate HAS_ALLZONEPRIVS(cr)) { 6780Sstevel@tonic-gate allzone = B_TRUE; 6790Sstevel@tonic-gate } else { 6800Sstevel@tonic-gate vattr_t va; 6810Sstevel@tonic-gate int err; 6820Sstevel@tonic-gate 6830Sstevel@tonic-gate va.va_mask = AT_UID|AT_MODE; 6845331Samw err = VOP_GETATTR(mvp, &va, 0, cr, NULL); 6850Sstevel@tonic-gate if (err != 0) 6860Sstevel@tonic-gate return (err); 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate if ((err = secpolicy_vnode_owner(cr, va.va_uid)) != 0) 6890Sstevel@tonic-gate return (err); 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate if ((va.va_mode & VWRITE) == 0 && 6920Sstevel@tonic-gate secpolicy_vnode_access(cr, mvp, va.va_uid, VWRITE) != 0) { 6930Sstevel@tonic-gate return (EACCES); 6940Sstevel@tonic-gate } 6950Sstevel@tonic-gate } 6966134Scasper return (priv_policy_va(cr, PRIV_SYS_MOUNT, allzone, EPERM, 6976134Scasper NULL, KLPDARG_VNODE, mvp, (char *)NULL, KLPDARG_NOMORE)); 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate 7004543Smarks void 7014543Smarks secpolicy_fs_mount_clearopts(cred_t *cr, struct vfs *vfsp) 7024543Smarks { 7034543Smarks boolean_t amsuper = HAS_ALLZONEPRIVS(cr); 7044543Smarks 7054543Smarks /* 7064543Smarks * check; if we don't have either "nosuid" or 7074543Smarks * both "nosetuid" and "nodevices", then we add 7084543Smarks * "nosuid"; this depends on how the current 7094543Smarks * implementation works (it first checks nosuid). In a 7104543Smarks * zone, a user with all zone privileges can mount with 7114543Smarks * "setuid" but never with "devices". 7124543Smarks */ 7134543Smarks if (!vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL) && 7144543Smarks (!vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL) || 7154543Smarks !vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL))) { 7164543Smarks if (crgetzoneid(cr) == GLOBAL_ZONEID || !amsuper) 7174543Smarks vfs_setmntopt(vfsp, MNTOPT_NOSUID, NULL, 0); 7184543Smarks else 7194543Smarks vfs_setmntopt(vfsp, MNTOPT_NODEVICES, NULL, 0); 7204543Smarks } 7214543Smarks /* 7224543Smarks * If we're not the local super user, we set the "restrict" 7234543Smarks * option to indicate to automountd that this mount should 7244543Smarks * be handled with care. 7254543Smarks */ 7264543Smarks if (!amsuper) 7274543Smarks vfs_setmntopt(vfsp, MNTOPT_RESTRICT, NULL, 0); 7284543Smarks 7294543Smarks } 7304543Smarks 731148Scasper extern vnode_t *rootvp; 732148Scasper extern vfs_t *rootvfs; 733148Scasper 7340Sstevel@tonic-gate int 7350Sstevel@tonic-gate secpolicy_fs_mount(cred_t *cr, vnode_t *mvp, struct vfs *vfsp) 7360Sstevel@tonic-gate { 7370Sstevel@tonic-gate boolean_t needoptchk; 7380Sstevel@tonic-gate int error; 7390Sstevel@tonic-gate 740148Scasper /* 741148Scasper * If it's a remount, get the underlying mount point, 742148Scasper * except for the root where we use the rootvp. 743148Scasper */ 744148Scasper if ((vfsp->vfs_flag & VFS_REMOUNT) != 0) { 745148Scasper if (vfsp == rootvfs) 746148Scasper mvp = rootvp; 747148Scasper else 748148Scasper mvp = vfsp->vfs_vnodecovered; 749148Scasper } 750148Scasper 7510Sstevel@tonic-gate error = secpolicy_fs_common(cr, mvp, vfsp, &needoptchk); 7520Sstevel@tonic-gate 7530Sstevel@tonic-gate if (error == 0 && needoptchk) { 7544543Smarks secpolicy_fs_mount_clearopts(cr, vfsp); 7554543Smarks } 7560Sstevel@tonic-gate 7570Sstevel@tonic-gate return (error); 7580Sstevel@tonic-gate } 7590Sstevel@tonic-gate 7600Sstevel@tonic-gate /* 7610Sstevel@tonic-gate * Does the policy computations for "ownership" of a mount; 7620Sstevel@tonic-gate * here ownership is defined as the ability to "mount" 7630Sstevel@tonic-gate * the filesystem originally. The rootvfs doesn't cover any 7640Sstevel@tonic-gate * vnodes; we attribute its ownership to the rootvp. 7650Sstevel@tonic-gate */ 7660Sstevel@tonic-gate static int 7670Sstevel@tonic-gate secpolicy_fs_owner(cred_t *cr, const struct vfs *vfsp) 7680Sstevel@tonic-gate { 7690Sstevel@tonic-gate vnode_t *mvp; 7700Sstevel@tonic-gate 7710Sstevel@tonic-gate if (vfsp == NULL) 7720Sstevel@tonic-gate mvp = NULL; 7730Sstevel@tonic-gate else if (vfsp == rootvfs) 7740Sstevel@tonic-gate mvp = rootvp; 7750Sstevel@tonic-gate else 7760Sstevel@tonic-gate mvp = vfsp->vfs_vnodecovered; 7770Sstevel@tonic-gate 7780Sstevel@tonic-gate return (secpolicy_fs_common(cr, mvp, vfsp, NULL)); 7790Sstevel@tonic-gate } 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate int 7820Sstevel@tonic-gate secpolicy_fs_unmount(cred_t *cr, struct vfs *vfsp) 7830Sstevel@tonic-gate { 7840Sstevel@tonic-gate return (secpolicy_fs_owner(cr, vfsp)); 7850Sstevel@tonic-gate } 7860Sstevel@tonic-gate 7870Sstevel@tonic-gate /* 7880Sstevel@tonic-gate * Quotas are a resource, but if one has the ability to mount a filesystem, he 7890Sstevel@tonic-gate * should be able to modify quotas on it. 7900Sstevel@tonic-gate */ 7910Sstevel@tonic-gate int 7920Sstevel@tonic-gate secpolicy_fs_quota(const cred_t *cr, const vfs_t *vfsp) 7930Sstevel@tonic-gate { 7940Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 7950Sstevel@tonic-gate } 7960Sstevel@tonic-gate 7970Sstevel@tonic-gate /* 7980Sstevel@tonic-gate * Exceeding minfree: also a per-mount resource constraint. 7990Sstevel@tonic-gate */ 8000Sstevel@tonic-gate int 8010Sstevel@tonic-gate secpolicy_fs_minfree(const cred_t *cr, const vfs_t *vfsp) 8020Sstevel@tonic-gate { 8030Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 8040Sstevel@tonic-gate } 8050Sstevel@tonic-gate 8060Sstevel@tonic-gate int 8070Sstevel@tonic-gate secpolicy_fs_config(const cred_t *cr, const vfs_t *vfsp) 8080Sstevel@tonic-gate { 8090Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 8100Sstevel@tonic-gate } 8110Sstevel@tonic-gate 8120Sstevel@tonic-gate /* ARGSUSED */ 8130Sstevel@tonic-gate int 8140Sstevel@tonic-gate secpolicy_fs_linkdir(const cred_t *cr, const vfs_t *vfsp) 8150Sstevel@tonic-gate { 8160Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_LINKDIR, B_FALSE, EPERM, NULL)); 8170Sstevel@tonic-gate } 8180Sstevel@tonic-gate 8190Sstevel@tonic-gate /* 8200Sstevel@tonic-gate * Name: secpolicy_vnode_access() 8210Sstevel@tonic-gate * 8220Sstevel@tonic-gate * Parameters: Process credential 8230Sstevel@tonic-gate * vnode 8240Sstevel@tonic-gate * uid of owner of vnode 8250Sstevel@tonic-gate * permission bits not granted to the caller when examining 8260Sstevel@tonic-gate * file mode bits (i.e., when a process wants to open a 8270Sstevel@tonic-gate * mode 444 file for VREAD|VWRITE, this function should be 8280Sstevel@tonic-gate * called only with a VWRITE argument). 8290Sstevel@tonic-gate * 8300Sstevel@tonic-gate * Normal: Verifies that cred has the appropriate privileges to 8310Sstevel@tonic-gate * override the mode bits that were denied. 8320Sstevel@tonic-gate * 8330Sstevel@tonic-gate * Override: file_dac_execute - if VEXEC bit was denied and vnode is 8340Sstevel@tonic-gate * not a directory. 8350Sstevel@tonic-gate * file_dac_read - if VREAD bit was denied. 8360Sstevel@tonic-gate * file_dac_search - if VEXEC bit was denied and vnode is 8370Sstevel@tonic-gate * a directory. 8380Sstevel@tonic-gate * file_dac_write - if VWRITE bit was denied. 8390Sstevel@tonic-gate * 8400Sstevel@tonic-gate * Root owned files are special cased to protect system 8410Sstevel@tonic-gate * configuration files and such. 8420Sstevel@tonic-gate * 8430Sstevel@tonic-gate * Output: EACCES - if privilege check fails. 8440Sstevel@tonic-gate */ 8450Sstevel@tonic-gate 8460Sstevel@tonic-gate /* ARGSUSED */ 8470Sstevel@tonic-gate int 8480Sstevel@tonic-gate secpolicy_vnode_access(const cred_t *cr, vnode_t *vp, uid_t owner, mode_t mode) 8490Sstevel@tonic-gate { 8506134Scasper if ((mode & VREAD) && priv_policy_va(cr, PRIV_FILE_DAC_READ, B_FALSE, 8516134Scasper EACCES, NULL, KLPDARG_VNODE, vp, (char *)NULL, 8526134Scasper KLPDARG_NOMORE) != 0) { 8530Sstevel@tonic-gate return (EACCES); 8546134Scasper } 8550Sstevel@tonic-gate 8560Sstevel@tonic-gate if (mode & VWRITE) { 8570Sstevel@tonic-gate boolean_t allzone; 8580Sstevel@tonic-gate 8590Sstevel@tonic-gate if (owner == 0 && cr->cr_uid != 0) 8600Sstevel@tonic-gate allzone = B_TRUE; 8610Sstevel@tonic-gate else 8620Sstevel@tonic-gate allzone = B_FALSE; 8636134Scasper if (priv_policy_va(cr, PRIV_FILE_DAC_WRITE, allzone, EACCES, 8646134Scasper NULL, KLPDARG_VNODE, vp, (char *)NULL, 8656134Scasper KLPDARG_NOMORE) != 0) { 8660Sstevel@tonic-gate return (EACCES); 8676134Scasper } 8680Sstevel@tonic-gate } 8690Sstevel@tonic-gate 8700Sstevel@tonic-gate if (mode & VEXEC) { 8710Sstevel@tonic-gate /* 8720Sstevel@tonic-gate * Directories use file_dac_search to override the execute bit. 8730Sstevel@tonic-gate */ 8746134Scasper int p = vp->v_type == VDIR ? PRIV_FILE_DAC_SEARCH : 8756134Scasper PRIV_FILE_DAC_EXECUTE; 8760Sstevel@tonic-gate 8776134Scasper return (priv_policy_va(cr, p, B_FALSE, EACCES, NULL, 8786134Scasper KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE)); 8790Sstevel@tonic-gate } 8800Sstevel@tonic-gate return (0); 8810Sstevel@tonic-gate } 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate /* 8840Sstevel@tonic-gate * Name: secpolicy_vnode_setid_modify() 8850Sstevel@tonic-gate * 8860Sstevel@tonic-gate * Normal: verify that subject can set the file setid flags. 8870Sstevel@tonic-gate * 8880Sstevel@tonic-gate * Output: EPERM - if not privileged. 8890Sstevel@tonic-gate */ 8900Sstevel@tonic-gate 8910Sstevel@tonic-gate static int 8920Sstevel@tonic-gate secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner) 8930Sstevel@tonic-gate { 8940Sstevel@tonic-gate /* If changing to suid root, must have all zone privs */ 8950Sstevel@tonic-gate boolean_t allzone = B_TRUE; 8960Sstevel@tonic-gate 8970Sstevel@tonic-gate if (owner != 0) { 8980Sstevel@tonic-gate if (owner == cr->cr_uid) 8990Sstevel@tonic-gate return (0); 9000Sstevel@tonic-gate allzone = B_FALSE; 9010Sstevel@tonic-gate } 9020Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_SETID, allzone, EPERM, NULL)); 9030Sstevel@tonic-gate } 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate /* 9060Sstevel@tonic-gate * Are we allowed to retain the set-uid/set-gid bits when 9070Sstevel@tonic-gate * changing ownership or when writing to a file? 9080Sstevel@tonic-gate * "issuid" should be true when set-uid; only in that case 9090Sstevel@tonic-gate * root ownership is checked (setgid is assumed). 9100Sstevel@tonic-gate */ 9110Sstevel@tonic-gate int 9120Sstevel@tonic-gate secpolicy_vnode_setid_retain(const cred_t *cred, boolean_t issuidroot) 9130Sstevel@tonic-gate { 9140Sstevel@tonic-gate if (issuidroot && !HAS_ALLZONEPRIVS(cred)) 9150Sstevel@tonic-gate return (EPERM); 9160Sstevel@tonic-gate 9170Sstevel@tonic-gate return (!PRIV_POLICY_CHOICE(cred, PRIV_FILE_SETID, B_FALSE)); 9180Sstevel@tonic-gate } 9190Sstevel@tonic-gate 9200Sstevel@tonic-gate /* 9210Sstevel@tonic-gate * Name: secpolicy_vnode_setids_setgids() 9220Sstevel@tonic-gate * 9230Sstevel@tonic-gate * Normal: verify that subject can set the file setgid flag. 9240Sstevel@tonic-gate * 9250Sstevel@tonic-gate * Output: EPERM - if not privileged 9260Sstevel@tonic-gate */ 9270Sstevel@tonic-gate 9280Sstevel@tonic-gate int 9290Sstevel@tonic-gate secpolicy_vnode_setids_setgids(const cred_t *cred, gid_t gid) 9300Sstevel@tonic-gate { 9310Sstevel@tonic-gate if (!groupmember(gid, cred)) 9320Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_SETID, B_FALSE, EPERM, 9330Sstevel@tonic-gate NULL)); 9340Sstevel@tonic-gate return (0); 9350Sstevel@tonic-gate } 9360Sstevel@tonic-gate 9370Sstevel@tonic-gate /* 9387624SMark.Shellenbaum@Sun.COM * Name: secpolicy_vnode_chown 9397624SMark.Shellenbaum@Sun.COM * 9407624SMark.Shellenbaum@Sun.COM * Normal: Determine if subject can chown owner of a file. 9417624SMark.Shellenbaum@Sun.COM * 9427624SMark.Shellenbaum@Sun.COM * Output: EPERM - if access denied 9437624SMark.Shellenbaum@Sun.COM */ 9447624SMark.Shellenbaum@Sun.COM 9457624SMark.Shellenbaum@Sun.COM int 9469866SMark.Shellenbaum@Sun.COM secpolicy_vnode_chown(const cred_t *cred, uid_t owner) 9477624SMark.Shellenbaum@Sun.COM { 9489866SMark.Shellenbaum@Sun.COM boolean_t is_owner = (owner == crgetuid(cred)); 9499866SMark.Shellenbaum@Sun.COM boolean_t allzone = B_FALSE; 9509866SMark.Shellenbaum@Sun.COM int priv; 9519866SMark.Shellenbaum@Sun.COM 9529866SMark.Shellenbaum@Sun.COM if (!is_owner) { 9539866SMark.Shellenbaum@Sun.COM allzone = (owner == 0); 9549866SMark.Shellenbaum@Sun.COM priv = PRIV_FILE_CHOWN; 9559866SMark.Shellenbaum@Sun.COM } else { 9569866SMark.Shellenbaum@Sun.COM priv = HAS_PRIVILEGE(cred, PRIV_FILE_CHOWN) ? 9579866SMark.Shellenbaum@Sun.COM PRIV_FILE_CHOWN : PRIV_FILE_CHOWN_SELF; 9589866SMark.Shellenbaum@Sun.COM } 9599866SMark.Shellenbaum@Sun.COM 9609866SMark.Shellenbaum@Sun.COM return (PRIV_POLICY(cred, priv, allzone, EPERM, NULL)); 9617624SMark.Shellenbaum@Sun.COM } 9627624SMark.Shellenbaum@Sun.COM 9637624SMark.Shellenbaum@Sun.COM /* 9647624SMark.Shellenbaum@Sun.COM * Name: secpolicy_vnode_create_gid 9657624SMark.Shellenbaum@Sun.COM * 9667624SMark.Shellenbaum@Sun.COM * Normal: Determine if subject can change group ownership of a file. 9677624SMark.Shellenbaum@Sun.COM * 9687624SMark.Shellenbaum@Sun.COM * Output: EPERM - if access denied 9690Sstevel@tonic-gate */ 9700Sstevel@tonic-gate int 9710Sstevel@tonic-gate secpolicy_vnode_create_gid(const cred_t *cred) 9720Sstevel@tonic-gate { 9739866SMark.Shellenbaum@Sun.COM if (HAS_PRIVILEGE(cred, PRIV_FILE_CHOWN)) 9749866SMark.Shellenbaum@Sun.COM return (PRIV_POLICY(cred, PRIV_FILE_CHOWN, B_FALSE, EPERM, 9759866SMark.Shellenbaum@Sun.COM NULL)); 9769866SMark.Shellenbaum@Sun.COM else 9779866SMark.Shellenbaum@Sun.COM return (PRIV_POLICY(cred, PRIV_FILE_CHOWN_SELF, B_FALSE, EPERM, 9789866SMark.Shellenbaum@Sun.COM NULL)); 9790Sstevel@tonic-gate } 9800Sstevel@tonic-gate 9810Sstevel@tonic-gate /* 9820Sstevel@tonic-gate * Name: secpolicy_vnode_utime_modify() 9830Sstevel@tonic-gate * 9840Sstevel@tonic-gate * Normal: verify that subject can modify the utime on a file. 9850Sstevel@tonic-gate * 9860Sstevel@tonic-gate * Output: EPERM - if access denied. 9870Sstevel@tonic-gate */ 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate static int 9900Sstevel@tonic-gate secpolicy_vnode_utime_modify(const cred_t *cred) 9910Sstevel@tonic-gate { 9920Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_OWNER, B_FALSE, EPERM, 9930Sstevel@tonic-gate "modify file times")); 9940Sstevel@tonic-gate } 9950Sstevel@tonic-gate 9960Sstevel@tonic-gate 9970Sstevel@tonic-gate /* 9980Sstevel@tonic-gate * Name: secpolicy_vnode_setdac() 9990Sstevel@tonic-gate * 10000Sstevel@tonic-gate * Normal: verify that subject can modify the mode of a file. 10010Sstevel@tonic-gate * allzone privilege needed when modifying root owned object. 10020Sstevel@tonic-gate * 10030Sstevel@tonic-gate * Output: EPERM - if access denied. 10040Sstevel@tonic-gate */ 10050Sstevel@tonic-gate 10060Sstevel@tonic-gate int 10070Sstevel@tonic-gate secpolicy_vnode_setdac(const cred_t *cred, uid_t owner) 10080Sstevel@tonic-gate { 10090Sstevel@tonic-gate if (owner == cred->cr_uid) 10100Sstevel@tonic-gate return (0); 10110Sstevel@tonic-gate 10120Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_OWNER, owner == 0, EPERM, NULL)); 10130Sstevel@tonic-gate } 10140Sstevel@tonic-gate /* 10150Sstevel@tonic-gate * Name: secpolicy_vnode_stky_modify() 10160Sstevel@tonic-gate * 10170Sstevel@tonic-gate * Normal: verify that subject can make a file a "sticky". 10180Sstevel@tonic-gate * 10190Sstevel@tonic-gate * Output: EPERM - if access denied. 10200Sstevel@tonic-gate */ 10210Sstevel@tonic-gate 10220Sstevel@tonic-gate int 10230Sstevel@tonic-gate secpolicy_vnode_stky_modify(const cred_t *cred) 10240Sstevel@tonic-gate { 10250Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_SYS_CONFIG, B_FALSE, EPERM, 10260Sstevel@tonic-gate "set file sticky")); 10270Sstevel@tonic-gate } 10280Sstevel@tonic-gate 10290Sstevel@tonic-gate /* 10300Sstevel@tonic-gate * Policy determines whether we can remove an entry from a directory, 10310Sstevel@tonic-gate * regardless of permission bits. 10320Sstevel@tonic-gate */ 10330Sstevel@tonic-gate int 10340Sstevel@tonic-gate secpolicy_vnode_remove(const cred_t *cr) 10350Sstevel@tonic-gate { 10360Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_OWNER, B_FALSE, EACCES, 10370Sstevel@tonic-gate "sticky directory")); 10380Sstevel@tonic-gate } 10390Sstevel@tonic-gate 10400Sstevel@tonic-gate int 10410Sstevel@tonic-gate secpolicy_vnode_owner(const cred_t *cr, uid_t owner) 10420Sstevel@tonic-gate { 10430Sstevel@tonic-gate boolean_t allzone = (owner == 0); 10440Sstevel@tonic-gate 10450Sstevel@tonic-gate if (owner == cr->cr_uid) 10460Sstevel@tonic-gate return (0); 10470Sstevel@tonic-gate 10480Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_OWNER, allzone, EPERM, NULL)); 10490Sstevel@tonic-gate } 10500Sstevel@tonic-gate 10511115Smarks void 10521115Smarks secpolicy_setid_clear(vattr_t *vap, cred_t *cr) 10531115Smarks { 10541115Smarks if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0 && 10551115Smarks secpolicy_vnode_setid_retain(cr, 10561115Smarks (vap->va_mode & S_ISUID) != 0 && 10571115Smarks (vap->va_mask & AT_UID) != 0 && vap->va_uid == 0) != 0) { 10581115Smarks vap->va_mask |= AT_MODE; 10591115Smarks vap->va_mode &= ~(S_ISUID|S_ISGID); 10601115Smarks } 10611115Smarks } 10621115Smarks 10632796Smarks int 10642796Smarks secpolicy_setid_setsticky_clear(vnode_t *vp, vattr_t *vap, const vattr_t *ovap, 10652796Smarks cred_t *cr) 10662796Smarks { 10672796Smarks int error; 10682796Smarks 10692796Smarks if ((vap->va_mode & S_ISUID) != 0 && 10702796Smarks (error = secpolicy_vnode_setid_modify(cr, 10712796Smarks ovap->va_uid)) != 0) { 10722796Smarks return (error); 10732796Smarks } 10742796Smarks 10752796Smarks /* 10762796Smarks * Check privilege if attempting to set the 10772796Smarks * sticky bit on a non-directory. 10782796Smarks */ 10792796Smarks if (vp->v_type != VDIR && (vap->va_mode & S_ISVTX) != 0 && 10802796Smarks secpolicy_vnode_stky_modify(cr) != 0) { 10814543Smarks vap->va_mode &= ~S_ISVTX; 10822796Smarks } 10832796Smarks 10842796Smarks /* 10852796Smarks * Check for privilege if attempting to set the 10862796Smarks * group-id bit. 10872796Smarks */ 10882796Smarks if ((vap->va_mode & S_ISGID) != 0 && 10892796Smarks secpolicy_vnode_setids_setgids(cr, ovap->va_gid) != 0) { 10904543Smarks vap->va_mode &= ~S_ISGID; 10912796Smarks } 10922796Smarks 10932796Smarks return (0); 10942796Smarks } 10952796Smarks 10965331Samw #define ATTR_FLAG_PRIV(attr, value, cr) \ 10975331Samw PRIV_POLICY(cr, value ? PRIV_FILE_FLAG_SET : PRIV_ALL, \ 10985331Samw B_FALSE, EPERM, NULL) 10995331Samw 11005331Samw /* 11015331Samw * Check privileges for setting xvattr attributes 11025331Samw */ 11035331Samw int 11045331Samw secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype) 11055331Samw { 11065331Samw xoptattr_t *xoap; 11075331Samw int error = 0; 11085331Samw 11095331Samw if ((xoap = xva_getxoptattr(xvap)) == NULL) 11105331Samw return (EINVAL); 11115331Samw 11125331Samw /* 11135331Samw * First process the DOS bits 11145331Samw */ 11155331Samw if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE) || 11165331Samw XVA_ISSET_REQ(xvap, XAT_HIDDEN) || 11175331Samw XVA_ISSET_REQ(xvap, XAT_READONLY) || 11185331Samw XVA_ISSET_REQ(xvap, XAT_SYSTEM) || 11195331Samw XVA_ISSET_REQ(xvap, XAT_CREATETIME)) { 11205331Samw if ((error = secpolicy_vnode_owner(cr, owner)) != 0) 11215331Samw return (error); 11225331Samw } 11235331Samw 11245331Samw /* 11255331Samw * Now handle special attributes 11265331Samw */ 11275331Samw 11285331Samw if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE)) 11295331Samw error = ATTR_FLAG_PRIV(XAT_IMMUTABLE, 11305331Samw xoap->xoa_immutable, cr); 11315331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_NOUNLINK)) 11325331Samw error = ATTR_FLAG_PRIV(XAT_NOUNLINK, 11335331Samw xoap->xoa_nounlink, cr); 11345331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_APPENDONLY)) 11355331Samw error = ATTR_FLAG_PRIV(XAT_APPENDONLY, 11365331Samw xoap->xoa_appendonly, cr); 11375331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_NODUMP)) 11385331Samw error = ATTR_FLAG_PRIV(XAT_NODUMP, 11395331Samw xoap->xoa_nodump, cr); 11405331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_OPAQUE)) 11415331Samw error = EPERM; 11425331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED)) { 11435331Samw error = ATTR_FLAG_PRIV(XAT_AV_QUARANTINED, 11445331Samw xoap->xoa_av_quarantined, cr); 11455545Smarks if (error == 0 && vtype != VREG && xoap->xoa_av_quarantined) 11465331Samw error = EINVAL; 11475331Samw } 11485331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED)) 11495331Samw error = ATTR_FLAG_PRIV(XAT_AV_MODIFIED, 11505331Samw xoap->xoa_av_modified, cr); 11515331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) { 11525331Samw error = ATTR_FLAG_PRIV(XAT_AV_SCANSTAMP, 11535331Samw xoap->xoa_av_scanstamp, cr); 11545331Samw if (error == 0 && vtype != VREG) 11555331Samw error = EINVAL; 11565331Samw } 11575331Samw return (error); 11585331Samw } 11595331Samw 11600Sstevel@tonic-gate /* 11610Sstevel@tonic-gate * This function checks the policy decisions surrounding the 11620Sstevel@tonic-gate * vop setattr call. 11630Sstevel@tonic-gate * 11640Sstevel@tonic-gate * It should be called after sufficient locks have been established 11650Sstevel@tonic-gate * on the underlying data structures. No concurrent modifications 11660Sstevel@tonic-gate * should be allowed. 11670Sstevel@tonic-gate * 11680Sstevel@tonic-gate * The caller must pass in unlocked version of its vaccess function 11690Sstevel@tonic-gate * this is required because vop_access function should lock the 11700Sstevel@tonic-gate * node for reading. A three argument function should be defined 11710Sstevel@tonic-gate * which accepts the following argument: 11720Sstevel@tonic-gate * A pointer to the internal "node" type (inode *) 11730Sstevel@tonic-gate * vnode access bits (VREAD|VWRITE|VEXEC) 11740Sstevel@tonic-gate * a pointer to the credential 11750Sstevel@tonic-gate * 11760Sstevel@tonic-gate * This function makes the following policy decisions: 11770Sstevel@tonic-gate * 11780Sstevel@tonic-gate * - change permissions 11790Sstevel@tonic-gate * - permission to change file mode if not owner 11800Sstevel@tonic-gate * - permission to add sticky bit to non-directory 11810Sstevel@tonic-gate * - permission to add set-gid bit 11820Sstevel@tonic-gate * 11830Sstevel@tonic-gate * The ovap argument should include AT_MODE|AT_UID|AT_GID. 11840Sstevel@tonic-gate * 11850Sstevel@tonic-gate * If the vap argument does not include AT_MODE, the mode will be copied from 11860Sstevel@tonic-gate * ovap. In certain situations set-uid/set-gid bits need to be removed; 11870Sstevel@tonic-gate * this is done by marking vap->va_mask to include AT_MODE and va_mode 11880Sstevel@tonic-gate * is updated to the newly computed mode. 11890Sstevel@tonic-gate */ 11900Sstevel@tonic-gate 11910Sstevel@tonic-gate int 11920Sstevel@tonic-gate secpolicy_vnode_setattr(cred_t *cr, struct vnode *vp, struct vattr *vap, 11930Sstevel@tonic-gate const struct vattr *ovap, int flags, 11940Sstevel@tonic-gate int unlocked_access(void *, int, cred_t *), 11950Sstevel@tonic-gate void *node) 11960Sstevel@tonic-gate { 11970Sstevel@tonic-gate int mask = vap->va_mask; 11980Sstevel@tonic-gate int error = 0; 11995331Samw boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE; 12000Sstevel@tonic-gate 12010Sstevel@tonic-gate if (mask & AT_SIZE) { 12020Sstevel@tonic-gate if (vp->v_type == VDIR) { 12030Sstevel@tonic-gate error = EISDIR; 12040Sstevel@tonic-gate goto out; 12050Sstevel@tonic-gate } 12065331Samw 12075331Samw /* 12085331Samw * If ATTR_NOACLCHECK is set in the flags, then we don't 12095331Samw * perform the secondary unlocked_access() call since the 12105331Samw * ACL (if any) is being checked there. 12115331Samw */ 12125331Samw if (skipaclchk == B_FALSE) { 12135331Samw error = unlocked_access(node, VWRITE, cr); 12145331Samw if (error) 12155331Samw goto out; 12165331Samw } 12170Sstevel@tonic-gate } 12180Sstevel@tonic-gate if (mask & AT_MODE) { 12190Sstevel@tonic-gate /* 12200Sstevel@tonic-gate * If not the owner of the file then check privilege 12210Sstevel@tonic-gate * for two things: the privilege to set the mode at all 12220Sstevel@tonic-gate * and, if we're setting setuid, we also need permissions 12230Sstevel@tonic-gate * to add the set-uid bit, if we're not the owner. 12240Sstevel@tonic-gate * In the specific case of creating a set-uid root 12250Sstevel@tonic-gate * file, we need even more permissions. 12260Sstevel@tonic-gate */ 12270Sstevel@tonic-gate if ((error = secpolicy_vnode_setdac(cr, ovap->va_uid)) != 0) 12280Sstevel@tonic-gate goto out; 12290Sstevel@tonic-gate 12302796Smarks if ((error = secpolicy_setid_setsticky_clear(vp, vap, 12312796Smarks ovap, cr)) != 0) 12320Sstevel@tonic-gate goto out; 12330Sstevel@tonic-gate } else 12340Sstevel@tonic-gate vap->va_mode = ovap->va_mode; 12350Sstevel@tonic-gate 12360Sstevel@tonic-gate if (mask & (AT_UID|AT_GID)) { 12370Sstevel@tonic-gate boolean_t checkpriv = B_FALSE; 12380Sstevel@tonic-gate 12390Sstevel@tonic-gate /* 12400Sstevel@tonic-gate * Chowning files. 12410Sstevel@tonic-gate * 12420Sstevel@tonic-gate * If you are the file owner: 12430Sstevel@tonic-gate * chown to other uid FILE_CHOWN_SELF 12440Sstevel@tonic-gate * chown to gid (non-member) FILE_CHOWN_SELF 12450Sstevel@tonic-gate * chown to gid (member) <none> 12460Sstevel@tonic-gate * 12470Sstevel@tonic-gate * Instead of PRIV_FILE_CHOWN_SELF, FILE_CHOWN is also 12480Sstevel@tonic-gate * acceptable but the first one is reported when debugging. 12490Sstevel@tonic-gate * 12500Sstevel@tonic-gate * If you are not the file owner: 12510Sstevel@tonic-gate * chown from root PRIV_FILE_CHOWN + zone 12520Sstevel@tonic-gate * chown from other to any PRIV_FILE_CHOWN 12530Sstevel@tonic-gate * 12540Sstevel@tonic-gate */ 12550Sstevel@tonic-gate if (cr->cr_uid != ovap->va_uid) { 12560Sstevel@tonic-gate checkpriv = B_TRUE; 12570Sstevel@tonic-gate } else { 12580Sstevel@tonic-gate if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || 12590Sstevel@tonic-gate ((mask & AT_GID) && vap->va_gid != ovap->va_gid && 12600Sstevel@tonic-gate !groupmember(vap->va_gid, cr))) { 12610Sstevel@tonic-gate checkpriv = B_TRUE; 12620Sstevel@tonic-gate } 12630Sstevel@tonic-gate } 12640Sstevel@tonic-gate /* 12650Sstevel@tonic-gate * If necessary, check privilege to see if update can be done. 12660Sstevel@tonic-gate */ 12670Sstevel@tonic-gate if (checkpriv && 12689866SMark.Shellenbaum@Sun.COM (error = secpolicy_vnode_chown(cr, ovap->va_uid)) != 0) { 12690Sstevel@tonic-gate goto out; 12700Sstevel@tonic-gate } 12710Sstevel@tonic-gate 12720Sstevel@tonic-gate /* 12730Sstevel@tonic-gate * If the file has either the set UID or set GID bits 12740Sstevel@tonic-gate * set and the caller can set the bits, then leave them. 12750Sstevel@tonic-gate */ 12761115Smarks secpolicy_setid_clear(vap, cr); 12770Sstevel@tonic-gate } 12780Sstevel@tonic-gate if (mask & (AT_ATIME|AT_MTIME)) { 12790Sstevel@tonic-gate /* 12800Sstevel@tonic-gate * If not the file owner and not otherwise privileged, 12810Sstevel@tonic-gate * always return an error when setting the 12820Sstevel@tonic-gate * time other than the current (ATTR_UTIME flag set). 12830Sstevel@tonic-gate * If setting the current time (ATTR_UTIME not set) then 12840Sstevel@tonic-gate * unlocked_access will check permissions according to policy. 12850Sstevel@tonic-gate */ 12860Sstevel@tonic-gate if (cr->cr_uid != ovap->va_uid) { 12870Sstevel@tonic-gate if (flags & ATTR_UTIME) 12880Sstevel@tonic-gate error = secpolicy_vnode_utime_modify(cr); 12895331Samw else if (skipaclchk == B_FALSE) { 12900Sstevel@tonic-gate error = unlocked_access(node, VWRITE, cr); 12910Sstevel@tonic-gate if (error == EACCES && 12920Sstevel@tonic-gate secpolicy_vnode_utime_modify(cr) == 0) 12930Sstevel@tonic-gate error = 0; 12940Sstevel@tonic-gate } 12950Sstevel@tonic-gate if (error) 12960Sstevel@tonic-gate goto out; 12970Sstevel@tonic-gate } 12980Sstevel@tonic-gate } 12995331Samw 13005331Samw /* 13015331Samw * Check for optional attributes here by checking the following: 13025331Samw */ 13035331Samw if (mask & AT_XVATTR) 13045331Samw error = secpolicy_xvattr((xvattr_t *)vap, ovap->va_uid, cr, 13055331Samw vp->v_type); 13060Sstevel@tonic-gate out: 13070Sstevel@tonic-gate return (error); 13080Sstevel@tonic-gate } 13090Sstevel@tonic-gate 13100Sstevel@tonic-gate /* 13110Sstevel@tonic-gate * Name: secpolicy_pcfs_modify_bootpartition() 13120Sstevel@tonic-gate * 13130Sstevel@tonic-gate * Normal: verify that subject can modify a pcfs boot partition. 13140Sstevel@tonic-gate * 13150Sstevel@tonic-gate * Output: EACCES - if privilege check failed. 13160Sstevel@tonic-gate */ 13170Sstevel@tonic-gate /*ARGSUSED*/ 13180Sstevel@tonic-gate int 13190Sstevel@tonic-gate secpolicy_pcfs_modify_bootpartition(const cred_t *cred) 13200Sstevel@tonic-gate { 13210Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_ALL, B_FALSE, EACCES, 13220Sstevel@tonic-gate "modify pcfs boot partition")); 13230Sstevel@tonic-gate } 13240Sstevel@tonic-gate 13250Sstevel@tonic-gate /* 13260Sstevel@tonic-gate * System V IPC routines 13270Sstevel@tonic-gate */ 13280Sstevel@tonic-gate int 13290Sstevel@tonic-gate secpolicy_ipc_owner(const cred_t *cr, const struct kipc_perm *ip) 13300Sstevel@tonic-gate { 13310Sstevel@tonic-gate if (crgetzoneid(cr) != ip->ipc_zoneid || 13320Sstevel@tonic-gate (cr->cr_uid != ip->ipc_uid && cr->cr_uid != ip->ipc_cuid)) { 13330Sstevel@tonic-gate boolean_t allzone = B_FALSE; 13340Sstevel@tonic-gate if (ip->ipc_uid == 0 || ip->ipc_cuid == 0) 13350Sstevel@tonic-gate allzone = B_TRUE; 13360Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_OWNER, allzone, EPERM, NULL)); 13370Sstevel@tonic-gate } 13380Sstevel@tonic-gate return (0); 13390Sstevel@tonic-gate } 13400Sstevel@tonic-gate 13410Sstevel@tonic-gate int 13420Sstevel@tonic-gate secpolicy_ipc_config(const cred_t *cr) 13430Sstevel@tonic-gate { 13440Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_IPC_CONFIG, B_FALSE, EPERM, NULL)); 13450Sstevel@tonic-gate } 13460Sstevel@tonic-gate 13470Sstevel@tonic-gate int 13480Sstevel@tonic-gate secpolicy_ipc_access(const cred_t *cr, const struct kipc_perm *ip, mode_t mode) 13490Sstevel@tonic-gate { 13500Sstevel@tonic-gate 13510Sstevel@tonic-gate boolean_t allzone = B_FALSE; 13520Sstevel@tonic-gate 13530Sstevel@tonic-gate ASSERT((mode & (MSG_R|MSG_W)) != 0); 13540Sstevel@tonic-gate 13550Sstevel@tonic-gate if ((mode & MSG_R) && 13560Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_IPC_DAC_READ, allzone, EACCES, NULL) != 0) 13570Sstevel@tonic-gate return (EACCES); 13580Sstevel@tonic-gate 13590Sstevel@tonic-gate if (mode & MSG_W) { 13600Sstevel@tonic-gate if (cr->cr_uid != 0 && (ip->ipc_uid == 0 || ip->ipc_cuid == 0)) 13610Sstevel@tonic-gate allzone = B_TRUE; 13620Sstevel@tonic-gate 13630Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_DAC_WRITE, allzone, EACCES, 13640Sstevel@tonic-gate NULL)); 13650Sstevel@tonic-gate } 13660Sstevel@tonic-gate return (0); 13670Sstevel@tonic-gate } 13680Sstevel@tonic-gate 13690Sstevel@tonic-gate int 13700Sstevel@tonic-gate secpolicy_rsm_access(const cred_t *cr, uid_t owner, mode_t mode) 13710Sstevel@tonic-gate { 13720Sstevel@tonic-gate boolean_t allzone = B_FALSE; 13730Sstevel@tonic-gate 13740Sstevel@tonic-gate ASSERT((mode & (MSG_R|MSG_W)) != 0); 13750Sstevel@tonic-gate 13760Sstevel@tonic-gate if ((mode & MSG_R) && 13770Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_IPC_DAC_READ, allzone, EACCES, NULL) != 0) 13780Sstevel@tonic-gate return (EACCES); 13790Sstevel@tonic-gate 13800Sstevel@tonic-gate if (mode & MSG_W) { 13810Sstevel@tonic-gate if (cr->cr_uid != 0 && owner == 0) 13820Sstevel@tonic-gate allzone = B_TRUE; 13830Sstevel@tonic-gate 13840Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_DAC_WRITE, allzone, EACCES, 13850Sstevel@tonic-gate NULL)); 13860Sstevel@tonic-gate } 13870Sstevel@tonic-gate return (0); 13880Sstevel@tonic-gate } 13890Sstevel@tonic-gate 13900Sstevel@tonic-gate /* 13910Sstevel@tonic-gate * Audit configuration. 13920Sstevel@tonic-gate */ 13930Sstevel@tonic-gate int 13940Sstevel@tonic-gate secpolicy_audit_config(const cred_t *cr) 13950Sstevel@tonic-gate { 13960Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_AUDIT, B_FALSE, EPERM, NULL)); 13970Sstevel@tonic-gate } 13980Sstevel@tonic-gate 13990Sstevel@tonic-gate /* 14000Sstevel@tonic-gate * Audit record generation. 14010Sstevel@tonic-gate */ 14020Sstevel@tonic-gate int 14030Sstevel@tonic-gate secpolicy_audit_modify(const cred_t *cr) 14040Sstevel@tonic-gate { 14050Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_AUDIT, B_FALSE, EPERM, NULL)); 14060Sstevel@tonic-gate } 14070Sstevel@tonic-gate 14080Sstevel@tonic-gate /* 14090Sstevel@tonic-gate * Get audit attributes. 14100Sstevel@tonic-gate * Either PRIV_SYS_AUDIT or PRIV_PROC_AUDIT required; report the 14110Sstevel@tonic-gate * "Least" of the two privileges on error. 14120Sstevel@tonic-gate */ 14130Sstevel@tonic-gate int 14140Sstevel@tonic-gate secpolicy_audit_getattr(const cred_t *cr) 14150Sstevel@tonic-gate { 14160Sstevel@tonic-gate if (!PRIV_POLICY_ONLY(cr, PRIV_SYS_AUDIT, B_FALSE)) { 14170Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_AUDIT, B_FALSE, EPERM, 14180Sstevel@tonic-gate NULL)); 14190Sstevel@tonic-gate } else { 14200Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_AUDIT, B_FALSE, EPERM, NULL)); 14210Sstevel@tonic-gate } 14220Sstevel@tonic-gate } 14230Sstevel@tonic-gate 14240Sstevel@tonic-gate 14250Sstevel@tonic-gate /* 14260Sstevel@tonic-gate * Locking physical memory 14270Sstevel@tonic-gate */ 14280Sstevel@tonic-gate int 14290Sstevel@tonic-gate secpolicy_lock_memory(const cred_t *cr) 14300Sstevel@tonic-gate { 14310Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_LOCK_MEMORY, B_FALSE, EPERM, NULL)); 14320Sstevel@tonic-gate } 14330Sstevel@tonic-gate 14340Sstevel@tonic-gate /* 14350Sstevel@tonic-gate * Accounting (both acct(2) and exacct). 14360Sstevel@tonic-gate */ 14370Sstevel@tonic-gate int 14380Sstevel@tonic-gate secpolicy_acct(const cred_t *cr) 14390Sstevel@tonic-gate { 14400Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ACCT, B_FALSE, EPERM, NULL)); 14410Sstevel@tonic-gate } 14420Sstevel@tonic-gate 14430Sstevel@tonic-gate /* 14440Sstevel@tonic-gate * Is this process privileged to change its uids at will? 14450Sstevel@tonic-gate * Uid 0 is still considered "special" and having the SETID 14460Sstevel@tonic-gate * privilege is not sufficient to get uid 0. 14470Sstevel@tonic-gate * Files are owned by root, so the privilege would give 14480Sstevel@tonic-gate * full access and euid 0 is still effective. 14490Sstevel@tonic-gate * 14500Sstevel@tonic-gate * If you have the privilege and euid 0 only then do you 14510Sstevel@tonic-gate * get the powers of root wrt uid 0. 14520Sstevel@tonic-gate * 14530Sstevel@tonic-gate * For gid manipulations, this is should be called with an 14540Sstevel@tonic-gate * uid of -1. 14550Sstevel@tonic-gate * 14560Sstevel@tonic-gate */ 14570Sstevel@tonic-gate int 14580Sstevel@tonic-gate secpolicy_allow_setid(const cred_t *cr, uid_t newuid, boolean_t checkonly) 14590Sstevel@tonic-gate { 14600Sstevel@tonic-gate boolean_t allzone = B_FALSE; 14610Sstevel@tonic-gate 14620Sstevel@tonic-gate if (newuid == 0 && cr->cr_uid != 0 && cr->cr_suid != 0 && 14630Sstevel@tonic-gate cr->cr_ruid != 0) { 14640Sstevel@tonic-gate allzone = B_TRUE; 14650Sstevel@tonic-gate } 14660Sstevel@tonic-gate 14670Sstevel@tonic-gate return (checkonly ? !PRIV_POLICY_ONLY(cr, PRIV_PROC_SETID, allzone) : 14680Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_PROC_SETID, allzone, EPERM, NULL)); 14690Sstevel@tonic-gate } 14700Sstevel@tonic-gate 14710Sstevel@tonic-gate 14720Sstevel@tonic-gate /* 14730Sstevel@tonic-gate * Acting on a different process: if the mode is for writing, 14740Sstevel@tonic-gate * the restrictions are more severe. This is called after 14750Sstevel@tonic-gate * we've verified that the uids do not match. 14760Sstevel@tonic-gate */ 14770Sstevel@tonic-gate int 14780Sstevel@tonic-gate secpolicy_proc_owner(const cred_t *scr, const cred_t *tcr, int mode) 14790Sstevel@tonic-gate { 14800Sstevel@tonic-gate boolean_t allzone = B_FALSE; 14810Sstevel@tonic-gate 14820Sstevel@tonic-gate if ((mode & VWRITE) && scr->cr_uid != 0 && 14830Sstevel@tonic-gate (tcr->cr_uid == 0 || tcr->cr_ruid == 0 || tcr->cr_suid == 0)) 14840Sstevel@tonic-gate allzone = B_TRUE; 14850Sstevel@tonic-gate 14860Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, allzone, EPERM, NULL)); 14870Sstevel@tonic-gate } 14880Sstevel@tonic-gate 14890Sstevel@tonic-gate int 14900Sstevel@tonic-gate secpolicy_proc_access(const cred_t *scr) 14910Sstevel@tonic-gate { 14920Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, B_FALSE, EACCES, NULL)); 14930Sstevel@tonic-gate } 14940Sstevel@tonic-gate 14950Sstevel@tonic-gate int 14960Sstevel@tonic-gate secpolicy_proc_excl_open(const cred_t *scr) 14970Sstevel@tonic-gate { 14980Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, B_FALSE, EBUSY, NULL)); 14990Sstevel@tonic-gate } 15000Sstevel@tonic-gate 15010Sstevel@tonic-gate int 15020Sstevel@tonic-gate secpolicy_proc_zone(const cred_t *scr) 15030Sstevel@tonic-gate { 15040Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_ZONE, B_FALSE, EPERM, NULL)); 15050Sstevel@tonic-gate } 15060Sstevel@tonic-gate 15070Sstevel@tonic-gate /* 15080Sstevel@tonic-gate * Destroying the system 15090Sstevel@tonic-gate */ 15100Sstevel@tonic-gate 15110Sstevel@tonic-gate int 15120Sstevel@tonic-gate secpolicy_kmdb(const cred_t *scr) 15130Sstevel@tonic-gate { 15140Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); 15150Sstevel@tonic-gate } 15160Sstevel@tonic-gate 15171414Scindi int 15181414Scindi secpolicy_error_inject(const cred_t *scr) 15191414Scindi { 15201414Scindi return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); 15211414Scindi } 15221414Scindi 15230Sstevel@tonic-gate /* 15240Sstevel@tonic-gate * Processor sets, cpu configuration, resource pools. 15250Sstevel@tonic-gate */ 15260Sstevel@tonic-gate int 15270Sstevel@tonic-gate secpolicy_pset(const cred_t *cr) 15280Sstevel@tonic-gate { 15290Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 15300Sstevel@tonic-gate } 15310Sstevel@tonic-gate 15320Sstevel@tonic-gate int 15330Sstevel@tonic-gate secpolicy_ponline(const cred_t *cr) 15340Sstevel@tonic-gate { 15350Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 15360Sstevel@tonic-gate } 15370Sstevel@tonic-gate 15380Sstevel@tonic-gate int 15390Sstevel@tonic-gate secpolicy_pool(const cred_t *cr) 15400Sstevel@tonic-gate { 15410Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 15420Sstevel@tonic-gate } 15430Sstevel@tonic-gate 15440Sstevel@tonic-gate int 15450Sstevel@tonic-gate secpolicy_blacklist(const cred_t *cr) 15460Sstevel@tonic-gate { 15470Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 15480Sstevel@tonic-gate } 15490Sstevel@tonic-gate 15500Sstevel@tonic-gate /* 15510Sstevel@tonic-gate * Catch all system configuration. 15520Sstevel@tonic-gate */ 15530Sstevel@tonic-gate int 15540Sstevel@tonic-gate secpolicy_sys_config(const cred_t *cr, boolean_t checkonly) 15550Sstevel@tonic-gate { 15560Sstevel@tonic-gate if (checkonly) { 15570Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_CONFIG, B_FALSE) ? 0 : 15580Sstevel@tonic-gate EPERM); 15590Sstevel@tonic-gate } else { 15600Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 15610Sstevel@tonic-gate } 15620Sstevel@tonic-gate } 15630Sstevel@tonic-gate 15640Sstevel@tonic-gate /* 15650Sstevel@tonic-gate * Zone administration (halt, reboot, etc.) from within zone. 15660Sstevel@tonic-gate */ 15670Sstevel@tonic-gate int 15680Sstevel@tonic-gate secpolicy_zone_admin(const cred_t *cr, boolean_t checkonly) 15690Sstevel@tonic-gate { 15700Sstevel@tonic-gate if (checkonly) { 15710Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_ADMIN, B_FALSE) ? 0 : 15720Sstevel@tonic-gate EPERM); 15730Sstevel@tonic-gate } else { 15740Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, 15750Sstevel@tonic-gate NULL)); 15760Sstevel@tonic-gate } 15770Sstevel@tonic-gate } 15780Sstevel@tonic-gate 15790Sstevel@tonic-gate /* 15800Sstevel@tonic-gate * Zone configuration (create, halt, enter). 15810Sstevel@tonic-gate */ 15820Sstevel@tonic-gate int 15830Sstevel@tonic-gate secpolicy_zone_config(const cred_t *cr) 15840Sstevel@tonic-gate { 15850Sstevel@tonic-gate /* 15860Sstevel@tonic-gate * Require all privileges to avoid possibility of privilege 15870Sstevel@tonic-gate * escalation. 15880Sstevel@tonic-gate */ 15890Sstevel@tonic-gate return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); 15900Sstevel@tonic-gate } 15910Sstevel@tonic-gate 15920Sstevel@tonic-gate /* 15930Sstevel@tonic-gate * Various other system configuration calls 15940Sstevel@tonic-gate */ 15950Sstevel@tonic-gate int 15960Sstevel@tonic-gate secpolicy_coreadm(const cred_t *cr) 15970Sstevel@tonic-gate { 15980Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, NULL)); 15990Sstevel@tonic-gate } 16000Sstevel@tonic-gate 16010Sstevel@tonic-gate int 16020Sstevel@tonic-gate secpolicy_systeminfo(const cred_t *cr) 16030Sstevel@tonic-gate { 16040Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, NULL)); 16050Sstevel@tonic-gate } 16060Sstevel@tonic-gate 16070Sstevel@tonic-gate int 16080Sstevel@tonic-gate secpolicy_dispadm(const cred_t *cr) 16090Sstevel@tonic-gate { 16100Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 16110Sstevel@tonic-gate } 16120Sstevel@tonic-gate 16130Sstevel@tonic-gate int 16140Sstevel@tonic-gate secpolicy_settime(const cred_t *cr) 16150Sstevel@tonic-gate { 16160Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_TIME, B_FALSE, EPERM, NULL)); 16170Sstevel@tonic-gate } 16180Sstevel@tonic-gate 16190Sstevel@tonic-gate /* 16200Sstevel@tonic-gate * For realtime users: high resolution clock. 16210Sstevel@tonic-gate */ 16220Sstevel@tonic-gate int 16230Sstevel@tonic-gate secpolicy_clock_highres(const cred_t *cr) 16240Sstevel@tonic-gate { 16250Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_CLOCK_HIGHRES, B_FALSE, EPERM, 16260Sstevel@tonic-gate NULL)); 16270Sstevel@tonic-gate } 16280Sstevel@tonic-gate 16290Sstevel@tonic-gate /* 16300Sstevel@tonic-gate * drv_priv() is documented as callable from interrupt context, not that 16310Sstevel@tonic-gate * anyone ever does, but still. No debugging or auditing can be done when 16320Sstevel@tonic-gate * it is called from interrupt context. 16330Sstevel@tonic-gate * returns 0 on succes, EPERM on failure. 16340Sstevel@tonic-gate */ 16350Sstevel@tonic-gate int 16360Sstevel@tonic-gate drv_priv(cred_t *cr) 16370Sstevel@tonic-gate { 16380Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 16390Sstevel@tonic-gate } 16400Sstevel@tonic-gate 16410Sstevel@tonic-gate int 16420Sstevel@tonic-gate secpolicy_sys_devices(const cred_t *cr) 16430Sstevel@tonic-gate { 16440Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 16450Sstevel@tonic-gate } 16460Sstevel@tonic-gate 16470Sstevel@tonic-gate int 16480Sstevel@tonic-gate secpolicy_excl_open(const cred_t *cr) 16490Sstevel@tonic-gate { 16500Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EBUSY, NULL)); 16510Sstevel@tonic-gate } 16520Sstevel@tonic-gate 16530Sstevel@tonic-gate int 16540Sstevel@tonic-gate secpolicy_rctlsys(const cred_t *cr, boolean_t is_zone_rctl) 16550Sstevel@tonic-gate { 16560Sstevel@tonic-gate /* zone.* rctls can only be set from the global zone */ 16570Sstevel@tonic-gate if (is_zone_rctl && priv_policy_global(cr) != 0) 16580Sstevel@tonic-gate return (EPERM); 16590Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 16600Sstevel@tonic-gate } 16610Sstevel@tonic-gate 16620Sstevel@tonic-gate int 16630Sstevel@tonic-gate secpolicy_resource(const cred_t *cr) 16640Sstevel@tonic-gate { 16650Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 16660Sstevel@tonic-gate } 16670Sstevel@tonic-gate 166810154SStan.Studzinski@Sun.COM int 166910154SStan.Studzinski@Sun.COM secpolicy_resource_anon_mem(const cred_t *cr) 167010154SStan.Studzinski@Sun.COM { 167110154SStan.Studzinski@Sun.COM return (PRIV_POLICY_ONLY(cr, PRIV_SYS_RESOURCE, B_FALSE)); 167210154SStan.Studzinski@Sun.COM } 167310154SStan.Studzinski@Sun.COM 16740Sstevel@tonic-gate /* 16750Sstevel@tonic-gate * Processes with a real uid of 0 escape any form of accounting, much 16760Sstevel@tonic-gate * like before. 16770Sstevel@tonic-gate */ 16780Sstevel@tonic-gate int 16790Sstevel@tonic-gate secpolicy_newproc(const cred_t *cr) 16800Sstevel@tonic-gate { 16810Sstevel@tonic-gate if (cr->cr_ruid == 0) 16820Sstevel@tonic-gate return (0); 16830Sstevel@tonic-gate 16840Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 16850Sstevel@tonic-gate } 16860Sstevel@tonic-gate 16870Sstevel@tonic-gate /* 16880Sstevel@tonic-gate * Networking 16890Sstevel@tonic-gate */ 16900Sstevel@tonic-gate int 16910Sstevel@tonic-gate secpolicy_net_rawaccess(const cred_t *cr) 16920Sstevel@tonic-gate { 16930Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_NET_RAWACCESS, B_FALSE, EACCES, NULL)); 16940Sstevel@tonic-gate } 16950Sstevel@tonic-gate 169610639SDarren.Reed@Sun.COM int 169710639SDarren.Reed@Sun.COM secpolicy_net_observability(const cred_t *cr) 169810639SDarren.Reed@Sun.COM { 169910639SDarren.Reed@Sun.COM return (PRIV_POLICY(cr, PRIV_NET_OBSERVABILITY, B_FALSE, EACCES, NULL)); 170010639SDarren.Reed@Sun.COM } 170110639SDarren.Reed@Sun.COM 17020Sstevel@tonic-gate /* 17030Sstevel@tonic-gate * Need this privilege for accessing the ICMP device 17040Sstevel@tonic-gate */ 17050Sstevel@tonic-gate int 17060Sstevel@tonic-gate secpolicy_net_icmpaccess(const cred_t *cr) 17070Sstevel@tonic-gate { 17080Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_NET_ICMPACCESS, B_FALSE, EACCES, NULL)); 17090Sstevel@tonic-gate } 17100Sstevel@tonic-gate 17110Sstevel@tonic-gate /* 17120Sstevel@tonic-gate * There are a few rare cases where the kernel generates ioctls() from 17130Sstevel@tonic-gate * interrupt context with a credential of kcred rather than NULL. 17140Sstevel@tonic-gate * In those cases, we take the safe and cheap test. 17150Sstevel@tonic-gate */ 17160Sstevel@tonic-gate int 17170Sstevel@tonic-gate secpolicy_net_config(const cred_t *cr, boolean_t checkonly) 17180Sstevel@tonic-gate { 17190Sstevel@tonic-gate if (checkonly) { 17200Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE) ? 17210Sstevel@tonic-gate 0 : EPERM); 17220Sstevel@tonic-gate } else { 17230Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_NET_CONFIG, B_FALSE, EPERM, 17240Sstevel@tonic-gate NULL)); 17250Sstevel@tonic-gate } 17260Sstevel@tonic-gate } 17270Sstevel@tonic-gate 17280Sstevel@tonic-gate 17290Sstevel@tonic-gate /* 17304962Sdh155122 * PRIV_SYS_NET_CONFIG is a superset of PRIV_SYS_IP_CONFIG. 17313448Sdh155122 * 17323448Sdh155122 * There are a few rare cases where the kernel generates ioctls() from 17333448Sdh155122 * interrupt context with a credential of kcred rather than NULL. 17343448Sdh155122 * In those cases, we take the safe and cheap test. 17353448Sdh155122 */ 17363448Sdh155122 int 17373448Sdh155122 secpolicy_ip_config(const cred_t *cr, boolean_t checkonly) 17383448Sdh155122 { 17393448Sdh155122 if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE)) 17403448Sdh155122 return (secpolicy_net_config(cr, checkonly)); 17413448Sdh155122 17423448Sdh155122 if (checkonly) { 17433448Sdh155122 return (PRIV_POLICY_ONLY(cr, PRIV_SYS_IP_CONFIG, B_FALSE) ? 17443448Sdh155122 0 : EPERM); 17453448Sdh155122 } else { 17463448Sdh155122 return (PRIV_POLICY(cr, PRIV_SYS_IP_CONFIG, B_FALSE, EPERM, 17473448Sdh155122 NULL)); 17483448Sdh155122 } 17493448Sdh155122 } 17503448Sdh155122 17517408SSebastien.Roy@Sun.COM /* 17527408SSebastien.Roy@Sun.COM * PRIV_SYS_NET_CONFIG is a superset of PRIV_SYS_DL_CONFIG. 17537408SSebastien.Roy@Sun.COM */ 17547408SSebastien.Roy@Sun.COM int 17557408SSebastien.Roy@Sun.COM secpolicy_dl_config(const cred_t *cr) 17567408SSebastien.Roy@Sun.COM { 17577408SSebastien.Roy@Sun.COM if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE)) 17587408SSebastien.Roy@Sun.COM return (secpolicy_net_config(cr, B_FALSE)); 175910616SSebastien.Roy@Sun.COM return (PRIV_POLICY(cr, PRIV_SYS_DL_CONFIG, B_FALSE, EPERM, NULL)); 17607408SSebastien.Roy@Sun.COM } 17617408SSebastien.Roy@Sun.COM 176210616SSebastien.Roy@Sun.COM /* 176310616SSebastien.Roy@Sun.COM * PRIV_SYS_DL_CONFIG is a superset of PRIV_SYS_IPTUN_CONFIG. 176410616SSebastien.Roy@Sun.COM */ 176510616SSebastien.Roy@Sun.COM int 176610616SSebastien.Roy@Sun.COM secpolicy_iptun_config(const cred_t *cr) 176710616SSebastien.Roy@Sun.COM { 176810616SSebastien.Roy@Sun.COM if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE)) 176910616SSebastien.Roy@Sun.COM return (secpolicy_net_config(cr, B_FALSE)); 177010616SSebastien.Roy@Sun.COM if (PRIV_POLICY_ONLY(cr, PRIV_SYS_DL_CONFIG, B_FALSE)) 177110616SSebastien.Roy@Sun.COM return (secpolicy_dl_config(cr)); 177210616SSebastien.Roy@Sun.COM return (PRIV_POLICY(cr, PRIV_SYS_IPTUN_CONFIG, B_FALSE, EPERM, NULL)); 177310616SSebastien.Roy@Sun.COM } 17743448Sdh155122 17753448Sdh155122 /* 17763448Sdh155122 * Map IP pseudo privileges to actual privileges. 17773448Sdh155122 * So we don't need to recompile IP when we change the privileges. 17783448Sdh155122 */ 17793448Sdh155122 int 17803448Sdh155122 secpolicy_ip(const cred_t *cr, int netpriv, boolean_t checkonly) 17813448Sdh155122 { 17823448Sdh155122 int priv = PRIV_ALL; 17833448Sdh155122 17843448Sdh155122 switch (netpriv) { 17853448Sdh155122 case OP_CONFIG: 17863448Sdh155122 priv = PRIV_SYS_IP_CONFIG; 17873448Sdh155122 break; 17883448Sdh155122 case OP_RAW: 17893448Sdh155122 priv = PRIV_NET_RAWACCESS; 17903448Sdh155122 break; 17913448Sdh155122 case OP_PRIVPORT: 17923448Sdh155122 priv = PRIV_NET_PRIVADDR; 17933448Sdh155122 break; 17943448Sdh155122 } 17953448Sdh155122 ASSERT(priv != PRIV_ALL); 17963448Sdh155122 if (checkonly) 17973448Sdh155122 return (PRIV_POLICY_ONLY(cr, priv, B_FALSE) ? 0 : EPERM); 17983448Sdh155122 else 17993448Sdh155122 return (PRIV_POLICY(cr, priv, B_FALSE, EPERM, NULL)); 18003448Sdh155122 } 18013448Sdh155122 18023448Sdh155122 /* 18030Sstevel@tonic-gate * Map network pseudo privileges to actual privileges. 18040Sstevel@tonic-gate * So we don't need to recompile IP when we change the privileges. 18050Sstevel@tonic-gate */ 18060Sstevel@tonic-gate int 18070Sstevel@tonic-gate secpolicy_net(const cred_t *cr, int netpriv, boolean_t checkonly) 18080Sstevel@tonic-gate { 18090Sstevel@tonic-gate int priv = PRIV_ALL; 18100Sstevel@tonic-gate 18110Sstevel@tonic-gate switch (netpriv) { 18120Sstevel@tonic-gate case OP_CONFIG: 18130Sstevel@tonic-gate priv = PRIV_SYS_NET_CONFIG; 18140Sstevel@tonic-gate break; 18150Sstevel@tonic-gate case OP_RAW: 18160Sstevel@tonic-gate priv = PRIV_NET_RAWACCESS; 18170Sstevel@tonic-gate break; 18180Sstevel@tonic-gate case OP_PRIVPORT: 18190Sstevel@tonic-gate priv = PRIV_NET_PRIVADDR; 18200Sstevel@tonic-gate break; 18210Sstevel@tonic-gate } 18220Sstevel@tonic-gate ASSERT(priv != PRIV_ALL); 18230Sstevel@tonic-gate if (checkonly) 18240Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, priv, B_FALSE) ? 0 : EPERM); 18250Sstevel@tonic-gate else 18260Sstevel@tonic-gate return (PRIV_POLICY(cr, priv, B_FALSE, EPERM, NULL)); 18270Sstevel@tonic-gate } 18280Sstevel@tonic-gate 18290Sstevel@tonic-gate /* 18300Sstevel@tonic-gate * Checks for operations that are either client-only or are used by 18310Sstevel@tonic-gate * both clients and servers. 18320Sstevel@tonic-gate */ 18330Sstevel@tonic-gate int 18340Sstevel@tonic-gate secpolicy_nfs(const cred_t *cr) 18350Sstevel@tonic-gate { 18360Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_NFS, B_FALSE, EPERM, NULL)); 18370Sstevel@tonic-gate } 18380Sstevel@tonic-gate 18390Sstevel@tonic-gate /* 18400Sstevel@tonic-gate * Special case for opening rpcmod: have NFS privileges or network 18410Sstevel@tonic-gate * config privileges. 18420Sstevel@tonic-gate */ 18430Sstevel@tonic-gate int 18440Sstevel@tonic-gate secpolicy_rpcmod_open(const cred_t *cr) 18450Sstevel@tonic-gate { 18460Sstevel@tonic-gate if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NFS, B_FALSE)) 18470Sstevel@tonic-gate return (secpolicy_nfs(cr)); 18480Sstevel@tonic-gate else 18490Sstevel@tonic-gate return (secpolicy_net_config(cr, NULL)); 18500Sstevel@tonic-gate } 18510Sstevel@tonic-gate 18520Sstevel@tonic-gate int 18530Sstevel@tonic-gate secpolicy_chroot(const cred_t *cr) 18540Sstevel@tonic-gate { 18550Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_CHROOT, B_FALSE, EPERM, NULL)); 18560Sstevel@tonic-gate } 18570Sstevel@tonic-gate 18580Sstevel@tonic-gate int 18590Sstevel@tonic-gate secpolicy_tasksys(const cred_t *cr) 18600Sstevel@tonic-gate { 18610Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_TASKID, B_FALSE, EPERM, NULL)); 18620Sstevel@tonic-gate } 18630Sstevel@tonic-gate 18640Sstevel@tonic-gate /* 18650Sstevel@tonic-gate * Basic privilege checks. 18660Sstevel@tonic-gate */ 18670Sstevel@tonic-gate int 18686134Scasper secpolicy_basic_exec(const cred_t *cr, vnode_t *vp) 18690Sstevel@tonic-gate { 18706134Scasper return (priv_policy_va(cr, PRIV_PROC_EXEC, B_FALSE, EPERM, NULL, 18716134Scasper KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE)); 18720Sstevel@tonic-gate } 18730Sstevel@tonic-gate 18740Sstevel@tonic-gate int 18750Sstevel@tonic-gate secpolicy_basic_fork(const cred_t *cr) 18760Sstevel@tonic-gate { 18770Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_FORK, B_FALSE, EPERM, NULL)); 18780Sstevel@tonic-gate } 18790Sstevel@tonic-gate 18800Sstevel@tonic-gate int 18810Sstevel@tonic-gate secpolicy_basic_proc(const cred_t *cr) 18820Sstevel@tonic-gate { 18830Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_SESSION, B_FALSE, EPERM, NULL)); 18840Sstevel@tonic-gate } 18850Sstevel@tonic-gate 18860Sstevel@tonic-gate /* 18870Sstevel@tonic-gate * Slightly complicated because we don't want to trigger the policy too 18880Sstevel@tonic-gate * often. First we shortcircuit access to "self" (tp == sp) or if 18890Sstevel@tonic-gate * we don't have the privilege but if we have permission 18900Sstevel@tonic-gate * just return (0) and we don't flag the privilege as needed. 18910Sstevel@tonic-gate * Else, we test for the privilege because we either have it or need it. 18920Sstevel@tonic-gate */ 18930Sstevel@tonic-gate int 18940Sstevel@tonic-gate secpolicy_basic_procinfo(const cred_t *cr, proc_t *tp, proc_t *sp) 18950Sstevel@tonic-gate { 18960Sstevel@tonic-gate if (tp == sp || 18970Sstevel@tonic-gate !HAS_PRIVILEGE(cr, PRIV_PROC_INFO) && prochasprocperm(tp, sp, cr)) { 18980Sstevel@tonic-gate return (0); 18990Sstevel@tonic-gate } else { 19000Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_INFO, B_FALSE, EPERM, NULL)); 19010Sstevel@tonic-gate } 19020Sstevel@tonic-gate } 19030Sstevel@tonic-gate 19040Sstevel@tonic-gate int 19050Sstevel@tonic-gate secpolicy_basic_link(const cred_t *cr) 19060Sstevel@tonic-gate { 19070Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_LINK_ANY, B_FALSE, EPERM, NULL)); 19080Sstevel@tonic-gate } 19090Sstevel@tonic-gate 1910*11537SCasper.Dik@Sun.COM int 1911*11537SCasper.Dik@Sun.COM secpolicy_basic_net_access(const cred_t *cr) 1912*11537SCasper.Dik@Sun.COM { 1913*11537SCasper.Dik@Sun.COM return (PRIV_POLICY(cr, PRIV_NET_ACCESS, B_FALSE, EACCES, NULL)); 1914*11537SCasper.Dik@Sun.COM } 1915*11537SCasper.Dik@Sun.COM 19160Sstevel@tonic-gate /* 19170Sstevel@tonic-gate * Additional device protection. 19180Sstevel@tonic-gate * 19190Sstevel@tonic-gate * Traditionally, a device has specific permissions on the node in 19200Sstevel@tonic-gate * the filesystem which govern which devices can be opened by what 19210Sstevel@tonic-gate * processes. In certain cases, it is desirable to add extra 19220Sstevel@tonic-gate * restrictions, as writing to certain devices is identical to 19230Sstevel@tonic-gate * having a complete run of the system. 19240Sstevel@tonic-gate * 19250Sstevel@tonic-gate * This mechanism is called the device policy. 19260Sstevel@tonic-gate * 19270Sstevel@tonic-gate * When a device is opened, its policy entry is looked up in the 19280Sstevel@tonic-gate * policy cache and checked. 19290Sstevel@tonic-gate */ 19300Sstevel@tonic-gate int 19310Sstevel@tonic-gate secpolicy_spec_open(const cred_t *cr, struct vnode *vp, int oflag) 19320Sstevel@tonic-gate { 19330Sstevel@tonic-gate devplcy_t *plcy; 19340Sstevel@tonic-gate int err; 19350Sstevel@tonic-gate struct snode *csp = VTOS(common_specvp(vp)); 19364962Sdh155122 priv_set_t pset; 19370Sstevel@tonic-gate 19380Sstevel@tonic-gate mutex_enter(&csp->s_lock); 19390Sstevel@tonic-gate 19400Sstevel@tonic-gate if (csp->s_plcy == NULL || csp->s_plcy->dp_gen != devplcy_gen) { 19410Sstevel@tonic-gate plcy = devpolicy_find(vp); 19420Sstevel@tonic-gate if (csp->s_plcy) 19430Sstevel@tonic-gate dpfree(csp->s_plcy); 19440Sstevel@tonic-gate csp->s_plcy = plcy; 19450Sstevel@tonic-gate ASSERT(plcy != NULL); 19460Sstevel@tonic-gate } else 19470Sstevel@tonic-gate plcy = csp->s_plcy; 19480Sstevel@tonic-gate 19490Sstevel@tonic-gate if (plcy == nullpolicy) { 19500Sstevel@tonic-gate mutex_exit(&csp->s_lock); 19510Sstevel@tonic-gate return (0); 19520Sstevel@tonic-gate } 19530Sstevel@tonic-gate 19540Sstevel@tonic-gate dphold(plcy); 19550Sstevel@tonic-gate 19560Sstevel@tonic-gate mutex_exit(&csp->s_lock); 19570Sstevel@tonic-gate 19584962Sdh155122 if (oflag & FWRITE) 19594962Sdh155122 pset = plcy->dp_wrp; 19604962Sdh155122 else 19614962Sdh155122 pset = plcy->dp_rdp; 19624962Sdh155122 /* 19634962Sdh155122 * Special case: 19644962Sdh155122 * PRIV_SYS_NET_CONFIG is a superset of PRIV_SYS_IP_CONFIG. 19654962Sdh155122 * If PRIV_SYS_NET_CONFIG is present and PRIV_SYS_IP_CONFIG is 19664962Sdh155122 * required, replace PRIV_SYS_IP_CONFIG with PRIV_SYS_NET_CONFIG 19674962Sdh155122 * in the required privilege set before doing the check. 19684962Sdh155122 */ 19694962Sdh155122 if (priv_ismember(&pset, PRIV_SYS_IP_CONFIG) && 19704962Sdh155122 priv_ismember(&CR_OEPRIV(cr), PRIV_SYS_NET_CONFIG) && 19714962Sdh155122 !priv_ismember(&CR_OEPRIV(cr), PRIV_SYS_IP_CONFIG)) { 19724962Sdh155122 priv_delset(&pset, PRIV_SYS_IP_CONFIG); 19734962Sdh155122 priv_addset(&pset, PRIV_SYS_NET_CONFIG); 19744962Sdh155122 } 19754962Sdh155122 19764962Sdh155122 err = secpolicy_require_set(cr, &pset, "devpolicy"); 19770Sstevel@tonic-gate dpfree(plcy); 19780Sstevel@tonic-gate 19790Sstevel@tonic-gate return (err); 19800Sstevel@tonic-gate } 19810Sstevel@tonic-gate 19820Sstevel@tonic-gate int 19830Sstevel@tonic-gate secpolicy_modctl(const cred_t *cr, int cmd) 19840Sstevel@tonic-gate { 19850Sstevel@tonic-gate switch (cmd) { 19860Sstevel@tonic-gate case MODINFO: 19872723Scth case MODGETMAJBIND: 19880Sstevel@tonic-gate case MODGETPATH: 19890Sstevel@tonic-gate case MODGETPATHLEN: 19902723Scth case MODGETNAME: 19910Sstevel@tonic-gate case MODGETFBNAME: 19920Sstevel@tonic-gate case MODGETDEVPOLICY: 19930Sstevel@tonic-gate case MODGETDEVPOLICYBYNAME: 19942723Scth case MODDEVT2INSTANCE: 19952723Scth case MODSIZEOF_DEVID: 19962723Scth case MODGETDEVID: 19972723Scth case MODSIZEOF_MINORNAME: 19982723Scth case MODGETMINORNAME: 19992723Scth case MODGETDEVFSPATH_LEN: 20002723Scth case MODGETDEVFSPATH: 20012723Scth case MODGETDEVFSPATH_MI_LEN: 20022723Scth case MODGETDEVFSPATH_MI: 20030Sstevel@tonic-gate /* Unprivileged */ 20040Sstevel@tonic-gate return (0); 20050Sstevel@tonic-gate case MODLOAD: 20060Sstevel@tonic-gate case MODSETDEVPOLICY: 20070Sstevel@tonic-gate return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); 20080Sstevel@tonic-gate default: 20090Sstevel@tonic-gate return (secpolicy_sys_config(cr, B_FALSE)); 20100Sstevel@tonic-gate } 20110Sstevel@tonic-gate } 20120Sstevel@tonic-gate 20130Sstevel@tonic-gate int 20140Sstevel@tonic-gate secpolicy_console(const cred_t *cr) 20150Sstevel@tonic-gate { 20160Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 20170Sstevel@tonic-gate } 20180Sstevel@tonic-gate 20190Sstevel@tonic-gate int 20200Sstevel@tonic-gate secpolicy_power_mgmt(const cred_t *cr) 20210Sstevel@tonic-gate { 20220Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 20230Sstevel@tonic-gate } 20240Sstevel@tonic-gate 20250Sstevel@tonic-gate /* 20260Sstevel@tonic-gate * Simulate terminal input; another escalation of privileges avenue. 20270Sstevel@tonic-gate */ 20280Sstevel@tonic-gate 20290Sstevel@tonic-gate int 20300Sstevel@tonic-gate secpolicy_sti(const cred_t *cr) 20310Sstevel@tonic-gate { 20320Sstevel@tonic-gate return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); 20330Sstevel@tonic-gate } 20340Sstevel@tonic-gate 20351676Sjpk boolean_t 20361676Sjpk secpolicy_net_reply_equal(const cred_t *cr) 20371676Sjpk { 20381676Sjpk return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 20391676Sjpk } 20401676Sjpk 20410Sstevel@tonic-gate int 20420Sstevel@tonic-gate secpolicy_swapctl(const cred_t *cr) 20430Sstevel@tonic-gate { 20440Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 20450Sstevel@tonic-gate } 20460Sstevel@tonic-gate 20470Sstevel@tonic-gate int 20480Sstevel@tonic-gate secpolicy_cpc_cpu(const cred_t *cr) 20490Sstevel@tonic-gate { 20500Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CPC_CPU, B_FALSE, EACCES, NULL)); 20510Sstevel@tonic-gate } 20520Sstevel@tonic-gate 20530Sstevel@tonic-gate /* 20546073Sacruz * secpolicy_contract_identity 20556073Sacruz * 20566073Sacruz * Determine if the subject may set the process contract FMRI value 20576073Sacruz */ 20586073Sacruz int 20596073Sacruz secpolicy_contract_identity(const cred_t *cr) 20606073Sacruz { 20616073Sacruz return (PRIV_POLICY(cr, PRIV_CONTRACT_IDENTITY, B_FALSE, EPERM, NULL)); 20626073Sacruz } 20636073Sacruz 20646073Sacruz /* 20650Sstevel@tonic-gate * secpolicy_contract_observer 20660Sstevel@tonic-gate * 20670Sstevel@tonic-gate * Determine if the subject may observe a specific contract's events. 20680Sstevel@tonic-gate */ 20690Sstevel@tonic-gate int 20700Sstevel@tonic-gate secpolicy_contract_observer(const cred_t *cr, struct contract *ct) 20710Sstevel@tonic-gate { 20720Sstevel@tonic-gate if (contract_owned(ct, cr, B_FALSE)) 20730Sstevel@tonic-gate return (0); 20740Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CONTRACT_OBSERVER, B_FALSE, EPERM, NULL)); 20750Sstevel@tonic-gate } 20760Sstevel@tonic-gate 20770Sstevel@tonic-gate /* 20780Sstevel@tonic-gate * secpolicy_contract_observer_choice 20790Sstevel@tonic-gate * 20800Sstevel@tonic-gate * Determine if the subject may observe any contract's events. Just 20810Sstevel@tonic-gate * tests privilege and audits on success. 20820Sstevel@tonic-gate */ 20830Sstevel@tonic-gate boolean_t 20840Sstevel@tonic-gate secpolicy_contract_observer_choice(const cred_t *cr) 20850Sstevel@tonic-gate { 20860Sstevel@tonic-gate return (PRIV_POLICY_CHOICE(cr, PRIV_CONTRACT_OBSERVER, B_FALSE)); 20870Sstevel@tonic-gate } 20880Sstevel@tonic-gate 20890Sstevel@tonic-gate /* 20900Sstevel@tonic-gate * secpolicy_contract_event 20910Sstevel@tonic-gate * 20920Sstevel@tonic-gate * Determine if the subject may request critical contract events or 20930Sstevel@tonic-gate * reliable contract event delivery. 20940Sstevel@tonic-gate */ 20950Sstevel@tonic-gate int 20960Sstevel@tonic-gate secpolicy_contract_event(const cred_t *cr) 20970Sstevel@tonic-gate { 20980Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CONTRACT_EVENT, B_FALSE, EPERM, NULL)); 20990Sstevel@tonic-gate } 21000Sstevel@tonic-gate 21010Sstevel@tonic-gate /* 21020Sstevel@tonic-gate * secpolicy_contract_event_choice 21030Sstevel@tonic-gate * 21040Sstevel@tonic-gate * Determine if the subject may retain contract events in its critical 21050Sstevel@tonic-gate * set when a change in other terms would normally require a change in 21060Sstevel@tonic-gate * the critical set. Just tests privilege and audits on success. 21070Sstevel@tonic-gate */ 21080Sstevel@tonic-gate boolean_t 21090Sstevel@tonic-gate secpolicy_contract_event_choice(const cred_t *cr) 21100Sstevel@tonic-gate { 21110Sstevel@tonic-gate return (PRIV_POLICY_CHOICE(cr, PRIV_CONTRACT_EVENT, B_FALSE)); 21120Sstevel@tonic-gate } 21130Sstevel@tonic-gate 21140Sstevel@tonic-gate /* 21151544Seschrock * secpolicy_gart_access 21160Sstevel@tonic-gate * 21171544Seschrock * Determine if the subject has sufficient priveleges to make ioctls to agpgart 21181544Seschrock * device. 21190Sstevel@tonic-gate */ 21200Sstevel@tonic-gate int 21210Sstevel@tonic-gate secpolicy_gart_access(const cred_t *cr) 21220Sstevel@tonic-gate { 21231862Scasper return (PRIV_POLICY(cr, PRIV_GRAPHICS_ACCESS, B_FALSE, EPERM, NULL)); 21240Sstevel@tonic-gate } 21250Sstevel@tonic-gate 21260Sstevel@tonic-gate /* 21271544Seschrock * secpolicy_gart_map 21280Sstevel@tonic-gate * 21291544Seschrock * Determine if the subject has sufficient priveleges to map aperture range 21301544Seschrock * through agpgart driver. 21310Sstevel@tonic-gate */ 21320Sstevel@tonic-gate int 21330Sstevel@tonic-gate secpolicy_gart_map(const cred_t *cr) 21340Sstevel@tonic-gate { 21351862Scasper if (PRIV_POLICY_ONLY(cr, PRIV_GRAPHICS_ACCESS, B_FALSE)) { 21361862Scasper return (PRIV_POLICY(cr, PRIV_GRAPHICS_ACCESS, B_FALSE, EPERM, 21371862Scasper NULL)); 21381862Scasper } else { 21391862Scasper return (PRIV_POLICY(cr, PRIV_GRAPHICS_MAP, B_FALSE, EPERM, 21401862Scasper NULL)); 21410Sstevel@tonic-gate } 21420Sstevel@tonic-gate } 2143789Sahrens 2144789Sahrens /* 21451544Seschrock * secpolicy_zinject 21461544Seschrock * 21471544Seschrock * Determine if the subject can inject faults in the ZFS fault injection 21481544Seschrock * framework. Requires all privileges. 21491544Seschrock */ 21501544Seschrock int 21511544Seschrock secpolicy_zinject(const cred_t *cr) 21521544Seschrock { 21531544Seschrock return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); 21541544Seschrock } 21551544Seschrock 21561544Seschrock /* 2157789Sahrens * secpolicy_zfs 2158789Sahrens * 21591544Seschrock * Determine if the subject has permission to manipulate ZFS datasets 21601544Seschrock * (not pools). Equivalent to the SYS_MOUNT privilege. 2161789Sahrens */ 2162789Sahrens int 2163789Sahrens secpolicy_zfs(const cred_t *cr) 2164789Sahrens { 2165789Sahrens return (PRIV_POLICY(cr, PRIV_SYS_MOUNT, B_FALSE, EPERM, NULL)); 2166789Sahrens } 21674321Scasper 21684321Scasper /* 21694321Scasper * secpolicy_idmap 21704321Scasper * 21714321Scasper * Determine if the calling process has permissions to register an SID 21724321Scasper * mapping daemon and allocate ephemeral IDs. 21734321Scasper */ 21744321Scasper int 21754321Scasper secpolicy_idmap(const cred_t *cr) 21764321Scasper { 21775771Sjp151216 return (PRIV_POLICY(cr, PRIV_FILE_SETID, B_TRUE, EPERM, NULL)); 21784321Scasper } 21794581Ssherrym 21804581Ssherrym /* 21814581Ssherrym * secpolicy_ucode_update 21824581Ssherrym * 21834581Ssherrym * Determine if the subject has sufficient privilege to update microcode. 21844581Ssherrym */ 21854581Ssherrym int 21864581Ssherrym secpolicy_ucode_update(const cred_t *scr) 21874581Ssherrym { 21884581Ssherrym return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); 21894581Ssherrym } 21904962Sdh155122 21914962Sdh155122 /* 21924962Sdh155122 * secpolicy_sadopen 21934962Sdh155122 * 21944962Sdh155122 * Determine if the subject has sufficient privilege to access /dev/sad/admin. 21954962Sdh155122 * /dev/sad/admin appear in global zone and exclusive-IP zones only. 21964962Sdh155122 * In global zone, sys_config is required. 21974962Sdh155122 * In exclusive-IP zones, sys_ip_config is required. 21984962Sdh155122 * Note that sys_config is prohibited in non-global zones. 21994962Sdh155122 */ 22004962Sdh155122 int 22014962Sdh155122 secpolicy_sadopen(const cred_t *credp) 22024962Sdh155122 { 22034962Sdh155122 priv_set_t pset; 22044962Sdh155122 22054962Sdh155122 priv_emptyset(&pset); 22064962Sdh155122 22074962Sdh155122 if (crgetzoneid(credp) == GLOBAL_ZONEID) 22084962Sdh155122 priv_addset(&pset, PRIV_SYS_CONFIG); 22094962Sdh155122 else 22104962Sdh155122 priv_addset(&pset, PRIV_SYS_IP_CONFIG); 22114962Sdh155122 22124962Sdh155122 return (secpolicy_require_set(credp, &pset, "devpolicy")); 22134962Sdh155122 } 22145331Samw 22156134Scasper 22166134Scasper /* 22176134Scasper * Add privileges to a particular privilege set; this is called when the 22186134Scasper * current sets of privileges are not sufficient. I.e., we should always 22196134Scasper * call the policy override functions from here. 22206134Scasper * What we are allowed to have is in the Observed Permitted set; so 22216134Scasper * we compute the difference between that and the newset. 22226134Scasper */ 22236134Scasper int 22246134Scasper secpolicy_require_privs(const cred_t *cr, const priv_set_t *nset) 22256134Scasper { 22266134Scasper priv_set_t rqd; 22276134Scasper 22286134Scasper rqd = CR_OPPRIV(cr); 22296134Scasper 22306134Scasper priv_inverse(&rqd); 22316134Scasper priv_intersect(nset, &rqd); 22326134Scasper 22336134Scasper return (secpolicy_require_set(cr, &rqd, NULL)); 22346134Scasper } 22356134Scasper 22365331Samw /* 22375331Samw * secpolicy_smb 22385331Samw * 22395331Samw * Determine if the cred_t has PRIV_SYS_SMB privilege, indicating 22405331Samw * that it has permission to access the smbsrv kernel driver. 22415331Samw * PRIV_POLICY checks the privilege and audits the check. 22425331Samw * 22435331Samw * Returns: 22445331Samw * 0 Driver access is allowed. 22455331Samw * EPERM Driver access is NOT permitted. 22465331Samw */ 22475331Samw int 22485331Samw secpolicy_smb(const cred_t *cr) 22495331Samw { 22505331Samw return (PRIV_POLICY(cr, PRIV_SYS_SMB, B_FALSE, EPERM, NULL)); 22515331Samw } 22525440Sjm199354 22535440Sjm199354 /* 22545440Sjm199354 * secpolicy_vscan 22555440Sjm199354 * 22565440Sjm199354 * Determine if cred_t has the necessary privileges to access a file 22575440Sjm199354 * for virus scanning and update its extended system attributes. 22585440Sjm199354 * PRIV_FILE_DAC_SEARCH, PRIV_FILE_DAC_READ - file access 22595440Sjm199354 * PRIV_FILE_FLAG_SET - set extended system attributes 22605440Sjm199354 * 22615440Sjm199354 * PRIV_POLICY checks the privilege and audits the check. 22625440Sjm199354 * 22635440Sjm199354 * Returns: 22645440Sjm199354 * 0 file access for virus scanning allowed. 22655440Sjm199354 * EPERM file access for virus scanning is NOT permitted. 22665440Sjm199354 */ 22675440Sjm199354 int 22685440Sjm199354 secpolicy_vscan(const cred_t *cr) 22695440Sjm199354 { 22705440Sjm199354 if ((PRIV_POLICY(cr, PRIV_FILE_DAC_SEARCH, B_FALSE, EPERM, NULL)) || 22715440Sjm199354 (PRIV_POLICY(cr, PRIV_FILE_DAC_READ, B_FALSE, EPERM, NULL)) || 22725440Sjm199354 (PRIV_POLICY(cr, PRIV_FILE_FLAG_SET, B_FALSE, EPERM, NULL))) { 22735440Sjm199354 return (EPERM); 22745440Sjm199354 } 22755440Sjm199354 22765440Sjm199354 return (0); 22775440Sjm199354 } 22786007Sthurlow 22796007Sthurlow /* 22806007Sthurlow * secpolicy_smbfs_login 22816007Sthurlow * 22826007Sthurlow * Determines if the caller can add and delete the smbfs login 22836007Sthurlow * password in the the nsmb kernel module for the CIFS client. 22846007Sthurlow * 22856007Sthurlow * Returns: 22866007Sthurlow * 0 access is allowed. 22876007Sthurlow * EPERM access is NOT allowed. 22886007Sthurlow */ 22896007Sthurlow int 22906007Sthurlow secpolicy_smbfs_login(const cred_t *cr, uid_t uid) 22916007Sthurlow { 22926007Sthurlow uid_t cruid = crgetruid(cr); 22936007Sthurlow 22946007Sthurlow if (cruid == uid) 22956007Sthurlow return (0); 22966007Sthurlow return (PRIV_POLICY(cr, PRIV_PROC_OWNER, B_FALSE, 22976007Sthurlow EPERM, NULL)); 22986007Sthurlow } 22996784Sjohnlev 23006784Sjohnlev /* 23016784Sjohnlev * secpolicy_xvm_control 23026784Sjohnlev * 23036784Sjohnlev * Determines if a caller can control the xVM hypervisor and/or running 23046784Sjohnlev * domains (x86 specific). 23056784Sjohnlev * 23066784Sjohnlev * Returns: 23076784Sjohnlev * 0 access is allowed. 23086784Sjohnlev * EPERM access is NOT allowed. 23096784Sjohnlev */ 23106784Sjohnlev int 23116784Sjohnlev secpolicy_xvm_control(const cred_t *cr) 23126784Sjohnlev { 23136784Sjohnlev if (PRIV_POLICY(cr, PRIV_XVM_CONTROL, B_FALSE, EPERM, NULL)) 23146784Sjohnlev return (EPERM); 23156784Sjohnlev return (0); 23166784Sjohnlev } 23178275SEric Cheng 23188275SEric Cheng /* 23199751Sjames.d.carlson@sun.com * secpolicy_ppp_config 23209751Sjames.d.carlson@sun.com * 23219751Sjames.d.carlson@sun.com * Determine if the subject has sufficient privileges to configure PPP and 23229751Sjames.d.carlson@sun.com * PPP-related devices. 23239751Sjames.d.carlson@sun.com */ 23249751Sjames.d.carlson@sun.com int 23259751Sjames.d.carlson@sun.com secpolicy_ppp_config(const cred_t *cr) 23269751Sjames.d.carlson@sun.com { 23279751Sjames.d.carlson@sun.com if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE)) 23289751Sjames.d.carlson@sun.com return (secpolicy_net_config(cr, B_FALSE)); 23299751Sjames.d.carlson@sun.com return (PRIV_POLICY(cr, PRIV_SYS_PPP_CONFIG, B_FALSE, EPERM, NULL)); 23309751Sjames.d.carlson@sun.com } 2331