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 5ea8dc4b6Seschrock * Common Development and Distribution License (the "License"). 6ea8dc4b6Seschrock * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22134a1f4eSCasper H.S. Dik * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 2324d819e6SJerry Jelinek * Copyright 2013, Joyent, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <sys/types.h> 277c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 287c478bd9Sstevel@tonic-gate #include <sys/param.h> 297c478bd9Sstevel@tonic-gate #include <sys/systm.h> 307c478bd9Sstevel@tonic-gate #include <sys/cred_impl.h> 317c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 327c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 337c478bd9Sstevel@tonic-gate #include <sys/stat.h> 347c478bd9Sstevel@tonic-gate #include <sys/errno.h> 357c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 367c478bd9Sstevel@tonic-gate #include <sys/user.h> 377c478bd9Sstevel@tonic-gate #include <sys/proc.h> 387c478bd9Sstevel@tonic-gate #include <sys/acct.h> 397c478bd9Sstevel@tonic-gate #include <sys/ipc_impl.h> 407c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 417c478bd9Sstevel@tonic-gate #include <sys/debug.h> 427c478bd9Sstevel@tonic-gate #include <sys/policy.h> 437c478bd9Sstevel@tonic-gate #include <sys/kobj.h> 447c478bd9Sstevel@tonic-gate #include <sys/msg.h> 457c478bd9Sstevel@tonic-gate #include <sys/devpolicy.h> 467c478bd9Sstevel@tonic-gate #include <c2/audit.h> 477c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 48ddf7fe95Scasper #include <sys/klpd.h> 497c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 507c478bd9Sstevel@tonic-gate #include <sys/disp.h> 517c478bd9Sstevel@tonic-gate #include <sys/zone.h> 527c478bd9Sstevel@tonic-gate #include <inet/optcom.h> 537c478bd9Sstevel@tonic-gate #include <sys/sdt.h> 547c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 557c478bd9Sstevel@tonic-gate #include <sys/mntent.h> 567c478bd9Sstevel@tonic-gate #include <sys/contract_impl.h> 57da14cebeSEric Cheng #include <sys/dld_ioc.h> 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate /* 607c478bd9Sstevel@tonic-gate * There are two possible layers of privilege routines and two possible 617c478bd9Sstevel@tonic-gate * levels of secpolicy. Plus one other we may not be interested in, so 627c478bd9Sstevel@tonic-gate * we may need as many as 6 but no more. 637c478bd9Sstevel@tonic-gate */ 647c478bd9Sstevel@tonic-gate #define MAXPRIVSTACK 6 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate int priv_debug = 0; 67634e26ecSCasper H.S. Dik int priv_basic_test = -1; 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate /* 707c478bd9Sstevel@tonic-gate * This file contains the majority of the policy routines. 717c478bd9Sstevel@tonic-gate * Since the policy routines are defined by function and not 727c478bd9Sstevel@tonic-gate * by privilege, there is quite a bit of duplication of 737c478bd9Sstevel@tonic-gate * functions. 747c478bd9Sstevel@tonic-gate * 75da6c28aaSamw * The secpolicy functions must not make assumptions about 767c478bd9Sstevel@tonic-gate * locks held or not held as any lock can be held while they're 777c478bd9Sstevel@tonic-gate * being called. 787c478bd9Sstevel@tonic-gate * 797c478bd9Sstevel@tonic-gate * Credentials are read-only so no special precautions need to 807c478bd9Sstevel@tonic-gate * be taken while locking them. 817c478bd9Sstevel@tonic-gate * 827c478bd9Sstevel@tonic-gate * When a new policy check needs to be added to the system the 837c478bd9Sstevel@tonic-gate * following procedure should be followed: 847c478bd9Sstevel@tonic-gate * 857c478bd9Sstevel@tonic-gate * Pick an appropriate secpolicy_*() function 867c478bd9Sstevel@tonic-gate * -> done if one exists. 877c478bd9Sstevel@tonic-gate * Create a new secpolicy function, preferably with 887c478bd9Sstevel@tonic-gate * a descriptive name using the standard template. 897c478bd9Sstevel@tonic-gate * Pick an appropriate privilege for the policy. 907c478bd9Sstevel@tonic-gate * If no appropraite privilege exists, define new one 917c478bd9Sstevel@tonic-gate * (this should be done with extreme care; in most cases 927c478bd9Sstevel@tonic-gate * little is gained by adding another privilege) 937c478bd9Sstevel@tonic-gate * 947c478bd9Sstevel@tonic-gate * WHY ROOT IS STILL SPECIAL. 957c478bd9Sstevel@tonic-gate * 967c478bd9Sstevel@tonic-gate * In a number of the policy functions, there are still explicit 977c478bd9Sstevel@tonic-gate * checks for uid 0. The rationale behind these is that many root 987c478bd9Sstevel@tonic-gate * owned files/objects hold configuration information which can give full 997c478bd9Sstevel@tonic-gate * privileges to the user once written to. To prevent escalation 1007c478bd9Sstevel@tonic-gate * of privilege by allowing just a single privilege to modify root owned 1017c478bd9Sstevel@tonic-gate * objects, we've added these root specific checks where we considered 1027c478bd9Sstevel@tonic-gate * them necessary: modifying root owned files, changing uids to 0, etc. 1037c478bd9Sstevel@tonic-gate * 1047c478bd9Sstevel@tonic-gate * PRIVILEGE ESCALATION AND ZONES. 1057c478bd9Sstevel@tonic-gate * 1067c478bd9Sstevel@tonic-gate * A number of operations potentially allow the caller to achieve 1077c478bd9Sstevel@tonic-gate * privileges beyond the ones normally required to perform the operation. 1087c478bd9Sstevel@tonic-gate * For example, if allowed to create a setuid 0 executable, a process can 1097c478bd9Sstevel@tonic-gate * gain privileges beyond PRIV_FILE_SETID. Zones, however, place 1107c478bd9Sstevel@tonic-gate * restrictions on the ability to gain privileges beyond those available 1117c478bd9Sstevel@tonic-gate * within the zone through file and process manipulation. Hence, such 1127c478bd9Sstevel@tonic-gate * operations require that the caller have an effective set that includes 1137c478bd9Sstevel@tonic-gate * all privileges available within the current zone, or all privileges 1147c478bd9Sstevel@tonic-gate * if executing in the global zone. 1157c478bd9Sstevel@tonic-gate * 1167c478bd9Sstevel@tonic-gate * This is indicated in the priv_policy* policy checking functions 1177c478bd9Sstevel@tonic-gate * through a combination of parameters. The "priv" parameter indicates 1187c478bd9Sstevel@tonic-gate * the privilege that is required, and the "allzone" parameter indicates 1197c478bd9Sstevel@tonic-gate * whether or not all privileges in the zone are required. In addition, 1207c478bd9Sstevel@tonic-gate * priv can be set to PRIV_ALL to indicate that all privileges are 1217c478bd9Sstevel@tonic-gate * required (regardless of zone). There are three scenarios of interest: 1227c478bd9Sstevel@tonic-gate * (1) operation requires a specific privilege 1237c478bd9Sstevel@tonic-gate * (2) operation requires a specific privilege, and requires all 1247c478bd9Sstevel@tonic-gate * privileges available within the zone (or all privileges if in 1257c478bd9Sstevel@tonic-gate * the global zone) 1267c478bd9Sstevel@tonic-gate * (3) operation requires all privileges, regardless of zone 1277c478bd9Sstevel@tonic-gate * 1287c478bd9Sstevel@tonic-gate * For (1), priv should be set to the specific privilege, and allzone 1297c478bd9Sstevel@tonic-gate * should be set to B_FALSE. 1307c478bd9Sstevel@tonic-gate * For (2), priv should be set to the specific privilege, and allzone 1317c478bd9Sstevel@tonic-gate * should be set to B_TRUE. 1327c478bd9Sstevel@tonic-gate * For (3), priv should be set to PRIV_ALL, and allzone should be set 1337c478bd9Sstevel@tonic-gate * to B_FALSE. 1347c478bd9Sstevel@tonic-gate * 1357c478bd9Sstevel@tonic-gate */ 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate /* 1387c478bd9Sstevel@tonic-gate * The privileges are checked against the Effective set for 1397c478bd9Sstevel@tonic-gate * ordinary processes and checked against the Limit set 1407c478bd9Sstevel@tonic-gate * for euid 0 processes that haven't manipulated their privilege 1417c478bd9Sstevel@tonic-gate * sets. 1427c478bd9Sstevel@tonic-gate */ 1437c478bd9Sstevel@tonic-gate #define HAS_ALLPRIVS(cr) priv_isfullset(&CR_OEPRIV(cr)) 1447c478bd9Sstevel@tonic-gate #define ZONEPRIVS(cr) ((cr)->cr_zone->zone_privset) 1457c478bd9Sstevel@tonic-gate #define HAS_ALLZONEPRIVS(cr) priv_issubset(ZONEPRIVS(cr), &CR_OEPRIV(cr)) 1467c478bd9Sstevel@tonic-gate #define HAS_PRIVILEGE(cr, pr) ((pr) == PRIV_ALL ? \ 1477c478bd9Sstevel@tonic-gate HAS_ALLPRIVS(cr) : \ 1487c478bd9Sstevel@tonic-gate PRIV_ISASSERT(&CR_OEPRIV(cr), pr)) 1497c478bd9Sstevel@tonic-gate 150134a1f4eSCasper H.S. Dik #define FAST_BASIC_CHECK(cr, priv) \ 151134a1f4eSCasper H.S. Dik if (PRIV_ISASSERT(&CR_OEPRIV(cr), priv)) { \ 152134a1f4eSCasper H.S. Dik DTRACE_PROBE2(priv__ok, int, priv, boolean_t, B_FALSE); \ 153134a1f4eSCasper H.S. Dik return (0); \ 154134a1f4eSCasper H.S. Dik } 155134a1f4eSCasper H.S. Dik 1567c478bd9Sstevel@tonic-gate /* 157ddf7fe95Scasper * Policy checking functions. 1587c478bd9Sstevel@tonic-gate * 159ddf7fe95Scasper * All of the system's policy should be implemented here. 1607c478bd9Sstevel@tonic-gate */ 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate /* 163ddf7fe95Scasper * Private functions which take an additional va_list argument to 164ddf7fe95Scasper * implement an object specific policy override. 165ddf7fe95Scasper */ 166ddf7fe95Scasper static int priv_policy_ap(const cred_t *, int, boolean_t, int, 167ddf7fe95Scasper const char *, va_list); 168ddf7fe95Scasper static int priv_policy_va(const cred_t *, int, boolean_t, int, 169ddf7fe95Scasper const char *, ...); 170ddf7fe95Scasper 171ddf7fe95Scasper /* 1727c478bd9Sstevel@tonic-gate * Generic policy calls 1737c478bd9Sstevel@tonic-gate * 1747c478bd9Sstevel@tonic-gate * The "bottom" functions of policy control 1757c478bd9Sstevel@tonic-gate */ 1767c478bd9Sstevel@tonic-gate static char * 1777c478bd9Sstevel@tonic-gate mprintf(const char *fmt, ...) 1787c478bd9Sstevel@tonic-gate { 1797c478bd9Sstevel@tonic-gate va_list args; 1807c478bd9Sstevel@tonic-gate char *buf; 1817c478bd9Sstevel@tonic-gate size_t len; 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate va_start(args, fmt); 1847c478bd9Sstevel@tonic-gate len = vsnprintf(NULL, 0, fmt, args) + 1; 1857c478bd9Sstevel@tonic-gate va_end(args); 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate buf = kmem_alloc(len, KM_NOSLEEP); 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate if (buf == NULL) 1907c478bd9Sstevel@tonic-gate return (NULL); 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate va_start(args, fmt); 1937c478bd9Sstevel@tonic-gate (void) vsnprintf(buf, len, fmt, args); 1947c478bd9Sstevel@tonic-gate va_end(args); 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate return (buf); 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate /* 2007c478bd9Sstevel@tonic-gate * priv_policy_errmsg() 2017c478bd9Sstevel@tonic-gate * 2027c478bd9Sstevel@tonic-gate * Generate an error message if privilege debugging is enabled system wide 2037c478bd9Sstevel@tonic-gate * or for this particular process. 2047c478bd9Sstevel@tonic-gate */ 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate #define FMTHDR "%s[%d]: missing privilege \"%s\" (euid = %d, syscall = %d)" 2077c478bd9Sstevel@tonic-gate #define FMTMSG " for \"%s\"" 2087c478bd9Sstevel@tonic-gate #define FMTFUN " needed at %s+0x%lx" 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate /* The maximum size privilege format: the concatenation of the above */ 2117c478bd9Sstevel@tonic-gate #define FMTMAX FMTHDR FMTMSG FMTFUN "\n" 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate static void 2147c478bd9Sstevel@tonic-gate priv_policy_errmsg(const cred_t *cr, int priv, const char *msg) 2157c478bd9Sstevel@tonic-gate { 2167c478bd9Sstevel@tonic-gate struct proc *me; 2177c478bd9Sstevel@tonic-gate pc_t stack[MAXPRIVSTACK]; 2187c478bd9Sstevel@tonic-gate int depth; 2197c478bd9Sstevel@tonic-gate int i; 2207c478bd9Sstevel@tonic-gate char *sym; 2217c478bd9Sstevel@tonic-gate ulong_t off; 2227c478bd9Sstevel@tonic-gate const char *pname; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate char *cmd; 2257c478bd9Sstevel@tonic-gate char fmt[sizeof (FMTMAX)]; 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate if ((me = curproc) == &p0) 2287c478bd9Sstevel@tonic-gate return; 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate /* Privileges must be defined */ 2317c478bd9Sstevel@tonic-gate ASSERT(priv == PRIV_ALL || priv == PRIV_MULTIPLE || 2327c478bd9Sstevel@tonic-gate priv == PRIV_ALLZONE || priv == PRIV_GLOBAL || 2337c478bd9Sstevel@tonic-gate priv_getbynum(priv) != NULL); 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate if (priv == PRIV_ALLZONE && INGLOBALZONE(me)) 2367c478bd9Sstevel@tonic-gate priv = PRIV_ALL; 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate if (curthread->t_pre_sys) 2397c478bd9Sstevel@tonic-gate ttolwp(curthread)->lwp_badpriv = (short)priv; 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate if (priv_debug == 0 && (CR_FLAGS(cr) & PRIV_DEBUG) == 0) 2427c478bd9Sstevel@tonic-gate return; 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate (void) strcpy(fmt, FMTHDR); 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate if (me->p_user.u_comm[0]) 2477c478bd9Sstevel@tonic-gate cmd = &me->p_user.u_comm[0]; 2487c478bd9Sstevel@tonic-gate else 2497c478bd9Sstevel@tonic-gate cmd = "priv_policy"; 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate if (msg != NULL && *msg != '\0') { 2527c478bd9Sstevel@tonic-gate (void) strcat(fmt, FMTMSG); 2537c478bd9Sstevel@tonic-gate } else { 2547c478bd9Sstevel@tonic-gate (void) strcat(fmt, "%s"); 2557c478bd9Sstevel@tonic-gate msg = ""; 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate sym = NULL; 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate depth = getpcstack(stack, MAXPRIVSTACK); 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate /* 2637c478bd9Sstevel@tonic-gate * Try to find the first interesting function on the stack. 2647c478bd9Sstevel@tonic-gate * priv_policy* that's us, so completely uninteresting. 2657c478bd9Sstevel@tonic-gate * suser(), drv_priv(), secpolicy_* are also called from 2667c478bd9Sstevel@tonic-gate * too many locations to convey useful information. 2677c478bd9Sstevel@tonic-gate */ 2687c478bd9Sstevel@tonic-gate for (i = 0; i < depth; i++) { 2697c478bd9Sstevel@tonic-gate sym = kobj_getsymname((uintptr_t)stack[i], &off); 2707c478bd9Sstevel@tonic-gate if (sym != NULL && 2717c478bd9Sstevel@tonic-gate strstr(sym, "hasprocperm") == 0 && 2727c478bd9Sstevel@tonic-gate strcmp("suser", sym) != 0 && 2737c478bd9Sstevel@tonic-gate strcmp("ipcaccess", sym) != 0 && 2747c478bd9Sstevel@tonic-gate strcmp("drv_priv", sym) != 0 && 2757c478bd9Sstevel@tonic-gate strncmp("secpolicy_", sym, 10) != 0 && 2767c478bd9Sstevel@tonic-gate strncmp("priv_policy", sym, 11) != 0) 2777c478bd9Sstevel@tonic-gate break; 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate if (sym != NULL) 2817c478bd9Sstevel@tonic-gate (void) strcat(fmt, FMTFUN); 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate (void) strcat(fmt, "\n"); 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate switch (priv) { 2867c478bd9Sstevel@tonic-gate case PRIV_ALL: 2877c478bd9Sstevel@tonic-gate pname = "ALL"; 2887c478bd9Sstevel@tonic-gate break; 2897c478bd9Sstevel@tonic-gate case PRIV_MULTIPLE: 2907c478bd9Sstevel@tonic-gate pname = "MULTIPLE"; 2917c478bd9Sstevel@tonic-gate break; 2927c478bd9Sstevel@tonic-gate case PRIV_ALLZONE: 2937c478bd9Sstevel@tonic-gate pname = "ZONE"; 2947c478bd9Sstevel@tonic-gate break; 2957c478bd9Sstevel@tonic-gate case PRIV_GLOBAL: 2967c478bd9Sstevel@tonic-gate pname = "GLOBAL"; 2977c478bd9Sstevel@tonic-gate break; 2987c478bd9Sstevel@tonic-gate default: 2997c478bd9Sstevel@tonic-gate pname = priv_getbynum(priv); 3007c478bd9Sstevel@tonic-gate break; 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate if (CR_FLAGS(cr) & PRIV_DEBUG) { 3047c478bd9Sstevel@tonic-gate /* Remember last message, just like lwp_badpriv. */ 3057c478bd9Sstevel@tonic-gate if (curthread->t_pdmsg != NULL) { 3067c478bd9Sstevel@tonic-gate kmem_free(curthread->t_pdmsg, 3077c478bd9Sstevel@tonic-gate strlen(curthread->t_pdmsg) + 1); 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate curthread->t_pdmsg = mprintf(fmt, cmd, me->p_pid, pname, 3117c478bd9Sstevel@tonic-gate cr->cr_uid, curthread->t_sysnum, msg, sym, off); 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate curthread->t_post_sys = 1; 314ddf7fe95Scasper } 315ddf7fe95Scasper if (priv_debug) { 3167c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, fmt, cmd, me->p_pid, pname, cr->cr_uid, 3177c478bd9Sstevel@tonic-gate curthread->t_sysnum, msg, sym, off); 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate } 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate /* 322ddf7fe95Scasper * Override the policy, if appropriate. Return 0 if the external 323ddf7fe95Scasper * policy engine approves. 324ddf7fe95Scasper */ 325ddf7fe95Scasper static int 326ddf7fe95Scasper priv_policy_override(const cred_t *cr, int priv, boolean_t allzone, va_list ap) 327ddf7fe95Scasper { 328ddf7fe95Scasper priv_set_t set; 329ddf7fe95Scasper int ret; 330ddf7fe95Scasper 331ddf7fe95Scasper if (!(CR_FLAGS(cr) & PRIV_XPOLICY)) 332ddf7fe95Scasper return (-1); 333ddf7fe95Scasper 334ddf7fe95Scasper if (priv == PRIV_ALL) { 335ddf7fe95Scasper priv_fillset(&set); 336ddf7fe95Scasper } else if (allzone) { 337ddf7fe95Scasper set = *ZONEPRIVS(cr); 338ddf7fe95Scasper } else { 339ddf7fe95Scasper priv_emptyset(&set); 340ddf7fe95Scasper priv_addset(&set, priv); 341ddf7fe95Scasper } 342ddf7fe95Scasper ret = klpd_call(cr, &set, ap); 343ddf7fe95Scasper return (ret); 344ddf7fe95Scasper } 345ddf7fe95Scasper 346ddf7fe95Scasper static int 347134a1f4eSCasper H.S. Dik priv_policy_override_set(const cred_t *cr, const priv_set_t *req, va_list ap) 348ddf7fe95Scasper { 349134a1f4eSCasper H.S. Dik if (CR_FLAGS(cr) & PRIV_PFEXEC) 350134a1f4eSCasper H.S. Dik return (check_user_privs(cr, req)); 351ddf7fe95Scasper if (CR_FLAGS(cr) & PRIV_XPOLICY) { 352ddf7fe95Scasper return (klpd_call(cr, req, ap)); 353ddf7fe95Scasper } 354ddf7fe95Scasper return (-1); 355ddf7fe95Scasper } 356ddf7fe95Scasper 357134a1f4eSCasper H.S. Dik static int 358134a1f4eSCasper H.S. Dik priv_policy_override_set_va(const cred_t *cr, const priv_set_t *req, ...) 359134a1f4eSCasper H.S. Dik { 360134a1f4eSCasper H.S. Dik va_list ap; 361134a1f4eSCasper H.S. Dik int ret; 362134a1f4eSCasper H.S. Dik 363134a1f4eSCasper H.S. Dik va_start(ap, req); 364134a1f4eSCasper H.S. Dik ret = priv_policy_override_set(cr, req, ap); 365134a1f4eSCasper H.S. Dik va_end(ap); 366134a1f4eSCasper H.S. Dik return (ret); 367134a1f4eSCasper H.S. Dik } 368134a1f4eSCasper H.S. Dik 369ddf7fe95Scasper /* 3707c478bd9Sstevel@tonic-gate * Audit failure, log error message. 3717c478bd9Sstevel@tonic-gate */ 3727c478bd9Sstevel@tonic-gate static void 3737c478bd9Sstevel@tonic-gate priv_policy_err(const cred_t *cr, int priv, boolean_t allzone, const char *msg) 3747c478bd9Sstevel@tonic-gate { 3757c478bd9Sstevel@tonic-gate 376005d3febSMarek Pospisil if (AU_AUDITING()) 3777c478bd9Sstevel@tonic-gate audit_priv(priv, allzone ? ZONEPRIVS(cr) : NULL, 0); 3787c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone); 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) || 3817c478bd9Sstevel@tonic-gate curthread->t_pre_sys) { 3827c478bd9Sstevel@tonic-gate if (allzone && !HAS_ALLZONEPRIVS(cr)) { 3837c478bd9Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_ALLZONE, msg); 3847c478bd9Sstevel@tonic-gate } else { 3857c478bd9Sstevel@tonic-gate ASSERT(!HAS_PRIVILEGE(cr, priv)); 3867c478bd9Sstevel@tonic-gate priv_policy_errmsg(cr, priv, msg); 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate } 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate /* 392ddf7fe95Scasper * priv_policy_ap() 3937c478bd9Sstevel@tonic-gate * return 0 or error. 3947c478bd9Sstevel@tonic-gate * See block comment above for a description of "priv" and "allzone" usage. 3957c478bd9Sstevel@tonic-gate */ 396ddf7fe95Scasper static int 397ddf7fe95Scasper priv_policy_ap(const cred_t *cr, int priv, boolean_t allzone, int err, 398ddf7fe95Scasper const char *msg, va_list ap) 3997c478bd9Sstevel@tonic-gate { 400ddf7fe95Scasper if ((HAS_PRIVILEGE(cr, priv) && (!allzone || HAS_ALLZONEPRIVS(cr))) || 401ddf7fe95Scasper (!servicing_interrupt() && 402ddf7fe95Scasper priv_policy_override(cr, priv, allzone, ap) == 0)) { 4037c478bd9Sstevel@tonic-gate if ((allzone || priv == PRIV_ALL || 4047c478bd9Sstevel@tonic-gate !PRIV_ISASSERT(priv_basic, priv)) && 4057c478bd9Sstevel@tonic-gate !servicing_interrupt()) { 406ae115bc7Smrj PTOU(curproc)->u_acflag |= ASU; /* Needed for SVVS */ 407005d3febSMarek Pospisil if (AU_AUDITING()) 4087c478bd9Sstevel@tonic-gate audit_priv(priv, 4097c478bd9Sstevel@tonic-gate allzone ? ZONEPRIVS(cr) : NULL, 1); 4107c478bd9Sstevel@tonic-gate } 4117c478bd9Sstevel@tonic-gate err = 0; 4127c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone); 4137c478bd9Sstevel@tonic-gate } else if (!servicing_interrupt()) { 4147c478bd9Sstevel@tonic-gate /* Failure audited in this procedure */ 4157c478bd9Sstevel@tonic-gate priv_policy_err(cr, priv, allzone, msg); 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate return (err); 4187c478bd9Sstevel@tonic-gate } 4197c478bd9Sstevel@tonic-gate 420ddf7fe95Scasper int 421ddf7fe95Scasper priv_policy_va(const cred_t *cr, int priv, boolean_t allzone, int err, 422ddf7fe95Scasper const char *msg, ...) 423ddf7fe95Scasper { 424ddf7fe95Scasper int ret; 425ddf7fe95Scasper va_list ap; 426ddf7fe95Scasper 427ddf7fe95Scasper va_start(ap, msg); 428ddf7fe95Scasper ret = priv_policy_ap(cr, priv, allzone, err, msg, ap); 429ddf7fe95Scasper va_end(ap); 430ddf7fe95Scasper 431ddf7fe95Scasper return (ret); 432ddf7fe95Scasper } 433ddf7fe95Scasper 434ddf7fe95Scasper int 435ddf7fe95Scasper priv_policy(const cred_t *cr, int priv, boolean_t allzone, int err, 436ddf7fe95Scasper const char *msg) 437ddf7fe95Scasper { 438134a1f4eSCasper H.S. Dik return (priv_policy_va(cr, priv, allzone, err, msg, KLPDARG_NONE)); 439ddf7fe95Scasper } 440ddf7fe95Scasper 4417c478bd9Sstevel@tonic-gate /* 4427c478bd9Sstevel@tonic-gate * Return B_TRUE for sufficient privileges, B_FALSE for insufficient privileges. 4437c478bd9Sstevel@tonic-gate */ 4447c478bd9Sstevel@tonic-gate boolean_t 4457c478bd9Sstevel@tonic-gate priv_policy_choice(const cred_t *cr, int priv, boolean_t allzone) 4467c478bd9Sstevel@tonic-gate { 4477c478bd9Sstevel@tonic-gate boolean_t res = HAS_PRIVILEGE(cr, priv) && 4487c478bd9Sstevel@tonic-gate (!allzone || HAS_ALLZONEPRIVS(cr)); 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate /* Audit success only */ 451005d3febSMarek Pospisil if (res && AU_AUDITING() && 4527c478bd9Sstevel@tonic-gate (allzone || priv == PRIV_ALL || !PRIV_ISASSERT(priv_basic, priv)) && 4537c478bd9Sstevel@tonic-gate !servicing_interrupt()) { 4547c478bd9Sstevel@tonic-gate audit_priv(priv, allzone ? ZONEPRIVS(cr) : NULL, 1); 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate if (res) { 4577c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone); 4587c478bd9Sstevel@tonic-gate } else { 4597c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone); 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate return (res); 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate /* 4657c478bd9Sstevel@tonic-gate * Non-auditing variant of priv_policy_choice(). 4667c478bd9Sstevel@tonic-gate */ 4677c478bd9Sstevel@tonic-gate boolean_t 4687c478bd9Sstevel@tonic-gate priv_policy_only(const cred_t *cr, int priv, boolean_t allzone) 4697c478bd9Sstevel@tonic-gate { 4707c478bd9Sstevel@tonic-gate boolean_t res = HAS_PRIVILEGE(cr, priv) && 4717c478bd9Sstevel@tonic-gate (!allzone || HAS_ALLZONEPRIVS(cr)); 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate if (res) { 4747c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone); 4757c478bd9Sstevel@tonic-gate } else { 4767c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone); 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate return (res); 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate /* 4827c478bd9Sstevel@tonic-gate * Check whether all privileges in the required set are present. 4837c478bd9Sstevel@tonic-gate */ 4847c478bd9Sstevel@tonic-gate static int 485134a1f4eSCasper H.S. Dik secpolicy_require_set(const cred_t *cr, const priv_set_t *req, 486134a1f4eSCasper H.S. Dik const char *msg, ...) 4877c478bd9Sstevel@tonic-gate { 4887c478bd9Sstevel@tonic-gate int priv; 4897c478bd9Sstevel@tonic-gate int pfound = -1; 4907c478bd9Sstevel@tonic-gate priv_set_t pset; 491134a1f4eSCasper H.S. Dik va_list ap; 492134a1f4eSCasper H.S. Dik int ret; 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate if (req == PRIV_FULLSET ? HAS_ALLPRIVS(cr) : priv_issubset(req, 4957c478bd9Sstevel@tonic-gate &CR_OEPRIV(cr))) { 4967c478bd9Sstevel@tonic-gate return (0); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate 499134a1f4eSCasper H.S. Dik va_start(ap, msg); 500134a1f4eSCasper H.S. Dik ret = priv_policy_override_set(cr, req, ap); 501134a1f4eSCasper H.S. Dik va_end(ap); 502134a1f4eSCasper H.S. Dik if (ret == 0) 503ddf7fe95Scasper return (0); 504ddf7fe95Scasper 5057c478bd9Sstevel@tonic-gate if (req == PRIV_FULLSET || priv_isfullset(req)) { 5067c478bd9Sstevel@tonic-gate priv_policy_err(cr, PRIV_ALL, B_FALSE, msg); 5077c478bd9Sstevel@tonic-gate return (EACCES); 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate pset = CR_OEPRIV(cr); /* present privileges */ 5117c478bd9Sstevel@tonic-gate priv_inverse(&pset); /* all non present privileges */ 5127c478bd9Sstevel@tonic-gate priv_intersect(req, &pset); /* the actual missing privs */ 5137c478bd9Sstevel@tonic-gate 514005d3febSMarek Pospisil if (AU_AUDITING()) 5157c478bd9Sstevel@tonic-gate audit_priv(PRIV_NONE, &pset, 0); 5167c478bd9Sstevel@tonic-gate /* 5177c478bd9Sstevel@tonic-gate * Privilege debugging; special case "one privilege in set". 5187c478bd9Sstevel@tonic-gate */ 5197c478bd9Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) || curthread->t_pre_sys) { 5207c478bd9Sstevel@tonic-gate for (priv = 0; priv < nprivs; priv++) { 5217c478bd9Sstevel@tonic-gate if (priv_ismember(&pset, priv)) { 5227c478bd9Sstevel@tonic-gate if (pfound != -1) { 5237c478bd9Sstevel@tonic-gate /* Multiple missing privs */ 5247c478bd9Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_MULTIPLE, 5257c478bd9Sstevel@tonic-gate msg); 5267c478bd9Sstevel@tonic-gate return (EACCES); 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate pfound = priv; 5297c478bd9Sstevel@tonic-gate } 5307c478bd9Sstevel@tonic-gate } 5317c478bd9Sstevel@tonic-gate ASSERT(pfound != -1); 5327c478bd9Sstevel@tonic-gate /* Just the one missing privilege */ 5337c478bd9Sstevel@tonic-gate priv_policy_errmsg(cr, pfound, msg); 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate return (EACCES); 5377c478bd9Sstevel@tonic-gate } 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate /* 5407c478bd9Sstevel@tonic-gate * Called when an operation requires that the caller be in the 5417c478bd9Sstevel@tonic-gate * global zone, regardless of privilege. 5427c478bd9Sstevel@tonic-gate */ 5437c478bd9Sstevel@tonic-gate static int 5447c478bd9Sstevel@tonic-gate priv_policy_global(const cred_t *cr) 5457c478bd9Sstevel@tonic-gate { 5467c478bd9Sstevel@tonic-gate if (crgetzoneid(cr) == GLOBAL_ZONEID) 5477c478bd9Sstevel@tonic-gate return (0); /* success */ 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) || 5507c478bd9Sstevel@tonic-gate curthread->t_pre_sys) { 5517c478bd9Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_GLOBAL, NULL); 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate return (EPERM); 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate /* 55724d819e6SJerry Jelinek * Raising process priority 55824d819e6SJerry Jelinek */ 55924d819e6SJerry Jelinek int 56024d819e6SJerry Jelinek secpolicy_raisepriority(const cred_t *cr) 56124d819e6SJerry Jelinek { 56224d819e6SJerry Jelinek if (PRIV_POLICY(cr, PRIV_PROC_PRIOUP, B_FALSE, EPERM, NULL) == 0) 56324d819e6SJerry Jelinek return (0); 56424d819e6SJerry Jelinek return (secpolicy_setpriority(cr)); 56524d819e6SJerry Jelinek } 56624d819e6SJerry Jelinek 56724d819e6SJerry Jelinek /* 56824d819e6SJerry Jelinek * Changing process priority or scheduling class 5697c478bd9Sstevel@tonic-gate */ 5707c478bd9Sstevel@tonic-gate int 5717c478bd9Sstevel@tonic-gate secpolicy_setpriority(const cred_t *cr) 5727c478bd9Sstevel@tonic-gate { 5737c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_PRIOCNTL, B_FALSE, EPERM, NULL)); 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate /* 5777c478bd9Sstevel@tonic-gate * Binding to a privileged port, port must be specified in host byte 5787c478bd9Sstevel@tonic-gate * order. 579134a1f4eSCasper H.S. Dik * When adding a new privilege which allows binding to currently privileged 580134a1f4eSCasper H.S. Dik * ports, then you MUST also allow processes with PRIV_NET_PRIVADDR bind 581134a1f4eSCasper H.S. Dik * to these ports because of backward compatibility. 5827c478bd9Sstevel@tonic-gate */ 5837c478bd9Sstevel@tonic-gate int 584ddf7fe95Scasper secpolicy_net_privaddr(const cred_t *cr, in_port_t port, int proto) 5857c478bd9Sstevel@tonic-gate { 586da6c28aaSamw char *reason; 587da6c28aaSamw int priv; 588da6c28aaSamw 589da6c28aaSamw switch (port) { 590da6c28aaSamw case 137: 591da6c28aaSamw case 138: 592da6c28aaSamw case 139: 593da6c28aaSamw case 445: 594da6c28aaSamw /* 595134a1f4eSCasper H.S. Dik * NBT and SMB ports, these are normal privileged ports, 596134a1f4eSCasper H.S. Dik * allow bind only if the SYS_SMB or NET_PRIVADDR privilege 597134a1f4eSCasper H.S. Dik * is present. 598134a1f4eSCasper H.S. Dik * Try both, if neither is present return an error for 599134a1f4eSCasper H.S. Dik * priv SYS_SMB. 600da6c28aaSamw */ 601134a1f4eSCasper H.S. Dik if (PRIV_POLICY_ONLY(cr, PRIV_NET_PRIVADDR, B_FALSE)) 602134a1f4eSCasper H.S. Dik priv = PRIV_NET_PRIVADDR; 603134a1f4eSCasper H.S. Dik else 604da6c28aaSamw priv = PRIV_SYS_SMB; 605da6c28aaSamw reason = "NBT or SMB port"; 606da6c28aaSamw break; 607da6c28aaSamw 608da6c28aaSamw case 2049: 609da6c28aaSamw case 4045: 6107c478bd9Sstevel@tonic-gate /* 6117c478bd9Sstevel@tonic-gate * NFS ports, these are extra privileged ports, allow bind 6127c478bd9Sstevel@tonic-gate * only if the SYS_NFS privilege is present. 6137c478bd9Sstevel@tonic-gate */ 614da6c28aaSamw priv = PRIV_SYS_NFS; 615da6c28aaSamw reason = "NFS port"; 616da6c28aaSamw break; 617da6c28aaSamw 618da6c28aaSamw default: 619da6c28aaSamw priv = PRIV_NET_PRIVADDR; 620da6c28aaSamw reason = NULL; 621da6c28aaSamw break; 622da6c28aaSamw 623da6c28aaSamw } 624da6c28aaSamw 625ddf7fe95Scasper return (priv_policy_va(cr, priv, B_FALSE, EACCES, reason, 626ddf7fe95Scasper KLPDARG_PORT, (int)proto, (int)port, KLPDARG_NOMORE)); 6277c478bd9Sstevel@tonic-gate } 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate /* 63045916cd2Sjpk * Binding to a multilevel port on a trusted (labeled) system. 63145916cd2Sjpk */ 63245916cd2Sjpk int 63345916cd2Sjpk secpolicy_net_bindmlp(const cred_t *cr) 63445916cd2Sjpk { 635ddf7fe95Scasper return (PRIV_POLICY(cr, PRIV_NET_BINDMLP, B_FALSE, EACCES, NULL)); 63645916cd2Sjpk } 63745916cd2Sjpk 63845916cd2Sjpk /* 63945916cd2Sjpk * Allow a communication between a zone and an unlabeled host when their 64045916cd2Sjpk * labels don't match. 64145916cd2Sjpk */ 64245916cd2Sjpk int 64345916cd2Sjpk secpolicy_net_mac_aware(const cred_t *cr) 64445916cd2Sjpk { 645ddf7fe95Scasper return (PRIV_POLICY(cr, PRIV_NET_MAC_AWARE, B_FALSE, EACCES, NULL)); 64645916cd2Sjpk } 64745916cd2Sjpk 64845916cd2Sjpk /* 6495d3b8cb7SBill Sommerfeld * Allow a privileged process to transmit traffic without explicit labels 6505d3b8cb7SBill Sommerfeld */ 6515d3b8cb7SBill Sommerfeld int 6525d3b8cb7SBill Sommerfeld secpolicy_net_mac_implicit(const cred_t *cr) 6535d3b8cb7SBill Sommerfeld { 6545d3b8cb7SBill Sommerfeld return (PRIV_POLICY(cr, PRIV_NET_MAC_IMPLICIT, B_FALSE, EACCES, NULL)); 6555d3b8cb7SBill Sommerfeld } 6565d3b8cb7SBill Sommerfeld 6575d3b8cb7SBill Sommerfeld /* 6587c478bd9Sstevel@tonic-gate * Common routine which determines whether a given credential can 6597c478bd9Sstevel@tonic-gate * act on a given mount. 6607c478bd9Sstevel@tonic-gate * When called through mount, the parameter needoptcheck is a pointer 6617c478bd9Sstevel@tonic-gate * to a boolean variable which will be set to either true or false, 6627c478bd9Sstevel@tonic-gate * depending on whether the mount policy should change the mount options. 6637c478bd9Sstevel@tonic-gate * In all other cases, needoptcheck should be a NULL pointer. 6647c478bd9Sstevel@tonic-gate */ 6657c478bd9Sstevel@tonic-gate static int 6667c478bd9Sstevel@tonic-gate secpolicy_fs_common(cred_t *cr, vnode_t *mvp, const vfs_t *vfsp, 6677c478bd9Sstevel@tonic-gate boolean_t *needoptcheck) 6687c478bd9Sstevel@tonic-gate { 6697c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 6707c478bd9Sstevel@tonic-gate boolean_t mounting = needoptcheck != NULL; 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate /* 6737c478bd9Sstevel@tonic-gate * Short circuit the following cases: 6747c478bd9Sstevel@tonic-gate * vfsp == NULL or mvp == NULL (pure privilege check) 6757c478bd9Sstevel@tonic-gate * have all privileges - no further checks required 6767c478bd9Sstevel@tonic-gate * and no mount options need to be set. 6777c478bd9Sstevel@tonic-gate */ 6787c478bd9Sstevel@tonic-gate if (vfsp == NULL || mvp == NULL || HAS_ALLPRIVS(cr)) { 6797c478bd9Sstevel@tonic-gate if (mounting) 6807c478bd9Sstevel@tonic-gate *needoptcheck = B_FALSE; 6817c478bd9Sstevel@tonic-gate 682ddf7fe95Scasper return (priv_policy_va(cr, PRIV_SYS_MOUNT, allzone, EPERM, 683ddf7fe95Scasper NULL, KLPDARG_VNODE, mvp, (char *)NULL, KLPDARG_NOMORE)); 6847c478bd9Sstevel@tonic-gate } 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate /* 6877c478bd9Sstevel@tonic-gate * When operating on an existing mount (either we're not mounting 6887c478bd9Sstevel@tonic-gate * or we're doing a remount and VFS_REMOUNT will be set), zones 6897c478bd9Sstevel@tonic-gate * can operate only on mounts established by the zone itself. 6907c478bd9Sstevel@tonic-gate */ 6917c478bd9Sstevel@tonic-gate if (!mounting || (vfsp->vfs_flag & VFS_REMOUNT) != 0) { 6927c478bd9Sstevel@tonic-gate zoneid_t zoneid = crgetzoneid(cr); 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate if (zoneid != GLOBAL_ZONEID && 6957c478bd9Sstevel@tonic-gate vfsp->vfs_zone->zone_id != zoneid) { 6967c478bd9Sstevel@tonic-gate return (EPERM); 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate if (mounting) 7017c478bd9Sstevel@tonic-gate *needoptcheck = B_TRUE; 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate /* 7047c478bd9Sstevel@tonic-gate * Overlay mounts may hide important stuff; if you can't write to a 7057c478bd9Sstevel@tonic-gate * mount point but would be able to mount on top of it, you can 7067c478bd9Sstevel@tonic-gate * escalate your privileges. 7077c478bd9Sstevel@tonic-gate * So we go about asking the same questions namefs does when it 7087c478bd9Sstevel@tonic-gate * decides whether you can mount over a file or not but with the 7097c478bd9Sstevel@tonic-gate * added restriction that you can only mount on top of a regular 7107c478bd9Sstevel@tonic-gate * file or directory. 7117c478bd9Sstevel@tonic-gate * If we have all the zone's privileges, we skip all other checks, 7127c478bd9Sstevel@tonic-gate * or else we may actually get in trouble inside the automounter. 7137c478bd9Sstevel@tonic-gate */ 7147c478bd9Sstevel@tonic-gate if ((mvp->v_flag & VROOT) != 0 || 7157c478bd9Sstevel@tonic-gate (mvp->v_type != VDIR && mvp->v_type != VREG) || 7167c478bd9Sstevel@tonic-gate HAS_ALLZONEPRIVS(cr)) { 7177c478bd9Sstevel@tonic-gate allzone = B_TRUE; 7187c478bd9Sstevel@tonic-gate } else { 7197c478bd9Sstevel@tonic-gate vattr_t va; 7207c478bd9Sstevel@tonic-gate int err; 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate va.va_mask = AT_UID|AT_MODE; 723da6c28aaSamw err = VOP_GETATTR(mvp, &va, 0, cr, NULL); 7247c478bd9Sstevel@tonic-gate if (err != 0) 7257c478bd9Sstevel@tonic-gate return (err); 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate if ((err = secpolicy_vnode_owner(cr, va.va_uid)) != 0) 7287c478bd9Sstevel@tonic-gate return (err); 7297c478bd9Sstevel@tonic-gate 730134a1f4eSCasper H.S. Dik if (secpolicy_vnode_access2(cr, mvp, va.va_uid, va.va_mode, 731134a1f4eSCasper H.S. Dik VWRITE) != 0) { 7327c478bd9Sstevel@tonic-gate return (EACCES); 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate } 735ddf7fe95Scasper return (priv_policy_va(cr, PRIV_SYS_MOUNT, allzone, EPERM, 736ddf7fe95Scasper NULL, KLPDARG_VNODE, mvp, (char *)NULL, KLPDARG_NOMORE)); 7377c478bd9Sstevel@tonic-gate } 7387c478bd9Sstevel@tonic-gate 739ecd6cf80Smarks void 740ecd6cf80Smarks secpolicy_fs_mount_clearopts(cred_t *cr, struct vfs *vfsp) 7417c478bd9Sstevel@tonic-gate { 7427c478bd9Sstevel@tonic-gate boolean_t amsuper = HAS_ALLZONEPRIVS(cr); 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate /* 745ecd6cf80Smarks * check; if we don't have either "nosuid" or 7467c478bd9Sstevel@tonic-gate * both "nosetuid" and "nodevices", then we add 7477c478bd9Sstevel@tonic-gate * "nosuid"; this depends on how the current 7487c478bd9Sstevel@tonic-gate * implementation works (it first checks nosuid). In a 7497c478bd9Sstevel@tonic-gate * zone, a user with all zone privileges can mount with 7507c478bd9Sstevel@tonic-gate * "setuid" but never with "devices". 7517c478bd9Sstevel@tonic-gate */ 7527c478bd9Sstevel@tonic-gate if (!vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL) && 7537c478bd9Sstevel@tonic-gate (!vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL) || 7547c478bd9Sstevel@tonic-gate !vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL))) { 7557c478bd9Sstevel@tonic-gate if (crgetzoneid(cr) == GLOBAL_ZONEID || !amsuper) 7567c478bd9Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_NOSUID, NULL, 0); 7577c478bd9Sstevel@tonic-gate else 7587c478bd9Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_NODEVICES, NULL, 0); 7597c478bd9Sstevel@tonic-gate } 7607c478bd9Sstevel@tonic-gate /* 7617c478bd9Sstevel@tonic-gate * If we're not the local super user, we set the "restrict" 7627c478bd9Sstevel@tonic-gate * option to indicate to automountd that this mount should 7637c478bd9Sstevel@tonic-gate * be handled with care. 7647c478bd9Sstevel@tonic-gate */ 7657c478bd9Sstevel@tonic-gate if (!amsuper) 7667c478bd9Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_RESTRICT, NULL, 0); 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate } 769ecd6cf80Smarks 7700fbb751dSJohn Levon int 7710fbb751dSJohn Levon secpolicy_fs_allowed_mount(const char *fsname) 7720fbb751dSJohn Levon { 7730fbb751dSJohn Levon struct vfssw *vswp; 7740fbb751dSJohn Levon const char *p; 7750fbb751dSJohn Levon size_t len; 7760fbb751dSJohn Levon 7770fbb751dSJohn Levon ASSERT(fsname != NULL); 7780fbb751dSJohn Levon ASSERT(fsname[0] != '\0'); 7790fbb751dSJohn Levon 7800fbb751dSJohn Levon if (INGLOBALZONE(curproc)) 7810fbb751dSJohn Levon return (0); 7820fbb751dSJohn Levon 7830fbb751dSJohn Levon vswp = vfs_getvfssw(fsname); 7840fbb751dSJohn Levon if (vswp == NULL) 7850fbb751dSJohn Levon return (ENOENT); 7860fbb751dSJohn Levon 7870fbb751dSJohn Levon if ((vswp->vsw_flag & VSW_ZMOUNT) != 0) { 7880fbb751dSJohn Levon vfs_unrefvfssw(vswp); 7890fbb751dSJohn Levon return (0); 7900fbb751dSJohn Levon } 7910fbb751dSJohn Levon 7920fbb751dSJohn Levon vfs_unrefvfssw(vswp); 7930fbb751dSJohn Levon 7940fbb751dSJohn Levon p = curzone->zone_fs_allowed; 7950fbb751dSJohn Levon len = strlen(fsname); 7960fbb751dSJohn Levon 7970fbb751dSJohn Levon while (p != NULL && *p != '\0') { 7980fbb751dSJohn Levon if (strncmp(p, fsname, len) == 0) { 7990fbb751dSJohn Levon char c = *(p + len); 8000fbb751dSJohn Levon if (c == '\0' || c == ',') 8010fbb751dSJohn Levon return (0); 8020fbb751dSJohn Levon } 8030fbb751dSJohn Levon 8040fbb751dSJohn Levon /* skip to beyond the next comma */ 8050fbb751dSJohn Levon if ((p = strchr(p, ',')) != NULL) 8060fbb751dSJohn Levon p++; 8070fbb751dSJohn Levon } 8080fbb751dSJohn Levon 8090fbb751dSJohn Levon return (EPERM); 8100fbb751dSJohn Levon } 8110fbb751dSJohn Levon 812ecd6cf80Smarks extern vnode_t *rootvp; 813ecd6cf80Smarks extern vfs_t *rootvfs; 814ecd6cf80Smarks 815ecd6cf80Smarks int 816ecd6cf80Smarks secpolicy_fs_mount(cred_t *cr, vnode_t *mvp, struct vfs *vfsp) 817ecd6cf80Smarks { 818ecd6cf80Smarks boolean_t needoptchk; 819ecd6cf80Smarks int error; 820ecd6cf80Smarks 821ecd6cf80Smarks /* 822ecd6cf80Smarks * If it's a remount, get the underlying mount point, 823ecd6cf80Smarks * except for the root where we use the rootvp. 824ecd6cf80Smarks */ 825ecd6cf80Smarks if ((vfsp->vfs_flag & VFS_REMOUNT) != 0) { 826ecd6cf80Smarks if (vfsp == rootvfs) 827ecd6cf80Smarks mvp = rootvp; 828ecd6cf80Smarks else 829ecd6cf80Smarks mvp = vfsp->vfs_vnodecovered; 830ecd6cf80Smarks } 831ecd6cf80Smarks 832ecd6cf80Smarks error = secpolicy_fs_common(cr, mvp, vfsp, &needoptchk); 833ecd6cf80Smarks 834ecd6cf80Smarks if (error == 0 && needoptchk) { 835ecd6cf80Smarks secpolicy_fs_mount_clearopts(cr, vfsp); 836ecd6cf80Smarks } 837ecd6cf80Smarks 8387c478bd9Sstevel@tonic-gate return (error); 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate /* 8427c478bd9Sstevel@tonic-gate * Does the policy computations for "ownership" of a mount; 8437c478bd9Sstevel@tonic-gate * here ownership is defined as the ability to "mount" 8447c478bd9Sstevel@tonic-gate * the filesystem originally. The rootvfs doesn't cover any 8457c478bd9Sstevel@tonic-gate * vnodes; we attribute its ownership to the rootvp. 8467c478bd9Sstevel@tonic-gate */ 8477c478bd9Sstevel@tonic-gate static int 8487c478bd9Sstevel@tonic-gate secpolicy_fs_owner(cred_t *cr, const struct vfs *vfsp) 8497c478bd9Sstevel@tonic-gate { 8507c478bd9Sstevel@tonic-gate vnode_t *mvp; 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate if (vfsp == NULL) 8537c478bd9Sstevel@tonic-gate mvp = NULL; 8547c478bd9Sstevel@tonic-gate else if (vfsp == rootvfs) 8557c478bd9Sstevel@tonic-gate mvp = rootvp; 8567c478bd9Sstevel@tonic-gate else 8577c478bd9Sstevel@tonic-gate mvp = vfsp->vfs_vnodecovered; 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate return (secpolicy_fs_common(cr, mvp, vfsp, NULL)); 8607c478bd9Sstevel@tonic-gate } 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate int 8637c478bd9Sstevel@tonic-gate secpolicy_fs_unmount(cred_t *cr, struct vfs *vfsp) 8647c478bd9Sstevel@tonic-gate { 8657c478bd9Sstevel@tonic-gate return (secpolicy_fs_owner(cr, vfsp)); 8667c478bd9Sstevel@tonic-gate } 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate /* 8697c478bd9Sstevel@tonic-gate * Quotas are a resource, but if one has the ability to mount a filesystem, he 8707c478bd9Sstevel@tonic-gate * should be able to modify quotas on it. 8717c478bd9Sstevel@tonic-gate */ 8727c478bd9Sstevel@tonic-gate int 8737c478bd9Sstevel@tonic-gate secpolicy_fs_quota(const cred_t *cr, const vfs_t *vfsp) 8747c478bd9Sstevel@tonic-gate { 8757c478bd9Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 8767c478bd9Sstevel@tonic-gate } 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate /* 8797c478bd9Sstevel@tonic-gate * Exceeding minfree: also a per-mount resource constraint. 8807c478bd9Sstevel@tonic-gate */ 8817c478bd9Sstevel@tonic-gate int 8827c478bd9Sstevel@tonic-gate secpolicy_fs_minfree(const cred_t *cr, const vfs_t *vfsp) 8837c478bd9Sstevel@tonic-gate { 8847c478bd9Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 8857c478bd9Sstevel@tonic-gate } 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate int 8887c478bd9Sstevel@tonic-gate secpolicy_fs_config(const cred_t *cr, const vfs_t *vfsp) 8897c478bd9Sstevel@tonic-gate { 8907c478bd9Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 8917c478bd9Sstevel@tonic-gate } 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate /* ARGSUSED */ 8947c478bd9Sstevel@tonic-gate int 8957c478bd9Sstevel@tonic-gate secpolicy_fs_linkdir(const cred_t *cr, const vfs_t *vfsp) 8967c478bd9Sstevel@tonic-gate { 8977c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_LINKDIR, B_FALSE, EPERM, NULL)); 8987c478bd9Sstevel@tonic-gate } 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate /* 9017c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_access() 9027c478bd9Sstevel@tonic-gate * 9037c478bd9Sstevel@tonic-gate * Parameters: Process credential 9047c478bd9Sstevel@tonic-gate * vnode 9057c478bd9Sstevel@tonic-gate * uid of owner of vnode 9067c478bd9Sstevel@tonic-gate * permission bits not granted to the caller when examining 9077c478bd9Sstevel@tonic-gate * file mode bits (i.e., when a process wants to open a 9087c478bd9Sstevel@tonic-gate * mode 444 file for VREAD|VWRITE, this function should be 9097c478bd9Sstevel@tonic-gate * called only with a VWRITE argument). 9107c478bd9Sstevel@tonic-gate * 9117c478bd9Sstevel@tonic-gate * Normal: Verifies that cred has the appropriate privileges to 9127c478bd9Sstevel@tonic-gate * override the mode bits that were denied. 9137c478bd9Sstevel@tonic-gate * 9147c478bd9Sstevel@tonic-gate * Override: file_dac_execute - if VEXEC bit was denied and vnode is 9157c478bd9Sstevel@tonic-gate * not a directory. 9167c478bd9Sstevel@tonic-gate * file_dac_read - if VREAD bit was denied. 9177c478bd9Sstevel@tonic-gate * file_dac_search - if VEXEC bit was denied and vnode is 9187c478bd9Sstevel@tonic-gate * a directory. 9197c478bd9Sstevel@tonic-gate * file_dac_write - if VWRITE bit was denied. 9207c478bd9Sstevel@tonic-gate * 9217c478bd9Sstevel@tonic-gate * Root owned files are special cased to protect system 9227c478bd9Sstevel@tonic-gate * configuration files and such. 9237c478bd9Sstevel@tonic-gate * 9247c478bd9Sstevel@tonic-gate * Output: EACCES - if privilege check fails. 9257c478bd9Sstevel@tonic-gate */ 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate int 9287c478bd9Sstevel@tonic-gate secpolicy_vnode_access(const cred_t *cr, vnode_t *vp, uid_t owner, mode_t mode) 9297c478bd9Sstevel@tonic-gate { 930ddf7fe95Scasper if ((mode & VREAD) && priv_policy_va(cr, PRIV_FILE_DAC_READ, B_FALSE, 931ddf7fe95Scasper EACCES, NULL, KLPDARG_VNODE, vp, (char *)NULL, 932ddf7fe95Scasper KLPDARG_NOMORE) != 0) { 9337c478bd9Sstevel@tonic-gate return (EACCES); 934ddf7fe95Scasper } 9357c478bd9Sstevel@tonic-gate 9367c478bd9Sstevel@tonic-gate if (mode & VWRITE) { 9377c478bd9Sstevel@tonic-gate boolean_t allzone; 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate if (owner == 0 && cr->cr_uid != 0) 9407c478bd9Sstevel@tonic-gate allzone = B_TRUE; 9417c478bd9Sstevel@tonic-gate else 9427c478bd9Sstevel@tonic-gate allzone = B_FALSE; 943ddf7fe95Scasper if (priv_policy_va(cr, PRIV_FILE_DAC_WRITE, allzone, EACCES, 944ddf7fe95Scasper NULL, KLPDARG_VNODE, vp, (char *)NULL, 945ddf7fe95Scasper KLPDARG_NOMORE) != 0) { 9467c478bd9Sstevel@tonic-gate return (EACCES); 9477c478bd9Sstevel@tonic-gate } 948ddf7fe95Scasper } 9497c478bd9Sstevel@tonic-gate 9507c478bd9Sstevel@tonic-gate if (mode & VEXEC) { 9517c478bd9Sstevel@tonic-gate /* 9527c478bd9Sstevel@tonic-gate * Directories use file_dac_search to override the execute bit. 9537c478bd9Sstevel@tonic-gate */ 954ddf7fe95Scasper int p = vp->v_type == VDIR ? PRIV_FILE_DAC_SEARCH : 955ddf7fe95Scasper PRIV_FILE_DAC_EXECUTE; 9567c478bd9Sstevel@tonic-gate 957ddf7fe95Scasper return (priv_policy_va(cr, p, B_FALSE, EACCES, NULL, 958ddf7fe95Scasper KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE)); 9597c478bd9Sstevel@tonic-gate } 9607c478bd9Sstevel@tonic-gate return (0); 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate /* 964134a1f4eSCasper H.S. Dik * Like secpolicy_vnode_access() but we get the actual wanted mode and the 965134a1f4eSCasper H.S. Dik * current mode of the file, not the missing bits. 966134a1f4eSCasper H.S. Dik */ 967134a1f4eSCasper H.S. Dik int 968134a1f4eSCasper H.S. Dik secpolicy_vnode_access2(const cred_t *cr, vnode_t *vp, uid_t owner, 969134a1f4eSCasper H.S. Dik mode_t curmode, mode_t wantmode) 970134a1f4eSCasper H.S. Dik { 971134a1f4eSCasper H.S. Dik mode_t mode; 972134a1f4eSCasper H.S. Dik 973134a1f4eSCasper H.S. Dik /* Inline the basic privileges tests. */ 974134a1f4eSCasper H.S. Dik if ((wantmode & VREAD) && 975134a1f4eSCasper H.S. Dik !PRIV_ISASSERT(&CR_OEPRIV(cr), PRIV_FILE_READ) && 976134a1f4eSCasper H.S. Dik priv_policy_va(cr, PRIV_FILE_READ, B_FALSE, EACCES, NULL, 977134a1f4eSCasper H.S. Dik KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE) != 0) { 978134a1f4eSCasper H.S. Dik return (EACCES); 979134a1f4eSCasper H.S. Dik } 980134a1f4eSCasper H.S. Dik 981134a1f4eSCasper H.S. Dik if ((wantmode & VWRITE) && 982134a1f4eSCasper H.S. Dik !PRIV_ISASSERT(&CR_OEPRIV(cr), PRIV_FILE_WRITE) && 983134a1f4eSCasper H.S. Dik priv_policy_va(cr, PRIV_FILE_WRITE, B_FALSE, EACCES, NULL, 984134a1f4eSCasper H.S. Dik KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE) != 0) { 985134a1f4eSCasper H.S. Dik return (EACCES); 986134a1f4eSCasper H.S. Dik } 987134a1f4eSCasper H.S. Dik 988134a1f4eSCasper H.S. Dik mode = ~curmode & wantmode; 989134a1f4eSCasper H.S. Dik 990134a1f4eSCasper H.S. Dik if (mode == 0) 991134a1f4eSCasper H.S. Dik return (0); 992134a1f4eSCasper H.S. Dik 993134a1f4eSCasper H.S. Dik if ((mode & VREAD) && priv_policy_va(cr, PRIV_FILE_DAC_READ, B_FALSE, 994134a1f4eSCasper H.S. Dik EACCES, NULL, KLPDARG_VNODE, vp, (char *)NULL, 995134a1f4eSCasper H.S. Dik KLPDARG_NOMORE) != 0) { 996134a1f4eSCasper H.S. Dik return (EACCES); 997134a1f4eSCasper H.S. Dik } 998134a1f4eSCasper H.S. Dik 999134a1f4eSCasper H.S. Dik if (mode & VWRITE) { 1000134a1f4eSCasper H.S. Dik boolean_t allzone; 1001134a1f4eSCasper H.S. Dik 1002134a1f4eSCasper H.S. Dik if (owner == 0 && cr->cr_uid != 0) 1003134a1f4eSCasper H.S. Dik allzone = B_TRUE; 1004134a1f4eSCasper H.S. Dik else 1005134a1f4eSCasper H.S. Dik allzone = B_FALSE; 1006134a1f4eSCasper H.S. Dik if (priv_policy_va(cr, PRIV_FILE_DAC_WRITE, allzone, EACCES, 1007134a1f4eSCasper H.S. Dik NULL, KLPDARG_VNODE, vp, (char *)NULL, 1008134a1f4eSCasper H.S. Dik KLPDARG_NOMORE) != 0) { 1009134a1f4eSCasper H.S. Dik return (EACCES); 1010134a1f4eSCasper H.S. Dik } 1011134a1f4eSCasper H.S. Dik } 1012134a1f4eSCasper H.S. Dik 1013134a1f4eSCasper H.S. Dik if (mode & VEXEC) { 1014134a1f4eSCasper H.S. Dik /* 1015134a1f4eSCasper H.S. Dik * Directories use file_dac_search to override the execute bit. 1016134a1f4eSCasper H.S. Dik */ 1017134a1f4eSCasper H.S. Dik int p = vp->v_type == VDIR ? PRIV_FILE_DAC_SEARCH : 1018134a1f4eSCasper H.S. Dik PRIV_FILE_DAC_EXECUTE; 1019134a1f4eSCasper H.S. Dik 1020134a1f4eSCasper H.S. Dik return (priv_policy_va(cr, p, B_FALSE, EACCES, NULL, 1021134a1f4eSCasper H.S. Dik KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE)); 1022134a1f4eSCasper H.S. Dik } 1023134a1f4eSCasper H.S. Dik return (0); 1024134a1f4eSCasper H.S. Dik } 1025134a1f4eSCasper H.S. Dik 1026134a1f4eSCasper H.S. Dik /* 1027134a1f4eSCasper H.S. Dik * This is a special routine for ZFS; it is used to determine whether 1028134a1f4eSCasper H.S. Dik * any of the privileges in effect allow any form of access to the 1029134a1f4eSCasper H.S. Dik * file. There's no reason to audit this or any reason to record 1030134a1f4eSCasper H.S. Dik * this. More work is needed to do the "KPLD" stuff. 1031134a1f4eSCasper H.S. Dik */ 1032134a1f4eSCasper H.S. Dik int 1033134a1f4eSCasper H.S. Dik secpolicy_vnode_any_access(const cred_t *cr, vnode_t *vp, uid_t owner) 1034134a1f4eSCasper H.S. Dik { 1035134a1f4eSCasper H.S. Dik static int privs[] = { 1036134a1f4eSCasper H.S. Dik PRIV_FILE_OWNER, 1037060fafacSCasper H.S. Dik PRIV_FILE_CHOWN, 1038134a1f4eSCasper H.S. Dik PRIV_FILE_DAC_READ, 1039134a1f4eSCasper H.S. Dik PRIV_FILE_DAC_WRITE, 1040134a1f4eSCasper H.S. Dik PRIV_FILE_DAC_EXECUTE, 1041134a1f4eSCasper H.S. Dik PRIV_FILE_DAC_SEARCH, 1042134a1f4eSCasper H.S. Dik }; 1043134a1f4eSCasper H.S. Dik int i; 1044134a1f4eSCasper H.S. Dik 1045134a1f4eSCasper H.S. Dik /* Same as secpolicy_vnode_setdac */ 1046134a1f4eSCasper H.S. Dik if (owner == cr->cr_uid) 1047134a1f4eSCasper H.S. Dik return (0); 1048134a1f4eSCasper H.S. Dik 1049134a1f4eSCasper H.S. Dik for (i = 0; i < sizeof (privs)/sizeof (int); i++) { 1050134a1f4eSCasper H.S. Dik boolean_t allzone = B_FALSE; 1051134a1f4eSCasper H.S. Dik int priv; 1052134a1f4eSCasper H.S. Dik 1053134a1f4eSCasper H.S. Dik switch (priv = privs[i]) { 1054134a1f4eSCasper H.S. Dik case PRIV_FILE_DAC_EXECUTE: 1055134a1f4eSCasper H.S. Dik if (vp->v_type == VDIR) 1056134a1f4eSCasper H.S. Dik continue; 1057134a1f4eSCasper H.S. Dik break; 1058134a1f4eSCasper H.S. Dik case PRIV_FILE_DAC_SEARCH: 1059134a1f4eSCasper H.S. Dik if (vp->v_type != VDIR) 1060134a1f4eSCasper H.S. Dik continue; 1061134a1f4eSCasper H.S. Dik break; 1062134a1f4eSCasper H.S. Dik case PRIV_FILE_DAC_WRITE: 1063134a1f4eSCasper H.S. Dik case PRIV_FILE_OWNER: 1064060fafacSCasper H.S. Dik case PRIV_FILE_CHOWN: 1065134a1f4eSCasper H.S. Dik /* We know here that if owner == 0, that cr_uid != 0 */ 1066134a1f4eSCasper H.S. Dik allzone = owner == 0; 1067134a1f4eSCasper H.S. Dik break; 1068134a1f4eSCasper H.S. Dik } 1069134a1f4eSCasper H.S. Dik if (PRIV_POLICY_CHOICE(cr, priv, allzone)) 1070134a1f4eSCasper H.S. Dik return (0); 1071134a1f4eSCasper H.S. Dik } 1072134a1f4eSCasper H.S. Dik return (EPERM); 1073134a1f4eSCasper H.S. Dik } 1074134a1f4eSCasper H.S. Dik 1075134a1f4eSCasper H.S. Dik /* 10767c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_setid_modify() 10777c478bd9Sstevel@tonic-gate * 10787c478bd9Sstevel@tonic-gate * Normal: verify that subject can set the file setid flags. 10797c478bd9Sstevel@tonic-gate * 10807c478bd9Sstevel@tonic-gate * Output: EPERM - if not privileged. 10817c478bd9Sstevel@tonic-gate */ 10827c478bd9Sstevel@tonic-gate 10837c478bd9Sstevel@tonic-gate static int 10847c478bd9Sstevel@tonic-gate secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner) 10857c478bd9Sstevel@tonic-gate { 10867c478bd9Sstevel@tonic-gate /* If changing to suid root, must have all zone privs */ 10877c478bd9Sstevel@tonic-gate boolean_t allzone = B_TRUE; 10887c478bd9Sstevel@tonic-gate 10897c478bd9Sstevel@tonic-gate if (owner != 0) { 10907c478bd9Sstevel@tonic-gate if (owner == cr->cr_uid) 10917c478bd9Sstevel@tonic-gate return (0); 10927c478bd9Sstevel@tonic-gate allzone = B_FALSE; 10937c478bd9Sstevel@tonic-gate } 10947c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_SETID, allzone, EPERM, NULL)); 10957c478bd9Sstevel@tonic-gate } 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate /* 10987c478bd9Sstevel@tonic-gate * Are we allowed to retain the set-uid/set-gid bits when 10997c478bd9Sstevel@tonic-gate * changing ownership or when writing to a file? 11007c478bd9Sstevel@tonic-gate * "issuid" should be true when set-uid; only in that case 11017c478bd9Sstevel@tonic-gate * root ownership is checked (setgid is assumed). 11027c478bd9Sstevel@tonic-gate */ 11037c478bd9Sstevel@tonic-gate int 11047c478bd9Sstevel@tonic-gate secpolicy_vnode_setid_retain(const cred_t *cred, boolean_t issuidroot) 11057c478bd9Sstevel@tonic-gate { 11067c478bd9Sstevel@tonic-gate if (issuidroot && !HAS_ALLZONEPRIVS(cred)) 11077c478bd9Sstevel@tonic-gate return (EPERM); 11087c478bd9Sstevel@tonic-gate 11097c478bd9Sstevel@tonic-gate return (!PRIV_POLICY_CHOICE(cred, PRIV_FILE_SETID, B_FALSE)); 11107c478bd9Sstevel@tonic-gate } 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate /* 11137c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_setids_setgids() 11147c478bd9Sstevel@tonic-gate * 11157c478bd9Sstevel@tonic-gate * Normal: verify that subject can set the file setgid flag. 11167c478bd9Sstevel@tonic-gate * 11177c478bd9Sstevel@tonic-gate * Output: EPERM - if not privileged 11187c478bd9Sstevel@tonic-gate */ 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate int 11217c478bd9Sstevel@tonic-gate secpolicy_vnode_setids_setgids(const cred_t *cred, gid_t gid) 11227c478bd9Sstevel@tonic-gate { 11237c478bd9Sstevel@tonic-gate if (!groupmember(gid, cred)) 11247c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_SETID, B_FALSE, EPERM, 11257c478bd9Sstevel@tonic-gate NULL)); 11267c478bd9Sstevel@tonic-gate return (0); 11277c478bd9Sstevel@tonic-gate } 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate /* 113047def0dcSMark Shellenbaum * Name: secpolicy_vnode_chown 113147def0dcSMark Shellenbaum * 113247def0dcSMark Shellenbaum * Normal: Determine if subject can chown owner of a file. 113347def0dcSMark Shellenbaum * 113447def0dcSMark Shellenbaum * Output: EPERM - if access denied 11357c478bd9Sstevel@tonic-gate */ 113647def0dcSMark Shellenbaum 11377c478bd9Sstevel@tonic-gate int 1138e02bc683SMark Shellenbaum secpolicy_vnode_chown(const cred_t *cred, uid_t owner) 11397c478bd9Sstevel@tonic-gate { 1140e02bc683SMark Shellenbaum boolean_t is_owner = (owner == crgetuid(cred)); 1141e02bc683SMark Shellenbaum boolean_t allzone = B_FALSE; 1142e02bc683SMark Shellenbaum int priv; 1143e02bc683SMark Shellenbaum 1144e02bc683SMark Shellenbaum if (!is_owner) { 1145e02bc683SMark Shellenbaum allzone = (owner == 0); 1146e02bc683SMark Shellenbaum priv = PRIV_FILE_CHOWN; 1147e02bc683SMark Shellenbaum } else { 1148e02bc683SMark Shellenbaum priv = HAS_PRIVILEGE(cred, PRIV_FILE_CHOWN) ? 1149e02bc683SMark Shellenbaum PRIV_FILE_CHOWN : PRIV_FILE_CHOWN_SELF; 1150e02bc683SMark Shellenbaum } 1151e02bc683SMark Shellenbaum 1152e02bc683SMark Shellenbaum return (PRIV_POLICY(cred, priv, allzone, EPERM, NULL)); 115347def0dcSMark Shellenbaum } 115447def0dcSMark Shellenbaum 115547def0dcSMark Shellenbaum /* 115647def0dcSMark Shellenbaum * Name: secpolicy_vnode_create_gid 115747def0dcSMark Shellenbaum * 115847def0dcSMark Shellenbaum * Normal: Determine if subject can change group ownership of a file. 115947def0dcSMark Shellenbaum * 116047def0dcSMark Shellenbaum * Output: EPERM - if access denied 116147def0dcSMark Shellenbaum */ 116247def0dcSMark Shellenbaum int 116347def0dcSMark Shellenbaum secpolicy_vnode_create_gid(const cred_t *cred) 116447def0dcSMark Shellenbaum { 1165e02bc683SMark Shellenbaum if (HAS_PRIVILEGE(cred, PRIV_FILE_CHOWN)) 1166e02bc683SMark Shellenbaum return (PRIV_POLICY(cred, PRIV_FILE_CHOWN, B_FALSE, EPERM, 1167e02bc683SMark Shellenbaum NULL)); 1168e02bc683SMark Shellenbaum else 1169e02bc683SMark Shellenbaum return (PRIV_POLICY(cred, PRIV_FILE_CHOWN_SELF, B_FALSE, EPERM, 1170e02bc683SMark Shellenbaum NULL)); 11717c478bd9Sstevel@tonic-gate } 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate /* 11747c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_utime_modify() 11757c478bd9Sstevel@tonic-gate * 11767c478bd9Sstevel@tonic-gate * Normal: verify that subject can modify the utime on a file. 11777c478bd9Sstevel@tonic-gate * 11787c478bd9Sstevel@tonic-gate * Output: EPERM - if access denied. 11797c478bd9Sstevel@tonic-gate */ 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate static int 11827c478bd9Sstevel@tonic-gate secpolicy_vnode_utime_modify(const cred_t *cred) 11837c478bd9Sstevel@tonic-gate { 11847c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_OWNER, B_FALSE, EPERM, 11857c478bd9Sstevel@tonic-gate "modify file times")); 11867c478bd9Sstevel@tonic-gate } 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate 11897c478bd9Sstevel@tonic-gate /* 11907c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_setdac() 11917c478bd9Sstevel@tonic-gate * 11927c478bd9Sstevel@tonic-gate * Normal: verify that subject can modify the mode of a file. 11937c478bd9Sstevel@tonic-gate * allzone privilege needed when modifying root owned object. 11947c478bd9Sstevel@tonic-gate * 11957c478bd9Sstevel@tonic-gate * Output: EPERM - if access denied. 11967c478bd9Sstevel@tonic-gate */ 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate int 11997c478bd9Sstevel@tonic-gate secpolicy_vnode_setdac(const cred_t *cred, uid_t owner) 12007c478bd9Sstevel@tonic-gate { 12017c478bd9Sstevel@tonic-gate if (owner == cred->cr_uid) 12027c478bd9Sstevel@tonic-gate return (0); 12037c478bd9Sstevel@tonic-gate 12047c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_OWNER, owner == 0, EPERM, NULL)); 12057c478bd9Sstevel@tonic-gate } 12067c478bd9Sstevel@tonic-gate /* 12077c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_stky_modify() 12087c478bd9Sstevel@tonic-gate * 12097c478bd9Sstevel@tonic-gate * Normal: verify that subject can make a file a "sticky". 12107c478bd9Sstevel@tonic-gate * 12117c478bd9Sstevel@tonic-gate * Output: EPERM - if access denied. 12127c478bd9Sstevel@tonic-gate */ 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate int 12157c478bd9Sstevel@tonic-gate secpolicy_vnode_stky_modify(const cred_t *cred) 12167c478bd9Sstevel@tonic-gate { 12177c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_SYS_CONFIG, B_FALSE, EPERM, 12187c478bd9Sstevel@tonic-gate "set file sticky")); 12197c478bd9Sstevel@tonic-gate } 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate /* 12227c478bd9Sstevel@tonic-gate * Policy determines whether we can remove an entry from a directory, 12237c478bd9Sstevel@tonic-gate * regardless of permission bits. 12247c478bd9Sstevel@tonic-gate */ 12257c478bd9Sstevel@tonic-gate int 12267c478bd9Sstevel@tonic-gate secpolicy_vnode_remove(const cred_t *cr) 12277c478bd9Sstevel@tonic-gate { 12287c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_OWNER, B_FALSE, EACCES, 12297c478bd9Sstevel@tonic-gate "sticky directory")); 12307c478bd9Sstevel@tonic-gate } 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate int 12337c478bd9Sstevel@tonic-gate secpolicy_vnode_owner(const cred_t *cr, uid_t owner) 12347c478bd9Sstevel@tonic-gate { 12357c478bd9Sstevel@tonic-gate boolean_t allzone = (owner == 0); 12367c478bd9Sstevel@tonic-gate 12377c478bd9Sstevel@tonic-gate if (owner == cr->cr_uid) 12387c478bd9Sstevel@tonic-gate return (0); 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_OWNER, allzone, EPERM, NULL)); 12417c478bd9Sstevel@tonic-gate } 12427c478bd9Sstevel@tonic-gate 124313f9f30eSmarks void 124413f9f30eSmarks secpolicy_setid_clear(vattr_t *vap, cred_t *cr) 124513f9f30eSmarks { 124613f9f30eSmarks if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0 && 124713f9f30eSmarks secpolicy_vnode_setid_retain(cr, 124813f9f30eSmarks (vap->va_mode & S_ISUID) != 0 && 124913f9f30eSmarks (vap->va_mask & AT_UID) != 0 && vap->va_uid == 0) != 0) { 125013f9f30eSmarks vap->va_mask |= AT_MODE; 125113f9f30eSmarks vap->va_mode &= ~(S_ISUID|S_ISGID); 125213f9f30eSmarks } 125313f9f30eSmarks } 125413f9f30eSmarks 1255f92daba9Smarks int 1256f92daba9Smarks secpolicy_setid_setsticky_clear(vnode_t *vp, vattr_t *vap, const vattr_t *ovap, 1257f92daba9Smarks cred_t *cr) 1258f92daba9Smarks { 1259f92daba9Smarks int error; 1260f92daba9Smarks 1261f92daba9Smarks if ((vap->va_mode & S_ISUID) != 0 && 1262f92daba9Smarks (error = secpolicy_vnode_setid_modify(cr, 1263f92daba9Smarks ovap->va_uid)) != 0) { 1264f92daba9Smarks return (error); 1265f92daba9Smarks } 1266f92daba9Smarks 1267f92daba9Smarks /* 1268f92daba9Smarks * Check privilege if attempting to set the 1269f92daba9Smarks * sticky bit on a non-directory. 1270f92daba9Smarks */ 1271f92daba9Smarks if (vp->v_type != VDIR && (vap->va_mode & S_ISVTX) != 0 && 1272f92daba9Smarks secpolicy_vnode_stky_modify(cr) != 0) { 1273f92daba9Smarks vap->va_mode &= ~S_ISVTX; 1274f92daba9Smarks } 1275f92daba9Smarks 1276f92daba9Smarks /* 1277f92daba9Smarks * Check for privilege if attempting to set the 1278f92daba9Smarks * group-id bit. 1279f92daba9Smarks */ 1280f92daba9Smarks if ((vap->va_mode & S_ISGID) != 0 && 1281f92daba9Smarks secpolicy_vnode_setids_setgids(cr, ovap->va_gid) != 0) { 1282f92daba9Smarks vap->va_mode &= ~S_ISGID; 1283f92daba9Smarks } 1284f92daba9Smarks 1285f92daba9Smarks return (0); 1286f92daba9Smarks } 1287f92daba9Smarks 1288da6c28aaSamw #define ATTR_FLAG_PRIV(attr, value, cr) \ 1289da6c28aaSamw PRIV_POLICY(cr, value ? PRIV_FILE_FLAG_SET : PRIV_ALL, \ 1290da6c28aaSamw B_FALSE, EPERM, NULL) 1291da6c28aaSamw 1292da6c28aaSamw /* 1293da6c28aaSamw * Check privileges for setting xvattr attributes 1294da6c28aaSamw */ 1295da6c28aaSamw int 1296da6c28aaSamw secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype) 1297da6c28aaSamw { 1298da6c28aaSamw xoptattr_t *xoap; 1299da6c28aaSamw int error = 0; 1300da6c28aaSamw 1301da6c28aaSamw if ((xoap = xva_getxoptattr(xvap)) == NULL) 1302da6c28aaSamw return (EINVAL); 1303da6c28aaSamw 1304da6c28aaSamw /* 1305da6c28aaSamw * First process the DOS bits 1306da6c28aaSamw */ 1307da6c28aaSamw if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE) || 1308da6c28aaSamw XVA_ISSET_REQ(xvap, XAT_HIDDEN) || 1309da6c28aaSamw XVA_ISSET_REQ(xvap, XAT_READONLY) || 1310da6c28aaSamw XVA_ISSET_REQ(xvap, XAT_SYSTEM) || 1311fd9ee8b5Sjoyce mcintosh XVA_ISSET_REQ(xvap, XAT_CREATETIME) || 1312fd9ee8b5Sjoyce mcintosh XVA_ISSET_REQ(xvap, XAT_OFFLINE) || 1313fd9ee8b5Sjoyce mcintosh XVA_ISSET_REQ(xvap, XAT_SPARSE)) { 1314da6c28aaSamw if ((error = secpolicy_vnode_owner(cr, owner)) != 0) 1315da6c28aaSamw return (error); 1316da6c28aaSamw } 1317da6c28aaSamw 1318da6c28aaSamw /* 1319da6c28aaSamw * Now handle special attributes 1320da6c28aaSamw */ 1321da6c28aaSamw 1322da6c28aaSamw if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE)) 1323da6c28aaSamw error = ATTR_FLAG_PRIV(XAT_IMMUTABLE, 1324da6c28aaSamw xoap->xoa_immutable, cr); 1325da6c28aaSamw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_NOUNLINK)) 1326da6c28aaSamw error = ATTR_FLAG_PRIV(XAT_NOUNLINK, 1327da6c28aaSamw xoap->xoa_nounlink, cr); 1328da6c28aaSamw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_APPENDONLY)) 1329da6c28aaSamw error = ATTR_FLAG_PRIV(XAT_APPENDONLY, 1330da6c28aaSamw xoap->xoa_appendonly, cr); 1331da6c28aaSamw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_NODUMP)) 1332da6c28aaSamw error = ATTR_FLAG_PRIV(XAT_NODUMP, 1333da6c28aaSamw xoap->xoa_nodump, cr); 1334da6c28aaSamw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_OPAQUE)) 1335da6c28aaSamw error = EPERM; 1336da6c28aaSamw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED)) { 1337da6c28aaSamw error = ATTR_FLAG_PRIV(XAT_AV_QUARANTINED, 1338da6c28aaSamw xoap->xoa_av_quarantined, cr); 1339e8f97327Smarks if (error == 0 && vtype != VREG && xoap->xoa_av_quarantined) 1340da6c28aaSamw error = EINVAL; 1341da6c28aaSamw } 1342da6c28aaSamw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED)) 1343da6c28aaSamw error = ATTR_FLAG_PRIV(XAT_AV_MODIFIED, 1344da6c28aaSamw xoap->xoa_av_modified, cr); 1345da6c28aaSamw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) { 1346da6c28aaSamw error = ATTR_FLAG_PRIV(XAT_AV_SCANSTAMP, 1347da6c28aaSamw xoap->xoa_av_scanstamp, cr); 1348da6c28aaSamw if (error == 0 && vtype != VREG) 1349da6c28aaSamw error = EINVAL; 1350da6c28aaSamw } 1351da6c28aaSamw return (error); 1352da6c28aaSamw } 1353da6c28aaSamw 13547c478bd9Sstevel@tonic-gate /* 13557c478bd9Sstevel@tonic-gate * This function checks the policy decisions surrounding the 13567c478bd9Sstevel@tonic-gate * vop setattr call. 13577c478bd9Sstevel@tonic-gate * 13587c478bd9Sstevel@tonic-gate * It should be called after sufficient locks have been established 13597c478bd9Sstevel@tonic-gate * on the underlying data structures. No concurrent modifications 13607c478bd9Sstevel@tonic-gate * should be allowed. 13617c478bd9Sstevel@tonic-gate * 13627c478bd9Sstevel@tonic-gate * The caller must pass in unlocked version of its vaccess function 13637c478bd9Sstevel@tonic-gate * this is required because vop_access function should lock the 13647c478bd9Sstevel@tonic-gate * node for reading. A three argument function should be defined 13657c478bd9Sstevel@tonic-gate * which accepts the following argument: 13667c478bd9Sstevel@tonic-gate * A pointer to the internal "node" type (inode *) 13677c478bd9Sstevel@tonic-gate * vnode access bits (VREAD|VWRITE|VEXEC) 13687c478bd9Sstevel@tonic-gate * a pointer to the credential 13697c478bd9Sstevel@tonic-gate * 13707c478bd9Sstevel@tonic-gate * This function makes the following policy decisions: 13717c478bd9Sstevel@tonic-gate * 13727c478bd9Sstevel@tonic-gate * - change permissions 13737c478bd9Sstevel@tonic-gate * - permission to change file mode if not owner 13747c478bd9Sstevel@tonic-gate * - permission to add sticky bit to non-directory 13757c478bd9Sstevel@tonic-gate * - permission to add set-gid bit 13767c478bd9Sstevel@tonic-gate * 13777c478bd9Sstevel@tonic-gate * The ovap argument should include AT_MODE|AT_UID|AT_GID. 13787c478bd9Sstevel@tonic-gate * 13797c478bd9Sstevel@tonic-gate * If the vap argument does not include AT_MODE, the mode will be copied from 13807c478bd9Sstevel@tonic-gate * ovap. In certain situations set-uid/set-gid bits need to be removed; 13817c478bd9Sstevel@tonic-gate * this is done by marking vap->va_mask to include AT_MODE and va_mode 13827c478bd9Sstevel@tonic-gate * is updated to the newly computed mode. 13837c478bd9Sstevel@tonic-gate */ 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate int 13867c478bd9Sstevel@tonic-gate secpolicy_vnode_setattr(cred_t *cr, struct vnode *vp, struct vattr *vap, 13877c478bd9Sstevel@tonic-gate const struct vattr *ovap, int flags, 13887c478bd9Sstevel@tonic-gate int unlocked_access(void *, int, cred_t *), 13897c478bd9Sstevel@tonic-gate void *node) 13907c478bd9Sstevel@tonic-gate { 13917c478bd9Sstevel@tonic-gate int mask = vap->va_mask; 13927c478bd9Sstevel@tonic-gate int error = 0; 1393da6c28aaSamw boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE; 13947c478bd9Sstevel@tonic-gate 13957c478bd9Sstevel@tonic-gate if (mask & AT_SIZE) { 13967c478bd9Sstevel@tonic-gate if (vp->v_type == VDIR) { 13977c478bd9Sstevel@tonic-gate error = EISDIR; 13987c478bd9Sstevel@tonic-gate goto out; 13997c478bd9Sstevel@tonic-gate } 1400da6c28aaSamw 1401da6c28aaSamw /* 1402da6c28aaSamw * If ATTR_NOACLCHECK is set in the flags, then we don't 1403da6c28aaSamw * perform the secondary unlocked_access() call since the 1404da6c28aaSamw * ACL (if any) is being checked there. 1405da6c28aaSamw */ 1406da6c28aaSamw if (skipaclchk == B_FALSE) { 14077c478bd9Sstevel@tonic-gate error = unlocked_access(node, VWRITE, cr); 14087c478bd9Sstevel@tonic-gate if (error) 14097c478bd9Sstevel@tonic-gate goto out; 14107c478bd9Sstevel@tonic-gate } 1411da6c28aaSamw } 14127c478bd9Sstevel@tonic-gate if (mask & AT_MODE) { 14137c478bd9Sstevel@tonic-gate /* 14147c478bd9Sstevel@tonic-gate * If not the owner of the file then check privilege 14157c478bd9Sstevel@tonic-gate * for two things: the privilege to set the mode at all 14167c478bd9Sstevel@tonic-gate * and, if we're setting setuid, we also need permissions 14177c478bd9Sstevel@tonic-gate * to add the set-uid bit, if we're not the owner. 14187c478bd9Sstevel@tonic-gate * In the specific case of creating a set-uid root 14197c478bd9Sstevel@tonic-gate * file, we need even more permissions. 14207c478bd9Sstevel@tonic-gate */ 14217c478bd9Sstevel@tonic-gate if ((error = secpolicy_vnode_setdac(cr, ovap->va_uid)) != 0) 14227c478bd9Sstevel@tonic-gate goto out; 14237c478bd9Sstevel@tonic-gate 1424f92daba9Smarks if ((error = secpolicy_setid_setsticky_clear(vp, vap, 1425f92daba9Smarks ovap, cr)) != 0) 14267c478bd9Sstevel@tonic-gate goto out; 14277c478bd9Sstevel@tonic-gate } else 14287c478bd9Sstevel@tonic-gate vap->va_mode = ovap->va_mode; 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate if (mask & (AT_UID|AT_GID)) { 14317c478bd9Sstevel@tonic-gate boolean_t checkpriv = B_FALSE; 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate /* 14347c478bd9Sstevel@tonic-gate * Chowning files. 14357c478bd9Sstevel@tonic-gate * 14367c478bd9Sstevel@tonic-gate * If you are the file owner: 14377c478bd9Sstevel@tonic-gate * chown to other uid FILE_CHOWN_SELF 14387c478bd9Sstevel@tonic-gate * chown to gid (non-member) FILE_CHOWN_SELF 14397c478bd9Sstevel@tonic-gate * chown to gid (member) <none> 14407c478bd9Sstevel@tonic-gate * 14417c478bd9Sstevel@tonic-gate * Instead of PRIV_FILE_CHOWN_SELF, FILE_CHOWN is also 14427c478bd9Sstevel@tonic-gate * acceptable but the first one is reported when debugging. 14437c478bd9Sstevel@tonic-gate * 14447c478bd9Sstevel@tonic-gate * If you are not the file owner: 14457c478bd9Sstevel@tonic-gate * chown from root PRIV_FILE_CHOWN + zone 14467c478bd9Sstevel@tonic-gate * chown from other to any PRIV_FILE_CHOWN 14477c478bd9Sstevel@tonic-gate * 14487c478bd9Sstevel@tonic-gate */ 14497c478bd9Sstevel@tonic-gate if (cr->cr_uid != ovap->va_uid) { 14507c478bd9Sstevel@tonic-gate checkpriv = B_TRUE; 14517c478bd9Sstevel@tonic-gate } else { 14527c478bd9Sstevel@tonic-gate if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || 14537c478bd9Sstevel@tonic-gate ((mask & AT_GID) && vap->va_gid != ovap->va_gid && 14547c478bd9Sstevel@tonic-gate !groupmember(vap->va_gid, cr))) { 14557c478bd9Sstevel@tonic-gate checkpriv = B_TRUE; 14567c478bd9Sstevel@tonic-gate } 14577c478bd9Sstevel@tonic-gate } 14587c478bd9Sstevel@tonic-gate /* 14597c478bd9Sstevel@tonic-gate * If necessary, check privilege to see if update can be done. 14607c478bd9Sstevel@tonic-gate */ 14617c478bd9Sstevel@tonic-gate if (checkpriv && 1462e02bc683SMark Shellenbaum (error = secpolicy_vnode_chown(cr, ovap->va_uid)) != 0) { 14637c478bd9Sstevel@tonic-gate goto out; 14647c478bd9Sstevel@tonic-gate } 14657c478bd9Sstevel@tonic-gate 14667c478bd9Sstevel@tonic-gate /* 14677c478bd9Sstevel@tonic-gate * If the file has either the set UID or set GID bits 14687c478bd9Sstevel@tonic-gate * set and the caller can set the bits, then leave them. 14697c478bd9Sstevel@tonic-gate */ 147013f9f30eSmarks secpolicy_setid_clear(vap, cr); 14717c478bd9Sstevel@tonic-gate } 14727c478bd9Sstevel@tonic-gate if (mask & (AT_ATIME|AT_MTIME)) { 14737c478bd9Sstevel@tonic-gate /* 14747c478bd9Sstevel@tonic-gate * If not the file owner and not otherwise privileged, 14757c478bd9Sstevel@tonic-gate * always return an error when setting the 14767c478bd9Sstevel@tonic-gate * time other than the current (ATTR_UTIME flag set). 14777c478bd9Sstevel@tonic-gate * If setting the current time (ATTR_UTIME not set) then 14787c478bd9Sstevel@tonic-gate * unlocked_access will check permissions according to policy. 14797c478bd9Sstevel@tonic-gate */ 14807c478bd9Sstevel@tonic-gate if (cr->cr_uid != ovap->va_uid) { 14817c478bd9Sstevel@tonic-gate if (flags & ATTR_UTIME) 14827c478bd9Sstevel@tonic-gate error = secpolicy_vnode_utime_modify(cr); 1483da6c28aaSamw else if (skipaclchk == B_FALSE) { 14847c478bd9Sstevel@tonic-gate error = unlocked_access(node, VWRITE, cr); 14857c478bd9Sstevel@tonic-gate if (error == EACCES && 14867c478bd9Sstevel@tonic-gate secpolicy_vnode_utime_modify(cr) == 0) 14877c478bd9Sstevel@tonic-gate error = 0; 14887c478bd9Sstevel@tonic-gate } 14897c478bd9Sstevel@tonic-gate if (error) 14907c478bd9Sstevel@tonic-gate goto out; 14917c478bd9Sstevel@tonic-gate } 14927c478bd9Sstevel@tonic-gate } 1493da6c28aaSamw 1494da6c28aaSamw /* 1495da6c28aaSamw * Check for optional attributes here by checking the following: 1496da6c28aaSamw */ 1497da6c28aaSamw if (mask & AT_XVATTR) 1498da6c28aaSamw error = secpolicy_xvattr((xvattr_t *)vap, ovap->va_uid, cr, 1499da6c28aaSamw vp->v_type); 15007c478bd9Sstevel@tonic-gate out: 15017c478bd9Sstevel@tonic-gate return (error); 15027c478bd9Sstevel@tonic-gate } 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate /* 15057c478bd9Sstevel@tonic-gate * Name: secpolicy_pcfs_modify_bootpartition() 15067c478bd9Sstevel@tonic-gate * 15077c478bd9Sstevel@tonic-gate * Normal: verify that subject can modify a pcfs boot partition. 15087c478bd9Sstevel@tonic-gate * 15097c478bd9Sstevel@tonic-gate * Output: EACCES - if privilege check failed. 15107c478bd9Sstevel@tonic-gate */ 15117c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 15127c478bd9Sstevel@tonic-gate int 15137c478bd9Sstevel@tonic-gate secpolicy_pcfs_modify_bootpartition(const cred_t *cred) 15147c478bd9Sstevel@tonic-gate { 15157c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_ALL, B_FALSE, EACCES, 15167c478bd9Sstevel@tonic-gate "modify pcfs boot partition")); 15177c478bd9Sstevel@tonic-gate } 15187c478bd9Sstevel@tonic-gate 15197c478bd9Sstevel@tonic-gate /* 15207c478bd9Sstevel@tonic-gate * System V IPC routines 15217c478bd9Sstevel@tonic-gate */ 15227c478bd9Sstevel@tonic-gate int 15237c478bd9Sstevel@tonic-gate secpolicy_ipc_owner(const cred_t *cr, const struct kipc_perm *ip) 15247c478bd9Sstevel@tonic-gate { 15257c478bd9Sstevel@tonic-gate if (crgetzoneid(cr) != ip->ipc_zoneid || 15267c478bd9Sstevel@tonic-gate (cr->cr_uid != ip->ipc_uid && cr->cr_uid != ip->ipc_cuid)) { 15277c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 15287c478bd9Sstevel@tonic-gate if (ip->ipc_uid == 0 || ip->ipc_cuid == 0) 15297c478bd9Sstevel@tonic-gate allzone = B_TRUE; 15307c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_OWNER, allzone, EPERM, NULL)); 15317c478bd9Sstevel@tonic-gate } 15327c478bd9Sstevel@tonic-gate return (0); 15337c478bd9Sstevel@tonic-gate } 15347c478bd9Sstevel@tonic-gate 15357c478bd9Sstevel@tonic-gate int 15367c478bd9Sstevel@tonic-gate secpolicy_ipc_config(const cred_t *cr) 15377c478bd9Sstevel@tonic-gate { 15387c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_IPC_CONFIG, B_FALSE, EPERM, NULL)); 15397c478bd9Sstevel@tonic-gate } 15407c478bd9Sstevel@tonic-gate 15417c478bd9Sstevel@tonic-gate int 15427c478bd9Sstevel@tonic-gate secpolicy_ipc_access(const cred_t *cr, const struct kipc_perm *ip, mode_t mode) 15437c478bd9Sstevel@tonic-gate { 15447c478bd9Sstevel@tonic-gate 15457c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 15467c478bd9Sstevel@tonic-gate 15477c478bd9Sstevel@tonic-gate ASSERT((mode & (MSG_R|MSG_W)) != 0); 15487c478bd9Sstevel@tonic-gate 15497c478bd9Sstevel@tonic-gate if ((mode & MSG_R) && 15507c478bd9Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_IPC_DAC_READ, allzone, EACCES, NULL) != 0) 15517c478bd9Sstevel@tonic-gate return (EACCES); 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate if (mode & MSG_W) { 15547c478bd9Sstevel@tonic-gate if (cr->cr_uid != 0 && (ip->ipc_uid == 0 || ip->ipc_cuid == 0)) 15557c478bd9Sstevel@tonic-gate allzone = B_TRUE; 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_DAC_WRITE, allzone, EACCES, 15587c478bd9Sstevel@tonic-gate NULL)); 15597c478bd9Sstevel@tonic-gate } 15607c478bd9Sstevel@tonic-gate return (0); 15617c478bd9Sstevel@tonic-gate } 15627c478bd9Sstevel@tonic-gate 15637c478bd9Sstevel@tonic-gate int 15647c478bd9Sstevel@tonic-gate secpolicy_rsm_access(const cred_t *cr, uid_t owner, mode_t mode) 15657c478bd9Sstevel@tonic-gate { 15667c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate ASSERT((mode & (MSG_R|MSG_W)) != 0); 15697c478bd9Sstevel@tonic-gate 15707c478bd9Sstevel@tonic-gate if ((mode & MSG_R) && 15717c478bd9Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_IPC_DAC_READ, allzone, EACCES, NULL) != 0) 15727c478bd9Sstevel@tonic-gate return (EACCES); 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate if (mode & MSG_W) { 15757c478bd9Sstevel@tonic-gate if (cr->cr_uid != 0 && owner == 0) 15767c478bd9Sstevel@tonic-gate allzone = B_TRUE; 15777c478bd9Sstevel@tonic-gate 15787c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_DAC_WRITE, allzone, EACCES, 15797c478bd9Sstevel@tonic-gate NULL)); 15807c478bd9Sstevel@tonic-gate } 15817c478bd9Sstevel@tonic-gate return (0); 15827c478bd9Sstevel@tonic-gate } 15837c478bd9Sstevel@tonic-gate 15847c478bd9Sstevel@tonic-gate /* 15857c478bd9Sstevel@tonic-gate * Audit configuration. 15867c478bd9Sstevel@tonic-gate */ 15877c478bd9Sstevel@tonic-gate int 15887c478bd9Sstevel@tonic-gate secpolicy_audit_config(const cred_t *cr) 15897c478bd9Sstevel@tonic-gate { 15907c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_AUDIT, B_FALSE, EPERM, NULL)); 15917c478bd9Sstevel@tonic-gate } 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate /* 15947c478bd9Sstevel@tonic-gate * Audit record generation. 15957c478bd9Sstevel@tonic-gate */ 15967c478bd9Sstevel@tonic-gate int 15977c478bd9Sstevel@tonic-gate secpolicy_audit_modify(const cred_t *cr) 15987c478bd9Sstevel@tonic-gate { 15997c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_AUDIT, B_FALSE, EPERM, NULL)); 16007c478bd9Sstevel@tonic-gate } 16017c478bd9Sstevel@tonic-gate 16027c478bd9Sstevel@tonic-gate /* 16037c478bd9Sstevel@tonic-gate * Get audit attributes. 16047c478bd9Sstevel@tonic-gate * Either PRIV_SYS_AUDIT or PRIV_PROC_AUDIT required; report the 16057c478bd9Sstevel@tonic-gate * "Least" of the two privileges on error. 16067c478bd9Sstevel@tonic-gate */ 16077c478bd9Sstevel@tonic-gate int 1608134a1f4eSCasper H.S. Dik secpolicy_audit_getattr(const cred_t *cr, boolean_t checkonly) 16097c478bd9Sstevel@tonic-gate { 1610134a1f4eSCasper H.S. Dik int priv; 1611134a1f4eSCasper H.S. Dik 1612134a1f4eSCasper H.S. Dik if (PRIV_POLICY_ONLY(cr, PRIV_SYS_AUDIT, B_FALSE)) 1613134a1f4eSCasper H.S. Dik priv = PRIV_SYS_AUDIT; 1614134a1f4eSCasper H.S. Dik else 1615134a1f4eSCasper H.S. Dik priv = PRIV_PROC_AUDIT; 1616134a1f4eSCasper H.S. Dik 1617134a1f4eSCasper H.S. Dik if (checkonly) 1618134a1f4eSCasper H.S. Dik return (!PRIV_POLICY_ONLY(cr, priv, B_FALSE)); 1619134a1f4eSCasper H.S. Dik else 1620134a1f4eSCasper H.S. Dik return (PRIV_POLICY(cr, priv, B_FALSE, EPERM, NULL)); 16217c478bd9Sstevel@tonic-gate } 16227c478bd9Sstevel@tonic-gate 16237c478bd9Sstevel@tonic-gate 16247c478bd9Sstevel@tonic-gate /* 16257c478bd9Sstevel@tonic-gate * Locking physical memory 16267c478bd9Sstevel@tonic-gate */ 16277c478bd9Sstevel@tonic-gate int 16287c478bd9Sstevel@tonic-gate secpolicy_lock_memory(const cred_t *cr) 16297c478bd9Sstevel@tonic-gate { 16307c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_LOCK_MEMORY, B_FALSE, EPERM, NULL)); 16317c478bd9Sstevel@tonic-gate } 16327c478bd9Sstevel@tonic-gate 16337c478bd9Sstevel@tonic-gate /* 16347c478bd9Sstevel@tonic-gate * Accounting (both acct(2) and exacct). 16357c478bd9Sstevel@tonic-gate */ 16367c478bd9Sstevel@tonic-gate int 16377c478bd9Sstevel@tonic-gate secpolicy_acct(const cred_t *cr) 16387c478bd9Sstevel@tonic-gate { 16397c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ACCT, B_FALSE, EPERM, NULL)); 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate 16427c478bd9Sstevel@tonic-gate /* 16437c478bd9Sstevel@tonic-gate * Is this process privileged to change its uids at will? 16447c478bd9Sstevel@tonic-gate * Uid 0 is still considered "special" and having the SETID 16457c478bd9Sstevel@tonic-gate * privilege is not sufficient to get uid 0. 16467c478bd9Sstevel@tonic-gate * Files are owned by root, so the privilege would give 16477c478bd9Sstevel@tonic-gate * full access and euid 0 is still effective. 16487c478bd9Sstevel@tonic-gate * 16497c478bd9Sstevel@tonic-gate * If you have the privilege and euid 0 only then do you 16507c478bd9Sstevel@tonic-gate * get the powers of root wrt uid 0. 16517c478bd9Sstevel@tonic-gate * 16527c478bd9Sstevel@tonic-gate * For gid manipulations, this is should be called with an 16537c478bd9Sstevel@tonic-gate * uid of -1. 16547c478bd9Sstevel@tonic-gate * 16557c478bd9Sstevel@tonic-gate */ 16567c478bd9Sstevel@tonic-gate int 16577c478bd9Sstevel@tonic-gate secpolicy_allow_setid(const cred_t *cr, uid_t newuid, boolean_t checkonly) 16587c478bd9Sstevel@tonic-gate { 16597c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 16607c478bd9Sstevel@tonic-gate 16617c478bd9Sstevel@tonic-gate if (newuid == 0 && cr->cr_uid != 0 && cr->cr_suid != 0 && 16627c478bd9Sstevel@tonic-gate cr->cr_ruid != 0) { 16637c478bd9Sstevel@tonic-gate allzone = B_TRUE; 16647c478bd9Sstevel@tonic-gate } 16657c478bd9Sstevel@tonic-gate 16667c478bd9Sstevel@tonic-gate return (checkonly ? !PRIV_POLICY_ONLY(cr, PRIV_PROC_SETID, allzone) : 16677c478bd9Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_PROC_SETID, allzone, EPERM, NULL)); 16687c478bd9Sstevel@tonic-gate } 16697c478bd9Sstevel@tonic-gate 16707c478bd9Sstevel@tonic-gate 16717c478bd9Sstevel@tonic-gate /* 16727c478bd9Sstevel@tonic-gate * Acting on a different process: if the mode is for writing, 16737c478bd9Sstevel@tonic-gate * the restrictions are more severe. This is called after 16747c478bd9Sstevel@tonic-gate * we've verified that the uids do not match. 16757c478bd9Sstevel@tonic-gate */ 16767c478bd9Sstevel@tonic-gate int 16777c478bd9Sstevel@tonic-gate secpolicy_proc_owner(const cred_t *scr, const cred_t *tcr, int mode) 16787c478bd9Sstevel@tonic-gate { 16797c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 16807c478bd9Sstevel@tonic-gate 16817c478bd9Sstevel@tonic-gate if ((mode & VWRITE) && scr->cr_uid != 0 && 16827c478bd9Sstevel@tonic-gate (tcr->cr_uid == 0 || tcr->cr_ruid == 0 || tcr->cr_suid == 0)) 16837c478bd9Sstevel@tonic-gate allzone = B_TRUE; 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, allzone, EPERM, NULL)); 16867c478bd9Sstevel@tonic-gate } 16877c478bd9Sstevel@tonic-gate 16887c478bd9Sstevel@tonic-gate int 16897c478bd9Sstevel@tonic-gate secpolicy_proc_access(const cred_t *scr) 16907c478bd9Sstevel@tonic-gate { 16917c478bd9Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, B_FALSE, EACCES, NULL)); 16927c478bd9Sstevel@tonic-gate } 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate int 16957c478bd9Sstevel@tonic-gate secpolicy_proc_excl_open(const cred_t *scr) 16967c478bd9Sstevel@tonic-gate { 16977c478bd9Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, B_FALSE, EBUSY, NULL)); 16987c478bd9Sstevel@tonic-gate } 16997c478bd9Sstevel@tonic-gate 17007c478bd9Sstevel@tonic-gate int 17017c478bd9Sstevel@tonic-gate secpolicy_proc_zone(const cred_t *scr) 17027c478bd9Sstevel@tonic-gate { 17037c478bd9Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_ZONE, B_FALSE, EPERM, NULL)); 17047c478bd9Sstevel@tonic-gate } 17057c478bd9Sstevel@tonic-gate 17067c478bd9Sstevel@tonic-gate /* 17077c478bd9Sstevel@tonic-gate * Destroying the system 17087c478bd9Sstevel@tonic-gate */ 17097c478bd9Sstevel@tonic-gate 17107c478bd9Sstevel@tonic-gate int 17117c478bd9Sstevel@tonic-gate secpolicy_kmdb(const cred_t *scr) 17127c478bd9Sstevel@tonic-gate { 17137c478bd9Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); 17147c478bd9Sstevel@tonic-gate } 17157c478bd9Sstevel@tonic-gate 17167aec1d6eScindi int 17177aec1d6eScindi secpolicy_error_inject(const cred_t *scr) 17187aec1d6eScindi { 17197aec1d6eScindi return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); 17207aec1d6eScindi } 17217aec1d6eScindi 17227c478bd9Sstevel@tonic-gate /* 17237c478bd9Sstevel@tonic-gate * Processor sets, cpu configuration, resource pools. 17247c478bd9Sstevel@tonic-gate */ 17257c478bd9Sstevel@tonic-gate int 17267c478bd9Sstevel@tonic-gate secpolicy_pset(const cred_t *cr) 17277c478bd9Sstevel@tonic-gate { 17287c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 17297c478bd9Sstevel@tonic-gate } 17307c478bd9Sstevel@tonic-gate 1731bbf58fc5S /* 1732bbf58fc5S * Processor set binding. 1733bbf58fc5S */ 1734bbf58fc5S int 1735bbf58fc5S secpolicy_pbind(const cred_t *cr) 1736bbf58fc5S { 1737bbf58fc5S if (PRIV_POLICY_ONLY(cr, PRIV_SYS_RES_CONFIG, B_FALSE)) 1738bbf58fc5S return (secpolicy_pset(cr)); 1739bbf58fc5S return (PRIV_POLICY(cr, PRIV_SYS_RES_BIND, B_FALSE, EPERM, NULL)); 1740bbf58fc5S } 1741bbf58fc5S 17427c478bd9Sstevel@tonic-gate int 17437c478bd9Sstevel@tonic-gate secpolicy_ponline(const cred_t *cr) 17447c478bd9Sstevel@tonic-gate { 17457c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 17467c478bd9Sstevel@tonic-gate } 17477c478bd9Sstevel@tonic-gate 17487c478bd9Sstevel@tonic-gate int 17497c478bd9Sstevel@tonic-gate secpolicy_pool(const cred_t *cr) 17507c478bd9Sstevel@tonic-gate { 17517c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 17527c478bd9Sstevel@tonic-gate } 17537c478bd9Sstevel@tonic-gate 17547c478bd9Sstevel@tonic-gate int 17557c478bd9Sstevel@tonic-gate secpolicy_blacklist(const cred_t *cr) 17567c478bd9Sstevel@tonic-gate { 17577c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 17587c478bd9Sstevel@tonic-gate } 17597c478bd9Sstevel@tonic-gate 17607c478bd9Sstevel@tonic-gate /* 17617c478bd9Sstevel@tonic-gate * Catch all system configuration. 17627c478bd9Sstevel@tonic-gate */ 17637c478bd9Sstevel@tonic-gate int 17647c478bd9Sstevel@tonic-gate secpolicy_sys_config(const cred_t *cr, boolean_t checkonly) 17657c478bd9Sstevel@tonic-gate { 17667c478bd9Sstevel@tonic-gate if (checkonly) { 17677c478bd9Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_CONFIG, B_FALSE) ? 0 : 17687c478bd9Sstevel@tonic-gate EPERM); 17697c478bd9Sstevel@tonic-gate } else { 17707c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 17717c478bd9Sstevel@tonic-gate } 17727c478bd9Sstevel@tonic-gate } 17737c478bd9Sstevel@tonic-gate 17747c478bd9Sstevel@tonic-gate /* 17757c478bd9Sstevel@tonic-gate * Zone administration (halt, reboot, etc.) from within zone. 17767c478bd9Sstevel@tonic-gate */ 17777c478bd9Sstevel@tonic-gate int 17787c478bd9Sstevel@tonic-gate secpolicy_zone_admin(const cred_t *cr, boolean_t checkonly) 17797c478bd9Sstevel@tonic-gate { 17807c478bd9Sstevel@tonic-gate if (checkonly) { 17817c478bd9Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_ADMIN, B_FALSE) ? 0 : 17827c478bd9Sstevel@tonic-gate EPERM); 17837c478bd9Sstevel@tonic-gate } else { 17847c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, 17857c478bd9Sstevel@tonic-gate NULL)); 17867c478bd9Sstevel@tonic-gate } 17877c478bd9Sstevel@tonic-gate } 17887c478bd9Sstevel@tonic-gate 17897c478bd9Sstevel@tonic-gate /* 17907c478bd9Sstevel@tonic-gate * Zone configuration (create, halt, enter). 17917c478bd9Sstevel@tonic-gate */ 17927c478bd9Sstevel@tonic-gate int 17937c478bd9Sstevel@tonic-gate secpolicy_zone_config(const cred_t *cr) 17947c478bd9Sstevel@tonic-gate { 17957c478bd9Sstevel@tonic-gate /* 17967c478bd9Sstevel@tonic-gate * Require all privileges to avoid possibility of privilege 17977c478bd9Sstevel@tonic-gate * escalation. 17987c478bd9Sstevel@tonic-gate */ 1799134a1f4eSCasper H.S. Dik return (secpolicy_require_set(cr, PRIV_FULLSET, NULL, KLPDARG_NONE)); 18007c478bd9Sstevel@tonic-gate } 18017c478bd9Sstevel@tonic-gate 18027c478bd9Sstevel@tonic-gate /* 18037c478bd9Sstevel@tonic-gate * Various other system configuration calls 18047c478bd9Sstevel@tonic-gate */ 18057c478bd9Sstevel@tonic-gate int 18067c478bd9Sstevel@tonic-gate secpolicy_coreadm(const cred_t *cr) 18077c478bd9Sstevel@tonic-gate { 18087c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, NULL)); 18097c478bd9Sstevel@tonic-gate } 18107c478bd9Sstevel@tonic-gate 18117c478bd9Sstevel@tonic-gate int 18127c478bd9Sstevel@tonic-gate secpolicy_systeminfo(const cred_t *cr) 18137c478bd9Sstevel@tonic-gate { 18147c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, NULL)); 18157c478bd9Sstevel@tonic-gate } 18167c478bd9Sstevel@tonic-gate 18177c478bd9Sstevel@tonic-gate int 18187c478bd9Sstevel@tonic-gate secpolicy_dispadm(const cred_t *cr) 18197c478bd9Sstevel@tonic-gate { 18207c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 18217c478bd9Sstevel@tonic-gate } 18227c478bd9Sstevel@tonic-gate 18237c478bd9Sstevel@tonic-gate int 18247c478bd9Sstevel@tonic-gate secpolicy_settime(const cred_t *cr) 18257c478bd9Sstevel@tonic-gate { 18267c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_TIME, B_FALSE, EPERM, NULL)); 18277c478bd9Sstevel@tonic-gate } 18287c478bd9Sstevel@tonic-gate 18297c478bd9Sstevel@tonic-gate /* 18307c478bd9Sstevel@tonic-gate * For realtime users: high resolution clock. 18317c478bd9Sstevel@tonic-gate */ 18327c478bd9Sstevel@tonic-gate int 18337c478bd9Sstevel@tonic-gate secpolicy_clock_highres(const cred_t *cr) 18347c478bd9Sstevel@tonic-gate { 18357c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_CLOCK_HIGHRES, B_FALSE, EPERM, 18367c478bd9Sstevel@tonic-gate NULL)); 18377c478bd9Sstevel@tonic-gate } 18387c478bd9Sstevel@tonic-gate 18397c478bd9Sstevel@tonic-gate /* 18407c478bd9Sstevel@tonic-gate * drv_priv() is documented as callable from interrupt context, not that 18417c478bd9Sstevel@tonic-gate * anyone ever does, but still. No debugging or auditing can be done when 18427c478bd9Sstevel@tonic-gate * it is called from interrupt context. 18437c478bd9Sstevel@tonic-gate * returns 0 on succes, EPERM on failure. 18447c478bd9Sstevel@tonic-gate */ 18457c478bd9Sstevel@tonic-gate int 18467c478bd9Sstevel@tonic-gate drv_priv(cred_t *cr) 18477c478bd9Sstevel@tonic-gate { 18487c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 18497c478bd9Sstevel@tonic-gate } 18507c478bd9Sstevel@tonic-gate 18517c478bd9Sstevel@tonic-gate int 18527c478bd9Sstevel@tonic-gate secpolicy_sys_devices(const cred_t *cr) 18537c478bd9Sstevel@tonic-gate { 18547c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 18557c478bd9Sstevel@tonic-gate } 18567c478bd9Sstevel@tonic-gate 18577c478bd9Sstevel@tonic-gate int 18587c478bd9Sstevel@tonic-gate secpolicy_excl_open(const cred_t *cr) 18597c478bd9Sstevel@tonic-gate { 18607c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EBUSY, NULL)); 18617c478bd9Sstevel@tonic-gate } 18627c478bd9Sstevel@tonic-gate 18637c478bd9Sstevel@tonic-gate int 18647c478bd9Sstevel@tonic-gate secpolicy_rctlsys(const cred_t *cr, boolean_t is_zone_rctl) 18657c478bd9Sstevel@tonic-gate { 18667c478bd9Sstevel@tonic-gate /* zone.* rctls can only be set from the global zone */ 18677c478bd9Sstevel@tonic-gate if (is_zone_rctl && priv_policy_global(cr) != 0) 18687c478bd9Sstevel@tonic-gate return (EPERM); 18697c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 18707c478bd9Sstevel@tonic-gate } 18717c478bd9Sstevel@tonic-gate 18727c478bd9Sstevel@tonic-gate int 18737c478bd9Sstevel@tonic-gate secpolicy_resource(const cred_t *cr) 18747c478bd9Sstevel@tonic-gate { 18757c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 18767c478bd9Sstevel@tonic-gate } 18777c478bd9Sstevel@tonic-gate 18781c7cef2bSStan Studzinski int 18791c7cef2bSStan Studzinski secpolicy_resource_anon_mem(const cred_t *cr) 18801c7cef2bSStan Studzinski { 18811c7cef2bSStan Studzinski return (PRIV_POLICY_ONLY(cr, PRIV_SYS_RESOURCE, B_FALSE)); 18821c7cef2bSStan Studzinski } 18831c7cef2bSStan Studzinski 18847c478bd9Sstevel@tonic-gate /* 18857c478bd9Sstevel@tonic-gate * Processes with a real uid of 0 escape any form of accounting, much 18867c478bd9Sstevel@tonic-gate * like before. 18877c478bd9Sstevel@tonic-gate */ 18887c478bd9Sstevel@tonic-gate int 18897c478bd9Sstevel@tonic-gate secpolicy_newproc(const cred_t *cr) 18907c478bd9Sstevel@tonic-gate { 18917c478bd9Sstevel@tonic-gate if (cr->cr_ruid == 0) 18927c478bd9Sstevel@tonic-gate return (0); 18937c478bd9Sstevel@tonic-gate 18947c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 18957c478bd9Sstevel@tonic-gate } 18967c478bd9Sstevel@tonic-gate 18977c478bd9Sstevel@tonic-gate /* 18987c478bd9Sstevel@tonic-gate * Networking 18997c478bd9Sstevel@tonic-gate */ 19007c478bd9Sstevel@tonic-gate int 19017c478bd9Sstevel@tonic-gate secpolicy_net_rawaccess(const cred_t *cr) 19027c478bd9Sstevel@tonic-gate { 19037c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_NET_RAWACCESS, B_FALSE, EACCES, NULL)); 19047c478bd9Sstevel@tonic-gate } 19057c478bd9Sstevel@tonic-gate 19060a0e9771SDarren Reed int 19070a0e9771SDarren Reed secpolicy_net_observability(const cred_t *cr) 19080a0e9771SDarren Reed { 19090a0e9771SDarren Reed return (PRIV_POLICY(cr, PRIV_NET_OBSERVABILITY, B_FALSE, EACCES, NULL)); 19100a0e9771SDarren Reed } 19110a0e9771SDarren Reed 19127c478bd9Sstevel@tonic-gate /* 19137c478bd9Sstevel@tonic-gate * Need this privilege for accessing the ICMP device 19147c478bd9Sstevel@tonic-gate */ 19157c478bd9Sstevel@tonic-gate int 19167c478bd9Sstevel@tonic-gate secpolicy_net_icmpaccess(const cred_t *cr) 19177c478bd9Sstevel@tonic-gate { 19187c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_NET_ICMPACCESS, B_FALSE, EACCES, NULL)); 19197c478bd9Sstevel@tonic-gate } 19207c478bd9Sstevel@tonic-gate 19217c478bd9Sstevel@tonic-gate /* 19227c478bd9Sstevel@tonic-gate * There are a few rare cases where the kernel generates ioctls() from 19237c478bd9Sstevel@tonic-gate * interrupt context with a credential of kcred rather than NULL. 19247c478bd9Sstevel@tonic-gate * In those cases, we take the safe and cheap test. 19257c478bd9Sstevel@tonic-gate */ 19267c478bd9Sstevel@tonic-gate int 19277c478bd9Sstevel@tonic-gate secpolicy_net_config(const cred_t *cr, boolean_t checkonly) 19287c478bd9Sstevel@tonic-gate { 19297c478bd9Sstevel@tonic-gate if (checkonly) { 19307c478bd9Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE) ? 19317c478bd9Sstevel@tonic-gate 0 : EPERM); 19327c478bd9Sstevel@tonic-gate } else { 19337c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_NET_CONFIG, B_FALSE, EPERM, 19347c478bd9Sstevel@tonic-gate NULL)); 19357c478bd9Sstevel@tonic-gate } 19367c478bd9Sstevel@tonic-gate } 19377c478bd9Sstevel@tonic-gate 19387c478bd9Sstevel@tonic-gate 19397c478bd9Sstevel@tonic-gate /* 1940e6bdcbd5Sdh155122 * PRIV_SYS_NET_CONFIG is a superset of PRIV_SYS_IP_CONFIG. 1941f4b3ec61Sdh155122 * 1942f4b3ec61Sdh155122 * There are a few rare cases where the kernel generates ioctls() from 1943f4b3ec61Sdh155122 * interrupt context with a credential of kcred rather than NULL. 1944f4b3ec61Sdh155122 * In those cases, we take the safe and cheap test. 1945f4b3ec61Sdh155122 */ 1946f4b3ec61Sdh155122 int 1947f4b3ec61Sdh155122 secpolicy_ip_config(const cred_t *cr, boolean_t checkonly) 1948f4b3ec61Sdh155122 { 1949f4b3ec61Sdh155122 if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE)) 1950f4b3ec61Sdh155122 return (secpolicy_net_config(cr, checkonly)); 1951f4b3ec61Sdh155122 1952f4b3ec61Sdh155122 if (checkonly) { 1953f4b3ec61Sdh155122 return (PRIV_POLICY_ONLY(cr, PRIV_SYS_IP_CONFIG, B_FALSE) ? 1954f4b3ec61Sdh155122 0 : EPERM); 1955f4b3ec61Sdh155122 } else { 1956f4b3ec61Sdh155122 return (PRIV_POLICY(cr, PRIV_SYS_IP_CONFIG, B_FALSE, EPERM, 1957f4b3ec61Sdh155122 NULL)); 1958f4b3ec61Sdh155122 } 1959f4b3ec61Sdh155122 } 1960f4b3ec61Sdh155122 1961eae72b5bSSebastien Roy /* 1962eae72b5bSSebastien Roy * PRIV_SYS_NET_CONFIG is a superset of PRIV_SYS_DL_CONFIG. 1963eae72b5bSSebastien Roy */ 1964eae72b5bSSebastien Roy int 1965eae72b5bSSebastien Roy secpolicy_dl_config(const cred_t *cr) 1966eae72b5bSSebastien Roy { 1967eae72b5bSSebastien Roy if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE)) 1968eae72b5bSSebastien Roy return (secpolicy_net_config(cr, B_FALSE)); 19692b24ab6bSSebastien Roy return (PRIV_POLICY(cr, PRIV_SYS_DL_CONFIG, B_FALSE, EPERM, NULL)); 1970eae72b5bSSebastien Roy } 1971eae72b5bSSebastien Roy 19722b24ab6bSSebastien Roy /* 19732b24ab6bSSebastien Roy * PRIV_SYS_DL_CONFIG is a superset of PRIV_SYS_IPTUN_CONFIG. 19742b24ab6bSSebastien Roy */ 19752b24ab6bSSebastien Roy int 19762b24ab6bSSebastien Roy secpolicy_iptun_config(const cred_t *cr) 19772b24ab6bSSebastien Roy { 19782b24ab6bSSebastien Roy if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE)) 19792b24ab6bSSebastien Roy return (secpolicy_net_config(cr, B_FALSE)); 19802b24ab6bSSebastien Roy if (PRIV_POLICY_ONLY(cr, PRIV_SYS_DL_CONFIG, B_FALSE)) 19812b24ab6bSSebastien Roy return (secpolicy_dl_config(cr)); 19822b24ab6bSSebastien Roy return (PRIV_POLICY(cr, PRIV_SYS_IPTUN_CONFIG, B_FALSE, EPERM, NULL)); 19832b24ab6bSSebastien Roy } 1984f4b3ec61Sdh155122 1985f4b3ec61Sdh155122 /* 1986f4b3ec61Sdh155122 * Map IP pseudo privileges to actual privileges. 1987f4b3ec61Sdh155122 * So we don't need to recompile IP when we change the privileges. 1988f4b3ec61Sdh155122 */ 1989f4b3ec61Sdh155122 int 1990f4b3ec61Sdh155122 secpolicy_ip(const cred_t *cr, int netpriv, boolean_t checkonly) 1991f4b3ec61Sdh155122 { 1992f4b3ec61Sdh155122 int priv = PRIV_ALL; 1993f4b3ec61Sdh155122 1994f4b3ec61Sdh155122 switch (netpriv) { 1995f4b3ec61Sdh155122 case OP_CONFIG: 1996f4b3ec61Sdh155122 priv = PRIV_SYS_IP_CONFIG; 1997f4b3ec61Sdh155122 break; 1998f4b3ec61Sdh155122 case OP_RAW: 1999f4b3ec61Sdh155122 priv = PRIV_NET_RAWACCESS; 2000f4b3ec61Sdh155122 break; 2001f4b3ec61Sdh155122 case OP_PRIVPORT: 2002f4b3ec61Sdh155122 priv = PRIV_NET_PRIVADDR; 2003f4b3ec61Sdh155122 break; 2004f4b3ec61Sdh155122 } 2005f4b3ec61Sdh155122 ASSERT(priv != PRIV_ALL); 2006f4b3ec61Sdh155122 if (checkonly) 2007f4b3ec61Sdh155122 return (PRIV_POLICY_ONLY(cr, priv, B_FALSE) ? 0 : EPERM); 2008f4b3ec61Sdh155122 else 2009f4b3ec61Sdh155122 return (PRIV_POLICY(cr, priv, B_FALSE, EPERM, NULL)); 2010f4b3ec61Sdh155122 } 2011f4b3ec61Sdh155122 2012f4b3ec61Sdh155122 /* 20137c478bd9Sstevel@tonic-gate * Map network pseudo privileges to actual privileges. 20147c478bd9Sstevel@tonic-gate * So we don't need to recompile IP when we change the privileges. 20157c478bd9Sstevel@tonic-gate */ 20167c478bd9Sstevel@tonic-gate int 20177c478bd9Sstevel@tonic-gate secpolicy_net(const cred_t *cr, int netpriv, boolean_t checkonly) 20187c478bd9Sstevel@tonic-gate { 20197c478bd9Sstevel@tonic-gate int priv = PRIV_ALL; 20207c478bd9Sstevel@tonic-gate 20217c478bd9Sstevel@tonic-gate switch (netpriv) { 20227c478bd9Sstevel@tonic-gate case OP_CONFIG: 20237c478bd9Sstevel@tonic-gate priv = PRIV_SYS_NET_CONFIG; 20247c478bd9Sstevel@tonic-gate break; 20257c478bd9Sstevel@tonic-gate case OP_RAW: 20267c478bd9Sstevel@tonic-gate priv = PRIV_NET_RAWACCESS; 20277c478bd9Sstevel@tonic-gate break; 20287c478bd9Sstevel@tonic-gate case OP_PRIVPORT: 20297c478bd9Sstevel@tonic-gate priv = PRIV_NET_PRIVADDR; 20307c478bd9Sstevel@tonic-gate break; 20317c478bd9Sstevel@tonic-gate } 20327c478bd9Sstevel@tonic-gate ASSERT(priv != PRIV_ALL); 20337c478bd9Sstevel@tonic-gate if (checkonly) 20347c478bd9Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, priv, B_FALSE) ? 0 : EPERM); 20357c478bd9Sstevel@tonic-gate else 20367c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, priv, B_FALSE, EPERM, NULL)); 20377c478bd9Sstevel@tonic-gate } 20387c478bd9Sstevel@tonic-gate 20397c478bd9Sstevel@tonic-gate /* 20407c478bd9Sstevel@tonic-gate * Checks for operations that are either client-only or are used by 20417c478bd9Sstevel@tonic-gate * both clients and servers. 20427c478bd9Sstevel@tonic-gate */ 20437c478bd9Sstevel@tonic-gate int 20447c478bd9Sstevel@tonic-gate secpolicy_nfs(const cred_t *cr) 20457c478bd9Sstevel@tonic-gate { 20467c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_NFS, B_FALSE, EPERM, NULL)); 20477c478bd9Sstevel@tonic-gate } 20487c478bd9Sstevel@tonic-gate 20497c478bd9Sstevel@tonic-gate /* 20507c478bd9Sstevel@tonic-gate * Special case for opening rpcmod: have NFS privileges or network 20517c478bd9Sstevel@tonic-gate * config privileges. 20527c478bd9Sstevel@tonic-gate */ 20537c478bd9Sstevel@tonic-gate int 20547c478bd9Sstevel@tonic-gate secpolicy_rpcmod_open(const cred_t *cr) 20557c478bd9Sstevel@tonic-gate { 20567c478bd9Sstevel@tonic-gate if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NFS, B_FALSE)) 20577c478bd9Sstevel@tonic-gate return (secpolicy_nfs(cr)); 20587c478bd9Sstevel@tonic-gate else 20597c478bd9Sstevel@tonic-gate return (secpolicy_net_config(cr, NULL)); 20607c478bd9Sstevel@tonic-gate } 20617c478bd9Sstevel@tonic-gate 20627c478bd9Sstevel@tonic-gate int 20637c478bd9Sstevel@tonic-gate secpolicy_chroot(const cred_t *cr) 20647c478bd9Sstevel@tonic-gate { 20657c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_CHROOT, B_FALSE, EPERM, NULL)); 20667c478bd9Sstevel@tonic-gate } 20677c478bd9Sstevel@tonic-gate 20687c478bd9Sstevel@tonic-gate int 20697c478bd9Sstevel@tonic-gate secpolicy_tasksys(const cred_t *cr) 20707c478bd9Sstevel@tonic-gate { 20717c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_TASKID, B_FALSE, EPERM, NULL)); 20727c478bd9Sstevel@tonic-gate } 20737c478bd9Sstevel@tonic-gate 2074134a1f4eSCasper H.S. Dik int 2075*37294019SJerry Jelinek secpolicy_meminfo(const cred_t *cr) 2076*37294019SJerry Jelinek { 2077*37294019SJerry Jelinek return (PRIV_POLICY(cr, PRIV_PROC_MEMINFO, B_FALSE, EPERM, NULL)); 2078*37294019SJerry Jelinek } 2079*37294019SJerry Jelinek 2080*37294019SJerry Jelinek int 2081134a1f4eSCasper H.S. Dik secpolicy_pfexec_register(const cred_t *cr) 2082134a1f4eSCasper H.S. Dik { 2083134a1f4eSCasper H.S. Dik return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_TRUE, EPERM, NULL)); 2084134a1f4eSCasper H.S. Dik } 2085134a1f4eSCasper H.S. Dik 20867c478bd9Sstevel@tonic-gate /* 20877c478bd9Sstevel@tonic-gate * Basic privilege checks. 20887c478bd9Sstevel@tonic-gate */ 20897c478bd9Sstevel@tonic-gate int 2090ddf7fe95Scasper secpolicy_basic_exec(const cred_t *cr, vnode_t *vp) 20917c478bd9Sstevel@tonic-gate { 2092134a1f4eSCasper H.S. Dik FAST_BASIC_CHECK(cr, PRIV_PROC_EXEC); 2093134a1f4eSCasper H.S. Dik 2094ddf7fe95Scasper return (priv_policy_va(cr, PRIV_PROC_EXEC, B_FALSE, EPERM, NULL, 2095ddf7fe95Scasper KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE)); 20967c478bd9Sstevel@tonic-gate } 20977c478bd9Sstevel@tonic-gate 20987c478bd9Sstevel@tonic-gate int 20997c478bd9Sstevel@tonic-gate secpolicy_basic_fork(const cred_t *cr) 21007c478bd9Sstevel@tonic-gate { 2101134a1f4eSCasper H.S. Dik FAST_BASIC_CHECK(cr, PRIV_PROC_FORK); 2102134a1f4eSCasper H.S. Dik 21037c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_FORK, B_FALSE, EPERM, NULL)); 21047c478bd9Sstevel@tonic-gate } 21057c478bd9Sstevel@tonic-gate 21067c478bd9Sstevel@tonic-gate int 21077c478bd9Sstevel@tonic-gate secpolicy_basic_proc(const cred_t *cr) 21087c478bd9Sstevel@tonic-gate { 2109134a1f4eSCasper H.S. Dik FAST_BASIC_CHECK(cr, PRIV_PROC_SESSION); 2110134a1f4eSCasper H.S. Dik 21117c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_SESSION, B_FALSE, EPERM, NULL)); 21127c478bd9Sstevel@tonic-gate } 21137c478bd9Sstevel@tonic-gate 21147c478bd9Sstevel@tonic-gate /* 21157c478bd9Sstevel@tonic-gate * Slightly complicated because we don't want to trigger the policy too 21167c478bd9Sstevel@tonic-gate * often. First we shortcircuit access to "self" (tp == sp) or if 21177c478bd9Sstevel@tonic-gate * we don't have the privilege but if we have permission 21187c478bd9Sstevel@tonic-gate * just return (0) and we don't flag the privilege as needed. 21197c478bd9Sstevel@tonic-gate * Else, we test for the privilege because we either have it or need it. 21207c478bd9Sstevel@tonic-gate */ 21217c478bd9Sstevel@tonic-gate int 21227c478bd9Sstevel@tonic-gate secpolicy_basic_procinfo(const cred_t *cr, proc_t *tp, proc_t *sp) 21237c478bd9Sstevel@tonic-gate { 21247c478bd9Sstevel@tonic-gate if (tp == sp || 21257c478bd9Sstevel@tonic-gate !HAS_PRIVILEGE(cr, PRIV_PROC_INFO) && prochasprocperm(tp, sp, cr)) { 21267c478bd9Sstevel@tonic-gate return (0); 21277c478bd9Sstevel@tonic-gate } else { 21287c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_INFO, B_FALSE, EPERM, NULL)); 21297c478bd9Sstevel@tonic-gate } 21307c478bd9Sstevel@tonic-gate } 21317c478bd9Sstevel@tonic-gate 21327c478bd9Sstevel@tonic-gate int 21337c478bd9Sstevel@tonic-gate secpolicy_basic_link(const cred_t *cr) 21347c478bd9Sstevel@tonic-gate { 2135134a1f4eSCasper H.S. Dik FAST_BASIC_CHECK(cr, PRIV_FILE_LINK_ANY); 2136134a1f4eSCasper H.S. Dik 21377c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_LINK_ANY, B_FALSE, EPERM, NULL)); 21387c478bd9Sstevel@tonic-gate } 21397c478bd9Sstevel@tonic-gate 2140634e26ecSCasper H.S. Dik int 2141634e26ecSCasper H.S. Dik secpolicy_basic_net_access(const cred_t *cr) 2142634e26ecSCasper H.S. Dik { 2143134a1f4eSCasper H.S. Dik FAST_BASIC_CHECK(cr, PRIV_NET_ACCESS); 2144134a1f4eSCasper H.S. Dik 2145634e26ecSCasper H.S. Dik return (PRIV_POLICY(cr, PRIV_NET_ACCESS, B_FALSE, EACCES, NULL)); 2146634e26ecSCasper H.S. Dik } 2147634e26ecSCasper H.S. Dik 2148134a1f4eSCasper H.S. Dik /* ARGSUSED */ 2149134a1f4eSCasper H.S. Dik int 2150134a1f4eSCasper H.S. Dik secpolicy_basic_file_read(const cred_t *cr, vnode_t *vp, const char *pn) 2151134a1f4eSCasper H.S. Dik { 2152134a1f4eSCasper H.S. Dik FAST_BASIC_CHECK(cr, PRIV_FILE_READ); 2153134a1f4eSCasper H.S. Dik 2154134a1f4eSCasper H.S. Dik return (priv_policy_va(cr, PRIV_FILE_READ, B_FALSE, EACCES, NULL, 2155134a1f4eSCasper H.S. Dik KLPDARG_VNODE, vp, (char *)pn, KLPDARG_NOMORE)); 2156134a1f4eSCasper H.S. Dik } 2157134a1f4eSCasper H.S. Dik 2158134a1f4eSCasper H.S. Dik /* ARGSUSED */ 2159134a1f4eSCasper H.S. Dik int 2160134a1f4eSCasper H.S. Dik secpolicy_basic_file_write(const cred_t *cr, vnode_t *vp, const char *pn) 2161134a1f4eSCasper H.S. Dik { 2162134a1f4eSCasper H.S. Dik FAST_BASIC_CHECK(cr, PRIV_FILE_WRITE); 2163134a1f4eSCasper H.S. Dik 2164134a1f4eSCasper H.S. Dik return (priv_policy_va(cr, PRIV_FILE_WRITE, B_FALSE, EACCES, NULL, 2165134a1f4eSCasper H.S. Dik KLPDARG_VNODE, vp, (char *)pn, KLPDARG_NOMORE)); 2166134a1f4eSCasper H.S. Dik } 2167134a1f4eSCasper H.S. Dik 21687c478bd9Sstevel@tonic-gate /* 21697c478bd9Sstevel@tonic-gate * Additional device protection. 21707c478bd9Sstevel@tonic-gate * 21717c478bd9Sstevel@tonic-gate * Traditionally, a device has specific permissions on the node in 21727c478bd9Sstevel@tonic-gate * the filesystem which govern which devices can be opened by what 21737c478bd9Sstevel@tonic-gate * processes. In certain cases, it is desirable to add extra 21747c478bd9Sstevel@tonic-gate * restrictions, as writing to certain devices is identical to 21757c478bd9Sstevel@tonic-gate * having a complete run of the system. 21767c478bd9Sstevel@tonic-gate * 21777c478bd9Sstevel@tonic-gate * This mechanism is called the device policy. 21787c478bd9Sstevel@tonic-gate * 21797c478bd9Sstevel@tonic-gate * When a device is opened, its policy entry is looked up in the 21807c478bd9Sstevel@tonic-gate * policy cache and checked. 21817c478bd9Sstevel@tonic-gate */ 21827c478bd9Sstevel@tonic-gate int 21837c478bd9Sstevel@tonic-gate secpolicy_spec_open(const cred_t *cr, struct vnode *vp, int oflag) 21847c478bd9Sstevel@tonic-gate { 21857c478bd9Sstevel@tonic-gate devplcy_t *plcy; 21867c478bd9Sstevel@tonic-gate int err; 21877c478bd9Sstevel@tonic-gate struct snode *csp = VTOS(common_specvp(vp)); 2188e6bdcbd5Sdh155122 priv_set_t pset; 21897c478bd9Sstevel@tonic-gate 21907c478bd9Sstevel@tonic-gate mutex_enter(&csp->s_lock); 21917c478bd9Sstevel@tonic-gate 21927c478bd9Sstevel@tonic-gate if (csp->s_plcy == NULL || csp->s_plcy->dp_gen != devplcy_gen) { 21937c478bd9Sstevel@tonic-gate plcy = devpolicy_find(vp); 21947c478bd9Sstevel@tonic-gate if (csp->s_plcy) 21957c478bd9Sstevel@tonic-gate dpfree(csp->s_plcy); 21967c478bd9Sstevel@tonic-gate csp->s_plcy = plcy; 21977c478bd9Sstevel@tonic-gate ASSERT(plcy != NULL); 21987c478bd9Sstevel@tonic-gate } else 21997c478bd9Sstevel@tonic-gate plcy = csp->s_plcy; 22007c478bd9Sstevel@tonic-gate 22017c478bd9Sstevel@tonic-gate if (plcy == nullpolicy) { 22027c478bd9Sstevel@tonic-gate mutex_exit(&csp->s_lock); 22037c478bd9Sstevel@tonic-gate return (0); 22047c478bd9Sstevel@tonic-gate } 22057c478bd9Sstevel@tonic-gate 22067c478bd9Sstevel@tonic-gate dphold(plcy); 22077c478bd9Sstevel@tonic-gate 22087c478bd9Sstevel@tonic-gate mutex_exit(&csp->s_lock); 22097c478bd9Sstevel@tonic-gate 2210e6bdcbd5Sdh155122 if (oflag & FWRITE) 2211e6bdcbd5Sdh155122 pset = plcy->dp_wrp; 2212e6bdcbd5Sdh155122 else 2213e6bdcbd5Sdh155122 pset = plcy->dp_rdp; 2214e6bdcbd5Sdh155122 /* 2215e6bdcbd5Sdh155122 * Special case: 2216e6bdcbd5Sdh155122 * PRIV_SYS_NET_CONFIG is a superset of PRIV_SYS_IP_CONFIG. 2217e6bdcbd5Sdh155122 * If PRIV_SYS_NET_CONFIG is present and PRIV_SYS_IP_CONFIG is 2218e6bdcbd5Sdh155122 * required, replace PRIV_SYS_IP_CONFIG with PRIV_SYS_NET_CONFIG 2219e6bdcbd5Sdh155122 * in the required privilege set before doing the check. 2220e6bdcbd5Sdh155122 */ 2221e6bdcbd5Sdh155122 if (priv_ismember(&pset, PRIV_SYS_IP_CONFIG) && 2222e6bdcbd5Sdh155122 priv_ismember(&CR_OEPRIV(cr), PRIV_SYS_NET_CONFIG) && 2223e6bdcbd5Sdh155122 !priv_ismember(&CR_OEPRIV(cr), PRIV_SYS_IP_CONFIG)) { 2224e6bdcbd5Sdh155122 priv_delset(&pset, PRIV_SYS_IP_CONFIG); 2225e6bdcbd5Sdh155122 priv_addset(&pset, PRIV_SYS_NET_CONFIG); 2226e6bdcbd5Sdh155122 } 2227e6bdcbd5Sdh155122 2228134a1f4eSCasper H.S. Dik err = secpolicy_require_set(cr, &pset, "devpolicy", KLPDARG_NONE); 22297c478bd9Sstevel@tonic-gate dpfree(plcy); 22307c478bd9Sstevel@tonic-gate 22317c478bd9Sstevel@tonic-gate return (err); 22327c478bd9Sstevel@tonic-gate } 22337c478bd9Sstevel@tonic-gate 22347c478bd9Sstevel@tonic-gate int 22357c478bd9Sstevel@tonic-gate secpolicy_modctl(const cred_t *cr, int cmd) 22367c478bd9Sstevel@tonic-gate { 22377c478bd9Sstevel@tonic-gate switch (cmd) { 22387c478bd9Sstevel@tonic-gate case MODINFO: 2239a08731ecScth case MODGETMAJBIND: 22407c478bd9Sstevel@tonic-gate case MODGETPATH: 22417c478bd9Sstevel@tonic-gate case MODGETPATHLEN: 22427c478bd9Sstevel@tonic-gate case MODGETNAME: 2243a08731ecScth case MODGETFBNAME: 22447c478bd9Sstevel@tonic-gate case MODGETDEVPOLICY: 22457c478bd9Sstevel@tonic-gate case MODGETDEVPOLICYBYNAME: 2246a08731ecScth case MODDEVT2INSTANCE: 2247a08731ecScth case MODSIZEOF_DEVID: 2248a08731ecScth case MODGETDEVID: 2249a08731ecScth case MODSIZEOF_MINORNAME: 2250a08731ecScth case MODGETMINORNAME: 2251a08731ecScth case MODGETDEVFSPATH_LEN: 2252a08731ecScth case MODGETDEVFSPATH: 2253a08731ecScth case MODGETDEVFSPATH_MI_LEN: 2254a08731ecScth case MODGETDEVFSPATH_MI: 22557c478bd9Sstevel@tonic-gate /* Unprivileged */ 22567c478bd9Sstevel@tonic-gate return (0); 22577c478bd9Sstevel@tonic-gate case MODLOAD: 22587c478bd9Sstevel@tonic-gate case MODSETDEVPOLICY: 2259134a1f4eSCasper H.S. Dik return (secpolicy_require_set(cr, PRIV_FULLSET, NULL, 2260134a1f4eSCasper H.S. Dik KLPDARG_NONE)); 22617c478bd9Sstevel@tonic-gate default: 22627c478bd9Sstevel@tonic-gate return (secpolicy_sys_config(cr, B_FALSE)); 22637c478bd9Sstevel@tonic-gate } 22647c478bd9Sstevel@tonic-gate } 22657c478bd9Sstevel@tonic-gate 22667c478bd9Sstevel@tonic-gate int 22677c478bd9Sstevel@tonic-gate secpolicy_console(const cred_t *cr) 22687c478bd9Sstevel@tonic-gate { 22697c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 22707c478bd9Sstevel@tonic-gate } 22717c478bd9Sstevel@tonic-gate 22727c478bd9Sstevel@tonic-gate int 22737c478bd9Sstevel@tonic-gate secpolicy_power_mgmt(const cred_t *cr) 22747c478bd9Sstevel@tonic-gate { 22757c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 22767c478bd9Sstevel@tonic-gate } 22777c478bd9Sstevel@tonic-gate 22787c478bd9Sstevel@tonic-gate /* 22797c478bd9Sstevel@tonic-gate * Simulate terminal input; another escalation of privileges avenue. 22807c478bd9Sstevel@tonic-gate */ 22817c478bd9Sstevel@tonic-gate 22827c478bd9Sstevel@tonic-gate int 22837c478bd9Sstevel@tonic-gate secpolicy_sti(const cred_t *cr) 22847c478bd9Sstevel@tonic-gate { 2285134a1f4eSCasper H.S. Dik return (secpolicy_require_set(cr, PRIV_FULLSET, NULL, KLPDARG_NONE)); 22867c478bd9Sstevel@tonic-gate } 22877c478bd9Sstevel@tonic-gate 228845916cd2Sjpk boolean_t 228945916cd2Sjpk secpolicy_net_reply_equal(const cred_t *cr) 229045916cd2Sjpk { 229145916cd2Sjpk return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 229245916cd2Sjpk } 229345916cd2Sjpk 22947c478bd9Sstevel@tonic-gate int 22957c478bd9Sstevel@tonic-gate secpolicy_swapctl(const cred_t *cr) 22967c478bd9Sstevel@tonic-gate { 22977c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 22987c478bd9Sstevel@tonic-gate } 22997c478bd9Sstevel@tonic-gate 23007c478bd9Sstevel@tonic-gate int 23017c478bd9Sstevel@tonic-gate secpolicy_cpc_cpu(const cred_t *cr) 23027c478bd9Sstevel@tonic-gate { 23037c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CPC_CPU, B_FALSE, EACCES, NULL)); 23047c478bd9Sstevel@tonic-gate } 23057c478bd9Sstevel@tonic-gate 23067c478bd9Sstevel@tonic-gate /* 23077b209c2cSacruz * secpolicy_contract_identity 23087b209c2cSacruz * 23097b209c2cSacruz * Determine if the subject may set the process contract FMRI value 23107b209c2cSacruz */ 23117b209c2cSacruz int 23127b209c2cSacruz secpolicy_contract_identity(const cred_t *cr) 23137b209c2cSacruz { 23147b209c2cSacruz return (PRIV_POLICY(cr, PRIV_CONTRACT_IDENTITY, B_FALSE, EPERM, NULL)); 23157b209c2cSacruz } 23167b209c2cSacruz 23177b209c2cSacruz /* 23187c478bd9Sstevel@tonic-gate * secpolicy_contract_observer 23197c478bd9Sstevel@tonic-gate * 23207c478bd9Sstevel@tonic-gate * Determine if the subject may observe a specific contract's events. 23217c478bd9Sstevel@tonic-gate */ 23227c478bd9Sstevel@tonic-gate int 23237c478bd9Sstevel@tonic-gate secpolicy_contract_observer(const cred_t *cr, struct contract *ct) 23247c478bd9Sstevel@tonic-gate { 23257c478bd9Sstevel@tonic-gate if (contract_owned(ct, cr, B_FALSE)) 23267c478bd9Sstevel@tonic-gate return (0); 23277c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CONTRACT_OBSERVER, B_FALSE, EPERM, NULL)); 23287c478bd9Sstevel@tonic-gate } 23297c478bd9Sstevel@tonic-gate 23307c478bd9Sstevel@tonic-gate /* 23317c478bd9Sstevel@tonic-gate * secpolicy_contract_observer_choice 23327c478bd9Sstevel@tonic-gate * 23337c478bd9Sstevel@tonic-gate * Determine if the subject may observe any contract's events. Just 23347c478bd9Sstevel@tonic-gate * tests privilege and audits on success. 23357c478bd9Sstevel@tonic-gate */ 23367c478bd9Sstevel@tonic-gate boolean_t 23377c478bd9Sstevel@tonic-gate secpolicy_contract_observer_choice(const cred_t *cr) 23387c478bd9Sstevel@tonic-gate { 23397c478bd9Sstevel@tonic-gate return (PRIV_POLICY_CHOICE(cr, PRIV_CONTRACT_OBSERVER, B_FALSE)); 23407c478bd9Sstevel@tonic-gate } 23417c478bd9Sstevel@tonic-gate 23427c478bd9Sstevel@tonic-gate /* 23437c478bd9Sstevel@tonic-gate * secpolicy_contract_event 23447c478bd9Sstevel@tonic-gate * 23457c478bd9Sstevel@tonic-gate * Determine if the subject may request critical contract events or 23467c478bd9Sstevel@tonic-gate * reliable contract event delivery. 23477c478bd9Sstevel@tonic-gate */ 23487c478bd9Sstevel@tonic-gate int 23497c478bd9Sstevel@tonic-gate secpolicy_contract_event(const cred_t *cr) 23507c478bd9Sstevel@tonic-gate { 23517c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CONTRACT_EVENT, B_FALSE, EPERM, NULL)); 23527c478bd9Sstevel@tonic-gate } 23537c478bd9Sstevel@tonic-gate 23547c478bd9Sstevel@tonic-gate /* 23557c478bd9Sstevel@tonic-gate * secpolicy_contract_event_choice 23567c478bd9Sstevel@tonic-gate * 23577c478bd9Sstevel@tonic-gate * Determine if the subject may retain contract events in its critical 23587c478bd9Sstevel@tonic-gate * set when a change in other terms would normally require a change in 23597c478bd9Sstevel@tonic-gate * the critical set. Just tests privilege and audits on success. 23607c478bd9Sstevel@tonic-gate */ 23617c478bd9Sstevel@tonic-gate boolean_t 23627c478bd9Sstevel@tonic-gate secpolicy_contract_event_choice(const cred_t *cr) 23637c478bd9Sstevel@tonic-gate { 23647c478bd9Sstevel@tonic-gate return (PRIV_POLICY_CHOICE(cr, PRIV_CONTRACT_EVENT, B_FALSE)); 23657c478bd9Sstevel@tonic-gate } 23667c478bd9Sstevel@tonic-gate 23677c478bd9Sstevel@tonic-gate /* 2368ea8dc4b6Seschrock * secpolicy_gart_access 23697c478bd9Sstevel@tonic-gate * 2370ea8dc4b6Seschrock * Determine if the subject has sufficient priveleges to make ioctls to agpgart 2371ea8dc4b6Seschrock * device. 23727c478bd9Sstevel@tonic-gate */ 23737c478bd9Sstevel@tonic-gate int 23747c478bd9Sstevel@tonic-gate secpolicy_gart_access(const cred_t *cr) 23757c478bd9Sstevel@tonic-gate { 237626f24838Scasper return (PRIV_POLICY(cr, PRIV_GRAPHICS_ACCESS, B_FALSE, EPERM, NULL)); 23777c478bd9Sstevel@tonic-gate } 23787c478bd9Sstevel@tonic-gate 23797c478bd9Sstevel@tonic-gate /* 2380ea8dc4b6Seschrock * secpolicy_gart_map 23817c478bd9Sstevel@tonic-gate * 2382ea8dc4b6Seschrock * Determine if the subject has sufficient priveleges to map aperture range 2383ea8dc4b6Seschrock * through agpgart driver. 23847c478bd9Sstevel@tonic-gate */ 23857c478bd9Sstevel@tonic-gate int 23867c478bd9Sstevel@tonic-gate secpolicy_gart_map(const cred_t *cr) 23877c478bd9Sstevel@tonic-gate { 238826f24838Scasper if (PRIV_POLICY_ONLY(cr, PRIV_GRAPHICS_ACCESS, B_FALSE)) { 238926f24838Scasper return (PRIV_POLICY(cr, PRIV_GRAPHICS_ACCESS, B_FALSE, EPERM, 239026f24838Scasper NULL)); 239126f24838Scasper } else { 239226f24838Scasper return (PRIV_POLICY(cr, PRIV_GRAPHICS_MAP, B_FALSE, EPERM, 239326f24838Scasper NULL)); 23947c478bd9Sstevel@tonic-gate } 23957c478bd9Sstevel@tonic-gate } 2396fa9e4066Sahrens 2397fa9e4066Sahrens /* 2398ea8dc4b6Seschrock * secpolicy_zinject 2399ea8dc4b6Seschrock * 2400ea8dc4b6Seschrock * Determine if the subject can inject faults in the ZFS fault injection 2401ea8dc4b6Seschrock * framework. Requires all privileges. 2402ea8dc4b6Seschrock */ 2403ea8dc4b6Seschrock int 2404ea8dc4b6Seschrock secpolicy_zinject(const cred_t *cr) 2405ea8dc4b6Seschrock { 2406134a1f4eSCasper H.S. Dik return (secpolicy_require_set(cr, PRIV_FULLSET, NULL, KLPDARG_NONE)); 2407ea8dc4b6Seschrock } 2408ea8dc4b6Seschrock 2409ea8dc4b6Seschrock /* 2410fa9e4066Sahrens * secpolicy_zfs 2411fa9e4066Sahrens * 2412ea8dc4b6Seschrock * Determine if the subject has permission to manipulate ZFS datasets 2413ea8dc4b6Seschrock * (not pools). Equivalent to the SYS_MOUNT privilege. 2414fa9e4066Sahrens */ 2415fa9e4066Sahrens int 2416fa9e4066Sahrens secpolicy_zfs(const cred_t *cr) 2417fa9e4066Sahrens { 2418fa9e4066Sahrens return (PRIV_POLICY(cr, PRIV_SYS_MOUNT, B_FALSE, EPERM, NULL)); 2419fa9e4066Sahrens } 2420f48205beScasper 2421f48205beScasper /* 2422f48205beScasper * secpolicy_idmap 2423f48205beScasper * 2424f48205beScasper * Determine if the calling process has permissions to register an SID 2425f48205beScasper * mapping daemon and allocate ephemeral IDs. 2426f48205beScasper */ 2427f48205beScasper int 2428f48205beScasper secpolicy_idmap(const cred_t *cr) 2429f48205beScasper { 2430bda89588Sjp151216 return (PRIV_POLICY(cr, PRIV_FILE_SETID, B_TRUE, EPERM, NULL)); 2431f48205beScasper } 24322449e17fSsherrym 24332449e17fSsherrym /* 24342449e17fSsherrym * secpolicy_ucode_update 24352449e17fSsherrym * 24362449e17fSsherrym * Determine if the subject has sufficient privilege to update microcode. 24372449e17fSsherrym */ 24382449e17fSsherrym int 24392449e17fSsherrym secpolicy_ucode_update(const cred_t *scr) 24402449e17fSsherrym { 24412449e17fSsherrym return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); 24422449e17fSsherrym } 2443e6bdcbd5Sdh155122 2444e6bdcbd5Sdh155122 /* 2445e6bdcbd5Sdh155122 * secpolicy_sadopen 2446e6bdcbd5Sdh155122 * 2447e6bdcbd5Sdh155122 * Determine if the subject has sufficient privilege to access /dev/sad/admin. 2448e6bdcbd5Sdh155122 * /dev/sad/admin appear in global zone and exclusive-IP zones only. 2449e6bdcbd5Sdh155122 * In global zone, sys_config is required. 2450e6bdcbd5Sdh155122 * In exclusive-IP zones, sys_ip_config is required. 2451e6bdcbd5Sdh155122 * Note that sys_config is prohibited in non-global zones. 2452e6bdcbd5Sdh155122 */ 2453e6bdcbd5Sdh155122 int 2454e6bdcbd5Sdh155122 secpolicy_sadopen(const cred_t *credp) 2455e6bdcbd5Sdh155122 { 2456e6bdcbd5Sdh155122 priv_set_t pset; 2457e6bdcbd5Sdh155122 2458e6bdcbd5Sdh155122 priv_emptyset(&pset); 2459e6bdcbd5Sdh155122 2460e6bdcbd5Sdh155122 if (crgetzoneid(credp) == GLOBAL_ZONEID) 2461e6bdcbd5Sdh155122 priv_addset(&pset, PRIV_SYS_CONFIG); 2462e6bdcbd5Sdh155122 else 2463e6bdcbd5Sdh155122 priv_addset(&pset, PRIV_SYS_IP_CONFIG); 2464e6bdcbd5Sdh155122 2465134a1f4eSCasper H.S. Dik return (secpolicy_require_set(credp, &pset, "devpolicy", KLPDARG_NONE)); 2466e6bdcbd5Sdh155122 } 2467da6c28aaSamw 2468ddf7fe95Scasper 2469ddf7fe95Scasper /* 2470ddf7fe95Scasper * Add privileges to a particular privilege set; this is called when the 2471ddf7fe95Scasper * current sets of privileges are not sufficient. I.e., we should always 2472ddf7fe95Scasper * call the policy override functions from here. 2473ddf7fe95Scasper * What we are allowed to have is in the Observed Permitted set; so 2474ddf7fe95Scasper * we compute the difference between that and the newset. 2475ddf7fe95Scasper */ 2476ddf7fe95Scasper int 2477ddf7fe95Scasper secpolicy_require_privs(const cred_t *cr, const priv_set_t *nset) 2478ddf7fe95Scasper { 2479ddf7fe95Scasper priv_set_t rqd; 2480ddf7fe95Scasper 2481ddf7fe95Scasper rqd = CR_OPPRIV(cr); 2482ddf7fe95Scasper 2483ddf7fe95Scasper priv_inverse(&rqd); 2484ddf7fe95Scasper priv_intersect(nset, &rqd); 2485ddf7fe95Scasper 2486134a1f4eSCasper H.S. Dik return (secpolicy_require_set(cr, &rqd, NULL, KLPDARG_NONE)); 2487ddf7fe95Scasper } 2488ddf7fe95Scasper 2489da6c28aaSamw /* 2490da6c28aaSamw * secpolicy_smb 2491da6c28aaSamw * 2492da6c28aaSamw * Determine if the cred_t has PRIV_SYS_SMB privilege, indicating 2493da6c28aaSamw * that it has permission to access the smbsrv kernel driver. 2494da6c28aaSamw * PRIV_POLICY checks the privilege and audits the check. 2495da6c28aaSamw * 2496da6c28aaSamw * Returns: 2497da6c28aaSamw * 0 Driver access is allowed. 2498da6c28aaSamw * EPERM Driver access is NOT permitted. 2499da6c28aaSamw */ 2500da6c28aaSamw int 2501da6c28aaSamw secpolicy_smb(const cred_t *cr) 2502da6c28aaSamw { 2503da6c28aaSamw return (PRIV_POLICY(cr, PRIV_SYS_SMB, B_FALSE, EPERM, NULL)); 2504da6c28aaSamw } 2505911106dfSjm199354 2506911106dfSjm199354 /* 2507911106dfSjm199354 * secpolicy_vscan 2508911106dfSjm199354 * 2509911106dfSjm199354 * Determine if cred_t has the necessary privileges to access a file 2510911106dfSjm199354 * for virus scanning and update its extended system attributes. 2511911106dfSjm199354 * PRIV_FILE_DAC_SEARCH, PRIV_FILE_DAC_READ - file access 2512911106dfSjm199354 * PRIV_FILE_FLAG_SET - set extended system attributes 2513911106dfSjm199354 * 2514911106dfSjm199354 * PRIV_POLICY checks the privilege and audits the check. 2515911106dfSjm199354 * 2516911106dfSjm199354 * Returns: 2517911106dfSjm199354 * 0 file access for virus scanning allowed. 2518911106dfSjm199354 * EPERM file access for virus scanning is NOT permitted. 2519911106dfSjm199354 */ 2520911106dfSjm199354 int 2521911106dfSjm199354 secpolicy_vscan(const cred_t *cr) 2522911106dfSjm199354 { 2523911106dfSjm199354 if ((PRIV_POLICY(cr, PRIV_FILE_DAC_SEARCH, B_FALSE, EPERM, NULL)) || 2524911106dfSjm199354 (PRIV_POLICY(cr, PRIV_FILE_DAC_READ, B_FALSE, EPERM, NULL)) || 2525911106dfSjm199354 (PRIV_POLICY(cr, PRIV_FILE_FLAG_SET, B_FALSE, EPERM, NULL))) { 2526911106dfSjm199354 return (EPERM); 2527911106dfSjm199354 } 2528911106dfSjm199354 2529911106dfSjm199354 return (0); 2530911106dfSjm199354 } 25314bff34e3Sthurlow 25324bff34e3Sthurlow /* 25334bff34e3Sthurlow * secpolicy_smbfs_login 25344bff34e3Sthurlow * 25354bff34e3Sthurlow * Determines if the caller can add and delete the smbfs login 25364bff34e3Sthurlow * password in the the nsmb kernel module for the CIFS client. 25374bff34e3Sthurlow * 25384bff34e3Sthurlow * Returns: 25394bff34e3Sthurlow * 0 access is allowed. 25404bff34e3Sthurlow * EPERM access is NOT allowed. 25414bff34e3Sthurlow */ 25424bff34e3Sthurlow int 25434bff34e3Sthurlow secpolicy_smbfs_login(const cred_t *cr, uid_t uid) 25444bff34e3Sthurlow { 25454bff34e3Sthurlow uid_t cruid = crgetruid(cr); 25464bff34e3Sthurlow 25474bff34e3Sthurlow if (cruid == uid) 25484bff34e3Sthurlow return (0); 25494bff34e3Sthurlow return (PRIV_POLICY(cr, PRIV_PROC_OWNER, B_FALSE, 25504bff34e3Sthurlow EPERM, NULL)); 25514bff34e3Sthurlow } 2552b26a64aeSjohnlev 2553b26a64aeSjohnlev /* 2554b26a64aeSjohnlev * secpolicy_xvm_control 2555b26a64aeSjohnlev * 2556b26a64aeSjohnlev * Determines if a caller can control the xVM hypervisor and/or running 2557b26a64aeSjohnlev * domains (x86 specific). 2558b26a64aeSjohnlev * 2559b26a64aeSjohnlev * Returns: 2560b26a64aeSjohnlev * 0 access is allowed. 2561b26a64aeSjohnlev * EPERM access is NOT allowed. 2562b26a64aeSjohnlev */ 2563b26a64aeSjohnlev int 2564b26a64aeSjohnlev secpolicy_xvm_control(const cred_t *cr) 2565b26a64aeSjohnlev { 2566b26a64aeSjohnlev if (PRIV_POLICY(cr, PRIV_XVM_CONTROL, B_FALSE, EPERM, NULL)) 2567b26a64aeSjohnlev return (EPERM); 2568b26a64aeSjohnlev return (0); 2569b26a64aeSjohnlev } 2570da14cebeSEric Cheng 2571da14cebeSEric Cheng /* 2572f53eecf5SJames Carlson * secpolicy_ppp_config 2573f53eecf5SJames Carlson * 2574f53eecf5SJames Carlson * Determine if the subject has sufficient privileges to configure PPP and 2575f53eecf5SJames Carlson * PPP-related devices. 2576f53eecf5SJames Carlson */ 2577f53eecf5SJames Carlson int 2578f53eecf5SJames Carlson secpolicy_ppp_config(const cred_t *cr) 2579f53eecf5SJames Carlson { 2580f53eecf5SJames Carlson if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE)) 2581f53eecf5SJames Carlson return (secpolicy_net_config(cr, B_FALSE)); 2582f53eecf5SJames Carlson return (PRIV_POLICY(cr, PRIV_SYS_PPP_CONFIG, B_FALSE, EPERM, NULL)); 2583f53eecf5SJames Carlson } 2584