17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 23*7aec1d6eScindi * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 317c478bd9Sstevel@tonic-gate #include <sys/param.h> 327c478bd9Sstevel@tonic-gate #include <sys/systm.h> 337c478bd9Sstevel@tonic-gate #include <sys/cred_impl.h> 347c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 357c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 367c478bd9Sstevel@tonic-gate #include <sys/stat.h> 377c478bd9Sstevel@tonic-gate #include <sys/errno.h> 387c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 397c478bd9Sstevel@tonic-gate #include <sys/user.h> 407c478bd9Sstevel@tonic-gate #include <sys/proc.h> 417c478bd9Sstevel@tonic-gate #include <sys/acct.h> 427c478bd9Sstevel@tonic-gate #include <sys/ipc_impl.h> 437c478bd9Sstevel@tonic-gate #include <sys/syscall.h> 447c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 457c478bd9Sstevel@tonic-gate #include <sys/debug.h> 467c478bd9Sstevel@tonic-gate #include <sys/policy.h> 477c478bd9Sstevel@tonic-gate #include <sys/kobj.h> 487c478bd9Sstevel@tonic-gate #include <sys/msg.h> 497c478bd9Sstevel@tonic-gate #include <sys/devpolicy.h> 507c478bd9Sstevel@tonic-gate #include <c2/audit.h> 517c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 527c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 537c478bd9Sstevel@tonic-gate #include <sys/disp.h> 547c478bd9Sstevel@tonic-gate #include <sys/zone.h> 557c478bd9Sstevel@tonic-gate #include <inet/common.h> 567c478bd9Sstevel@tonic-gate #include <inet/optcom.h> 577c478bd9Sstevel@tonic-gate #include <sys/sdt.h> 587c478bd9Sstevel@tonic-gate #include <sys/mount.h> 597c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 607c478bd9Sstevel@tonic-gate #include <sys/mntent.h> 617c478bd9Sstevel@tonic-gate #include <sys/contract_impl.h> 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate /* 667c478bd9Sstevel@tonic-gate * There are two possible layers of privilege routines and two possible 677c478bd9Sstevel@tonic-gate * levels of secpolicy. Plus one other we may not be interested in, so 687c478bd9Sstevel@tonic-gate * we may need as many as 6 but no more. 697c478bd9Sstevel@tonic-gate */ 707c478bd9Sstevel@tonic-gate #define MAXPRIVSTACK 6 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate int priv_debug = 0; 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate /* 757c478bd9Sstevel@tonic-gate * This file contains the majority of the policy routines. 767c478bd9Sstevel@tonic-gate * Since the policy routines are defined by function and not 777c478bd9Sstevel@tonic-gate * by privilege, there is quite a bit of duplication of 787c478bd9Sstevel@tonic-gate * functions. 797c478bd9Sstevel@tonic-gate * 807c478bd9Sstevel@tonic-gate * The secpolicy functions must not make asssumptions about 817c478bd9Sstevel@tonic-gate * locks held or not held as any lock can be held while they're 827c478bd9Sstevel@tonic-gate * being called. 837c478bd9Sstevel@tonic-gate * 847c478bd9Sstevel@tonic-gate * Credentials are read-only so no special precautions need to 857c478bd9Sstevel@tonic-gate * be taken while locking them. 867c478bd9Sstevel@tonic-gate * 877c478bd9Sstevel@tonic-gate * When a new policy check needs to be added to the system the 887c478bd9Sstevel@tonic-gate * following procedure should be followed: 897c478bd9Sstevel@tonic-gate * 907c478bd9Sstevel@tonic-gate * Pick an appropriate secpolicy_*() function 917c478bd9Sstevel@tonic-gate * -> done if one exists. 927c478bd9Sstevel@tonic-gate * Create a new secpolicy function, preferably with 937c478bd9Sstevel@tonic-gate * a descriptive name using the standard template. 947c478bd9Sstevel@tonic-gate * Pick an appropriate privilege for the policy. 957c478bd9Sstevel@tonic-gate * If no appropraite privilege exists, define new one 967c478bd9Sstevel@tonic-gate * (this should be done with extreme care; in most cases 977c478bd9Sstevel@tonic-gate * little is gained by adding another privilege) 987c478bd9Sstevel@tonic-gate * 997c478bd9Sstevel@tonic-gate * WHY ROOT IS STILL SPECIAL. 1007c478bd9Sstevel@tonic-gate * 1017c478bd9Sstevel@tonic-gate * In a number of the policy functions, there are still explicit 1027c478bd9Sstevel@tonic-gate * checks for uid 0. The rationale behind these is that many root 1037c478bd9Sstevel@tonic-gate * owned files/objects hold configuration information which can give full 1047c478bd9Sstevel@tonic-gate * privileges to the user once written to. To prevent escalation 1057c478bd9Sstevel@tonic-gate * of privilege by allowing just a single privilege to modify root owned 1067c478bd9Sstevel@tonic-gate * objects, we've added these root specific checks where we considered 1077c478bd9Sstevel@tonic-gate * them necessary: modifying root owned files, changing uids to 0, etc. 1087c478bd9Sstevel@tonic-gate * 1097c478bd9Sstevel@tonic-gate * PRIVILEGE ESCALATION AND ZONES. 1107c478bd9Sstevel@tonic-gate * 1117c478bd9Sstevel@tonic-gate * A number of operations potentially allow the caller to achieve 1127c478bd9Sstevel@tonic-gate * privileges beyond the ones normally required to perform the operation. 1137c478bd9Sstevel@tonic-gate * For example, if allowed to create a setuid 0 executable, a process can 1147c478bd9Sstevel@tonic-gate * gain privileges beyond PRIV_FILE_SETID. Zones, however, place 1157c478bd9Sstevel@tonic-gate * restrictions on the ability to gain privileges beyond those available 1167c478bd9Sstevel@tonic-gate * within the zone through file and process manipulation. Hence, such 1177c478bd9Sstevel@tonic-gate * operations require that the caller have an effective set that includes 1187c478bd9Sstevel@tonic-gate * all privileges available within the current zone, or all privileges 1197c478bd9Sstevel@tonic-gate * if executing in the global zone. 1207c478bd9Sstevel@tonic-gate * 1217c478bd9Sstevel@tonic-gate * This is indicated in the priv_policy* policy checking functions 1227c478bd9Sstevel@tonic-gate * through a combination of parameters. The "priv" parameter indicates 1237c478bd9Sstevel@tonic-gate * the privilege that is required, and the "allzone" parameter indicates 1247c478bd9Sstevel@tonic-gate * whether or not all privileges in the zone are required. In addition, 1257c478bd9Sstevel@tonic-gate * priv can be set to PRIV_ALL to indicate that all privileges are 1267c478bd9Sstevel@tonic-gate * required (regardless of zone). There are three scenarios of interest: 1277c478bd9Sstevel@tonic-gate * (1) operation requires a specific privilege 1287c478bd9Sstevel@tonic-gate * (2) operation requires a specific privilege, and requires all 1297c478bd9Sstevel@tonic-gate * privileges available within the zone (or all privileges if in 1307c478bd9Sstevel@tonic-gate * the global zone) 1317c478bd9Sstevel@tonic-gate * (3) operation requires all privileges, regardless of zone 1327c478bd9Sstevel@tonic-gate * 1337c478bd9Sstevel@tonic-gate * For (1), priv should be set to the specific privilege, and allzone 1347c478bd9Sstevel@tonic-gate * should be set to B_FALSE. 1357c478bd9Sstevel@tonic-gate * For (2), priv should be set to the specific privilege, and allzone 1367c478bd9Sstevel@tonic-gate * should be set to B_TRUE. 1377c478bd9Sstevel@tonic-gate * For (3), priv should be set to PRIV_ALL, and allzone should be set 1387c478bd9Sstevel@tonic-gate * to B_FALSE. 1397c478bd9Sstevel@tonic-gate * 1407c478bd9Sstevel@tonic-gate */ 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate /* 1437c478bd9Sstevel@tonic-gate * The privileges are checked against the Effective set for 1447c478bd9Sstevel@tonic-gate * ordinary processes and checked against the Limit set 1457c478bd9Sstevel@tonic-gate * for euid 0 processes that haven't manipulated their privilege 1467c478bd9Sstevel@tonic-gate * sets. 1477c478bd9Sstevel@tonic-gate */ 1487c478bd9Sstevel@tonic-gate #define HAS_ALLPRIVS(cr) priv_isfullset(&CR_OEPRIV(cr)) 1497c478bd9Sstevel@tonic-gate #define ZONEPRIVS(cr) ((cr)->cr_zone->zone_privset) 1507c478bd9Sstevel@tonic-gate #define HAS_ALLZONEPRIVS(cr) priv_issubset(ZONEPRIVS(cr), &CR_OEPRIV(cr)) 1517c478bd9Sstevel@tonic-gate #define HAS_PRIVILEGE(cr, pr) ((pr) == PRIV_ALL ? \ 1527c478bd9Sstevel@tonic-gate HAS_ALLPRIVS(cr) : \ 1537c478bd9Sstevel@tonic-gate PRIV_ISASSERT(&CR_OEPRIV(cr), pr)) 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate /* 1567c478bd9Sstevel@tonic-gate * Policy checking functions 1577c478bd9Sstevel@tonic-gate * 1587c478bd9Sstevel@tonic-gate * In future, these will migrate to several files when policy 1597c478bd9Sstevel@tonic-gate * becomes more or less pluggable. 1607c478bd9Sstevel@tonic-gate * 1617c478bd9Sstevel@tonic-gate * For now, there's only one policy and this is it. 1627c478bd9Sstevel@tonic-gate */ 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate /* 1657c478bd9Sstevel@tonic-gate * Generic policy calls 1667c478bd9Sstevel@tonic-gate * 1677c478bd9Sstevel@tonic-gate * The "bottom" functions of policy control 1687c478bd9Sstevel@tonic-gate */ 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate static char * 1717c478bd9Sstevel@tonic-gate mprintf(const char *fmt, ...) 1727c478bd9Sstevel@tonic-gate { 1737c478bd9Sstevel@tonic-gate va_list args; 1747c478bd9Sstevel@tonic-gate char *buf; 1757c478bd9Sstevel@tonic-gate size_t len; 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate va_start(args, fmt); 1787c478bd9Sstevel@tonic-gate len = vsnprintf(NULL, 0, fmt, args) + 1; 1797c478bd9Sstevel@tonic-gate va_end(args); 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate buf = kmem_alloc(len, KM_NOSLEEP); 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate if (buf == NULL) 1847c478bd9Sstevel@tonic-gate return (NULL); 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate va_start(args, fmt); 1877c478bd9Sstevel@tonic-gate (void) vsnprintf(buf, len, fmt, args); 1887c478bd9Sstevel@tonic-gate va_end(args); 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate return (buf); 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate /* 1947c478bd9Sstevel@tonic-gate * priv_policy_errmsg() 1957c478bd9Sstevel@tonic-gate * 1967c478bd9Sstevel@tonic-gate * Generate an error message if privilege debugging is enabled system wide 1977c478bd9Sstevel@tonic-gate * or for this particular process. 1987c478bd9Sstevel@tonic-gate */ 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate #define FMTHDR "%s[%d]: missing privilege \"%s\" (euid = %d, syscall = %d)" 2017c478bd9Sstevel@tonic-gate #define FMTMSG " for \"%s\"" 2027c478bd9Sstevel@tonic-gate #define FMTFUN " needed at %s+0x%lx" 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate /* The maximum size privilege format: the concatenation of the above */ 2057c478bd9Sstevel@tonic-gate #define FMTMAX FMTHDR FMTMSG FMTFUN "\n" 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate static void 2087c478bd9Sstevel@tonic-gate priv_policy_errmsg(const cred_t *cr, int priv, const char *msg) 2097c478bd9Sstevel@tonic-gate { 2107c478bd9Sstevel@tonic-gate struct proc *me; 2117c478bd9Sstevel@tonic-gate pc_t stack[MAXPRIVSTACK]; 2127c478bd9Sstevel@tonic-gate int depth; 2137c478bd9Sstevel@tonic-gate int i; 2147c478bd9Sstevel@tonic-gate char *sym; 2157c478bd9Sstevel@tonic-gate ulong_t off; 2167c478bd9Sstevel@tonic-gate const char *pname; 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate char *cmd; 2197c478bd9Sstevel@tonic-gate char fmt[sizeof (FMTMAX)]; 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate if ((me = curproc) == &p0) 2227c478bd9Sstevel@tonic-gate return; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate /* Privileges must be defined */ 2257c478bd9Sstevel@tonic-gate ASSERT(priv == PRIV_ALL || priv == PRIV_MULTIPLE || 2267c478bd9Sstevel@tonic-gate priv == PRIV_ALLZONE || priv == PRIV_GLOBAL || 2277c478bd9Sstevel@tonic-gate priv_getbynum(priv) != NULL); 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate if (priv == PRIV_ALLZONE && INGLOBALZONE(me)) 2307c478bd9Sstevel@tonic-gate priv = PRIV_ALL; 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate if (curthread->t_pre_sys) 2337c478bd9Sstevel@tonic-gate ttolwp(curthread)->lwp_badpriv = (short)priv; 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate if (priv_debug == 0 && (CR_FLAGS(cr) & PRIV_DEBUG) == 0) 2367c478bd9Sstevel@tonic-gate return; 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate (void) strcpy(fmt, FMTHDR); 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate if (me->p_user.u_comm[0]) 2417c478bd9Sstevel@tonic-gate cmd = &me->p_user.u_comm[0]; 2427c478bd9Sstevel@tonic-gate else 2437c478bd9Sstevel@tonic-gate cmd = "priv_policy"; 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate if (msg != NULL && *msg != '\0') { 2467c478bd9Sstevel@tonic-gate (void) strcat(fmt, FMTMSG); 2477c478bd9Sstevel@tonic-gate } else { 2487c478bd9Sstevel@tonic-gate (void) strcat(fmt, "%s"); 2497c478bd9Sstevel@tonic-gate msg = ""; 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate sym = NULL; 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate depth = getpcstack(stack, MAXPRIVSTACK); 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate /* 2577c478bd9Sstevel@tonic-gate * Try to find the first interesting function on the stack. 2587c478bd9Sstevel@tonic-gate * priv_policy* that's us, so completely uninteresting. 2597c478bd9Sstevel@tonic-gate * suser(), drv_priv(), secpolicy_* are also called from 2607c478bd9Sstevel@tonic-gate * too many locations to convey useful information. 2617c478bd9Sstevel@tonic-gate */ 2627c478bd9Sstevel@tonic-gate for (i = 0; i < depth; i++) { 2637c478bd9Sstevel@tonic-gate sym = kobj_getsymname((uintptr_t)stack[i], &off); 2647c478bd9Sstevel@tonic-gate if (sym != NULL && 2657c478bd9Sstevel@tonic-gate strstr(sym, "hasprocperm") == 0 && 2667c478bd9Sstevel@tonic-gate strcmp("suser", sym) != 0 && 2677c478bd9Sstevel@tonic-gate strcmp("ipcaccess", sym) != 0 && 2687c478bd9Sstevel@tonic-gate strcmp("drv_priv", sym) != 0 && 2697c478bd9Sstevel@tonic-gate strncmp("secpolicy_", sym, 10) != 0 && 2707c478bd9Sstevel@tonic-gate strncmp("priv_policy", sym, 11) != 0) 2717c478bd9Sstevel@tonic-gate break; 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate if (sym != NULL) 2757c478bd9Sstevel@tonic-gate (void) strcat(fmt, FMTFUN); 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate (void) strcat(fmt, "\n"); 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate switch (priv) { 2807c478bd9Sstevel@tonic-gate case PRIV_ALL: 2817c478bd9Sstevel@tonic-gate pname = "ALL"; 2827c478bd9Sstevel@tonic-gate break; 2837c478bd9Sstevel@tonic-gate case PRIV_MULTIPLE: 2847c478bd9Sstevel@tonic-gate pname = "MULTIPLE"; 2857c478bd9Sstevel@tonic-gate break; 2867c478bd9Sstevel@tonic-gate case PRIV_ALLZONE: 2877c478bd9Sstevel@tonic-gate pname = "ZONE"; 2887c478bd9Sstevel@tonic-gate break; 2897c478bd9Sstevel@tonic-gate case PRIV_GLOBAL: 2907c478bd9Sstevel@tonic-gate pname = "GLOBAL"; 2917c478bd9Sstevel@tonic-gate break; 2927c478bd9Sstevel@tonic-gate default: 2937c478bd9Sstevel@tonic-gate pname = priv_getbynum(priv); 2947c478bd9Sstevel@tonic-gate break; 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate if (CR_FLAGS(cr) & PRIV_DEBUG) { 2987c478bd9Sstevel@tonic-gate /* Remember last message, just like lwp_badpriv. */ 2997c478bd9Sstevel@tonic-gate if (curthread->t_pdmsg != NULL) { 3007c478bd9Sstevel@tonic-gate kmem_free(curthread->t_pdmsg, 3017c478bd9Sstevel@tonic-gate strlen(curthread->t_pdmsg) + 1); 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate curthread->t_pdmsg = mprintf(fmt, cmd, me->p_pid, pname, 3057c478bd9Sstevel@tonic-gate cr->cr_uid, curthread->t_sysnum, msg, sym, off); 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate curthread->t_post_sys = 1; 3087c478bd9Sstevel@tonic-gate } else { 3097c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, fmt, cmd, me->p_pid, pname, cr->cr_uid, 3107c478bd9Sstevel@tonic-gate curthread->t_sysnum, msg, sym, off); 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate /* 3157c478bd9Sstevel@tonic-gate * Audit failure, log error message. 3167c478bd9Sstevel@tonic-gate */ 3177c478bd9Sstevel@tonic-gate static void 3187c478bd9Sstevel@tonic-gate priv_policy_err(const cred_t *cr, int priv, boolean_t allzone, const char *msg) 3197c478bd9Sstevel@tonic-gate { 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT 3227c478bd9Sstevel@tonic-gate if (audit_active) 3237c478bd9Sstevel@tonic-gate audit_priv(priv, allzone ? ZONEPRIVS(cr) : NULL, 0); 3247c478bd9Sstevel@tonic-gate #endif 3257c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone); 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) || 3287c478bd9Sstevel@tonic-gate curthread->t_pre_sys) { 3297c478bd9Sstevel@tonic-gate if (allzone && !HAS_ALLZONEPRIVS(cr)) { 3307c478bd9Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_ALLZONE, msg); 3317c478bd9Sstevel@tonic-gate } else { 3327c478bd9Sstevel@tonic-gate ASSERT(!HAS_PRIVILEGE(cr, priv)); 3337c478bd9Sstevel@tonic-gate priv_policy_errmsg(cr, priv, msg); 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate /* 3397c478bd9Sstevel@tonic-gate * priv_policy() 3407c478bd9Sstevel@tonic-gate * return 0 or error. 3417c478bd9Sstevel@tonic-gate * See block comment above for a description of "priv" and "allzone" usage. 3427c478bd9Sstevel@tonic-gate */ 3437c478bd9Sstevel@tonic-gate int 3447c478bd9Sstevel@tonic-gate priv_policy(const cred_t *cr, int priv, boolean_t allzone, int err, 3457c478bd9Sstevel@tonic-gate const char *msg) 3467c478bd9Sstevel@tonic-gate { 3477c478bd9Sstevel@tonic-gate if (HAS_PRIVILEGE(cr, priv) && (!allzone || HAS_ALLZONEPRIVS(cr))) { 3487c478bd9Sstevel@tonic-gate if ((allzone || priv == PRIV_ALL || 3497c478bd9Sstevel@tonic-gate !PRIV_ISASSERT(priv_basic, priv)) && 3507c478bd9Sstevel@tonic-gate !servicing_interrupt()) { 3517c478bd9Sstevel@tonic-gate u.u_acflag |= ASU; /* Needed for SVVS */ 3527c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT 3537c478bd9Sstevel@tonic-gate if (audit_active) 3547c478bd9Sstevel@tonic-gate audit_priv(priv, 3557c478bd9Sstevel@tonic-gate allzone ? ZONEPRIVS(cr) : NULL, 1); 3567c478bd9Sstevel@tonic-gate #endif 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate err = 0; 3597c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone); 3607c478bd9Sstevel@tonic-gate } else if (!servicing_interrupt()) { 3617c478bd9Sstevel@tonic-gate /* Failure audited in this procedure */ 3627c478bd9Sstevel@tonic-gate priv_policy_err(cr, priv, allzone, msg); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate return (err); 3667c478bd9Sstevel@tonic-gate } 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate /* 3697c478bd9Sstevel@tonic-gate * Return B_TRUE for sufficient privileges, B_FALSE for insufficient privileges. 3707c478bd9Sstevel@tonic-gate */ 3717c478bd9Sstevel@tonic-gate boolean_t 3727c478bd9Sstevel@tonic-gate priv_policy_choice(const cred_t *cr, int priv, boolean_t allzone) 3737c478bd9Sstevel@tonic-gate { 3747c478bd9Sstevel@tonic-gate boolean_t res = HAS_PRIVILEGE(cr, priv) && 3757c478bd9Sstevel@tonic-gate (!allzone || HAS_ALLZONEPRIVS(cr)); 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT 3787c478bd9Sstevel@tonic-gate /* Audit success only */ 3797c478bd9Sstevel@tonic-gate if (res && audit_active && 3807c478bd9Sstevel@tonic-gate (allzone || priv == PRIV_ALL || !PRIV_ISASSERT(priv_basic, priv)) && 3817c478bd9Sstevel@tonic-gate !servicing_interrupt()) { 3827c478bd9Sstevel@tonic-gate audit_priv(priv, allzone ? ZONEPRIVS(cr) : NULL, 1); 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate #endif 3857c478bd9Sstevel@tonic-gate if (res) { 3867c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone); 3877c478bd9Sstevel@tonic-gate } else { 3887c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone); 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate return (res); 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate /* 3947c478bd9Sstevel@tonic-gate * Non-auditing variant of priv_policy_choice(). 3957c478bd9Sstevel@tonic-gate */ 3967c478bd9Sstevel@tonic-gate boolean_t 3977c478bd9Sstevel@tonic-gate priv_policy_only(const cred_t *cr, int priv, boolean_t allzone) 3987c478bd9Sstevel@tonic-gate { 3997c478bd9Sstevel@tonic-gate boolean_t res = HAS_PRIVILEGE(cr, priv) && 4007c478bd9Sstevel@tonic-gate (!allzone || HAS_ALLZONEPRIVS(cr)); 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate if (res) { 4037c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone); 4047c478bd9Sstevel@tonic-gate } else { 4057c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone); 4067c478bd9Sstevel@tonic-gate } 4077c478bd9Sstevel@tonic-gate return (res); 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate /* 4117c478bd9Sstevel@tonic-gate * Check whether all privileges in the required set are present. 4127c478bd9Sstevel@tonic-gate */ 4137c478bd9Sstevel@tonic-gate static int 4147c478bd9Sstevel@tonic-gate secpolicy_require_set(const cred_t *cr, const priv_set_t *req, const char *msg) 4157c478bd9Sstevel@tonic-gate { 4167c478bd9Sstevel@tonic-gate int priv; 4177c478bd9Sstevel@tonic-gate int pfound = -1; 4187c478bd9Sstevel@tonic-gate priv_set_t pset; 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate if (req == PRIV_FULLSET ? HAS_ALLPRIVS(cr) : priv_issubset(req, 4217c478bd9Sstevel@tonic-gate &CR_OEPRIV(cr))) { 4227c478bd9Sstevel@tonic-gate return (0); 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate if (req == PRIV_FULLSET || priv_isfullset(req)) { 4267c478bd9Sstevel@tonic-gate priv_policy_err(cr, PRIV_ALL, B_FALSE, msg); 4277c478bd9Sstevel@tonic-gate return (EACCES); 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate pset = CR_OEPRIV(cr); /* present privileges */ 4317c478bd9Sstevel@tonic-gate priv_inverse(&pset); /* all non present privileges */ 4327c478bd9Sstevel@tonic-gate priv_intersect(req, &pset); /* the actual missing privs */ 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT 4357c478bd9Sstevel@tonic-gate if (audit_active) 4367c478bd9Sstevel@tonic-gate audit_priv(PRIV_NONE, &pset, 0); 4377c478bd9Sstevel@tonic-gate #endif 4387c478bd9Sstevel@tonic-gate /* 4397c478bd9Sstevel@tonic-gate * Privilege debugging; special case "one privilege in set". 4407c478bd9Sstevel@tonic-gate */ 4417c478bd9Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) || curthread->t_pre_sys) { 4427c478bd9Sstevel@tonic-gate for (priv = 0; priv < nprivs; priv++) { 4437c478bd9Sstevel@tonic-gate if (priv_ismember(&pset, priv)) { 4447c478bd9Sstevel@tonic-gate if (pfound != -1) { 4457c478bd9Sstevel@tonic-gate /* Multiple missing privs */ 4467c478bd9Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_MULTIPLE, 4477c478bd9Sstevel@tonic-gate msg); 4487c478bd9Sstevel@tonic-gate return (EACCES); 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate pfound = priv; 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate ASSERT(pfound != -1); 4547c478bd9Sstevel@tonic-gate /* Just the one missing privilege */ 4557c478bd9Sstevel@tonic-gate priv_policy_errmsg(cr, pfound, msg); 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate return (EACCES); 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate /* 4627c478bd9Sstevel@tonic-gate * Called when an operation requires that the caller be in the 4637c478bd9Sstevel@tonic-gate * global zone, regardless of privilege. 4647c478bd9Sstevel@tonic-gate */ 4657c478bd9Sstevel@tonic-gate static int 4667c478bd9Sstevel@tonic-gate priv_policy_global(const cred_t *cr) 4677c478bd9Sstevel@tonic-gate { 4687c478bd9Sstevel@tonic-gate if (crgetzoneid(cr) == GLOBAL_ZONEID) 4697c478bd9Sstevel@tonic-gate return (0); /* success */ 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) || 4727c478bd9Sstevel@tonic-gate curthread->t_pre_sys) { 4737c478bd9Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_GLOBAL, NULL); 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate return (EPERM); 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate /* 4797c478bd9Sstevel@tonic-gate * Changing process priority 4807c478bd9Sstevel@tonic-gate */ 4817c478bd9Sstevel@tonic-gate int 4827c478bd9Sstevel@tonic-gate secpolicy_setpriority(const cred_t *cr) 4837c478bd9Sstevel@tonic-gate { 4847c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_PRIOCNTL, B_FALSE, EPERM, NULL)); 4857c478bd9Sstevel@tonic-gate } 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate /* 4887c478bd9Sstevel@tonic-gate * Binding to a privileged port, port must be specified in host byte 4897c478bd9Sstevel@tonic-gate * order. 4907c478bd9Sstevel@tonic-gate */ 4917c478bd9Sstevel@tonic-gate int 4927c478bd9Sstevel@tonic-gate secpolicy_net_privaddr(const cred_t *cr, in_port_t port) 4937c478bd9Sstevel@tonic-gate { 4947c478bd9Sstevel@tonic-gate /* 4957c478bd9Sstevel@tonic-gate * NFS ports, these are extra privileged ports, allow bind 4967c478bd9Sstevel@tonic-gate * only if the SYS_NFS privilege is present. 4977c478bd9Sstevel@tonic-gate */ 4987c478bd9Sstevel@tonic-gate if (port == 2049 || port == 4045) 4997c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_NFS, B_FALSE, EACCES, 5007c478bd9Sstevel@tonic-gate "NFS port")); 5017c478bd9Sstevel@tonic-gate else 5027c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_NET_PRIVADDR, B_FALSE, EACCES, 5037c478bd9Sstevel@tonic-gate NULL)); 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate /* 5077c478bd9Sstevel@tonic-gate * Common routine which determines whether a given credential can 5087c478bd9Sstevel@tonic-gate * act on a given mount. 5097c478bd9Sstevel@tonic-gate * When called through mount, the parameter needoptcheck is a pointer 5107c478bd9Sstevel@tonic-gate * to a boolean variable which will be set to either true or false, 5117c478bd9Sstevel@tonic-gate * depending on whether the mount policy should change the mount options. 5127c478bd9Sstevel@tonic-gate * In all other cases, needoptcheck should be a NULL pointer. 5137c478bd9Sstevel@tonic-gate */ 5147c478bd9Sstevel@tonic-gate static int 5157c478bd9Sstevel@tonic-gate secpolicy_fs_common(cred_t *cr, vnode_t *mvp, const vfs_t *vfsp, 5167c478bd9Sstevel@tonic-gate boolean_t *needoptcheck) 5177c478bd9Sstevel@tonic-gate { 5187c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 5197c478bd9Sstevel@tonic-gate boolean_t mounting = needoptcheck != NULL; 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate /* 5227c478bd9Sstevel@tonic-gate * Short circuit the following cases: 5237c478bd9Sstevel@tonic-gate * vfsp == NULL or mvp == NULL (pure privilege check) 5247c478bd9Sstevel@tonic-gate * have all privileges - no further checks required 5257c478bd9Sstevel@tonic-gate * and no mount options need to be set. 5267c478bd9Sstevel@tonic-gate */ 5277c478bd9Sstevel@tonic-gate if (vfsp == NULL || mvp == NULL || HAS_ALLPRIVS(cr)) { 5287c478bd9Sstevel@tonic-gate if (mounting) 5297c478bd9Sstevel@tonic-gate *needoptcheck = B_FALSE; 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_MOUNT, allzone, EPERM, NULL)); 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate /* 5357c478bd9Sstevel@tonic-gate * When operating on an existing mount (either we're not mounting 5367c478bd9Sstevel@tonic-gate * or we're doing a remount and VFS_REMOUNT will be set), zones 5377c478bd9Sstevel@tonic-gate * can operate only on mounts established by the zone itself. 5387c478bd9Sstevel@tonic-gate */ 5397c478bd9Sstevel@tonic-gate if (!mounting || (vfsp->vfs_flag & VFS_REMOUNT) != 0) { 5407c478bd9Sstevel@tonic-gate zoneid_t zoneid = crgetzoneid(cr); 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate if (zoneid != GLOBAL_ZONEID && 5437c478bd9Sstevel@tonic-gate vfsp->vfs_zone->zone_id != zoneid) { 5447c478bd9Sstevel@tonic-gate return (EPERM); 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate if (mounting) 5497c478bd9Sstevel@tonic-gate *needoptcheck = B_TRUE; 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate /* 5527c478bd9Sstevel@tonic-gate * Overlay mounts may hide important stuff; if you can't write to a 5537c478bd9Sstevel@tonic-gate * mount point but would be able to mount on top of it, you can 5547c478bd9Sstevel@tonic-gate * escalate your privileges. 5557c478bd9Sstevel@tonic-gate * So we go about asking the same questions namefs does when it 5567c478bd9Sstevel@tonic-gate * decides whether you can mount over a file or not but with the 5577c478bd9Sstevel@tonic-gate * added restriction that you can only mount on top of a regular 5587c478bd9Sstevel@tonic-gate * file or directory. 5597c478bd9Sstevel@tonic-gate * If we have all the zone's privileges, we skip all other checks, 5607c478bd9Sstevel@tonic-gate * or else we may actually get in trouble inside the automounter. 5617c478bd9Sstevel@tonic-gate */ 5627c478bd9Sstevel@tonic-gate if ((mvp->v_flag & VROOT) != 0 || 5637c478bd9Sstevel@tonic-gate (mvp->v_type != VDIR && mvp->v_type != VREG) || 5647c478bd9Sstevel@tonic-gate HAS_ALLZONEPRIVS(cr)) { 5657c478bd9Sstevel@tonic-gate allzone = B_TRUE; 5667c478bd9Sstevel@tonic-gate } else { 5677c478bd9Sstevel@tonic-gate vattr_t va; 5687c478bd9Sstevel@tonic-gate int err; 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate va.va_mask = AT_UID|AT_MODE; 5717c478bd9Sstevel@tonic-gate err = VOP_GETATTR(mvp, &va, 0, cr); 5727c478bd9Sstevel@tonic-gate if (err != 0) 5737c478bd9Sstevel@tonic-gate return (err); 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate if ((err = secpolicy_vnode_owner(cr, va.va_uid)) != 0) 5767c478bd9Sstevel@tonic-gate return (err); 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate if ((va.va_mode & VWRITE) == 0 && 5797c478bd9Sstevel@tonic-gate secpolicy_vnode_access(cr, mvp, va.va_uid, VWRITE) != 0) { 5807c478bd9Sstevel@tonic-gate return (EACCES); 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_MOUNT, allzone, EPERM, NULL)); 5847c478bd9Sstevel@tonic-gate } 5857c478bd9Sstevel@tonic-gate 586dc7ca608Scasper extern vnode_t *rootvp; 587dc7ca608Scasper extern vfs_t *rootvfs; 588dc7ca608Scasper 5897c478bd9Sstevel@tonic-gate int 5907c478bd9Sstevel@tonic-gate secpolicy_fs_mount(cred_t *cr, vnode_t *mvp, struct vfs *vfsp) 5917c478bd9Sstevel@tonic-gate { 5927c478bd9Sstevel@tonic-gate boolean_t needoptchk; 5937c478bd9Sstevel@tonic-gate int error; 5947c478bd9Sstevel@tonic-gate 595dc7ca608Scasper /* 596dc7ca608Scasper * If it's a remount, get the underlying mount point, 597dc7ca608Scasper * except for the root where we use the rootvp. 598dc7ca608Scasper */ 599dc7ca608Scasper if ((vfsp->vfs_flag & VFS_REMOUNT) != 0) { 600dc7ca608Scasper if (vfsp == rootvfs) 601dc7ca608Scasper mvp = rootvp; 602dc7ca608Scasper else 603dc7ca608Scasper mvp = vfsp->vfs_vnodecovered; 604dc7ca608Scasper } 605dc7ca608Scasper 6067c478bd9Sstevel@tonic-gate error = secpolicy_fs_common(cr, mvp, vfsp, &needoptchk); 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate if (error == 0 && needoptchk) { 6097c478bd9Sstevel@tonic-gate boolean_t amsuper = HAS_ALLZONEPRIVS(cr); 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate /* 6127c478bd9Sstevel@tonic-gate * Third check; if we don't have either "nosuid" or 6137c478bd9Sstevel@tonic-gate * both "nosetuid" and "nodevices", then we add 6147c478bd9Sstevel@tonic-gate * "nosuid"; this depends on how the current 6157c478bd9Sstevel@tonic-gate * implementation works (it first checks nosuid). In a 6167c478bd9Sstevel@tonic-gate * zone, a user with all zone privileges can mount with 6177c478bd9Sstevel@tonic-gate * "setuid" but never with "devices". 6187c478bd9Sstevel@tonic-gate */ 6197c478bd9Sstevel@tonic-gate if (!vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL) && 6207c478bd9Sstevel@tonic-gate (!vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL) || 6217c478bd9Sstevel@tonic-gate !vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL))) { 6227c478bd9Sstevel@tonic-gate if (crgetzoneid(cr) == GLOBAL_ZONEID || !amsuper) 6237c478bd9Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_NOSUID, NULL, 0); 6247c478bd9Sstevel@tonic-gate else 6257c478bd9Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_NODEVICES, NULL, 0); 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate /* 6287c478bd9Sstevel@tonic-gate * If we're not the local super user, we set the "restrict" 6297c478bd9Sstevel@tonic-gate * option to indicate to automountd that this mount should 6307c478bd9Sstevel@tonic-gate * be handled with care. 6317c478bd9Sstevel@tonic-gate */ 6327c478bd9Sstevel@tonic-gate if (!amsuper) 6337c478bd9Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_RESTRICT, NULL, 0); 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate } 6367c478bd9Sstevel@tonic-gate return (error); 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate /* 6407c478bd9Sstevel@tonic-gate * Does the policy computations for "ownership" of a mount; 6417c478bd9Sstevel@tonic-gate * here ownership is defined as the ability to "mount" 6427c478bd9Sstevel@tonic-gate * the filesystem originally. The rootvfs doesn't cover any 6437c478bd9Sstevel@tonic-gate * vnodes; we attribute its ownership to the rootvp. 6447c478bd9Sstevel@tonic-gate */ 6457c478bd9Sstevel@tonic-gate static int 6467c478bd9Sstevel@tonic-gate secpolicy_fs_owner(cred_t *cr, const struct vfs *vfsp) 6477c478bd9Sstevel@tonic-gate { 6487c478bd9Sstevel@tonic-gate vnode_t *mvp; 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate if (vfsp == NULL) 6517c478bd9Sstevel@tonic-gate mvp = NULL; 6527c478bd9Sstevel@tonic-gate else if (vfsp == rootvfs) 6537c478bd9Sstevel@tonic-gate mvp = rootvp; 6547c478bd9Sstevel@tonic-gate else 6557c478bd9Sstevel@tonic-gate mvp = vfsp->vfs_vnodecovered; 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate return (secpolicy_fs_common(cr, mvp, vfsp, NULL)); 6587c478bd9Sstevel@tonic-gate } 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate int 6617c478bd9Sstevel@tonic-gate secpolicy_fs_unmount(cred_t *cr, struct vfs *vfsp) 6627c478bd9Sstevel@tonic-gate { 6637c478bd9Sstevel@tonic-gate return (secpolicy_fs_owner(cr, vfsp)); 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate /* 6677c478bd9Sstevel@tonic-gate * Quotas are a resource, but if one has the ability to mount a filesystem, he 6687c478bd9Sstevel@tonic-gate * should be able to modify quotas on it. 6697c478bd9Sstevel@tonic-gate */ 6707c478bd9Sstevel@tonic-gate int 6717c478bd9Sstevel@tonic-gate secpolicy_fs_quota(const cred_t *cr, const vfs_t *vfsp) 6727c478bd9Sstevel@tonic-gate { 6737c478bd9Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate /* 6777c478bd9Sstevel@tonic-gate * Exceeding minfree: also a per-mount resource constraint. 6787c478bd9Sstevel@tonic-gate */ 6797c478bd9Sstevel@tonic-gate int 6807c478bd9Sstevel@tonic-gate secpolicy_fs_minfree(const cred_t *cr, const vfs_t *vfsp) 6817c478bd9Sstevel@tonic-gate { 6827c478bd9Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate int 6867c478bd9Sstevel@tonic-gate secpolicy_fs_config(const cred_t *cr, const vfs_t *vfsp) 6877c478bd9Sstevel@tonic-gate { 6887c478bd9Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 6897c478bd9Sstevel@tonic-gate } 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate /* ARGSUSED */ 6927c478bd9Sstevel@tonic-gate int 6937c478bd9Sstevel@tonic-gate secpolicy_fs_linkdir(const cred_t *cr, const vfs_t *vfsp) 6947c478bd9Sstevel@tonic-gate { 6957c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_LINKDIR, B_FALSE, EPERM, NULL)); 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate /* 6997c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_access() 7007c478bd9Sstevel@tonic-gate * 7017c478bd9Sstevel@tonic-gate * Parameters: Process credential 7027c478bd9Sstevel@tonic-gate * vnode 7037c478bd9Sstevel@tonic-gate * uid of owner of vnode 7047c478bd9Sstevel@tonic-gate * permission bits not granted to the caller when examining 7057c478bd9Sstevel@tonic-gate * file mode bits (i.e., when a process wants to open a 7067c478bd9Sstevel@tonic-gate * mode 444 file for VREAD|VWRITE, this function should be 7077c478bd9Sstevel@tonic-gate * called only with a VWRITE argument). 7087c478bd9Sstevel@tonic-gate * 7097c478bd9Sstevel@tonic-gate * Normal: Verifies that cred has the appropriate privileges to 7107c478bd9Sstevel@tonic-gate * override the mode bits that were denied. 7117c478bd9Sstevel@tonic-gate * 7127c478bd9Sstevel@tonic-gate * Override: file_dac_execute - if VEXEC bit was denied and vnode is 7137c478bd9Sstevel@tonic-gate * not a directory. 7147c478bd9Sstevel@tonic-gate * file_dac_read - if VREAD bit was denied. 7157c478bd9Sstevel@tonic-gate * file_dac_search - if VEXEC bit was denied and vnode is 7167c478bd9Sstevel@tonic-gate * a directory. 7177c478bd9Sstevel@tonic-gate * file_dac_write - if VWRITE bit was denied. 7187c478bd9Sstevel@tonic-gate * 7197c478bd9Sstevel@tonic-gate * Root owned files are special cased to protect system 7207c478bd9Sstevel@tonic-gate * configuration files and such. 7217c478bd9Sstevel@tonic-gate * 7227c478bd9Sstevel@tonic-gate * Output: EACCES - if privilege check fails. 7237c478bd9Sstevel@tonic-gate */ 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate /* ARGSUSED */ 7267c478bd9Sstevel@tonic-gate int 7277c478bd9Sstevel@tonic-gate secpolicy_vnode_access(const cred_t *cr, vnode_t *vp, uid_t owner, mode_t mode) 7287c478bd9Sstevel@tonic-gate { 7297c478bd9Sstevel@tonic-gate if ((mode & VREAD) && 7307c478bd9Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_FILE_DAC_READ, B_FALSE, EACCES, NULL) != 0) 7317c478bd9Sstevel@tonic-gate return (EACCES); 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate if (mode & VWRITE) { 7347c478bd9Sstevel@tonic-gate boolean_t allzone; 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate if (owner == 0 && cr->cr_uid != 0) 7377c478bd9Sstevel@tonic-gate allzone = B_TRUE; 7387c478bd9Sstevel@tonic-gate else 7397c478bd9Sstevel@tonic-gate allzone = B_FALSE; 7407c478bd9Sstevel@tonic-gate if (PRIV_POLICY(cr, PRIV_FILE_DAC_WRITE, allzone, EACCES, NULL) 7417c478bd9Sstevel@tonic-gate != 0) 7427c478bd9Sstevel@tonic-gate return (EACCES); 7437c478bd9Sstevel@tonic-gate } 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate if (mode & VEXEC) { 7467c478bd9Sstevel@tonic-gate /* 7477c478bd9Sstevel@tonic-gate * Directories use file_dac_search to override the execute bit. 7487c478bd9Sstevel@tonic-gate */ 7497c478bd9Sstevel@tonic-gate vtype_t vtype = vp->v_type; 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate if (vtype == VDIR) 7527c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_DAC_SEARCH, B_FALSE, 7537c478bd9Sstevel@tonic-gate EACCES, NULL)); 7547c478bd9Sstevel@tonic-gate else 7557c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_DAC_EXECUTE, B_FALSE, 7567c478bd9Sstevel@tonic-gate EACCES, NULL)); 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate return (0); 7597c478bd9Sstevel@tonic-gate } 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate /* 7627c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_setid_modify() 7637c478bd9Sstevel@tonic-gate * 7647c478bd9Sstevel@tonic-gate * Normal: verify that subject can set the file setid flags. 7657c478bd9Sstevel@tonic-gate * 7667c478bd9Sstevel@tonic-gate * Output: EPERM - if not privileged. 7677c478bd9Sstevel@tonic-gate */ 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate static int 7707c478bd9Sstevel@tonic-gate secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner) 7717c478bd9Sstevel@tonic-gate { 7727c478bd9Sstevel@tonic-gate /* If changing to suid root, must have all zone privs */ 7737c478bd9Sstevel@tonic-gate boolean_t allzone = B_TRUE; 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate if (owner != 0) { 7767c478bd9Sstevel@tonic-gate if (owner == cr->cr_uid) 7777c478bd9Sstevel@tonic-gate return (0); 7787c478bd9Sstevel@tonic-gate allzone = B_FALSE; 7797c478bd9Sstevel@tonic-gate } 7807c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_SETID, allzone, EPERM, NULL)); 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate /* 7847c478bd9Sstevel@tonic-gate * Are we allowed to retain the set-uid/set-gid bits when 7857c478bd9Sstevel@tonic-gate * changing ownership or when writing to a file? 7867c478bd9Sstevel@tonic-gate * "issuid" should be true when set-uid; only in that case 7877c478bd9Sstevel@tonic-gate * root ownership is checked (setgid is assumed). 7887c478bd9Sstevel@tonic-gate */ 7897c478bd9Sstevel@tonic-gate int 7907c478bd9Sstevel@tonic-gate secpolicy_vnode_setid_retain(const cred_t *cred, boolean_t issuidroot) 7917c478bd9Sstevel@tonic-gate { 7927c478bd9Sstevel@tonic-gate if (issuidroot && !HAS_ALLZONEPRIVS(cred)) 7937c478bd9Sstevel@tonic-gate return (EPERM); 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate return (!PRIV_POLICY_CHOICE(cred, PRIV_FILE_SETID, B_FALSE)); 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate 7987c478bd9Sstevel@tonic-gate /* 7997c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_setids_setgids() 8007c478bd9Sstevel@tonic-gate * 8017c478bd9Sstevel@tonic-gate * Normal: verify that subject can set the file setgid flag. 8027c478bd9Sstevel@tonic-gate * 8037c478bd9Sstevel@tonic-gate * Output: EPERM - if not privileged 8047c478bd9Sstevel@tonic-gate */ 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate int 8077c478bd9Sstevel@tonic-gate secpolicy_vnode_setids_setgids(const cred_t *cred, gid_t gid) 8087c478bd9Sstevel@tonic-gate { 8097c478bd9Sstevel@tonic-gate if (!groupmember(gid, cred)) 8107c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_SETID, B_FALSE, EPERM, 8117c478bd9Sstevel@tonic-gate NULL)); 8127c478bd9Sstevel@tonic-gate return (0); 8137c478bd9Sstevel@tonic-gate } 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate /* 8167c478bd9Sstevel@tonic-gate * Create a file with a group different than any of the groups allowed: 8177c478bd9Sstevel@tonic-gate * the group of the directory the file is created in, the effective 8187c478bd9Sstevel@tonic-gate * group or any of the supplementary groups. 8197c478bd9Sstevel@tonic-gate */ 8207c478bd9Sstevel@tonic-gate int 8217c478bd9Sstevel@tonic-gate secpolicy_vnode_create_gid(const cred_t *cred) 8227c478bd9Sstevel@tonic-gate { 8237c478bd9Sstevel@tonic-gate if (HAS_PRIVILEGE(cred, PRIV_FILE_CHOWN)) 8247c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_CHOWN, B_FALSE, EPERM, 8257c478bd9Sstevel@tonic-gate NULL)); 8267c478bd9Sstevel@tonic-gate else 8277c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_CHOWN_SELF, B_FALSE, EPERM, 8287c478bd9Sstevel@tonic-gate NULL)); 8297c478bd9Sstevel@tonic-gate } 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate /* 8327c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_utime_modify() 8337c478bd9Sstevel@tonic-gate * 8347c478bd9Sstevel@tonic-gate * Normal: verify that subject can modify the utime on a file. 8357c478bd9Sstevel@tonic-gate * 8367c478bd9Sstevel@tonic-gate * Output: EPERM - if access denied. 8377c478bd9Sstevel@tonic-gate */ 8387c478bd9Sstevel@tonic-gate 8397c478bd9Sstevel@tonic-gate static int 8407c478bd9Sstevel@tonic-gate secpolicy_vnode_utime_modify(const cred_t *cred) 8417c478bd9Sstevel@tonic-gate { 8427c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_OWNER, B_FALSE, EPERM, 8437c478bd9Sstevel@tonic-gate "modify file times")); 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate /* 8487c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_setdac() 8497c478bd9Sstevel@tonic-gate * 8507c478bd9Sstevel@tonic-gate * Normal: verify that subject can modify the mode of a file. 8517c478bd9Sstevel@tonic-gate * allzone privilege needed when modifying root owned object. 8527c478bd9Sstevel@tonic-gate * 8537c478bd9Sstevel@tonic-gate * Output: EPERM - if access denied. 8547c478bd9Sstevel@tonic-gate */ 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate int 8577c478bd9Sstevel@tonic-gate secpolicy_vnode_setdac(const cred_t *cred, uid_t owner) 8587c478bd9Sstevel@tonic-gate { 8597c478bd9Sstevel@tonic-gate if (owner == cred->cr_uid) 8607c478bd9Sstevel@tonic-gate return (0); 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_OWNER, owner == 0, EPERM, NULL)); 8637c478bd9Sstevel@tonic-gate } 8647c478bd9Sstevel@tonic-gate /* 8657c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_stky_modify() 8667c478bd9Sstevel@tonic-gate * 8677c478bd9Sstevel@tonic-gate * Normal: verify that subject can make a file a "sticky". 8687c478bd9Sstevel@tonic-gate * 8697c478bd9Sstevel@tonic-gate * Output: EPERM - if access denied. 8707c478bd9Sstevel@tonic-gate */ 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate int 8737c478bd9Sstevel@tonic-gate secpolicy_vnode_stky_modify(const cred_t *cred) 8747c478bd9Sstevel@tonic-gate { 8757c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_SYS_CONFIG, B_FALSE, EPERM, 8767c478bd9Sstevel@tonic-gate "set file sticky")); 8777c478bd9Sstevel@tonic-gate } 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate /* 8807c478bd9Sstevel@tonic-gate * Policy determines whether we can remove an entry from a directory, 8817c478bd9Sstevel@tonic-gate * regardless of permission bits. 8827c478bd9Sstevel@tonic-gate */ 8837c478bd9Sstevel@tonic-gate int 8847c478bd9Sstevel@tonic-gate secpolicy_vnode_remove(const cred_t *cr) 8857c478bd9Sstevel@tonic-gate { 8867c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_OWNER, B_FALSE, EACCES, 8877c478bd9Sstevel@tonic-gate "sticky directory")); 8887c478bd9Sstevel@tonic-gate } 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate int 8917c478bd9Sstevel@tonic-gate secpolicy_vnode_owner(const cred_t *cr, uid_t owner) 8927c478bd9Sstevel@tonic-gate { 8937c478bd9Sstevel@tonic-gate boolean_t allzone = (owner == 0); 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate if (owner == cr->cr_uid) 8967c478bd9Sstevel@tonic-gate return (0); 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_OWNER, allzone, EPERM, NULL)); 8997c478bd9Sstevel@tonic-gate } 9007c478bd9Sstevel@tonic-gate 90113f9f30eSmarks void 90213f9f30eSmarks secpolicy_setid_clear(vattr_t *vap, cred_t *cr) 90313f9f30eSmarks { 90413f9f30eSmarks if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0 && 90513f9f30eSmarks secpolicy_vnode_setid_retain(cr, 90613f9f30eSmarks (vap->va_mode & S_ISUID) != 0 && 90713f9f30eSmarks (vap->va_mask & AT_UID) != 0 && vap->va_uid == 0) != 0) { 90813f9f30eSmarks vap->va_mask |= AT_MODE; 90913f9f30eSmarks vap->va_mode &= ~(S_ISUID|S_ISGID); 91013f9f30eSmarks } 91113f9f30eSmarks } 91213f9f30eSmarks 9137c478bd9Sstevel@tonic-gate /* 9147c478bd9Sstevel@tonic-gate * This function checks the policy decisions surrounding the 9157c478bd9Sstevel@tonic-gate * vop setattr call. 9167c478bd9Sstevel@tonic-gate * 9177c478bd9Sstevel@tonic-gate * It should be called after sufficient locks have been established 9187c478bd9Sstevel@tonic-gate * on the underlying data structures. No concurrent modifications 9197c478bd9Sstevel@tonic-gate * should be allowed. 9207c478bd9Sstevel@tonic-gate * 9217c478bd9Sstevel@tonic-gate * The caller must pass in unlocked version of its vaccess function 9227c478bd9Sstevel@tonic-gate * this is required because vop_access function should lock the 9237c478bd9Sstevel@tonic-gate * node for reading. A three argument function should be defined 9247c478bd9Sstevel@tonic-gate * which accepts the following argument: 9257c478bd9Sstevel@tonic-gate * A pointer to the internal "node" type (inode *) 9267c478bd9Sstevel@tonic-gate * vnode access bits (VREAD|VWRITE|VEXEC) 9277c478bd9Sstevel@tonic-gate * a pointer to the credential 9287c478bd9Sstevel@tonic-gate * 9297c478bd9Sstevel@tonic-gate * This function makes the following policy decisions: 9307c478bd9Sstevel@tonic-gate * 9317c478bd9Sstevel@tonic-gate * - change permissions 9327c478bd9Sstevel@tonic-gate * - permission to change file mode if not owner 9337c478bd9Sstevel@tonic-gate * - permission to add sticky bit to non-directory 9347c478bd9Sstevel@tonic-gate * - permission to add set-gid bit 9357c478bd9Sstevel@tonic-gate * 9367c478bd9Sstevel@tonic-gate * The ovap argument should include AT_MODE|AT_UID|AT_GID. 9377c478bd9Sstevel@tonic-gate * 9387c478bd9Sstevel@tonic-gate * If the vap argument does not include AT_MODE, the mode will be copied from 9397c478bd9Sstevel@tonic-gate * ovap. In certain situations set-uid/set-gid bits need to be removed; 9407c478bd9Sstevel@tonic-gate * this is done by marking vap->va_mask to include AT_MODE and va_mode 9417c478bd9Sstevel@tonic-gate * is updated to the newly computed mode. 9427c478bd9Sstevel@tonic-gate */ 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate int 9457c478bd9Sstevel@tonic-gate secpolicy_vnode_setattr(cred_t *cr, struct vnode *vp, struct vattr *vap, 9467c478bd9Sstevel@tonic-gate const struct vattr *ovap, int flags, 9477c478bd9Sstevel@tonic-gate int unlocked_access(void *, int, cred_t *), 9487c478bd9Sstevel@tonic-gate void *node) 9497c478bd9Sstevel@tonic-gate { 9507c478bd9Sstevel@tonic-gate int mask = vap->va_mask; 9517c478bd9Sstevel@tonic-gate int error = 0; 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate if (mask & AT_SIZE) { 9547c478bd9Sstevel@tonic-gate if (vp->v_type == VDIR) { 9557c478bd9Sstevel@tonic-gate error = EISDIR; 9567c478bd9Sstevel@tonic-gate goto out; 9577c478bd9Sstevel@tonic-gate } 9587c478bd9Sstevel@tonic-gate error = unlocked_access(node, VWRITE, cr); 9597c478bd9Sstevel@tonic-gate if (error) 9607c478bd9Sstevel@tonic-gate goto out; 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate if (mask & AT_MODE) { 9637c478bd9Sstevel@tonic-gate /* 9647c478bd9Sstevel@tonic-gate * If not the owner of the file then check privilege 9657c478bd9Sstevel@tonic-gate * for two things: the privilege to set the mode at all 9667c478bd9Sstevel@tonic-gate * and, if we're setting setuid, we also need permissions 9677c478bd9Sstevel@tonic-gate * to add the set-uid bit, if we're not the owner. 9687c478bd9Sstevel@tonic-gate * In the specific case of creating a set-uid root 9697c478bd9Sstevel@tonic-gate * file, we need even more permissions. 9707c478bd9Sstevel@tonic-gate */ 9717c478bd9Sstevel@tonic-gate if ((error = secpolicy_vnode_setdac(cr, ovap->va_uid)) != 0) 9727c478bd9Sstevel@tonic-gate goto out; 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate if ((vap->va_mode & S_ISUID) != 0 && 9757c478bd9Sstevel@tonic-gate (error = secpolicy_vnode_setid_modify(cr, 9767c478bd9Sstevel@tonic-gate ovap->va_uid)) != 0) { 9777c478bd9Sstevel@tonic-gate goto out; 9787c478bd9Sstevel@tonic-gate } 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate /* 9817c478bd9Sstevel@tonic-gate * Check privilege if attempting to set the 9827c478bd9Sstevel@tonic-gate * sticky bit on a non-directory. 9837c478bd9Sstevel@tonic-gate */ 9847c478bd9Sstevel@tonic-gate if (vp->v_type != VDIR && (vap->va_mode & S_ISVTX) != 0 && 9857c478bd9Sstevel@tonic-gate secpolicy_vnode_stky_modify(cr) != 0) { 9867c478bd9Sstevel@tonic-gate vap->va_mode &= ~S_ISVTX; 9877c478bd9Sstevel@tonic-gate } 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate /* 9907c478bd9Sstevel@tonic-gate * Check for privilege if attempting to set the 9917c478bd9Sstevel@tonic-gate * group-id bit. 9927c478bd9Sstevel@tonic-gate */ 9937c478bd9Sstevel@tonic-gate if ((vap->va_mode & S_ISGID) != 0 && 9947c478bd9Sstevel@tonic-gate secpolicy_vnode_setids_setgids(cr, ovap->va_gid) != 0) { 9957c478bd9Sstevel@tonic-gate vap->va_mode &= ~S_ISGID; 9967c478bd9Sstevel@tonic-gate } 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate } else 9997c478bd9Sstevel@tonic-gate vap->va_mode = ovap->va_mode; 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate if (mask & (AT_UID|AT_GID)) { 10027c478bd9Sstevel@tonic-gate boolean_t checkpriv = B_FALSE; 10037c478bd9Sstevel@tonic-gate int priv; 10047c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate /* 10077c478bd9Sstevel@tonic-gate * Chowning files. 10087c478bd9Sstevel@tonic-gate * 10097c478bd9Sstevel@tonic-gate * If you are the file owner: 10107c478bd9Sstevel@tonic-gate * chown to other uid FILE_CHOWN_SELF 10117c478bd9Sstevel@tonic-gate * chown to gid (non-member) FILE_CHOWN_SELF 10127c478bd9Sstevel@tonic-gate * chown to gid (member) <none> 10137c478bd9Sstevel@tonic-gate * 10147c478bd9Sstevel@tonic-gate * Instead of PRIV_FILE_CHOWN_SELF, FILE_CHOWN is also 10157c478bd9Sstevel@tonic-gate * acceptable but the first one is reported when debugging. 10167c478bd9Sstevel@tonic-gate * 10177c478bd9Sstevel@tonic-gate * If you are not the file owner: 10187c478bd9Sstevel@tonic-gate * chown from root PRIV_FILE_CHOWN + zone 10197c478bd9Sstevel@tonic-gate * chown from other to any PRIV_FILE_CHOWN 10207c478bd9Sstevel@tonic-gate * 10217c478bd9Sstevel@tonic-gate */ 10227c478bd9Sstevel@tonic-gate if (cr->cr_uid != ovap->va_uid) { 10237c478bd9Sstevel@tonic-gate checkpriv = B_TRUE; 10247c478bd9Sstevel@tonic-gate allzone = (ovap->va_uid == 0); 10257c478bd9Sstevel@tonic-gate priv = PRIV_FILE_CHOWN; 10267c478bd9Sstevel@tonic-gate } else { 10277c478bd9Sstevel@tonic-gate if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || 10287c478bd9Sstevel@tonic-gate ((mask & AT_GID) && vap->va_gid != ovap->va_gid && 10297c478bd9Sstevel@tonic-gate !groupmember(vap->va_gid, cr))) { 10307c478bd9Sstevel@tonic-gate checkpriv = B_TRUE; 10317c478bd9Sstevel@tonic-gate priv = HAS_PRIVILEGE(cr, PRIV_FILE_CHOWN) ? 10327c478bd9Sstevel@tonic-gate PRIV_FILE_CHOWN : PRIV_FILE_CHOWN_SELF; 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate } 10357c478bd9Sstevel@tonic-gate /* 10367c478bd9Sstevel@tonic-gate * If necessary, check privilege to see if update can be done. 10377c478bd9Sstevel@tonic-gate */ 10387c478bd9Sstevel@tonic-gate if (checkpriv && 10397c478bd9Sstevel@tonic-gate (error = PRIV_POLICY(cr, priv, allzone, EPERM, NULL)) 10407c478bd9Sstevel@tonic-gate != 0) { 10417c478bd9Sstevel@tonic-gate goto out; 10427c478bd9Sstevel@tonic-gate } 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate /* 10457c478bd9Sstevel@tonic-gate * If the file has either the set UID or set GID bits 10467c478bd9Sstevel@tonic-gate * set and the caller can set the bits, then leave them. 10477c478bd9Sstevel@tonic-gate */ 104813f9f30eSmarks secpolicy_setid_clear(vap, cr); 10497c478bd9Sstevel@tonic-gate } 10507c478bd9Sstevel@tonic-gate if (mask & (AT_ATIME|AT_MTIME)) { 10517c478bd9Sstevel@tonic-gate /* 10527c478bd9Sstevel@tonic-gate * If not the file owner and not otherwise privileged, 10537c478bd9Sstevel@tonic-gate * always return an error when setting the 10547c478bd9Sstevel@tonic-gate * time other than the current (ATTR_UTIME flag set). 10557c478bd9Sstevel@tonic-gate * If setting the current time (ATTR_UTIME not set) then 10567c478bd9Sstevel@tonic-gate * unlocked_access will check permissions according to policy. 10577c478bd9Sstevel@tonic-gate */ 10587c478bd9Sstevel@tonic-gate if (cr->cr_uid != ovap->va_uid) { 10597c478bd9Sstevel@tonic-gate if (flags & ATTR_UTIME) 10607c478bd9Sstevel@tonic-gate error = secpolicy_vnode_utime_modify(cr); 10617c478bd9Sstevel@tonic-gate else { 10627c478bd9Sstevel@tonic-gate error = unlocked_access(node, VWRITE, cr); 10637c478bd9Sstevel@tonic-gate if (error == EACCES && 10647c478bd9Sstevel@tonic-gate secpolicy_vnode_utime_modify(cr) == 0) 10657c478bd9Sstevel@tonic-gate error = 0; 10667c478bd9Sstevel@tonic-gate } 10677c478bd9Sstevel@tonic-gate if (error) 10687c478bd9Sstevel@tonic-gate goto out; 10697c478bd9Sstevel@tonic-gate } 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate out: 10727c478bd9Sstevel@tonic-gate return (error); 10737c478bd9Sstevel@tonic-gate } 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate /* 10767c478bd9Sstevel@tonic-gate * Name: secpolicy_pcfs_modify_bootpartition() 10777c478bd9Sstevel@tonic-gate * 10787c478bd9Sstevel@tonic-gate * Normal: verify that subject can modify a pcfs boot partition. 10797c478bd9Sstevel@tonic-gate * 10807c478bd9Sstevel@tonic-gate * Output: EACCES - if privilege check failed. 10817c478bd9Sstevel@tonic-gate */ 10827c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10837c478bd9Sstevel@tonic-gate int 10847c478bd9Sstevel@tonic-gate secpolicy_pcfs_modify_bootpartition(const cred_t *cred) 10857c478bd9Sstevel@tonic-gate { 10867c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_ALL, B_FALSE, EACCES, 10877c478bd9Sstevel@tonic-gate "modify pcfs boot partition")); 10887c478bd9Sstevel@tonic-gate } 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate /* 10917c478bd9Sstevel@tonic-gate * System V IPC routines 10927c478bd9Sstevel@tonic-gate */ 10937c478bd9Sstevel@tonic-gate int 10947c478bd9Sstevel@tonic-gate secpolicy_ipc_owner(const cred_t *cr, const struct kipc_perm *ip) 10957c478bd9Sstevel@tonic-gate { 10967c478bd9Sstevel@tonic-gate if (crgetzoneid(cr) != ip->ipc_zoneid || 10977c478bd9Sstevel@tonic-gate (cr->cr_uid != ip->ipc_uid && cr->cr_uid != ip->ipc_cuid)) { 10987c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 10997c478bd9Sstevel@tonic-gate if (ip->ipc_uid == 0 || ip->ipc_cuid == 0) 11007c478bd9Sstevel@tonic-gate allzone = B_TRUE; 11017c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_OWNER, allzone, EPERM, NULL)); 11027c478bd9Sstevel@tonic-gate } 11037c478bd9Sstevel@tonic-gate return (0); 11047c478bd9Sstevel@tonic-gate } 11057c478bd9Sstevel@tonic-gate 11067c478bd9Sstevel@tonic-gate int 11077c478bd9Sstevel@tonic-gate secpolicy_ipc_config(const cred_t *cr) 11087c478bd9Sstevel@tonic-gate { 11097c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_IPC_CONFIG, B_FALSE, EPERM, NULL)); 11107c478bd9Sstevel@tonic-gate } 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate int 11137c478bd9Sstevel@tonic-gate secpolicy_ipc_access(const cred_t *cr, const struct kipc_perm *ip, mode_t mode) 11147c478bd9Sstevel@tonic-gate { 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 11177c478bd9Sstevel@tonic-gate 11187c478bd9Sstevel@tonic-gate ASSERT((mode & (MSG_R|MSG_W)) != 0); 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate if ((mode & MSG_R) && 11217c478bd9Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_IPC_DAC_READ, allzone, EACCES, NULL) != 0) 11227c478bd9Sstevel@tonic-gate return (EACCES); 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate if (mode & MSG_W) { 11257c478bd9Sstevel@tonic-gate if (cr->cr_uid != 0 && (ip->ipc_uid == 0 || ip->ipc_cuid == 0)) 11267c478bd9Sstevel@tonic-gate allzone = B_TRUE; 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_DAC_WRITE, allzone, EACCES, 11297c478bd9Sstevel@tonic-gate NULL)); 11307c478bd9Sstevel@tonic-gate } 11317c478bd9Sstevel@tonic-gate return (0); 11327c478bd9Sstevel@tonic-gate } 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate int 11357c478bd9Sstevel@tonic-gate secpolicy_rsm_access(const cred_t *cr, uid_t owner, mode_t mode) 11367c478bd9Sstevel@tonic-gate { 11377c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate ASSERT((mode & (MSG_R|MSG_W)) != 0); 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate if ((mode & MSG_R) && 11427c478bd9Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_IPC_DAC_READ, allzone, EACCES, NULL) != 0) 11437c478bd9Sstevel@tonic-gate return (EACCES); 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate if (mode & MSG_W) { 11467c478bd9Sstevel@tonic-gate if (cr->cr_uid != 0 && owner == 0) 11477c478bd9Sstevel@tonic-gate allzone = B_TRUE; 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_DAC_WRITE, allzone, EACCES, 11507c478bd9Sstevel@tonic-gate NULL)); 11517c478bd9Sstevel@tonic-gate } 11527c478bd9Sstevel@tonic-gate return (0); 11537c478bd9Sstevel@tonic-gate } 11547c478bd9Sstevel@tonic-gate 11557c478bd9Sstevel@tonic-gate /* 11567c478bd9Sstevel@tonic-gate * Audit configuration. 11577c478bd9Sstevel@tonic-gate */ 11587c478bd9Sstevel@tonic-gate int 11597c478bd9Sstevel@tonic-gate secpolicy_audit_config(const cred_t *cr) 11607c478bd9Sstevel@tonic-gate { 11617c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_AUDIT, B_FALSE, EPERM, NULL)); 11627c478bd9Sstevel@tonic-gate } 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate /* 11657c478bd9Sstevel@tonic-gate * Audit record generation. 11667c478bd9Sstevel@tonic-gate */ 11677c478bd9Sstevel@tonic-gate int 11687c478bd9Sstevel@tonic-gate secpolicy_audit_modify(const cred_t *cr) 11697c478bd9Sstevel@tonic-gate { 11707c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_AUDIT, B_FALSE, EPERM, NULL)); 11717c478bd9Sstevel@tonic-gate } 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate /* 11747c478bd9Sstevel@tonic-gate * Get audit attributes. 11757c478bd9Sstevel@tonic-gate * Either PRIV_SYS_AUDIT or PRIV_PROC_AUDIT required; report the 11767c478bd9Sstevel@tonic-gate * "Least" of the two privileges on error. 11777c478bd9Sstevel@tonic-gate */ 11787c478bd9Sstevel@tonic-gate int 11797c478bd9Sstevel@tonic-gate secpolicy_audit_getattr(const cred_t *cr) 11807c478bd9Sstevel@tonic-gate { 11817c478bd9Sstevel@tonic-gate if (!PRIV_POLICY_ONLY(cr, PRIV_SYS_AUDIT, B_FALSE)) { 11827c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_AUDIT, B_FALSE, EPERM, 11837c478bd9Sstevel@tonic-gate NULL)); 11847c478bd9Sstevel@tonic-gate } else { 11857c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_AUDIT, B_FALSE, EPERM, NULL)); 11867c478bd9Sstevel@tonic-gate } 11877c478bd9Sstevel@tonic-gate } 11887c478bd9Sstevel@tonic-gate 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate /* 11917c478bd9Sstevel@tonic-gate * Locking physical memory 11927c478bd9Sstevel@tonic-gate */ 11937c478bd9Sstevel@tonic-gate int 11947c478bd9Sstevel@tonic-gate secpolicy_lock_memory(const cred_t *cr) 11957c478bd9Sstevel@tonic-gate { 11967c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_LOCK_MEMORY, B_FALSE, EPERM, NULL)); 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate /* 12007c478bd9Sstevel@tonic-gate * Accounting (both acct(2) and exacct). 12017c478bd9Sstevel@tonic-gate */ 12027c478bd9Sstevel@tonic-gate int 12037c478bd9Sstevel@tonic-gate secpolicy_acct(const cred_t *cr) 12047c478bd9Sstevel@tonic-gate { 12057c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ACCT, B_FALSE, EPERM, NULL)); 12067c478bd9Sstevel@tonic-gate } 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate /* 12097c478bd9Sstevel@tonic-gate * Is this process privileged to change its uids at will? 12107c478bd9Sstevel@tonic-gate * Uid 0 is still considered "special" and having the SETID 12117c478bd9Sstevel@tonic-gate * privilege is not sufficient to get uid 0. 12127c478bd9Sstevel@tonic-gate * Files are owned by root, so the privilege would give 12137c478bd9Sstevel@tonic-gate * full access and euid 0 is still effective. 12147c478bd9Sstevel@tonic-gate * 12157c478bd9Sstevel@tonic-gate * If you have the privilege and euid 0 only then do you 12167c478bd9Sstevel@tonic-gate * get the powers of root wrt uid 0. 12177c478bd9Sstevel@tonic-gate * 12187c478bd9Sstevel@tonic-gate * For gid manipulations, this is should be called with an 12197c478bd9Sstevel@tonic-gate * uid of -1. 12207c478bd9Sstevel@tonic-gate * 12217c478bd9Sstevel@tonic-gate */ 12227c478bd9Sstevel@tonic-gate int 12237c478bd9Sstevel@tonic-gate secpolicy_allow_setid(const cred_t *cr, uid_t newuid, boolean_t checkonly) 12247c478bd9Sstevel@tonic-gate { 12257c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate if (newuid == 0 && cr->cr_uid != 0 && cr->cr_suid != 0 && 12287c478bd9Sstevel@tonic-gate cr->cr_ruid != 0) { 12297c478bd9Sstevel@tonic-gate allzone = B_TRUE; 12307c478bd9Sstevel@tonic-gate } 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate return (checkonly ? !PRIV_POLICY_ONLY(cr, PRIV_PROC_SETID, allzone) : 12337c478bd9Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_PROC_SETID, allzone, EPERM, NULL)); 12347c478bd9Sstevel@tonic-gate } 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate 12377c478bd9Sstevel@tonic-gate /* 12387c478bd9Sstevel@tonic-gate * Acting on a different process: if the mode is for writing, 12397c478bd9Sstevel@tonic-gate * the restrictions are more severe. This is called after 12407c478bd9Sstevel@tonic-gate * we've verified that the uids do not match. 12417c478bd9Sstevel@tonic-gate */ 12427c478bd9Sstevel@tonic-gate int 12437c478bd9Sstevel@tonic-gate secpolicy_proc_owner(const cred_t *scr, const cred_t *tcr, int mode) 12447c478bd9Sstevel@tonic-gate { 12457c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 12467c478bd9Sstevel@tonic-gate 12477c478bd9Sstevel@tonic-gate if ((mode & VWRITE) && scr->cr_uid != 0 && 12487c478bd9Sstevel@tonic-gate (tcr->cr_uid == 0 || tcr->cr_ruid == 0 || tcr->cr_suid == 0)) 12497c478bd9Sstevel@tonic-gate allzone = B_TRUE; 12507c478bd9Sstevel@tonic-gate 12517c478bd9Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, allzone, EPERM, NULL)); 12527c478bd9Sstevel@tonic-gate } 12537c478bd9Sstevel@tonic-gate 12547c478bd9Sstevel@tonic-gate int 12557c478bd9Sstevel@tonic-gate secpolicy_proc_access(const cred_t *scr) 12567c478bd9Sstevel@tonic-gate { 12577c478bd9Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, B_FALSE, EACCES, NULL)); 12587c478bd9Sstevel@tonic-gate } 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate int 12617c478bd9Sstevel@tonic-gate secpolicy_proc_excl_open(const cred_t *scr) 12627c478bd9Sstevel@tonic-gate { 12637c478bd9Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, B_FALSE, EBUSY, NULL)); 12647c478bd9Sstevel@tonic-gate } 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate int 12677c478bd9Sstevel@tonic-gate secpolicy_proc_zone(const cred_t *scr) 12687c478bd9Sstevel@tonic-gate { 12697c478bd9Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_ZONE, B_FALSE, EPERM, NULL)); 12707c478bd9Sstevel@tonic-gate } 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate /* 12737c478bd9Sstevel@tonic-gate * Destroying the system 12747c478bd9Sstevel@tonic-gate */ 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate int 12777c478bd9Sstevel@tonic-gate secpolicy_kmdb(const cred_t *scr) 12787c478bd9Sstevel@tonic-gate { 12797c478bd9Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); 12807c478bd9Sstevel@tonic-gate } 12817c478bd9Sstevel@tonic-gate 1282*7aec1d6eScindi int 1283*7aec1d6eScindi secpolicy_error_inject(const cred_t *scr) 1284*7aec1d6eScindi { 1285*7aec1d6eScindi return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); 1286*7aec1d6eScindi } 1287*7aec1d6eScindi 12887c478bd9Sstevel@tonic-gate /* 12897c478bd9Sstevel@tonic-gate * Processor sets, cpu configuration, resource pools. 12907c478bd9Sstevel@tonic-gate */ 12917c478bd9Sstevel@tonic-gate int 12927c478bd9Sstevel@tonic-gate secpolicy_pset(const cred_t *cr) 12937c478bd9Sstevel@tonic-gate { 12947c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 12957c478bd9Sstevel@tonic-gate } 12967c478bd9Sstevel@tonic-gate 12977c478bd9Sstevel@tonic-gate int 12987c478bd9Sstevel@tonic-gate secpolicy_ponline(const cred_t *cr) 12997c478bd9Sstevel@tonic-gate { 13007c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 13017c478bd9Sstevel@tonic-gate } 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate int 13047c478bd9Sstevel@tonic-gate secpolicy_pool(const cred_t *cr) 13057c478bd9Sstevel@tonic-gate { 13067c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 13077c478bd9Sstevel@tonic-gate } 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate int 13107c478bd9Sstevel@tonic-gate secpolicy_blacklist(const cred_t *cr) 13117c478bd9Sstevel@tonic-gate { 13127c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 13137c478bd9Sstevel@tonic-gate } 13147c478bd9Sstevel@tonic-gate 13157c478bd9Sstevel@tonic-gate /* 13167c478bd9Sstevel@tonic-gate * Catch all system configuration. 13177c478bd9Sstevel@tonic-gate */ 13187c478bd9Sstevel@tonic-gate int 13197c478bd9Sstevel@tonic-gate secpolicy_sys_config(const cred_t *cr, boolean_t checkonly) 13207c478bd9Sstevel@tonic-gate { 13217c478bd9Sstevel@tonic-gate if (checkonly) { 13227c478bd9Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_CONFIG, B_FALSE) ? 0 : 13237c478bd9Sstevel@tonic-gate EPERM); 13247c478bd9Sstevel@tonic-gate } else { 13257c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 13267c478bd9Sstevel@tonic-gate } 13277c478bd9Sstevel@tonic-gate } 13287c478bd9Sstevel@tonic-gate 13297c478bd9Sstevel@tonic-gate /* 13307c478bd9Sstevel@tonic-gate * Zone administration (halt, reboot, etc.) from within zone. 13317c478bd9Sstevel@tonic-gate */ 13327c478bd9Sstevel@tonic-gate int 13337c478bd9Sstevel@tonic-gate secpolicy_zone_admin(const cred_t *cr, boolean_t checkonly) 13347c478bd9Sstevel@tonic-gate { 13357c478bd9Sstevel@tonic-gate if (checkonly) { 13367c478bd9Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_ADMIN, B_FALSE) ? 0 : 13377c478bd9Sstevel@tonic-gate EPERM); 13387c478bd9Sstevel@tonic-gate } else { 13397c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, 13407c478bd9Sstevel@tonic-gate NULL)); 13417c478bd9Sstevel@tonic-gate } 13427c478bd9Sstevel@tonic-gate } 13437c478bd9Sstevel@tonic-gate 13447c478bd9Sstevel@tonic-gate /* 13457c478bd9Sstevel@tonic-gate * Zone configuration (create, halt, enter). 13467c478bd9Sstevel@tonic-gate */ 13477c478bd9Sstevel@tonic-gate int 13487c478bd9Sstevel@tonic-gate secpolicy_zone_config(const cred_t *cr) 13497c478bd9Sstevel@tonic-gate { 13507c478bd9Sstevel@tonic-gate /* 13517c478bd9Sstevel@tonic-gate * Require all privileges to avoid possibility of privilege 13527c478bd9Sstevel@tonic-gate * escalation. 13537c478bd9Sstevel@tonic-gate */ 13547c478bd9Sstevel@tonic-gate return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); 13557c478bd9Sstevel@tonic-gate } 13567c478bd9Sstevel@tonic-gate 13577c478bd9Sstevel@tonic-gate /* 13587c478bd9Sstevel@tonic-gate * Various other system configuration calls 13597c478bd9Sstevel@tonic-gate */ 13607c478bd9Sstevel@tonic-gate int 13617c478bd9Sstevel@tonic-gate secpolicy_coreadm(const cred_t *cr) 13627c478bd9Sstevel@tonic-gate { 13637c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, NULL)); 13647c478bd9Sstevel@tonic-gate } 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate int 13677c478bd9Sstevel@tonic-gate secpolicy_systeminfo(const cred_t *cr) 13687c478bd9Sstevel@tonic-gate { 13697c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, NULL)); 13707c478bd9Sstevel@tonic-gate } 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate int 13737c478bd9Sstevel@tonic-gate secpolicy_dispadm(const cred_t *cr) 13747c478bd9Sstevel@tonic-gate { 13757c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 13767c478bd9Sstevel@tonic-gate } 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate int 13797c478bd9Sstevel@tonic-gate secpolicy_settime(const cred_t *cr) 13807c478bd9Sstevel@tonic-gate { 13817c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_TIME, B_FALSE, EPERM, NULL)); 13827c478bd9Sstevel@tonic-gate } 13837c478bd9Sstevel@tonic-gate 13847c478bd9Sstevel@tonic-gate /* 13857c478bd9Sstevel@tonic-gate * For realtime users: high resolution clock. 13867c478bd9Sstevel@tonic-gate */ 13877c478bd9Sstevel@tonic-gate int 13887c478bd9Sstevel@tonic-gate secpolicy_clock_highres(const cred_t *cr) 13897c478bd9Sstevel@tonic-gate { 13907c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_CLOCK_HIGHRES, B_FALSE, EPERM, 13917c478bd9Sstevel@tonic-gate NULL)); 13927c478bd9Sstevel@tonic-gate } 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate /* 13957c478bd9Sstevel@tonic-gate * drv_priv() is documented as callable from interrupt context, not that 13967c478bd9Sstevel@tonic-gate * anyone ever does, but still. No debugging or auditing can be done when 13977c478bd9Sstevel@tonic-gate * it is called from interrupt context. 13987c478bd9Sstevel@tonic-gate * returns 0 on succes, EPERM on failure. 13997c478bd9Sstevel@tonic-gate */ 14007c478bd9Sstevel@tonic-gate int 14017c478bd9Sstevel@tonic-gate drv_priv(cred_t *cr) 14027c478bd9Sstevel@tonic-gate { 14037c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 14047c478bd9Sstevel@tonic-gate } 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate int 14077c478bd9Sstevel@tonic-gate secpolicy_sys_devices(const cred_t *cr) 14087c478bd9Sstevel@tonic-gate { 14097c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 14107c478bd9Sstevel@tonic-gate } 14117c478bd9Sstevel@tonic-gate 14127c478bd9Sstevel@tonic-gate int 14137c478bd9Sstevel@tonic-gate secpolicy_excl_open(const cred_t *cr) 14147c478bd9Sstevel@tonic-gate { 14157c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EBUSY, NULL)); 14167c478bd9Sstevel@tonic-gate } 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate int 14197c478bd9Sstevel@tonic-gate secpolicy_rctlsys(const cred_t *cr, boolean_t is_zone_rctl) 14207c478bd9Sstevel@tonic-gate { 14217c478bd9Sstevel@tonic-gate /* zone.* rctls can only be set from the global zone */ 14227c478bd9Sstevel@tonic-gate if (is_zone_rctl && priv_policy_global(cr) != 0) 14237c478bd9Sstevel@tonic-gate return (EPERM); 14247c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 14257c478bd9Sstevel@tonic-gate } 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate int 14287c478bd9Sstevel@tonic-gate secpolicy_resource(const cred_t *cr) 14297c478bd9Sstevel@tonic-gate { 14307c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 14317c478bd9Sstevel@tonic-gate } 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate /* 14347c478bd9Sstevel@tonic-gate * Processes with a real uid of 0 escape any form of accounting, much 14357c478bd9Sstevel@tonic-gate * like before. 14367c478bd9Sstevel@tonic-gate */ 14377c478bd9Sstevel@tonic-gate int 14387c478bd9Sstevel@tonic-gate secpolicy_newproc(const cred_t *cr) 14397c478bd9Sstevel@tonic-gate { 14407c478bd9Sstevel@tonic-gate if (cr->cr_ruid == 0) 14417c478bd9Sstevel@tonic-gate return (0); 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 14447c478bd9Sstevel@tonic-gate } 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate /* 14477c478bd9Sstevel@tonic-gate * Networking 14487c478bd9Sstevel@tonic-gate */ 14497c478bd9Sstevel@tonic-gate int 14507c478bd9Sstevel@tonic-gate secpolicy_net_rawaccess(const cred_t *cr) 14517c478bd9Sstevel@tonic-gate { 14527c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_NET_RAWACCESS, B_FALSE, EACCES, NULL)); 14537c478bd9Sstevel@tonic-gate } 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate /* 14567c478bd9Sstevel@tonic-gate * Need this privilege for accessing the ICMP device 14577c478bd9Sstevel@tonic-gate */ 14587c478bd9Sstevel@tonic-gate int 14597c478bd9Sstevel@tonic-gate secpolicy_net_icmpaccess(const cred_t *cr) 14607c478bd9Sstevel@tonic-gate { 14617c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_NET_ICMPACCESS, B_FALSE, EACCES, NULL)); 14627c478bd9Sstevel@tonic-gate } 14637c478bd9Sstevel@tonic-gate 14647c478bd9Sstevel@tonic-gate /* 14657c478bd9Sstevel@tonic-gate * There are a few rare cases where the kernel generates ioctls() from 14667c478bd9Sstevel@tonic-gate * interrupt context with a credential of kcred rather than NULL. 14677c478bd9Sstevel@tonic-gate * In those cases, we take the safe and cheap test. 14687c478bd9Sstevel@tonic-gate */ 14697c478bd9Sstevel@tonic-gate int 14707c478bd9Sstevel@tonic-gate secpolicy_net_config(const cred_t *cr, boolean_t checkonly) 14717c478bd9Sstevel@tonic-gate { 14727c478bd9Sstevel@tonic-gate if (checkonly) { 14737c478bd9Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE) ? 14747c478bd9Sstevel@tonic-gate 0 : EPERM); 14757c478bd9Sstevel@tonic-gate } else { 14767c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_NET_CONFIG, B_FALSE, EPERM, 14777c478bd9Sstevel@tonic-gate NULL)); 14787c478bd9Sstevel@tonic-gate } 14797c478bd9Sstevel@tonic-gate } 14807c478bd9Sstevel@tonic-gate 14817c478bd9Sstevel@tonic-gate 14827c478bd9Sstevel@tonic-gate /* 14837c478bd9Sstevel@tonic-gate * Map network pseudo privileges to actual privileges. 14847c478bd9Sstevel@tonic-gate * So we don't need to recompile IP when we change the privileges. 14857c478bd9Sstevel@tonic-gate */ 14867c478bd9Sstevel@tonic-gate int 14877c478bd9Sstevel@tonic-gate secpolicy_net(const cred_t *cr, int netpriv, boolean_t checkonly) 14887c478bd9Sstevel@tonic-gate { 14897c478bd9Sstevel@tonic-gate int priv = PRIV_ALL; 14907c478bd9Sstevel@tonic-gate 14917c478bd9Sstevel@tonic-gate switch (netpriv) { 14927c478bd9Sstevel@tonic-gate case OP_CONFIG: 14937c478bd9Sstevel@tonic-gate priv = PRIV_SYS_NET_CONFIG; 14947c478bd9Sstevel@tonic-gate break; 14957c478bd9Sstevel@tonic-gate case OP_RAW: 14967c478bd9Sstevel@tonic-gate priv = PRIV_NET_RAWACCESS; 14977c478bd9Sstevel@tonic-gate break; 14987c478bd9Sstevel@tonic-gate case OP_PRIVPORT: 14997c478bd9Sstevel@tonic-gate priv = PRIV_NET_PRIVADDR; 15007c478bd9Sstevel@tonic-gate break; 15017c478bd9Sstevel@tonic-gate } 15027c478bd9Sstevel@tonic-gate ASSERT(priv != PRIV_ALL); 15037c478bd9Sstevel@tonic-gate if (checkonly) 15047c478bd9Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, priv, B_FALSE) ? 0 : EPERM); 15057c478bd9Sstevel@tonic-gate else 15067c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, priv, B_FALSE, EPERM, NULL)); 15077c478bd9Sstevel@tonic-gate } 15087c478bd9Sstevel@tonic-gate 15097c478bd9Sstevel@tonic-gate /* 15107c478bd9Sstevel@tonic-gate * Checks for operations that are either client-only or are used by 15117c478bd9Sstevel@tonic-gate * both clients and servers. 15127c478bd9Sstevel@tonic-gate */ 15137c478bd9Sstevel@tonic-gate int 15147c478bd9Sstevel@tonic-gate secpolicy_nfs(const cred_t *cr) 15157c478bd9Sstevel@tonic-gate { 15167c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_NFS, B_FALSE, EPERM, NULL)); 15177c478bd9Sstevel@tonic-gate } 15187c478bd9Sstevel@tonic-gate 15197c478bd9Sstevel@tonic-gate /* 15207c478bd9Sstevel@tonic-gate * Special case for opening rpcmod: have NFS privileges or network 15217c478bd9Sstevel@tonic-gate * config privileges. 15227c478bd9Sstevel@tonic-gate */ 15237c478bd9Sstevel@tonic-gate int 15247c478bd9Sstevel@tonic-gate secpolicy_rpcmod_open(const cred_t *cr) 15257c478bd9Sstevel@tonic-gate { 15267c478bd9Sstevel@tonic-gate if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NFS, B_FALSE)) 15277c478bd9Sstevel@tonic-gate return (secpolicy_nfs(cr)); 15287c478bd9Sstevel@tonic-gate else 15297c478bd9Sstevel@tonic-gate return (secpolicy_net_config(cr, NULL)); 15307c478bd9Sstevel@tonic-gate } 15317c478bd9Sstevel@tonic-gate 15327c478bd9Sstevel@tonic-gate int 15337c478bd9Sstevel@tonic-gate secpolicy_chroot(const cred_t *cr) 15347c478bd9Sstevel@tonic-gate { 15357c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_CHROOT, B_FALSE, EPERM, NULL)); 15367c478bd9Sstevel@tonic-gate } 15377c478bd9Sstevel@tonic-gate 15387c478bd9Sstevel@tonic-gate int 15397c478bd9Sstevel@tonic-gate secpolicy_tasksys(const cred_t *cr) 15407c478bd9Sstevel@tonic-gate { 15417c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_TASKID, B_FALSE, EPERM, NULL)); 15427c478bd9Sstevel@tonic-gate } 15437c478bd9Sstevel@tonic-gate 15447c478bd9Sstevel@tonic-gate /* 15457c478bd9Sstevel@tonic-gate * Basic privilege checks. 15467c478bd9Sstevel@tonic-gate */ 15477c478bd9Sstevel@tonic-gate int 15487c478bd9Sstevel@tonic-gate secpolicy_basic_exec(const cred_t *cr) 15497c478bd9Sstevel@tonic-gate { 15507c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_EXEC, B_FALSE, EPERM, NULL)); 15517c478bd9Sstevel@tonic-gate } 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate int 15547c478bd9Sstevel@tonic-gate secpolicy_basic_fork(const cred_t *cr) 15557c478bd9Sstevel@tonic-gate { 15567c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_FORK, B_FALSE, EPERM, NULL)); 15577c478bd9Sstevel@tonic-gate } 15587c478bd9Sstevel@tonic-gate 15597c478bd9Sstevel@tonic-gate int 15607c478bd9Sstevel@tonic-gate secpolicy_basic_proc(const cred_t *cr) 15617c478bd9Sstevel@tonic-gate { 15627c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_SESSION, B_FALSE, EPERM, NULL)); 15637c478bd9Sstevel@tonic-gate } 15647c478bd9Sstevel@tonic-gate 15657c478bd9Sstevel@tonic-gate /* 15667c478bd9Sstevel@tonic-gate * Slightly complicated because we don't want to trigger the policy too 15677c478bd9Sstevel@tonic-gate * often. First we shortcircuit access to "self" (tp == sp) or if 15687c478bd9Sstevel@tonic-gate * we don't have the privilege but if we have permission 15697c478bd9Sstevel@tonic-gate * just return (0) and we don't flag the privilege as needed. 15707c478bd9Sstevel@tonic-gate * Else, we test for the privilege because we either have it or need it. 15717c478bd9Sstevel@tonic-gate */ 15727c478bd9Sstevel@tonic-gate int 15737c478bd9Sstevel@tonic-gate secpolicy_basic_procinfo(const cred_t *cr, proc_t *tp, proc_t *sp) 15747c478bd9Sstevel@tonic-gate { 15757c478bd9Sstevel@tonic-gate if (tp == sp || 15767c478bd9Sstevel@tonic-gate !HAS_PRIVILEGE(cr, PRIV_PROC_INFO) && prochasprocperm(tp, sp, cr)) { 15777c478bd9Sstevel@tonic-gate return (0); 15787c478bd9Sstevel@tonic-gate } else { 15797c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_INFO, B_FALSE, EPERM, NULL)); 15807c478bd9Sstevel@tonic-gate } 15817c478bd9Sstevel@tonic-gate } 15827c478bd9Sstevel@tonic-gate 15837c478bd9Sstevel@tonic-gate int 15847c478bd9Sstevel@tonic-gate secpolicy_basic_link(const cred_t *cr) 15857c478bd9Sstevel@tonic-gate { 15867c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_LINK_ANY, B_FALSE, EPERM, NULL)); 15877c478bd9Sstevel@tonic-gate } 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate /* 15907c478bd9Sstevel@tonic-gate * Additional device protection. 15917c478bd9Sstevel@tonic-gate * 15927c478bd9Sstevel@tonic-gate * Traditionally, a device has specific permissions on the node in 15937c478bd9Sstevel@tonic-gate * the filesystem which govern which devices can be opened by what 15947c478bd9Sstevel@tonic-gate * processes. In certain cases, it is desirable to add extra 15957c478bd9Sstevel@tonic-gate * restrictions, as writing to certain devices is identical to 15967c478bd9Sstevel@tonic-gate * having a complete run of the system. 15977c478bd9Sstevel@tonic-gate * 15987c478bd9Sstevel@tonic-gate * This mechanism is called the device policy. 15997c478bd9Sstevel@tonic-gate * 16007c478bd9Sstevel@tonic-gate * When a device is opened, its policy entry is looked up in the 16017c478bd9Sstevel@tonic-gate * policy cache and checked. 16027c478bd9Sstevel@tonic-gate */ 16037c478bd9Sstevel@tonic-gate int 16047c478bd9Sstevel@tonic-gate secpolicy_spec_open(const cred_t *cr, struct vnode *vp, int oflag) 16057c478bd9Sstevel@tonic-gate { 16067c478bd9Sstevel@tonic-gate devplcy_t *plcy; 16077c478bd9Sstevel@tonic-gate int err; 16087c478bd9Sstevel@tonic-gate struct snode *csp = VTOS(common_specvp(vp)); 16097c478bd9Sstevel@tonic-gate 16107c478bd9Sstevel@tonic-gate mutex_enter(&csp->s_lock); 16117c478bd9Sstevel@tonic-gate 16127c478bd9Sstevel@tonic-gate if (csp->s_plcy == NULL || csp->s_plcy->dp_gen != devplcy_gen) { 16137c478bd9Sstevel@tonic-gate plcy = devpolicy_find(vp); 16147c478bd9Sstevel@tonic-gate if (csp->s_plcy) 16157c478bd9Sstevel@tonic-gate dpfree(csp->s_plcy); 16167c478bd9Sstevel@tonic-gate csp->s_plcy = plcy; 16177c478bd9Sstevel@tonic-gate ASSERT(plcy != NULL); 16187c478bd9Sstevel@tonic-gate } else 16197c478bd9Sstevel@tonic-gate plcy = csp->s_plcy; 16207c478bd9Sstevel@tonic-gate 16217c478bd9Sstevel@tonic-gate if (plcy == nullpolicy) { 16227c478bd9Sstevel@tonic-gate mutex_exit(&csp->s_lock); 16237c478bd9Sstevel@tonic-gate return (0); 16247c478bd9Sstevel@tonic-gate } 16257c478bd9Sstevel@tonic-gate 16267c478bd9Sstevel@tonic-gate dphold(plcy); 16277c478bd9Sstevel@tonic-gate 16287c478bd9Sstevel@tonic-gate mutex_exit(&csp->s_lock); 16297c478bd9Sstevel@tonic-gate 16307c478bd9Sstevel@tonic-gate err = secpolicy_require_set(cr, 16317c478bd9Sstevel@tonic-gate (oflag & FWRITE) ? &plcy->dp_wrp : &plcy->dp_rdp, "devpolicy"); 16327c478bd9Sstevel@tonic-gate dpfree(plcy); 16337c478bd9Sstevel@tonic-gate 16347c478bd9Sstevel@tonic-gate return (err); 16357c478bd9Sstevel@tonic-gate } 16367c478bd9Sstevel@tonic-gate 16377c478bd9Sstevel@tonic-gate int 16387c478bd9Sstevel@tonic-gate secpolicy_modctl(const cred_t *cr, int cmd) 16397c478bd9Sstevel@tonic-gate { 16407c478bd9Sstevel@tonic-gate switch (cmd) { 16417c478bd9Sstevel@tonic-gate case MODINFO: 16427c478bd9Sstevel@tonic-gate case MODGETPATH: 16437c478bd9Sstevel@tonic-gate case MODGETPATHLEN: 16447c478bd9Sstevel@tonic-gate case MODGETFBNAME: 16457c478bd9Sstevel@tonic-gate case MODGETNAME: 16467c478bd9Sstevel@tonic-gate case MODGETDEVPOLICY: 16477c478bd9Sstevel@tonic-gate case MODGETDEVPOLICYBYNAME: 16487c478bd9Sstevel@tonic-gate case MODGETMAJBIND: 16497c478bd9Sstevel@tonic-gate /* Unprivileged */ 16507c478bd9Sstevel@tonic-gate return (0); 16517c478bd9Sstevel@tonic-gate case MODLOAD: 16527c478bd9Sstevel@tonic-gate case MODSETDEVPOLICY: 16537c478bd9Sstevel@tonic-gate return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); 16547c478bd9Sstevel@tonic-gate default: 16557c478bd9Sstevel@tonic-gate return (secpolicy_sys_config(cr, B_FALSE)); 16567c478bd9Sstevel@tonic-gate } 16577c478bd9Sstevel@tonic-gate } 16587c478bd9Sstevel@tonic-gate 16597c478bd9Sstevel@tonic-gate int 16607c478bd9Sstevel@tonic-gate secpolicy_console(const cred_t *cr) 16617c478bd9Sstevel@tonic-gate { 16627c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 16637c478bd9Sstevel@tonic-gate } 16647c478bd9Sstevel@tonic-gate 16657c478bd9Sstevel@tonic-gate int 16667c478bd9Sstevel@tonic-gate secpolicy_power_mgmt(const cred_t *cr) 16677c478bd9Sstevel@tonic-gate { 16687c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 16697c478bd9Sstevel@tonic-gate } 16707c478bd9Sstevel@tonic-gate 16717c478bd9Sstevel@tonic-gate /* 16727c478bd9Sstevel@tonic-gate * Simulate terminal input; another escalation of privileges avenue. 16737c478bd9Sstevel@tonic-gate */ 16747c478bd9Sstevel@tonic-gate 16757c478bd9Sstevel@tonic-gate int 16767c478bd9Sstevel@tonic-gate secpolicy_sti(const cred_t *cr) 16777c478bd9Sstevel@tonic-gate { 16787c478bd9Sstevel@tonic-gate return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); 16797c478bd9Sstevel@tonic-gate } 16807c478bd9Sstevel@tonic-gate 16817c478bd9Sstevel@tonic-gate int 16827c478bd9Sstevel@tonic-gate secpolicy_swapctl(const cred_t *cr) 16837c478bd9Sstevel@tonic-gate { 16847c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 16857c478bd9Sstevel@tonic-gate } 16867c478bd9Sstevel@tonic-gate 16877c478bd9Sstevel@tonic-gate int 16887c478bd9Sstevel@tonic-gate secpolicy_cpc_cpu(const cred_t *cr) 16897c478bd9Sstevel@tonic-gate { 16907c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CPC_CPU, B_FALSE, EACCES, NULL)); 16917c478bd9Sstevel@tonic-gate } 16927c478bd9Sstevel@tonic-gate 16937c478bd9Sstevel@tonic-gate /* 16947c478bd9Sstevel@tonic-gate * secpolicy_contract_observer 16957c478bd9Sstevel@tonic-gate * 16967c478bd9Sstevel@tonic-gate * Determine if the subject may observe a specific contract's events. 16977c478bd9Sstevel@tonic-gate */ 16987c478bd9Sstevel@tonic-gate int 16997c478bd9Sstevel@tonic-gate secpolicy_contract_observer(const cred_t *cr, struct contract *ct) 17007c478bd9Sstevel@tonic-gate { 17017c478bd9Sstevel@tonic-gate if (contract_owned(ct, cr, B_FALSE)) 17027c478bd9Sstevel@tonic-gate return (0); 17037c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CONTRACT_OBSERVER, B_FALSE, EPERM, NULL)); 17047c478bd9Sstevel@tonic-gate } 17057c478bd9Sstevel@tonic-gate 17067c478bd9Sstevel@tonic-gate /* 17077c478bd9Sstevel@tonic-gate * secpolicy_contract_observer_choice 17087c478bd9Sstevel@tonic-gate * 17097c478bd9Sstevel@tonic-gate * Determine if the subject may observe any contract's events. Just 17107c478bd9Sstevel@tonic-gate * tests privilege and audits on success. 17117c478bd9Sstevel@tonic-gate */ 17127c478bd9Sstevel@tonic-gate boolean_t 17137c478bd9Sstevel@tonic-gate secpolicy_contract_observer_choice(const cred_t *cr) 17147c478bd9Sstevel@tonic-gate { 17157c478bd9Sstevel@tonic-gate return (PRIV_POLICY_CHOICE(cr, PRIV_CONTRACT_OBSERVER, B_FALSE)); 17167c478bd9Sstevel@tonic-gate } 17177c478bd9Sstevel@tonic-gate 17187c478bd9Sstevel@tonic-gate /* 17197c478bd9Sstevel@tonic-gate * secpolicy_contract_event 17207c478bd9Sstevel@tonic-gate * 17217c478bd9Sstevel@tonic-gate * Determine if the subject may request critical contract events or 17227c478bd9Sstevel@tonic-gate * reliable contract event delivery. 17237c478bd9Sstevel@tonic-gate */ 17247c478bd9Sstevel@tonic-gate int 17257c478bd9Sstevel@tonic-gate secpolicy_contract_event(const cred_t *cr) 17267c478bd9Sstevel@tonic-gate { 17277c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CONTRACT_EVENT, B_FALSE, EPERM, NULL)); 17287c478bd9Sstevel@tonic-gate } 17297c478bd9Sstevel@tonic-gate 17307c478bd9Sstevel@tonic-gate /* 17317c478bd9Sstevel@tonic-gate * secpolicy_contract_event_choice 17327c478bd9Sstevel@tonic-gate * 17337c478bd9Sstevel@tonic-gate * Determine if the subject may retain contract events in its critical 17347c478bd9Sstevel@tonic-gate * set when a change in other terms would normally require a change in 17357c478bd9Sstevel@tonic-gate * the critical set. Just tests privilege and audits on success. 17367c478bd9Sstevel@tonic-gate */ 17377c478bd9Sstevel@tonic-gate boolean_t 17387c478bd9Sstevel@tonic-gate secpolicy_contract_event_choice(const cred_t *cr) 17397c478bd9Sstevel@tonic-gate { 17407c478bd9Sstevel@tonic-gate return (PRIV_POLICY_CHOICE(cr, PRIV_CONTRACT_EVENT, B_FALSE)); 17417c478bd9Sstevel@tonic-gate } 17427c478bd9Sstevel@tonic-gate 17437c478bd9Sstevel@tonic-gate /* 17447c478bd9Sstevel@tonic-gate * Name: secpolicy_gart_access 17457c478bd9Sstevel@tonic-gate * 17467c478bd9Sstevel@tonic-gate * Normal: Verify if the subject has sufficient priveleges to make ioctls 17477c478bd9Sstevel@tonic-gate * to agpgart device 17487c478bd9Sstevel@tonic-gate * 17497c478bd9Sstevel@tonic-gate * Output: EPERM - if not privileged 17507c478bd9Sstevel@tonic-gate * 17517c478bd9Sstevel@tonic-gate */ 17527c478bd9Sstevel@tonic-gate int 17537c478bd9Sstevel@tonic-gate secpolicy_gart_access(const cred_t *cr) 17547c478bd9Sstevel@tonic-gate { 17557c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_GART_ACCESS, B_FALSE, EPERM, NULL)); 17567c478bd9Sstevel@tonic-gate } 17577c478bd9Sstevel@tonic-gate 17587c478bd9Sstevel@tonic-gate /* 17597c478bd9Sstevel@tonic-gate * Name: secpolicy_gart_map 17607c478bd9Sstevel@tonic-gate * 17617c478bd9Sstevel@tonic-gate * Normal: Verify if the subject has sufficient privelegs to map aperture 17627c478bd9Sstevel@tonic-gate * range through agpgart driver 17637c478bd9Sstevel@tonic-gate * 17647c478bd9Sstevel@tonic-gate * Output: EPERM - if not privileged 17657c478bd9Sstevel@tonic-gate * 17667c478bd9Sstevel@tonic-gate */ 17677c478bd9Sstevel@tonic-gate int 17687c478bd9Sstevel@tonic-gate secpolicy_gart_map(const cred_t *cr) 17697c478bd9Sstevel@tonic-gate { 17707c478bd9Sstevel@tonic-gate if (PRIV_POLICY(cr, PRIV_GART_ACCESS, B_FALSE, EPERM, NULL)) { 17717c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_GART_MAP, B_FALSE, EPERM, NULL)); 17727c478bd9Sstevel@tonic-gate } 17737c478bd9Sstevel@tonic-gate return (0); 17747c478bd9Sstevel@tonic-gate } 1775fa9e4066Sahrens 1776fa9e4066Sahrens /* 1777fa9e4066Sahrens * secpolicy_zfs 1778fa9e4066Sahrens * 1779fa9e4066Sahrens * Determine if the user has permission to manipulate ZFS datasets (not pools). 1780fa9e4066Sahrens * Equivalent to the SYS_MOUNT privilege. 1781fa9e4066Sahrens */ 1782fa9e4066Sahrens int 1783fa9e4066Sahrens secpolicy_zfs(const cred_t *cr) 1784fa9e4066Sahrens { 1785fa9e4066Sahrens return (PRIV_POLICY(cr, PRIV_SYS_MOUNT, B_FALSE, EPERM, NULL)); 1786fa9e4066Sahrens } 1787