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 /* 22bda89588Sjp151216 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 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> 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate /* 597c478bd9Sstevel@tonic-gate * There are two possible layers of privilege routines and two possible 607c478bd9Sstevel@tonic-gate * levels of secpolicy. Plus one other we may not be interested in, so 617c478bd9Sstevel@tonic-gate * we may need as many as 6 but no more. 627c478bd9Sstevel@tonic-gate */ 637c478bd9Sstevel@tonic-gate #define MAXPRIVSTACK 6 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate int priv_debug = 0; 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate /* 687c478bd9Sstevel@tonic-gate * This file contains the majority of the policy routines. 697c478bd9Sstevel@tonic-gate * Since the policy routines are defined by function and not 707c478bd9Sstevel@tonic-gate * by privilege, there is quite a bit of duplication of 717c478bd9Sstevel@tonic-gate * functions. 727c478bd9Sstevel@tonic-gate * 73da6c28aaSamw * The secpolicy functions must not make assumptions about 747c478bd9Sstevel@tonic-gate * locks held or not held as any lock can be held while they're 757c478bd9Sstevel@tonic-gate * being called. 767c478bd9Sstevel@tonic-gate * 777c478bd9Sstevel@tonic-gate * Credentials are read-only so no special precautions need to 787c478bd9Sstevel@tonic-gate * be taken while locking them. 797c478bd9Sstevel@tonic-gate * 807c478bd9Sstevel@tonic-gate * When a new policy check needs to be added to the system the 817c478bd9Sstevel@tonic-gate * following procedure should be followed: 827c478bd9Sstevel@tonic-gate * 837c478bd9Sstevel@tonic-gate * Pick an appropriate secpolicy_*() function 847c478bd9Sstevel@tonic-gate * -> done if one exists. 857c478bd9Sstevel@tonic-gate * Create a new secpolicy function, preferably with 867c478bd9Sstevel@tonic-gate * a descriptive name using the standard template. 877c478bd9Sstevel@tonic-gate * Pick an appropriate privilege for the policy. 887c478bd9Sstevel@tonic-gate * If no appropraite privilege exists, define new one 897c478bd9Sstevel@tonic-gate * (this should be done with extreme care; in most cases 907c478bd9Sstevel@tonic-gate * little is gained by adding another privilege) 917c478bd9Sstevel@tonic-gate * 927c478bd9Sstevel@tonic-gate * WHY ROOT IS STILL SPECIAL. 937c478bd9Sstevel@tonic-gate * 947c478bd9Sstevel@tonic-gate * In a number of the policy functions, there are still explicit 957c478bd9Sstevel@tonic-gate * checks for uid 0. The rationale behind these is that many root 967c478bd9Sstevel@tonic-gate * owned files/objects hold configuration information which can give full 977c478bd9Sstevel@tonic-gate * privileges to the user once written to. To prevent escalation 987c478bd9Sstevel@tonic-gate * of privilege by allowing just a single privilege to modify root owned 997c478bd9Sstevel@tonic-gate * objects, we've added these root specific checks where we considered 1007c478bd9Sstevel@tonic-gate * them necessary: modifying root owned files, changing uids to 0, etc. 1017c478bd9Sstevel@tonic-gate * 1027c478bd9Sstevel@tonic-gate * PRIVILEGE ESCALATION AND ZONES. 1037c478bd9Sstevel@tonic-gate * 1047c478bd9Sstevel@tonic-gate * A number of operations potentially allow the caller to achieve 1057c478bd9Sstevel@tonic-gate * privileges beyond the ones normally required to perform the operation. 1067c478bd9Sstevel@tonic-gate * For example, if allowed to create a setuid 0 executable, a process can 1077c478bd9Sstevel@tonic-gate * gain privileges beyond PRIV_FILE_SETID. Zones, however, place 1087c478bd9Sstevel@tonic-gate * restrictions on the ability to gain privileges beyond those available 1097c478bd9Sstevel@tonic-gate * within the zone through file and process manipulation. Hence, such 1107c478bd9Sstevel@tonic-gate * operations require that the caller have an effective set that includes 1117c478bd9Sstevel@tonic-gate * all privileges available within the current zone, or all privileges 1127c478bd9Sstevel@tonic-gate * if executing in the global zone. 1137c478bd9Sstevel@tonic-gate * 1147c478bd9Sstevel@tonic-gate * This is indicated in the priv_policy* policy checking functions 1157c478bd9Sstevel@tonic-gate * through a combination of parameters. The "priv" parameter indicates 1167c478bd9Sstevel@tonic-gate * the privilege that is required, and the "allzone" parameter indicates 1177c478bd9Sstevel@tonic-gate * whether or not all privileges in the zone are required. In addition, 1187c478bd9Sstevel@tonic-gate * priv can be set to PRIV_ALL to indicate that all privileges are 1197c478bd9Sstevel@tonic-gate * required (regardless of zone). There are three scenarios of interest: 1207c478bd9Sstevel@tonic-gate * (1) operation requires a specific privilege 1217c478bd9Sstevel@tonic-gate * (2) operation requires a specific privilege, and requires all 1227c478bd9Sstevel@tonic-gate * privileges available within the zone (or all privileges if in 1237c478bd9Sstevel@tonic-gate * the global zone) 1247c478bd9Sstevel@tonic-gate * (3) operation requires all privileges, regardless of zone 1257c478bd9Sstevel@tonic-gate * 1267c478bd9Sstevel@tonic-gate * For (1), priv should be set to the specific privilege, and allzone 1277c478bd9Sstevel@tonic-gate * should be set to B_FALSE. 1287c478bd9Sstevel@tonic-gate * For (2), priv should be set to the specific privilege, and allzone 1297c478bd9Sstevel@tonic-gate * should be set to B_TRUE. 1307c478bd9Sstevel@tonic-gate * For (3), priv should be set to PRIV_ALL, and allzone should be set 1317c478bd9Sstevel@tonic-gate * to B_FALSE. 1327c478bd9Sstevel@tonic-gate * 1337c478bd9Sstevel@tonic-gate */ 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate /* 1367c478bd9Sstevel@tonic-gate * The privileges are checked against the Effective set for 1377c478bd9Sstevel@tonic-gate * ordinary processes and checked against the Limit set 1387c478bd9Sstevel@tonic-gate * for euid 0 processes that haven't manipulated their privilege 1397c478bd9Sstevel@tonic-gate * sets. 1407c478bd9Sstevel@tonic-gate */ 1417c478bd9Sstevel@tonic-gate #define HAS_ALLPRIVS(cr) priv_isfullset(&CR_OEPRIV(cr)) 1427c478bd9Sstevel@tonic-gate #define ZONEPRIVS(cr) ((cr)->cr_zone->zone_privset) 1437c478bd9Sstevel@tonic-gate #define HAS_ALLZONEPRIVS(cr) priv_issubset(ZONEPRIVS(cr), &CR_OEPRIV(cr)) 1447c478bd9Sstevel@tonic-gate #define HAS_PRIVILEGE(cr, pr) ((pr) == PRIV_ALL ? \ 1457c478bd9Sstevel@tonic-gate HAS_ALLPRIVS(cr) : \ 1467c478bd9Sstevel@tonic-gate PRIV_ISASSERT(&CR_OEPRIV(cr), pr)) 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* 149ddf7fe95Scasper * Policy checking functions. 1507c478bd9Sstevel@tonic-gate * 151ddf7fe95Scasper * All of the system's policy should be implemented here. 1527c478bd9Sstevel@tonic-gate */ 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate /* 155ddf7fe95Scasper * Private functions which take an additional va_list argument to 156ddf7fe95Scasper * implement an object specific policy override. 157ddf7fe95Scasper */ 158ddf7fe95Scasper static int priv_policy_ap(const cred_t *, int, boolean_t, int, 159ddf7fe95Scasper const char *, va_list); 160ddf7fe95Scasper static int priv_policy_va(const cred_t *, int, boolean_t, int, 161ddf7fe95Scasper const char *, ...); 162ddf7fe95Scasper 163ddf7fe95Scasper /* 1647c478bd9Sstevel@tonic-gate * Generic policy calls 1657c478bd9Sstevel@tonic-gate * 1667c478bd9Sstevel@tonic-gate * The "bottom" functions of policy control 1677c478bd9Sstevel@tonic-gate */ 1687c478bd9Sstevel@tonic-gate static char * 1697c478bd9Sstevel@tonic-gate mprintf(const char *fmt, ...) 1707c478bd9Sstevel@tonic-gate { 1717c478bd9Sstevel@tonic-gate va_list args; 1727c478bd9Sstevel@tonic-gate char *buf; 1737c478bd9Sstevel@tonic-gate size_t len; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate va_start(args, fmt); 1767c478bd9Sstevel@tonic-gate len = vsnprintf(NULL, 0, fmt, args) + 1; 1777c478bd9Sstevel@tonic-gate va_end(args); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate buf = kmem_alloc(len, KM_NOSLEEP); 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate if (buf == NULL) 1827c478bd9Sstevel@tonic-gate return (NULL); 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate va_start(args, fmt); 1857c478bd9Sstevel@tonic-gate (void) vsnprintf(buf, len, fmt, args); 1867c478bd9Sstevel@tonic-gate va_end(args); 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate return (buf); 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate /* 1927c478bd9Sstevel@tonic-gate * priv_policy_errmsg() 1937c478bd9Sstevel@tonic-gate * 1947c478bd9Sstevel@tonic-gate * Generate an error message if privilege debugging is enabled system wide 1957c478bd9Sstevel@tonic-gate * or for this particular process. 1967c478bd9Sstevel@tonic-gate */ 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate #define FMTHDR "%s[%d]: missing privilege \"%s\" (euid = %d, syscall = %d)" 1997c478bd9Sstevel@tonic-gate #define FMTMSG " for \"%s\"" 2007c478bd9Sstevel@tonic-gate #define FMTFUN " needed at %s+0x%lx" 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate /* The maximum size privilege format: the concatenation of the above */ 2037c478bd9Sstevel@tonic-gate #define FMTMAX FMTHDR FMTMSG FMTFUN "\n" 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate static void 2067c478bd9Sstevel@tonic-gate priv_policy_errmsg(const cred_t *cr, int priv, const char *msg) 2077c478bd9Sstevel@tonic-gate { 2087c478bd9Sstevel@tonic-gate struct proc *me; 2097c478bd9Sstevel@tonic-gate pc_t stack[MAXPRIVSTACK]; 2107c478bd9Sstevel@tonic-gate int depth; 2117c478bd9Sstevel@tonic-gate int i; 2127c478bd9Sstevel@tonic-gate char *sym; 2137c478bd9Sstevel@tonic-gate ulong_t off; 2147c478bd9Sstevel@tonic-gate const char *pname; 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate char *cmd; 2177c478bd9Sstevel@tonic-gate char fmt[sizeof (FMTMAX)]; 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate if ((me = curproc) == &p0) 2207c478bd9Sstevel@tonic-gate return; 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate /* Privileges must be defined */ 2237c478bd9Sstevel@tonic-gate ASSERT(priv == PRIV_ALL || priv == PRIV_MULTIPLE || 2247c478bd9Sstevel@tonic-gate priv == PRIV_ALLZONE || priv == PRIV_GLOBAL || 2257c478bd9Sstevel@tonic-gate priv_getbynum(priv) != NULL); 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate if (priv == PRIV_ALLZONE && INGLOBALZONE(me)) 2287c478bd9Sstevel@tonic-gate priv = PRIV_ALL; 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate if (curthread->t_pre_sys) 2317c478bd9Sstevel@tonic-gate ttolwp(curthread)->lwp_badpriv = (short)priv; 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate if (priv_debug == 0 && (CR_FLAGS(cr) & PRIV_DEBUG) == 0) 2347c478bd9Sstevel@tonic-gate return; 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate (void) strcpy(fmt, FMTHDR); 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate if (me->p_user.u_comm[0]) 2397c478bd9Sstevel@tonic-gate cmd = &me->p_user.u_comm[0]; 2407c478bd9Sstevel@tonic-gate else 2417c478bd9Sstevel@tonic-gate cmd = "priv_policy"; 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate if (msg != NULL && *msg != '\0') { 2447c478bd9Sstevel@tonic-gate (void) strcat(fmt, FMTMSG); 2457c478bd9Sstevel@tonic-gate } else { 2467c478bd9Sstevel@tonic-gate (void) strcat(fmt, "%s"); 2477c478bd9Sstevel@tonic-gate msg = ""; 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate sym = NULL; 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate depth = getpcstack(stack, MAXPRIVSTACK); 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate /* 2557c478bd9Sstevel@tonic-gate * Try to find the first interesting function on the stack. 2567c478bd9Sstevel@tonic-gate * priv_policy* that's us, so completely uninteresting. 2577c478bd9Sstevel@tonic-gate * suser(), drv_priv(), secpolicy_* are also called from 2587c478bd9Sstevel@tonic-gate * too many locations to convey useful information. 2597c478bd9Sstevel@tonic-gate */ 2607c478bd9Sstevel@tonic-gate for (i = 0; i < depth; i++) { 2617c478bd9Sstevel@tonic-gate sym = kobj_getsymname((uintptr_t)stack[i], &off); 2627c478bd9Sstevel@tonic-gate if (sym != NULL && 2637c478bd9Sstevel@tonic-gate strstr(sym, "hasprocperm") == 0 && 2647c478bd9Sstevel@tonic-gate strcmp("suser", sym) != 0 && 2657c478bd9Sstevel@tonic-gate strcmp("ipcaccess", sym) != 0 && 2667c478bd9Sstevel@tonic-gate strcmp("drv_priv", sym) != 0 && 2677c478bd9Sstevel@tonic-gate strncmp("secpolicy_", sym, 10) != 0 && 2687c478bd9Sstevel@tonic-gate strncmp("priv_policy", sym, 11) != 0) 2697c478bd9Sstevel@tonic-gate break; 2707c478bd9Sstevel@tonic-gate } 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate if (sym != NULL) 2737c478bd9Sstevel@tonic-gate (void) strcat(fmt, FMTFUN); 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate (void) strcat(fmt, "\n"); 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate switch (priv) { 2787c478bd9Sstevel@tonic-gate case PRIV_ALL: 2797c478bd9Sstevel@tonic-gate pname = "ALL"; 2807c478bd9Sstevel@tonic-gate break; 2817c478bd9Sstevel@tonic-gate case PRIV_MULTIPLE: 2827c478bd9Sstevel@tonic-gate pname = "MULTIPLE"; 2837c478bd9Sstevel@tonic-gate break; 2847c478bd9Sstevel@tonic-gate case PRIV_ALLZONE: 2857c478bd9Sstevel@tonic-gate pname = "ZONE"; 2867c478bd9Sstevel@tonic-gate break; 2877c478bd9Sstevel@tonic-gate case PRIV_GLOBAL: 2887c478bd9Sstevel@tonic-gate pname = "GLOBAL"; 2897c478bd9Sstevel@tonic-gate break; 2907c478bd9Sstevel@tonic-gate default: 2917c478bd9Sstevel@tonic-gate pname = priv_getbynum(priv); 2927c478bd9Sstevel@tonic-gate break; 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate if (CR_FLAGS(cr) & PRIV_DEBUG) { 2967c478bd9Sstevel@tonic-gate /* Remember last message, just like lwp_badpriv. */ 2977c478bd9Sstevel@tonic-gate if (curthread->t_pdmsg != NULL) { 2987c478bd9Sstevel@tonic-gate kmem_free(curthread->t_pdmsg, 2997c478bd9Sstevel@tonic-gate strlen(curthread->t_pdmsg) + 1); 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate curthread->t_pdmsg = mprintf(fmt, cmd, me->p_pid, pname, 3037c478bd9Sstevel@tonic-gate cr->cr_uid, curthread->t_sysnum, msg, sym, off); 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate curthread->t_post_sys = 1; 306ddf7fe95Scasper } 307ddf7fe95Scasper if (priv_debug) { 3087c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, fmt, cmd, me->p_pid, pname, cr->cr_uid, 3097c478bd9Sstevel@tonic-gate curthread->t_sysnum, msg, sym, off); 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate /* 314ddf7fe95Scasper * Override the policy, if appropriate. Return 0 if the external 315ddf7fe95Scasper * policy engine approves. 316ddf7fe95Scasper */ 317ddf7fe95Scasper static int 318ddf7fe95Scasper priv_policy_override(const cred_t *cr, int priv, boolean_t allzone, va_list ap) 319ddf7fe95Scasper { 320ddf7fe95Scasper priv_set_t set; 321ddf7fe95Scasper int ret; 322ddf7fe95Scasper 323ddf7fe95Scasper if (!(CR_FLAGS(cr) & PRIV_XPOLICY)) 324ddf7fe95Scasper return (-1); 325ddf7fe95Scasper 326ddf7fe95Scasper if (priv == PRIV_ALL) { 327ddf7fe95Scasper priv_fillset(&set); 328ddf7fe95Scasper } else if (allzone) { 329ddf7fe95Scasper set = *ZONEPRIVS(cr); 330ddf7fe95Scasper } else { 331ddf7fe95Scasper priv_emptyset(&set); 332ddf7fe95Scasper priv_addset(&set, priv); 333ddf7fe95Scasper } 334ddf7fe95Scasper ret = klpd_call(cr, &set, ap); 335ddf7fe95Scasper return (ret); 336ddf7fe95Scasper } 337ddf7fe95Scasper 338ddf7fe95Scasper static int 339ddf7fe95Scasper priv_policy_override_set(const cred_t *cr, const priv_set_t *req, ...) 340ddf7fe95Scasper { 341ddf7fe95Scasper va_list ap; 342ddf7fe95Scasper 343ddf7fe95Scasper if (CR_FLAGS(cr) & PRIV_XPOLICY) { 344ddf7fe95Scasper va_start(ap, req); 345ddf7fe95Scasper return (klpd_call(cr, req, ap)); 346ddf7fe95Scasper } 347ddf7fe95Scasper return (-1); 348ddf7fe95Scasper } 349ddf7fe95Scasper 350ddf7fe95Scasper /* 3517c478bd9Sstevel@tonic-gate * Audit failure, log error message. 3527c478bd9Sstevel@tonic-gate */ 3537c478bd9Sstevel@tonic-gate static void 3547c478bd9Sstevel@tonic-gate priv_policy_err(const cred_t *cr, int priv, boolean_t allzone, const char *msg) 3557c478bd9Sstevel@tonic-gate { 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate if (audit_active) 3587c478bd9Sstevel@tonic-gate audit_priv(priv, allzone ? ZONEPRIVS(cr) : NULL, 0); 3597c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone); 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) || 3627c478bd9Sstevel@tonic-gate curthread->t_pre_sys) { 3637c478bd9Sstevel@tonic-gate if (allzone && !HAS_ALLZONEPRIVS(cr)) { 3647c478bd9Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_ALLZONE, msg); 3657c478bd9Sstevel@tonic-gate } else { 3667c478bd9Sstevel@tonic-gate ASSERT(!HAS_PRIVILEGE(cr, priv)); 3677c478bd9Sstevel@tonic-gate priv_policy_errmsg(cr, priv, msg); 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate } 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate /* 373ddf7fe95Scasper * priv_policy_ap() 3747c478bd9Sstevel@tonic-gate * return 0 or error. 3757c478bd9Sstevel@tonic-gate * See block comment above for a description of "priv" and "allzone" usage. 3767c478bd9Sstevel@tonic-gate */ 377ddf7fe95Scasper static int 378ddf7fe95Scasper priv_policy_ap(const cred_t *cr, int priv, boolean_t allzone, int err, 379ddf7fe95Scasper const char *msg, va_list ap) 3807c478bd9Sstevel@tonic-gate { 381ddf7fe95Scasper if ((HAS_PRIVILEGE(cr, priv) && (!allzone || HAS_ALLZONEPRIVS(cr))) || 382ddf7fe95Scasper (!servicing_interrupt() && 383ddf7fe95Scasper priv_policy_override(cr, priv, allzone, ap) == 0)) { 3847c478bd9Sstevel@tonic-gate if ((allzone || priv == PRIV_ALL || 3857c478bd9Sstevel@tonic-gate !PRIV_ISASSERT(priv_basic, priv)) && 3867c478bd9Sstevel@tonic-gate !servicing_interrupt()) { 387ae115bc7Smrj PTOU(curproc)->u_acflag |= ASU; /* Needed for SVVS */ 3887c478bd9Sstevel@tonic-gate if (audit_active) 3897c478bd9Sstevel@tonic-gate audit_priv(priv, 3907c478bd9Sstevel@tonic-gate allzone ? ZONEPRIVS(cr) : NULL, 1); 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate err = 0; 3937c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone); 3947c478bd9Sstevel@tonic-gate } else if (!servicing_interrupt()) { 3957c478bd9Sstevel@tonic-gate /* Failure audited in this procedure */ 3967c478bd9Sstevel@tonic-gate priv_policy_err(cr, priv, allzone, msg); 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate return (err); 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate 401ddf7fe95Scasper int 402ddf7fe95Scasper priv_policy_va(const cred_t *cr, int priv, boolean_t allzone, int err, 403ddf7fe95Scasper const char *msg, ...) 404ddf7fe95Scasper { 405ddf7fe95Scasper int ret; 406ddf7fe95Scasper va_list ap; 407ddf7fe95Scasper 408ddf7fe95Scasper va_start(ap, msg); 409ddf7fe95Scasper ret = priv_policy_ap(cr, priv, allzone, err, msg, ap); 410ddf7fe95Scasper va_end(ap); 411ddf7fe95Scasper 412ddf7fe95Scasper return (ret); 413ddf7fe95Scasper } 414ddf7fe95Scasper 415ddf7fe95Scasper int 416ddf7fe95Scasper priv_policy(const cred_t *cr, int priv, boolean_t allzone, int err, 417ddf7fe95Scasper const char *msg) 418ddf7fe95Scasper { 419ddf7fe95Scasper return (priv_policy_va(cr, priv, allzone, err, msg, KLPDARG_NOMORE)); 420ddf7fe95Scasper } 421ddf7fe95Scasper 4227c478bd9Sstevel@tonic-gate /* 4237c478bd9Sstevel@tonic-gate * Return B_TRUE for sufficient privileges, B_FALSE for insufficient privileges. 4247c478bd9Sstevel@tonic-gate */ 4257c478bd9Sstevel@tonic-gate boolean_t 4267c478bd9Sstevel@tonic-gate priv_policy_choice(const cred_t *cr, int priv, boolean_t allzone) 4277c478bd9Sstevel@tonic-gate { 4287c478bd9Sstevel@tonic-gate boolean_t res = HAS_PRIVILEGE(cr, priv) && 4297c478bd9Sstevel@tonic-gate (!allzone || HAS_ALLZONEPRIVS(cr)); 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate /* Audit success only */ 4327c478bd9Sstevel@tonic-gate if (res && audit_active && 4337c478bd9Sstevel@tonic-gate (allzone || priv == PRIV_ALL || !PRIV_ISASSERT(priv_basic, priv)) && 4347c478bd9Sstevel@tonic-gate !servicing_interrupt()) { 4357c478bd9Sstevel@tonic-gate audit_priv(priv, allzone ? ZONEPRIVS(cr) : NULL, 1); 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate if (res) { 4387c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone); 4397c478bd9Sstevel@tonic-gate } else { 4407c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone); 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate return (res); 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate /* 4467c478bd9Sstevel@tonic-gate * Non-auditing variant of priv_policy_choice(). 4477c478bd9Sstevel@tonic-gate */ 4487c478bd9Sstevel@tonic-gate boolean_t 4497c478bd9Sstevel@tonic-gate priv_policy_only(const cred_t *cr, int priv, boolean_t allzone) 4507c478bd9Sstevel@tonic-gate { 4517c478bd9Sstevel@tonic-gate boolean_t res = HAS_PRIVILEGE(cr, priv) && 4527c478bd9Sstevel@tonic-gate (!allzone || HAS_ALLZONEPRIVS(cr)); 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate if (res) { 4557c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone); 4567c478bd9Sstevel@tonic-gate } else { 4577c478bd9Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone); 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate return (res); 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate /* 4637c478bd9Sstevel@tonic-gate * Check whether all privileges in the required set are present. 4647c478bd9Sstevel@tonic-gate */ 4657c478bd9Sstevel@tonic-gate static int 4667c478bd9Sstevel@tonic-gate secpolicy_require_set(const cred_t *cr, const priv_set_t *req, const char *msg) 4677c478bd9Sstevel@tonic-gate { 4687c478bd9Sstevel@tonic-gate int priv; 4697c478bd9Sstevel@tonic-gate int pfound = -1; 4707c478bd9Sstevel@tonic-gate priv_set_t pset; 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate if (req == PRIV_FULLSET ? HAS_ALLPRIVS(cr) : priv_issubset(req, 4737c478bd9Sstevel@tonic-gate &CR_OEPRIV(cr))) { 4747c478bd9Sstevel@tonic-gate return (0); 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 477ddf7fe95Scasper if (priv_policy_override_set(cr, req, KLPDARG_NOMORE) == 0) 478ddf7fe95Scasper return (0); 479ddf7fe95Scasper 4807c478bd9Sstevel@tonic-gate if (req == PRIV_FULLSET || priv_isfullset(req)) { 4817c478bd9Sstevel@tonic-gate priv_policy_err(cr, PRIV_ALL, B_FALSE, msg); 4827c478bd9Sstevel@tonic-gate return (EACCES); 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate pset = CR_OEPRIV(cr); /* present privileges */ 4867c478bd9Sstevel@tonic-gate priv_inverse(&pset); /* all non present privileges */ 4877c478bd9Sstevel@tonic-gate priv_intersect(req, &pset); /* the actual missing privs */ 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate if (audit_active) 4907c478bd9Sstevel@tonic-gate audit_priv(PRIV_NONE, &pset, 0); 4917c478bd9Sstevel@tonic-gate /* 4927c478bd9Sstevel@tonic-gate * Privilege debugging; special case "one privilege in set". 4937c478bd9Sstevel@tonic-gate */ 4947c478bd9Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) || curthread->t_pre_sys) { 4957c478bd9Sstevel@tonic-gate for (priv = 0; priv < nprivs; priv++) { 4967c478bd9Sstevel@tonic-gate if (priv_ismember(&pset, priv)) { 4977c478bd9Sstevel@tonic-gate if (pfound != -1) { 4987c478bd9Sstevel@tonic-gate /* Multiple missing privs */ 4997c478bd9Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_MULTIPLE, 5007c478bd9Sstevel@tonic-gate msg); 5017c478bd9Sstevel@tonic-gate return (EACCES); 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate pfound = priv; 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate } 5067c478bd9Sstevel@tonic-gate ASSERT(pfound != -1); 5077c478bd9Sstevel@tonic-gate /* Just the one missing privilege */ 5087c478bd9Sstevel@tonic-gate priv_policy_errmsg(cr, pfound, msg); 5097c478bd9Sstevel@tonic-gate } 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate return (EACCES); 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate /* 5157c478bd9Sstevel@tonic-gate * Called when an operation requires that the caller be in the 5167c478bd9Sstevel@tonic-gate * global zone, regardless of privilege. 5177c478bd9Sstevel@tonic-gate */ 5187c478bd9Sstevel@tonic-gate static int 5197c478bd9Sstevel@tonic-gate priv_policy_global(const cred_t *cr) 5207c478bd9Sstevel@tonic-gate { 5217c478bd9Sstevel@tonic-gate if (crgetzoneid(cr) == GLOBAL_ZONEID) 5227c478bd9Sstevel@tonic-gate return (0); /* success */ 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) || 5257c478bd9Sstevel@tonic-gate curthread->t_pre_sys) { 5267c478bd9Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_GLOBAL, NULL); 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate return (EPERM); 5297c478bd9Sstevel@tonic-gate } 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate /* 5327c478bd9Sstevel@tonic-gate * Changing process priority 5337c478bd9Sstevel@tonic-gate */ 5347c478bd9Sstevel@tonic-gate int 5357c478bd9Sstevel@tonic-gate secpolicy_setpriority(const cred_t *cr) 5367c478bd9Sstevel@tonic-gate { 5377c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_PRIOCNTL, B_FALSE, EPERM, NULL)); 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate /* 5417c478bd9Sstevel@tonic-gate * Binding to a privileged port, port must be specified in host byte 5427c478bd9Sstevel@tonic-gate * order. 5437c478bd9Sstevel@tonic-gate */ 5447c478bd9Sstevel@tonic-gate int 545ddf7fe95Scasper secpolicy_net_privaddr(const cred_t *cr, in_port_t port, int proto) 5467c478bd9Sstevel@tonic-gate { 547da6c28aaSamw char *reason; 548da6c28aaSamw int priv; 549da6c28aaSamw 550da6c28aaSamw switch (port) { 551da6c28aaSamw case 137: 552da6c28aaSamw case 138: 553da6c28aaSamw case 139: 554da6c28aaSamw case 445: 555da6c28aaSamw /* 556da6c28aaSamw * NBT and SMB ports, these are extra privileged ports, 557da6c28aaSamw * allow bind only if the SYS_SMB privilege is present. 558da6c28aaSamw */ 559da6c28aaSamw priv = PRIV_SYS_SMB; 560da6c28aaSamw reason = "NBT or SMB port"; 561da6c28aaSamw break; 562da6c28aaSamw 563da6c28aaSamw case 2049: 564da6c28aaSamw case 4045: 5657c478bd9Sstevel@tonic-gate /* 5667c478bd9Sstevel@tonic-gate * NFS ports, these are extra privileged ports, allow bind 5677c478bd9Sstevel@tonic-gate * only if the SYS_NFS privilege is present. 5687c478bd9Sstevel@tonic-gate */ 569da6c28aaSamw priv = PRIV_SYS_NFS; 570da6c28aaSamw reason = "NFS port"; 571da6c28aaSamw break; 572da6c28aaSamw 573da6c28aaSamw default: 574da6c28aaSamw priv = PRIV_NET_PRIVADDR; 575da6c28aaSamw reason = NULL; 576da6c28aaSamw break; 577da6c28aaSamw 578da6c28aaSamw } 579da6c28aaSamw 580ddf7fe95Scasper return (priv_policy_va(cr, priv, B_FALSE, EACCES, reason, 581ddf7fe95Scasper KLPDARG_PORT, (int)proto, (int)port, KLPDARG_NOMORE)); 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate /* 58545916cd2Sjpk * Binding to a multilevel port on a trusted (labeled) system. 58645916cd2Sjpk */ 58745916cd2Sjpk int 58845916cd2Sjpk secpolicy_net_bindmlp(const cred_t *cr) 58945916cd2Sjpk { 590ddf7fe95Scasper return (PRIV_POLICY(cr, PRIV_NET_BINDMLP, B_FALSE, EACCES, NULL)); 59145916cd2Sjpk } 59245916cd2Sjpk 59345916cd2Sjpk /* 59445916cd2Sjpk * Allow a communication between a zone and an unlabeled host when their 59545916cd2Sjpk * labels don't match. 59645916cd2Sjpk */ 59745916cd2Sjpk int 59845916cd2Sjpk secpolicy_net_mac_aware(const cred_t *cr) 59945916cd2Sjpk { 600ddf7fe95Scasper return (PRIV_POLICY(cr, PRIV_NET_MAC_AWARE, B_FALSE, EACCES, NULL)); 60145916cd2Sjpk } 60245916cd2Sjpk 60345916cd2Sjpk /* 6047c478bd9Sstevel@tonic-gate * Common routine which determines whether a given credential can 6057c478bd9Sstevel@tonic-gate * act on a given mount. 6067c478bd9Sstevel@tonic-gate * When called through mount, the parameter needoptcheck is a pointer 6077c478bd9Sstevel@tonic-gate * to a boolean variable which will be set to either true or false, 6087c478bd9Sstevel@tonic-gate * depending on whether the mount policy should change the mount options. 6097c478bd9Sstevel@tonic-gate * In all other cases, needoptcheck should be a NULL pointer. 6107c478bd9Sstevel@tonic-gate */ 6117c478bd9Sstevel@tonic-gate static int 6127c478bd9Sstevel@tonic-gate secpolicy_fs_common(cred_t *cr, vnode_t *mvp, const vfs_t *vfsp, 6137c478bd9Sstevel@tonic-gate boolean_t *needoptcheck) 6147c478bd9Sstevel@tonic-gate { 6157c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 6167c478bd9Sstevel@tonic-gate boolean_t mounting = needoptcheck != NULL; 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate /* 6197c478bd9Sstevel@tonic-gate * Short circuit the following cases: 6207c478bd9Sstevel@tonic-gate * vfsp == NULL or mvp == NULL (pure privilege check) 6217c478bd9Sstevel@tonic-gate * have all privileges - no further checks required 6227c478bd9Sstevel@tonic-gate * and no mount options need to be set. 6237c478bd9Sstevel@tonic-gate */ 6247c478bd9Sstevel@tonic-gate if (vfsp == NULL || mvp == NULL || HAS_ALLPRIVS(cr)) { 6257c478bd9Sstevel@tonic-gate if (mounting) 6267c478bd9Sstevel@tonic-gate *needoptcheck = B_FALSE; 6277c478bd9Sstevel@tonic-gate 628ddf7fe95Scasper return (priv_policy_va(cr, PRIV_SYS_MOUNT, allzone, EPERM, 629ddf7fe95Scasper NULL, KLPDARG_VNODE, mvp, (char *)NULL, KLPDARG_NOMORE)); 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate /* 6337c478bd9Sstevel@tonic-gate * When operating on an existing mount (either we're not mounting 6347c478bd9Sstevel@tonic-gate * or we're doing a remount and VFS_REMOUNT will be set), zones 6357c478bd9Sstevel@tonic-gate * can operate only on mounts established by the zone itself. 6367c478bd9Sstevel@tonic-gate */ 6377c478bd9Sstevel@tonic-gate if (!mounting || (vfsp->vfs_flag & VFS_REMOUNT) != 0) { 6387c478bd9Sstevel@tonic-gate zoneid_t zoneid = crgetzoneid(cr); 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate if (zoneid != GLOBAL_ZONEID && 6417c478bd9Sstevel@tonic-gate vfsp->vfs_zone->zone_id != zoneid) { 6427c478bd9Sstevel@tonic-gate return (EPERM); 6437c478bd9Sstevel@tonic-gate } 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate if (mounting) 6477c478bd9Sstevel@tonic-gate *needoptcheck = B_TRUE; 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate /* 6507c478bd9Sstevel@tonic-gate * Overlay mounts may hide important stuff; if you can't write to a 6517c478bd9Sstevel@tonic-gate * mount point but would be able to mount on top of it, you can 6527c478bd9Sstevel@tonic-gate * escalate your privileges. 6537c478bd9Sstevel@tonic-gate * So we go about asking the same questions namefs does when it 6547c478bd9Sstevel@tonic-gate * decides whether you can mount over a file or not but with the 6557c478bd9Sstevel@tonic-gate * added restriction that you can only mount on top of a regular 6567c478bd9Sstevel@tonic-gate * file or directory. 6577c478bd9Sstevel@tonic-gate * If we have all the zone's privileges, we skip all other checks, 6587c478bd9Sstevel@tonic-gate * or else we may actually get in trouble inside the automounter. 6597c478bd9Sstevel@tonic-gate */ 6607c478bd9Sstevel@tonic-gate if ((mvp->v_flag & VROOT) != 0 || 6617c478bd9Sstevel@tonic-gate (mvp->v_type != VDIR && mvp->v_type != VREG) || 6627c478bd9Sstevel@tonic-gate HAS_ALLZONEPRIVS(cr)) { 6637c478bd9Sstevel@tonic-gate allzone = B_TRUE; 6647c478bd9Sstevel@tonic-gate } else { 6657c478bd9Sstevel@tonic-gate vattr_t va; 6667c478bd9Sstevel@tonic-gate int err; 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate va.va_mask = AT_UID|AT_MODE; 669da6c28aaSamw err = VOP_GETATTR(mvp, &va, 0, cr, NULL); 6707c478bd9Sstevel@tonic-gate if (err != 0) 6717c478bd9Sstevel@tonic-gate return (err); 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate if ((err = secpolicy_vnode_owner(cr, va.va_uid)) != 0) 6747c478bd9Sstevel@tonic-gate return (err); 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate if ((va.va_mode & VWRITE) == 0 && 6777c478bd9Sstevel@tonic-gate secpolicy_vnode_access(cr, mvp, va.va_uid, VWRITE) != 0) { 6787c478bd9Sstevel@tonic-gate return (EACCES); 6797c478bd9Sstevel@tonic-gate } 6807c478bd9Sstevel@tonic-gate } 681ddf7fe95Scasper return (priv_policy_va(cr, PRIV_SYS_MOUNT, allzone, EPERM, 682ddf7fe95Scasper NULL, KLPDARG_VNODE, mvp, (char *)NULL, KLPDARG_NOMORE)); 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate 685ecd6cf80Smarks void 686ecd6cf80Smarks secpolicy_fs_mount_clearopts(cred_t *cr, struct vfs *vfsp) 6877c478bd9Sstevel@tonic-gate { 6887c478bd9Sstevel@tonic-gate boolean_t amsuper = HAS_ALLZONEPRIVS(cr); 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate /* 691ecd6cf80Smarks * check; if we don't have either "nosuid" or 6927c478bd9Sstevel@tonic-gate * both "nosetuid" and "nodevices", then we add 6937c478bd9Sstevel@tonic-gate * "nosuid"; this depends on how the current 6947c478bd9Sstevel@tonic-gate * implementation works (it first checks nosuid). In a 6957c478bd9Sstevel@tonic-gate * zone, a user with all zone privileges can mount with 6967c478bd9Sstevel@tonic-gate * "setuid" but never with "devices". 6977c478bd9Sstevel@tonic-gate */ 6987c478bd9Sstevel@tonic-gate if (!vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL) && 6997c478bd9Sstevel@tonic-gate (!vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL) || 7007c478bd9Sstevel@tonic-gate !vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL))) { 7017c478bd9Sstevel@tonic-gate if (crgetzoneid(cr) == GLOBAL_ZONEID || !amsuper) 7027c478bd9Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_NOSUID, NULL, 0); 7037c478bd9Sstevel@tonic-gate else 7047c478bd9Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_NODEVICES, NULL, 0); 7057c478bd9Sstevel@tonic-gate } 7067c478bd9Sstevel@tonic-gate /* 7077c478bd9Sstevel@tonic-gate * If we're not the local super user, we set the "restrict" 7087c478bd9Sstevel@tonic-gate * option to indicate to automountd that this mount should 7097c478bd9Sstevel@tonic-gate * be handled with care. 7107c478bd9Sstevel@tonic-gate */ 7117c478bd9Sstevel@tonic-gate if (!amsuper) 7127c478bd9Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_RESTRICT, NULL, 0); 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate } 715ecd6cf80Smarks 716ecd6cf80Smarks extern vnode_t *rootvp; 717ecd6cf80Smarks extern vfs_t *rootvfs; 718ecd6cf80Smarks 719ecd6cf80Smarks int 720ecd6cf80Smarks secpolicy_fs_mount(cred_t *cr, vnode_t *mvp, struct vfs *vfsp) 721ecd6cf80Smarks { 722ecd6cf80Smarks boolean_t needoptchk; 723ecd6cf80Smarks int error; 724ecd6cf80Smarks 725ecd6cf80Smarks /* 726ecd6cf80Smarks * If it's a remount, get the underlying mount point, 727ecd6cf80Smarks * except for the root where we use the rootvp. 728ecd6cf80Smarks */ 729ecd6cf80Smarks if ((vfsp->vfs_flag & VFS_REMOUNT) != 0) { 730ecd6cf80Smarks if (vfsp == rootvfs) 731ecd6cf80Smarks mvp = rootvp; 732ecd6cf80Smarks else 733ecd6cf80Smarks mvp = vfsp->vfs_vnodecovered; 734ecd6cf80Smarks } 735ecd6cf80Smarks 736ecd6cf80Smarks error = secpolicy_fs_common(cr, mvp, vfsp, &needoptchk); 737ecd6cf80Smarks 738ecd6cf80Smarks if (error == 0 && needoptchk) { 739ecd6cf80Smarks secpolicy_fs_mount_clearopts(cr, vfsp); 740ecd6cf80Smarks } 741ecd6cf80Smarks 7427c478bd9Sstevel@tonic-gate return (error); 7437c478bd9Sstevel@tonic-gate } 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate /* 7467c478bd9Sstevel@tonic-gate * Does the policy computations for "ownership" of a mount; 7477c478bd9Sstevel@tonic-gate * here ownership is defined as the ability to "mount" 7487c478bd9Sstevel@tonic-gate * the filesystem originally. The rootvfs doesn't cover any 7497c478bd9Sstevel@tonic-gate * vnodes; we attribute its ownership to the rootvp. 7507c478bd9Sstevel@tonic-gate */ 7517c478bd9Sstevel@tonic-gate static int 7527c478bd9Sstevel@tonic-gate secpolicy_fs_owner(cred_t *cr, const struct vfs *vfsp) 7537c478bd9Sstevel@tonic-gate { 7547c478bd9Sstevel@tonic-gate vnode_t *mvp; 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate if (vfsp == NULL) 7577c478bd9Sstevel@tonic-gate mvp = NULL; 7587c478bd9Sstevel@tonic-gate else if (vfsp == rootvfs) 7597c478bd9Sstevel@tonic-gate mvp = rootvp; 7607c478bd9Sstevel@tonic-gate else 7617c478bd9Sstevel@tonic-gate mvp = vfsp->vfs_vnodecovered; 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate return (secpolicy_fs_common(cr, mvp, vfsp, NULL)); 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate int 7677c478bd9Sstevel@tonic-gate secpolicy_fs_unmount(cred_t *cr, struct vfs *vfsp) 7687c478bd9Sstevel@tonic-gate { 7697c478bd9Sstevel@tonic-gate return (secpolicy_fs_owner(cr, vfsp)); 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate /* 7737c478bd9Sstevel@tonic-gate * Quotas are a resource, but if one has the ability to mount a filesystem, he 7747c478bd9Sstevel@tonic-gate * should be able to modify quotas on it. 7757c478bd9Sstevel@tonic-gate */ 7767c478bd9Sstevel@tonic-gate int 7777c478bd9Sstevel@tonic-gate secpolicy_fs_quota(const cred_t *cr, const vfs_t *vfsp) 7787c478bd9Sstevel@tonic-gate { 7797c478bd9Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 7807c478bd9Sstevel@tonic-gate } 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate /* 7837c478bd9Sstevel@tonic-gate * Exceeding minfree: also a per-mount resource constraint. 7847c478bd9Sstevel@tonic-gate */ 7857c478bd9Sstevel@tonic-gate int 7867c478bd9Sstevel@tonic-gate secpolicy_fs_minfree(const cred_t *cr, const vfs_t *vfsp) 7877c478bd9Sstevel@tonic-gate { 7887c478bd9Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 7897c478bd9Sstevel@tonic-gate } 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate int 7927c478bd9Sstevel@tonic-gate secpolicy_fs_config(const cred_t *cr, const vfs_t *vfsp) 7937c478bd9Sstevel@tonic-gate { 7947c478bd9Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 7957c478bd9Sstevel@tonic-gate } 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate /* ARGSUSED */ 7987c478bd9Sstevel@tonic-gate int 7997c478bd9Sstevel@tonic-gate secpolicy_fs_linkdir(const cred_t *cr, const vfs_t *vfsp) 8007c478bd9Sstevel@tonic-gate { 8017c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_LINKDIR, B_FALSE, EPERM, NULL)); 8027c478bd9Sstevel@tonic-gate } 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate /* 8057c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_access() 8067c478bd9Sstevel@tonic-gate * 8077c478bd9Sstevel@tonic-gate * Parameters: Process credential 8087c478bd9Sstevel@tonic-gate * vnode 8097c478bd9Sstevel@tonic-gate * uid of owner of vnode 8107c478bd9Sstevel@tonic-gate * permission bits not granted to the caller when examining 8117c478bd9Sstevel@tonic-gate * file mode bits (i.e., when a process wants to open a 8127c478bd9Sstevel@tonic-gate * mode 444 file for VREAD|VWRITE, this function should be 8137c478bd9Sstevel@tonic-gate * called only with a VWRITE argument). 8147c478bd9Sstevel@tonic-gate * 8157c478bd9Sstevel@tonic-gate * Normal: Verifies that cred has the appropriate privileges to 8167c478bd9Sstevel@tonic-gate * override the mode bits that were denied. 8177c478bd9Sstevel@tonic-gate * 8187c478bd9Sstevel@tonic-gate * Override: file_dac_execute - if VEXEC bit was denied and vnode is 8197c478bd9Sstevel@tonic-gate * not a directory. 8207c478bd9Sstevel@tonic-gate * file_dac_read - if VREAD bit was denied. 8217c478bd9Sstevel@tonic-gate * file_dac_search - if VEXEC bit was denied and vnode is 8227c478bd9Sstevel@tonic-gate * a directory. 8237c478bd9Sstevel@tonic-gate * file_dac_write - if VWRITE bit was denied. 8247c478bd9Sstevel@tonic-gate * 8257c478bd9Sstevel@tonic-gate * Root owned files are special cased to protect system 8267c478bd9Sstevel@tonic-gate * configuration files and such. 8277c478bd9Sstevel@tonic-gate * 8287c478bd9Sstevel@tonic-gate * Output: EACCES - if privilege check fails. 8297c478bd9Sstevel@tonic-gate */ 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate /* ARGSUSED */ 8327c478bd9Sstevel@tonic-gate int 8337c478bd9Sstevel@tonic-gate secpolicy_vnode_access(const cred_t *cr, vnode_t *vp, uid_t owner, mode_t mode) 8347c478bd9Sstevel@tonic-gate { 835ddf7fe95Scasper if ((mode & VREAD) && priv_policy_va(cr, PRIV_FILE_DAC_READ, B_FALSE, 836ddf7fe95Scasper EACCES, NULL, KLPDARG_VNODE, vp, (char *)NULL, 837ddf7fe95Scasper KLPDARG_NOMORE) != 0) { 8387c478bd9Sstevel@tonic-gate return (EACCES); 839ddf7fe95Scasper } 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate if (mode & VWRITE) { 8427c478bd9Sstevel@tonic-gate boolean_t allzone; 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate if (owner == 0 && cr->cr_uid != 0) 8457c478bd9Sstevel@tonic-gate allzone = B_TRUE; 8467c478bd9Sstevel@tonic-gate else 8477c478bd9Sstevel@tonic-gate allzone = B_FALSE; 848ddf7fe95Scasper if (priv_policy_va(cr, PRIV_FILE_DAC_WRITE, allzone, EACCES, 849ddf7fe95Scasper NULL, KLPDARG_VNODE, vp, (char *)NULL, 850ddf7fe95Scasper KLPDARG_NOMORE) != 0) { 8517c478bd9Sstevel@tonic-gate return (EACCES); 8527c478bd9Sstevel@tonic-gate } 853ddf7fe95Scasper } 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate if (mode & VEXEC) { 8567c478bd9Sstevel@tonic-gate /* 8577c478bd9Sstevel@tonic-gate * Directories use file_dac_search to override the execute bit. 8587c478bd9Sstevel@tonic-gate */ 859ddf7fe95Scasper int p = vp->v_type == VDIR ? PRIV_FILE_DAC_SEARCH : 860ddf7fe95Scasper PRIV_FILE_DAC_EXECUTE; 8617c478bd9Sstevel@tonic-gate 862ddf7fe95Scasper return (priv_policy_va(cr, p, B_FALSE, EACCES, NULL, 863ddf7fe95Scasper KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE)); 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate return (0); 8667c478bd9Sstevel@tonic-gate } 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate /* 8697c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_setid_modify() 8707c478bd9Sstevel@tonic-gate * 8717c478bd9Sstevel@tonic-gate * Normal: verify that subject can set the file setid flags. 8727c478bd9Sstevel@tonic-gate * 8737c478bd9Sstevel@tonic-gate * Output: EPERM - if not privileged. 8747c478bd9Sstevel@tonic-gate */ 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate static int 8777c478bd9Sstevel@tonic-gate secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner) 8787c478bd9Sstevel@tonic-gate { 8797c478bd9Sstevel@tonic-gate /* If changing to suid root, must have all zone privs */ 8807c478bd9Sstevel@tonic-gate boolean_t allzone = B_TRUE; 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate if (owner != 0) { 8837c478bd9Sstevel@tonic-gate if (owner == cr->cr_uid) 8847c478bd9Sstevel@tonic-gate return (0); 8857c478bd9Sstevel@tonic-gate allzone = B_FALSE; 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_SETID, allzone, EPERM, NULL)); 8887c478bd9Sstevel@tonic-gate } 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate /* 8917c478bd9Sstevel@tonic-gate * Are we allowed to retain the set-uid/set-gid bits when 8927c478bd9Sstevel@tonic-gate * changing ownership or when writing to a file? 8937c478bd9Sstevel@tonic-gate * "issuid" should be true when set-uid; only in that case 8947c478bd9Sstevel@tonic-gate * root ownership is checked (setgid is assumed). 8957c478bd9Sstevel@tonic-gate */ 8967c478bd9Sstevel@tonic-gate int 8977c478bd9Sstevel@tonic-gate secpolicy_vnode_setid_retain(const cred_t *cred, boolean_t issuidroot) 8987c478bd9Sstevel@tonic-gate { 8997c478bd9Sstevel@tonic-gate if (issuidroot && !HAS_ALLZONEPRIVS(cred)) 9007c478bd9Sstevel@tonic-gate return (EPERM); 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate return (!PRIV_POLICY_CHOICE(cred, PRIV_FILE_SETID, B_FALSE)); 9037c478bd9Sstevel@tonic-gate } 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate /* 9067c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_setids_setgids() 9077c478bd9Sstevel@tonic-gate * 9087c478bd9Sstevel@tonic-gate * Normal: verify that subject can set the file setgid flag. 9097c478bd9Sstevel@tonic-gate * 9107c478bd9Sstevel@tonic-gate * Output: EPERM - if not privileged 9117c478bd9Sstevel@tonic-gate */ 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate int 9147c478bd9Sstevel@tonic-gate secpolicy_vnode_setids_setgids(const cred_t *cred, gid_t gid) 9157c478bd9Sstevel@tonic-gate { 9167c478bd9Sstevel@tonic-gate if (!groupmember(gid, cred)) 9177c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_SETID, B_FALSE, EPERM, 9187c478bd9Sstevel@tonic-gate NULL)); 9197c478bd9Sstevel@tonic-gate return (0); 9207c478bd9Sstevel@tonic-gate } 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate /* 923*47def0dcSMark Shellenbaum * Name: secpolicy_vnode_chown 924*47def0dcSMark Shellenbaum * 925*47def0dcSMark Shellenbaum * Normal: Determine if subject can chown owner of a file. 926*47def0dcSMark Shellenbaum * 927*47def0dcSMark Shellenbaum * Output: EPERM - if access denied 9287c478bd9Sstevel@tonic-gate */ 929*47def0dcSMark Shellenbaum 9307c478bd9Sstevel@tonic-gate int 931*47def0dcSMark Shellenbaum secpolicy_vnode_chown(const cred_t *cred, boolean_t check_self) 9327c478bd9Sstevel@tonic-gate { 9337c478bd9Sstevel@tonic-gate if (HAS_PRIVILEGE(cred, PRIV_FILE_CHOWN)) 9347c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_CHOWN, B_FALSE, EPERM, 9357c478bd9Sstevel@tonic-gate NULL)); 936*47def0dcSMark Shellenbaum else if (check_self) 9377c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_CHOWN_SELF, B_FALSE, EPERM, 9387c478bd9Sstevel@tonic-gate NULL)); 939*47def0dcSMark Shellenbaum else 940*47def0dcSMark Shellenbaum return (EPERM); 941*47def0dcSMark Shellenbaum } 942*47def0dcSMark Shellenbaum 943*47def0dcSMark Shellenbaum /* 944*47def0dcSMark Shellenbaum * Name: secpolicy_vnode_create_gid 945*47def0dcSMark Shellenbaum * 946*47def0dcSMark Shellenbaum * Normal: Determine if subject can change group ownership of a file. 947*47def0dcSMark Shellenbaum * 948*47def0dcSMark Shellenbaum * Output: EPERM - if access denied 949*47def0dcSMark Shellenbaum */ 950*47def0dcSMark Shellenbaum int 951*47def0dcSMark Shellenbaum secpolicy_vnode_create_gid(const cred_t *cred) 952*47def0dcSMark Shellenbaum { 953*47def0dcSMark Shellenbaum return (secpolicy_vnode_chown(cred, B_TRUE)); 9547c478bd9Sstevel@tonic-gate } 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate /* 9577c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_utime_modify() 9587c478bd9Sstevel@tonic-gate * 9597c478bd9Sstevel@tonic-gate * Normal: verify that subject can modify the utime on a file. 9607c478bd9Sstevel@tonic-gate * 9617c478bd9Sstevel@tonic-gate * Output: EPERM - if access denied. 9627c478bd9Sstevel@tonic-gate */ 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate static int 9657c478bd9Sstevel@tonic-gate secpolicy_vnode_utime_modify(const cred_t *cred) 9667c478bd9Sstevel@tonic-gate { 9677c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_OWNER, B_FALSE, EPERM, 9687c478bd9Sstevel@tonic-gate "modify file times")); 9697c478bd9Sstevel@tonic-gate } 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate /* 9737c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_setdac() 9747c478bd9Sstevel@tonic-gate * 9757c478bd9Sstevel@tonic-gate * Normal: verify that subject can modify the mode of a file. 9767c478bd9Sstevel@tonic-gate * allzone privilege needed when modifying root owned object. 9777c478bd9Sstevel@tonic-gate * 9787c478bd9Sstevel@tonic-gate * Output: EPERM - if access denied. 9797c478bd9Sstevel@tonic-gate */ 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate int 9827c478bd9Sstevel@tonic-gate secpolicy_vnode_setdac(const cred_t *cred, uid_t owner) 9837c478bd9Sstevel@tonic-gate { 9847c478bd9Sstevel@tonic-gate if (owner == cred->cr_uid) 9857c478bd9Sstevel@tonic-gate return (0); 9867c478bd9Sstevel@tonic-gate 9877c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_OWNER, owner == 0, EPERM, NULL)); 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate /* 9907c478bd9Sstevel@tonic-gate * Name: secpolicy_vnode_stky_modify() 9917c478bd9Sstevel@tonic-gate * 9927c478bd9Sstevel@tonic-gate * Normal: verify that subject can make a file a "sticky". 9937c478bd9Sstevel@tonic-gate * 9947c478bd9Sstevel@tonic-gate * Output: EPERM - if access denied. 9957c478bd9Sstevel@tonic-gate */ 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate int 9987c478bd9Sstevel@tonic-gate secpolicy_vnode_stky_modify(const cred_t *cred) 9997c478bd9Sstevel@tonic-gate { 10007c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_SYS_CONFIG, B_FALSE, EPERM, 10017c478bd9Sstevel@tonic-gate "set file sticky")); 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate /* 10057c478bd9Sstevel@tonic-gate * Policy determines whether we can remove an entry from a directory, 10067c478bd9Sstevel@tonic-gate * regardless of permission bits. 10077c478bd9Sstevel@tonic-gate */ 10087c478bd9Sstevel@tonic-gate int 10097c478bd9Sstevel@tonic-gate secpolicy_vnode_remove(const cred_t *cr) 10107c478bd9Sstevel@tonic-gate { 10117c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_OWNER, B_FALSE, EACCES, 10127c478bd9Sstevel@tonic-gate "sticky directory")); 10137c478bd9Sstevel@tonic-gate } 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate int 10167c478bd9Sstevel@tonic-gate secpolicy_vnode_owner(const cred_t *cr, uid_t owner) 10177c478bd9Sstevel@tonic-gate { 10187c478bd9Sstevel@tonic-gate boolean_t allzone = (owner == 0); 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate if (owner == cr->cr_uid) 10217c478bd9Sstevel@tonic-gate return (0); 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_OWNER, allzone, EPERM, NULL)); 10247c478bd9Sstevel@tonic-gate } 10257c478bd9Sstevel@tonic-gate 102613f9f30eSmarks void 102713f9f30eSmarks secpolicy_setid_clear(vattr_t *vap, cred_t *cr) 102813f9f30eSmarks { 102913f9f30eSmarks if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0 && 103013f9f30eSmarks secpolicy_vnode_setid_retain(cr, 103113f9f30eSmarks (vap->va_mode & S_ISUID) != 0 && 103213f9f30eSmarks (vap->va_mask & AT_UID) != 0 && vap->va_uid == 0) != 0) { 103313f9f30eSmarks vap->va_mask |= AT_MODE; 103413f9f30eSmarks vap->va_mode &= ~(S_ISUID|S_ISGID); 103513f9f30eSmarks } 103613f9f30eSmarks } 103713f9f30eSmarks 1038f92daba9Smarks int 1039f92daba9Smarks secpolicy_setid_setsticky_clear(vnode_t *vp, vattr_t *vap, const vattr_t *ovap, 1040f92daba9Smarks cred_t *cr) 1041f92daba9Smarks { 1042f92daba9Smarks int error; 1043f92daba9Smarks 1044f92daba9Smarks if ((vap->va_mode & S_ISUID) != 0 && 1045f92daba9Smarks (error = secpolicy_vnode_setid_modify(cr, 1046f92daba9Smarks ovap->va_uid)) != 0) { 1047f92daba9Smarks return (error); 1048f92daba9Smarks } 1049f92daba9Smarks 1050f92daba9Smarks /* 1051f92daba9Smarks * Check privilege if attempting to set the 1052f92daba9Smarks * sticky bit on a non-directory. 1053f92daba9Smarks */ 1054f92daba9Smarks if (vp->v_type != VDIR && (vap->va_mode & S_ISVTX) != 0 && 1055f92daba9Smarks secpolicy_vnode_stky_modify(cr) != 0) { 1056f92daba9Smarks vap->va_mode &= ~S_ISVTX; 1057f92daba9Smarks } 1058f92daba9Smarks 1059f92daba9Smarks /* 1060f92daba9Smarks * Check for privilege if attempting to set the 1061f92daba9Smarks * group-id bit. 1062f92daba9Smarks */ 1063f92daba9Smarks if ((vap->va_mode & S_ISGID) != 0 && 1064f92daba9Smarks secpolicy_vnode_setids_setgids(cr, ovap->va_gid) != 0) { 1065f92daba9Smarks vap->va_mode &= ~S_ISGID; 1066f92daba9Smarks } 1067f92daba9Smarks 1068f92daba9Smarks return (0); 1069f92daba9Smarks } 1070f92daba9Smarks 1071da6c28aaSamw #define ATTR_FLAG_PRIV(attr, value, cr) \ 1072da6c28aaSamw PRIV_POLICY(cr, value ? PRIV_FILE_FLAG_SET : PRIV_ALL, \ 1073da6c28aaSamw B_FALSE, EPERM, NULL) 1074da6c28aaSamw 1075da6c28aaSamw /* 1076da6c28aaSamw * Check privileges for setting xvattr attributes 1077da6c28aaSamw */ 1078da6c28aaSamw int 1079da6c28aaSamw secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype) 1080da6c28aaSamw { 1081da6c28aaSamw xoptattr_t *xoap; 1082da6c28aaSamw int error = 0; 1083da6c28aaSamw 1084da6c28aaSamw if ((xoap = xva_getxoptattr(xvap)) == NULL) 1085da6c28aaSamw return (EINVAL); 1086da6c28aaSamw 1087da6c28aaSamw /* 1088da6c28aaSamw * First process the DOS bits 1089da6c28aaSamw */ 1090da6c28aaSamw if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE) || 1091da6c28aaSamw XVA_ISSET_REQ(xvap, XAT_HIDDEN) || 1092da6c28aaSamw XVA_ISSET_REQ(xvap, XAT_READONLY) || 1093da6c28aaSamw XVA_ISSET_REQ(xvap, XAT_SYSTEM) || 1094da6c28aaSamw XVA_ISSET_REQ(xvap, XAT_CREATETIME)) { 1095da6c28aaSamw if ((error = secpolicy_vnode_owner(cr, owner)) != 0) 1096da6c28aaSamw return (error); 1097da6c28aaSamw } 1098da6c28aaSamw 1099da6c28aaSamw /* 1100da6c28aaSamw * Now handle special attributes 1101da6c28aaSamw */ 1102da6c28aaSamw 1103da6c28aaSamw if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE)) 1104da6c28aaSamw error = ATTR_FLAG_PRIV(XAT_IMMUTABLE, 1105da6c28aaSamw xoap->xoa_immutable, cr); 1106da6c28aaSamw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_NOUNLINK)) 1107da6c28aaSamw error = ATTR_FLAG_PRIV(XAT_NOUNLINK, 1108da6c28aaSamw xoap->xoa_nounlink, cr); 1109da6c28aaSamw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_APPENDONLY)) 1110da6c28aaSamw error = ATTR_FLAG_PRIV(XAT_APPENDONLY, 1111da6c28aaSamw xoap->xoa_appendonly, cr); 1112da6c28aaSamw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_NODUMP)) 1113da6c28aaSamw error = ATTR_FLAG_PRIV(XAT_NODUMP, 1114da6c28aaSamw xoap->xoa_nodump, cr); 1115da6c28aaSamw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_OPAQUE)) 1116da6c28aaSamw error = EPERM; 1117da6c28aaSamw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED)) { 1118da6c28aaSamw error = ATTR_FLAG_PRIV(XAT_AV_QUARANTINED, 1119da6c28aaSamw xoap->xoa_av_quarantined, cr); 1120e8f97327Smarks if (error == 0 && vtype != VREG && xoap->xoa_av_quarantined) 1121da6c28aaSamw error = EINVAL; 1122da6c28aaSamw } 1123da6c28aaSamw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED)) 1124da6c28aaSamw error = ATTR_FLAG_PRIV(XAT_AV_MODIFIED, 1125da6c28aaSamw xoap->xoa_av_modified, cr); 1126da6c28aaSamw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) { 1127da6c28aaSamw error = ATTR_FLAG_PRIV(XAT_AV_SCANSTAMP, 1128da6c28aaSamw xoap->xoa_av_scanstamp, cr); 1129da6c28aaSamw if (error == 0 && vtype != VREG) 1130da6c28aaSamw error = EINVAL; 1131da6c28aaSamw } 1132da6c28aaSamw return (error); 1133da6c28aaSamw } 1134da6c28aaSamw 11357c478bd9Sstevel@tonic-gate /* 11367c478bd9Sstevel@tonic-gate * This function checks the policy decisions surrounding the 11377c478bd9Sstevel@tonic-gate * vop setattr call. 11387c478bd9Sstevel@tonic-gate * 11397c478bd9Sstevel@tonic-gate * It should be called after sufficient locks have been established 11407c478bd9Sstevel@tonic-gate * on the underlying data structures. No concurrent modifications 11417c478bd9Sstevel@tonic-gate * should be allowed. 11427c478bd9Sstevel@tonic-gate * 11437c478bd9Sstevel@tonic-gate * The caller must pass in unlocked version of its vaccess function 11447c478bd9Sstevel@tonic-gate * this is required because vop_access function should lock the 11457c478bd9Sstevel@tonic-gate * node for reading. A three argument function should be defined 11467c478bd9Sstevel@tonic-gate * which accepts the following argument: 11477c478bd9Sstevel@tonic-gate * A pointer to the internal "node" type (inode *) 11487c478bd9Sstevel@tonic-gate * vnode access bits (VREAD|VWRITE|VEXEC) 11497c478bd9Sstevel@tonic-gate * a pointer to the credential 11507c478bd9Sstevel@tonic-gate * 11517c478bd9Sstevel@tonic-gate * This function makes the following policy decisions: 11527c478bd9Sstevel@tonic-gate * 11537c478bd9Sstevel@tonic-gate * - change permissions 11547c478bd9Sstevel@tonic-gate * - permission to change file mode if not owner 11557c478bd9Sstevel@tonic-gate * - permission to add sticky bit to non-directory 11567c478bd9Sstevel@tonic-gate * - permission to add set-gid bit 11577c478bd9Sstevel@tonic-gate * 11587c478bd9Sstevel@tonic-gate * The ovap argument should include AT_MODE|AT_UID|AT_GID. 11597c478bd9Sstevel@tonic-gate * 11607c478bd9Sstevel@tonic-gate * If the vap argument does not include AT_MODE, the mode will be copied from 11617c478bd9Sstevel@tonic-gate * ovap. In certain situations set-uid/set-gid bits need to be removed; 11627c478bd9Sstevel@tonic-gate * this is done by marking vap->va_mask to include AT_MODE and va_mode 11637c478bd9Sstevel@tonic-gate * is updated to the newly computed mode. 11647c478bd9Sstevel@tonic-gate */ 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate int 11677c478bd9Sstevel@tonic-gate secpolicy_vnode_setattr(cred_t *cr, struct vnode *vp, struct vattr *vap, 11687c478bd9Sstevel@tonic-gate const struct vattr *ovap, int flags, 11697c478bd9Sstevel@tonic-gate int unlocked_access(void *, int, cred_t *), 11707c478bd9Sstevel@tonic-gate void *node) 11717c478bd9Sstevel@tonic-gate { 11727c478bd9Sstevel@tonic-gate int mask = vap->va_mask; 11737c478bd9Sstevel@tonic-gate int error = 0; 1174da6c28aaSamw boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE; 11757c478bd9Sstevel@tonic-gate 11767c478bd9Sstevel@tonic-gate if (mask & AT_SIZE) { 11777c478bd9Sstevel@tonic-gate if (vp->v_type == VDIR) { 11787c478bd9Sstevel@tonic-gate error = EISDIR; 11797c478bd9Sstevel@tonic-gate goto out; 11807c478bd9Sstevel@tonic-gate } 1181da6c28aaSamw 1182da6c28aaSamw /* 1183da6c28aaSamw * If ATTR_NOACLCHECK is set in the flags, then we don't 1184da6c28aaSamw * perform the secondary unlocked_access() call since the 1185da6c28aaSamw * ACL (if any) is being checked there. 1186da6c28aaSamw */ 1187da6c28aaSamw if (skipaclchk == B_FALSE) { 11887c478bd9Sstevel@tonic-gate error = unlocked_access(node, VWRITE, cr); 11897c478bd9Sstevel@tonic-gate if (error) 11907c478bd9Sstevel@tonic-gate goto out; 11917c478bd9Sstevel@tonic-gate } 1192da6c28aaSamw } 11937c478bd9Sstevel@tonic-gate if (mask & AT_MODE) { 11947c478bd9Sstevel@tonic-gate /* 11957c478bd9Sstevel@tonic-gate * If not the owner of the file then check privilege 11967c478bd9Sstevel@tonic-gate * for two things: the privilege to set the mode at all 11977c478bd9Sstevel@tonic-gate * and, if we're setting setuid, we also need permissions 11987c478bd9Sstevel@tonic-gate * to add the set-uid bit, if we're not the owner. 11997c478bd9Sstevel@tonic-gate * In the specific case of creating a set-uid root 12007c478bd9Sstevel@tonic-gate * file, we need even more permissions. 12017c478bd9Sstevel@tonic-gate */ 12027c478bd9Sstevel@tonic-gate if ((error = secpolicy_vnode_setdac(cr, ovap->va_uid)) != 0) 12037c478bd9Sstevel@tonic-gate goto out; 12047c478bd9Sstevel@tonic-gate 1205f92daba9Smarks if ((error = secpolicy_setid_setsticky_clear(vp, vap, 1206f92daba9Smarks ovap, cr)) != 0) 12077c478bd9Sstevel@tonic-gate goto out; 12087c478bd9Sstevel@tonic-gate } else 12097c478bd9Sstevel@tonic-gate vap->va_mode = ovap->va_mode; 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate if (mask & (AT_UID|AT_GID)) { 12127c478bd9Sstevel@tonic-gate boolean_t checkpriv = B_FALSE; 12137c478bd9Sstevel@tonic-gate int priv; 12147c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate /* 12177c478bd9Sstevel@tonic-gate * Chowning files. 12187c478bd9Sstevel@tonic-gate * 12197c478bd9Sstevel@tonic-gate * If you are the file owner: 12207c478bd9Sstevel@tonic-gate * chown to other uid FILE_CHOWN_SELF 12217c478bd9Sstevel@tonic-gate * chown to gid (non-member) FILE_CHOWN_SELF 12227c478bd9Sstevel@tonic-gate * chown to gid (member) <none> 12237c478bd9Sstevel@tonic-gate * 12247c478bd9Sstevel@tonic-gate * Instead of PRIV_FILE_CHOWN_SELF, FILE_CHOWN is also 12257c478bd9Sstevel@tonic-gate * acceptable but the first one is reported when debugging. 12267c478bd9Sstevel@tonic-gate * 12277c478bd9Sstevel@tonic-gate * If you are not the file owner: 12287c478bd9Sstevel@tonic-gate * chown from root PRIV_FILE_CHOWN + zone 12297c478bd9Sstevel@tonic-gate * chown from other to any PRIV_FILE_CHOWN 12307c478bd9Sstevel@tonic-gate * 12317c478bd9Sstevel@tonic-gate */ 12327c478bd9Sstevel@tonic-gate if (cr->cr_uid != ovap->va_uid) { 12337c478bd9Sstevel@tonic-gate checkpriv = B_TRUE; 12347c478bd9Sstevel@tonic-gate allzone = (ovap->va_uid == 0); 12357c478bd9Sstevel@tonic-gate priv = PRIV_FILE_CHOWN; 12367c478bd9Sstevel@tonic-gate } else { 12377c478bd9Sstevel@tonic-gate if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || 12387c478bd9Sstevel@tonic-gate ((mask & AT_GID) && vap->va_gid != ovap->va_gid && 12397c478bd9Sstevel@tonic-gate !groupmember(vap->va_gid, cr))) { 12407c478bd9Sstevel@tonic-gate checkpriv = B_TRUE; 12417c478bd9Sstevel@tonic-gate priv = HAS_PRIVILEGE(cr, PRIV_FILE_CHOWN) ? 12427c478bd9Sstevel@tonic-gate PRIV_FILE_CHOWN : PRIV_FILE_CHOWN_SELF; 12437c478bd9Sstevel@tonic-gate } 12447c478bd9Sstevel@tonic-gate } 12457c478bd9Sstevel@tonic-gate /* 12467c478bd9Sstevel@tonic-gate * If necessary, check privilege to see if update can be done. 12477c478bd9Sstevel@tonic-gate */ 12487c478bd9Sstevel@tonic-gate if (checkpriv && 12497c478bd9Sstevel@tonic-gate (error = PRIV_POLICY(cr, priv, allzone, EPERM, NULL)) 12507c478bd9Sstevel@tonic-gate != 0) { 12517c478bd9Sstevel@tonic-gate goto out; 12527c478bd9Sstevel@tonic-gate } 12537c478bd9Sstevel@tonic-gate 12547c478bd9Sstevel@tonic-gate /* 12557c478bd9Sstevel@tonic-gate * If the file has either the set UID or set GID bits 12567c478bd9Sstevel@tonic-gate * set and the caller can set the bits, then leave them. 12577c478bd9Sstevel@tonic-gate */ 125813f9f30eSmarks secpolicy_setid_clear(vap, cr); 12597c478bd9Sstevel@tonic-gate } 12607c478bd9Sstevel@tonic-gate if (mask & (AT_ATIME|AT_MTIME)) { 12617c478bd9Sstevel@tonic-gate /* 12627c478bd9Sstevel@tonic-gate * If not the file owner and not otherwise privileged, 12637c478bd9Sstevel@tonic-gate * always return an error when setting the 12647c478bd9Sstevel@tonic-gate * time other than the current (ATTR_UTIME flag set). 12657c478bd9Sstevel@tonic-gate * If setting the current time (ATTR_UTIME not set) then 12667c478bd9Sstevel@tonic-gate * unlocked_access will check permissions according to policy. 12677c478bd9Sstevel@tonic-gate */ 12687c478bd9Sstevel@tonic-gate if (cr->cr_uid != ovap->va_uid) { 12697c478bd9Sstevel@tonic-gate if (flags & ATTR_UTIME) 12707c478bd9Sstevel@tonic-gate error = secpolicy_vnode_utime_modify(cr); 1271da6c28aaSamw else if (skipaclchk == B_FALSE) { 12727c478bd9Sstevel@tonic-gate error = unlocked_access(node, VWRITE, cr); 12737c478bd9Sstevel@tonic-gate if (error == EACCES && 12747c478bd9Sstevel@tonic-gate secpolicy_vnode_utime_modify(cr) == 0) 12757c478bd9Sstevel@tonic-gate error = 0; 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate if (error) 12787c478bd9Sstevel@tonic-gate goto out; 12797c478bd9Sstevel@tonic-gate } 12807c478bd9Sstevel@tonic-gate } 1281da6c28aaSamw 1282da6c28aaSamw /* 1283da6c28aaSamw * Check for optional attributes here by checking the following: 1284da6c28aaSamw */ 1285da6c28aaSamw if (mask & AT_XVATTR) 1286da6c28aaSamw error = secpolicy_xvattr((xvattr_t *)vap, ovap->va_uid, cr, 1287da6c28aaSamw vp->v_type); 12887c478bd9Sstevel@tonic-gate out: 12897c478bd9Sstevel@tonic-gate return (error); 12907c478bd9Sstevel@tonic-gate } 12917c478bd9Sstevel@tonic-gate 12927c478bd9Sstevel@tonic-gate /* 12937c478bd9Sstevel@tonic-gate * Name: secpolicy_pcfs_modify_bootpartition() 12947c478bd9Sstevel@tonic-gate * 12957c478bd9Sstevel@tonic-gate * Normal: verify that subject can modify a pcfs boot partition. 12967c478bd9Sstevel@tonic-gate * 12977c478bd9Sstevel@tonic-gate * Output: EACCES - if privilege check failed. 12987c478bd9Sstevel@tonic-gate */ 12997c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 13007c478bd9Sstevel@tonic-gate int 13017c478bd9Sstevel@tonic-gate secpolicy_pcfs_modify_bootpartition(const cred_t *cred) 13027c478bd9Sstevel@tonic-gate { 13037c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_ALL, B_FALSE, EACCES, 13047c478bd9Sstevel@tonic-gate "modify pcfs boot partition")); 13057c478bd9Sstevel@tonic-gate } 13067c478bd9Sstevel@tonic-gate 13077c478bd9Sstevel@tonic-gate /* 13087c478bd9Sstevel@tonic-gate * System V IPC routines 13097c478bd9Sstevel@tonic-gate */ 13107c478bd9Sstevel@tonic-gate int 13117c478bd9Sstevel@tonic-gate secpolicy_ipc_owner(const cred_t *cr, const struct kipc_perm *ip) 13127c478bd9Sstevel@tonic-gate { 13137c478bd9Sstevel@tonic-gate if (crgetzoneid(cr) != ip->ipc_zoneid || 13147c478bd9Sstevel@tonic-gate (cr->cr_uid != ip->ipc_uid && cr->cr_uid != ip->ipc_cuid)) { 13157c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 13167c478bd9Sstevel@tonic-gate if (ip->ipc_uid == 0 || ip->ipc_cuid == 0) 13177c478bd9Sstevel@tonic-gate allzone = B_TRUE; 13187c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_OWNER, allzone, EPERM, NULL)); 13197c478bd9Sstevel@tonic-gate } 13207c478bd9Sstevel@tonic-gate return (0); 13217c478bd9Sstevel@tonic-gate } 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate int 13247c478bd9Sstevel@tonic-gate secpolicy_ipc_config(const cred_t *cr) 13257c478bd9Sstevel@tonic-gate { 13267c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_IPC_CONFIG, B_FALSE, EPERM, NULL)); 13277c478bd9Sstevel@tonic-gate } 13287c478bd9Sstevel@tonic-gate 13297c478bd9Sstevel@tonic-gate int 13307c478bd9Sstevel@tonic-gate secpolicy_ipc_access(const cred_t *cr, const struct kipc_perm *ip, mode_t mode) 13317c478bd9Sstevel@tonic-gate { 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate ASSERT((mode & (MSG_R|MSG_W)) != 0); 13367c478bd9Sstevel@tonic-gate 13377c478bd9Sstevel@tonic-gate if ((mode & MSG_R) && 13387c478bd9Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_IPC_DAC_READ, allzone, EACCES, NULL) != 0) 13397c478bd9Sstevel@tonic-gate return (EACCES); 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate if (mode & MSG_W) { 13427c478bd9Sstevel@tonic-gate if (cr->cr_uid != 0 && (ip->ipc_uid == 0 || ip->ipc_cuid == 0)) 13437c478bd9Sstevel@tonic-gate allzone = B_TRUE; 13447c478bd9Sstevel@tonic-gate 13457c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_DAC_WRITE, allzone, EACCES, 13467c478bd9Sstevel@tonic-gate NULL)); 13477c478bd9Sstevel@tonic-gate } 13487c478bd9Sstevel@tonic-gate return (0); 13497c478bd9Sstevel@tonic-gate } 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate int 13527c478bd9Sstevel@tonic-gate secpolicy_rsm_access(const cred_t *cr, uid_t owner, mode_t mode) 13537c478bd9Sstevel@tonic-gate { 13547c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate ASSERT((mode & (MSG_R|MSG_W)) != 0); 13577c478bd9Sstevel@tonic-gate 13587c478bd9Sstevel@tonic-gate if ((mode & MSG_R) && 13597c478bd9Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_IPC_DAC_READ, allzone, EACCES, NULL) != 0) 13607c478bd9Sstevel@tonic-gate return (EACCES); 13617c478bd9Sstevel@tonic-gate 13627c478bd9Sstevel@tonic-gate if (mode & MSG_W) { 13637c478bd9Sstevel@tonic-gate if (cr->cr_uid != 0 && owner == 0) 13647c478bd9Sstevel@tonic-gate allzone = B_TRUE; 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_DAC_WRITE, allzone, EACCES, 13677c478bd9Sstevel@tonic-gate NULL)); 13687c478bd9Sstevel@tonic-gate } 13697c478bd9Sstevel@tonic-gate return (0); 13707c478bd9Sstevel@tonic-gate } 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate /* 13737c478bd9Sstevel@tonic-gate * Audit configuration. 13747c478bd9Sstevel@tonic-gate */ 13757c478bd9Sstevel@tonic-gate int 13767c478bd9Sstevel@tonic-gate secpolicy_audit_config(const cred_t *cr) 13777c478bd9Sstevel@tonic-gate { 13787c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_AUDIT, B_FALSE, EPERM, NULL)); 13797c478bd9Sstevel@tonic-gate } 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate /* 13827c478bd9Sstevel@tonic-gate * Audit record generation. 13837c478bd9Sstevel@tonic-gate */ 13847c478bd9Sstevel@tonic-gate int 13857c478bd9Sstevel@tonic-gate secpolicy_audit_modify(const cred_t *cr) 13867c478bd9Sstevel@tonic-gate { 13877c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_AUDIT, B_FALSE, EPERM, NULL)); 13887c478bd9Sstevel@tonic-gate } 13897c478bd9Sstevel@tonic-gate 13907c478bd9Sstevel@tonic-gate /* 13917c478bd9Sstevel@tonic-gate * Get audit attributes. 13927c478bd9Sstevel@tonic-gate * Either PRIV_SYS_AUDIT or PRIV_PROC_AUDIT required; report the 13937c478bd9Sstevel@tonic-gate * "Least" of the two privileges on error. 13947c478bd9Sstevel@tonic-gate */ 13957c478bd9Sstevel@tonic-gate int 13967c478bd9Sstevel@tonic-gate secpolicy_audit_getattr(const cred_t *cr) 13977c478bd9Sstevel@tonic-gate { 13987c478bd9Sstevel@tonic-gate if (!PRIV_POLICY_ONLY(cr, PRIV_SYS_AUDIT, B_FALSE)) { 13997c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_AUDIT, B_FALSE, EPERM, 14007c478bd9Sstevel@tonic-gate NULL)); 14017c478bd9Sstevel@tonic-gate } else { 14027c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_AUDIT, B_FALSE, EPERM, NULL)); 14037c478bd9Sstevel@tonic-gate } 14047c478bd9Sstevel@tonic-gate } 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate 14077c478bd9Sstevel@tonic-gate /* 14087c478bd9Sstevel@tonic-gate * Locking physical memory 14097c478bd9Sstevel@tonic-gate */ 14107c478bd9Sstevel@tonic-gate int 14117c478bd9Sstevel@tonic-gate secpolicy_lock_memory(const cred_t *cr) 14127c478bd9Sstevel@tonic-gate { 14137c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_LOCK_MEMORY, B_FALSE, EPERM, NULL)); 14147c478bd9Sstevel@tonic-gate } 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate /* 14177c478bd9Sstevel@tonic-gate * Accounting (both acct(2) and exacct). 14187c478bd9Sstevel@tonic-gate */ 14197c478bd9Sstevel@tonic-gate int 14207c478bd9Sstevel@tonic-gate secpolicy_acct(const cred_t *cr) 14217c478bd9Sstevel@tonic-gate { 14227c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ACCT, B_FALSE, EPERM, NULL)); 14237c478bd9Sstevel@tonic-gate } 14247c478bd9Sstevel@tonic-gate 14257c478bd9Sstevel@tonic-gate /* 14267c478bd9Sstevel@tonic-gate * Is this process privileged to change its uids at will? 14277c478bd9Sstevel@tonic-gate * Uid 0 is still considered "special" and having the SETID 14287c478bd9Sstevel@tonic-gate * privilege is not sufficient to get uid 0. 14297c478bd9Sstevel@tonic-gate * Files are owned by root, so the privilege would give 14307c478bd9Sstevel@tonic-gate * full access and euid 0 is still effective. 14317c478bd9Sstevel@tonic-gate * 14327c478bd9Sstevel@tonic-gate * If you have the privilege and euid 0 only then do you 14337c478bd9Sstevel@tonic-gate * get the powers of root wrt uid 0. 14347c478bd9Sstevel@tonic-gate * 14357c478bd9Sstevel@tonic-gate * For gid manipulations, this is should be called with an 14367c478bd9Sstevel@tonic-gate * uid of -1. 14377c478bd9Sstevel@tonic-gate * 14387c478bd9Sstevel@tonic-gate */ 14397c478bd9Sstevel@tonic-gate int 14407c478bd9Sstevel@tonic-gate secpolicy_allow_setid(const cred_t *cr, uid_t newuid, boolean_t checkonly) 14417c478bd9Sstevel@tonic-gate { 14427c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate if (newuid == 0 && cr->cr_uid != 0 && cr->cr_suid != 0 && 14457c478bd9Sstevel@tonic-gate cr->cr_ruid != 0) { 14467c478bd9Sstevel@tonic-gate allzone = B_TRUE; 14477c478bd9Sstevel@tonic-gate } 14487c478bd9Sstevel@tonic-gate 14497c478bd9Sstevel@tonic-gate return (checkonly ? !PRIV_POLICY_ONLY(cr, PRIV_PROC_SETID, allzone) : 14507c478bd9Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_PROC_SETID, allzone, EPERM, NULL)); 14517c478bd9Sstevel@tonic-gate } 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate /* 14557c478bd9Sstevel@tonic-gate * Acting on a different process: if the mode is for writing, 14567c478bd9Sstevel@tonic-gate * the restrictions are more severe. This is called after 14577c478bd9Sstevel@tonic-gate * we've verified that the uids do not match. 14587c478bd9Sstevel@tonic-gate */ 14597c478bd9Sstevel@tonic-gate int 14607c478bd9Sstevel@tonic-gate secpolicy_proc_owner(const cred_t *scr, const cred_t *tcr, int mode) 14617c478bd9Sstevel@tonic-gate { 14627c478bd9Sstevel@tonic-gate boolean_t allzone = B_FALSE; 14637c478bd9Sstevel@tonic-gate 14647c478bd9Sstevel@tonic-gate if ((mode & VWRITE) && scr->cr_uid != 0 && 14657c478bd9Sstevel@tonic-gate (tcr->cr_uid == 0 || tcr->cr_ruid == 0 || tcr->cr_suid == 0)) 14667c478bd9Sstevel@tonic-gate allzone = B_TRUE; 14677c478bd9Sstevel@tonic-gate 14687c478bd9Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, allzone, EPERM, NULL)); 14697c478bd9Sstevel@tonic-gate } 14707c478bd9Sstevel@tonic-gate 14717c478bd9Sstevel@tonic-gate int 14727c478bd9Sstevel@tonic-gate secpolicy_proc_access(const cred_t *scr) 14737c478bd9Sstevel@tonic-gate { 14747c478bd9Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, B_FALSE, EACCES, NULL)); 14757c478bd9Sstevel@tonic-gate } 14767c478bd9Sstevel@tonic-gate 14777c478bd9Sstevel@tonic-gate int 14787c478bd9Sstevel@tonic-gate secpolicy_proc_excl_open(const cred_t *scr) 14797c478bd9Sstevel@tonic-gate { 14807c478bd9Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, B_FALSE, EBUSY, NULL)); 14817c478bd9Sstevel@tonic-gate } 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate int 14847c478bd9Sstevel@tonic-gate secpolicy_proc_zone(const cred_t *scr) 14857c478bd9Sstevel@tonic-gate { 14867c478bd9Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_ZONE, B_FALSE, EPERM, NULL)); 14877c478bd9Sstevel@tonic-gate } 14887c478bd9Sstevel@tonic-gate 14897c478bd9Sstevel@tonic-gate /* 14907c478bd9Sstevel@tonic-gate * Destroying the system 14917c478bd9Sstevel@tonic-gate */ 14927c478bd9Sstevel@tonic-gate 14937c478bd9Sstevel@tonic-gate int 14947c478bd9Sstevel@tonic-gate secpolicy_kmdb(const cred_t *scr) 14957c478bd9Sstevel@tonic-gate { 14967c478bd9Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); 14977c478bd9Sstevel@tonic-gate } 14987c478bd9Sstevel@tonic-gate 14997aec1d6eScindi int 15007aec1d6eScindi secpolicy_error_inject(const cred_t *scr) 15017aec1d6eScindi { 15027aec1d6eScindi return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); 15037aec1d6eScindi } 15047aec1d6eScindi 15057c478bd9Sstevel@tonic-gate /* 15067c478bd9Sstevel@tonic-gate * Processor sets, cpu configuration, resource pools. 15077c478bd9Sstevel@tonic-gate */ 15087c478bd9Sstevel@tonic-gate int 15097c478bd9Sstevel@tonic-gate secpolicy_pset(const cred_t *cr) 15107c478bd9Sstevel@tonic-gate { 15117c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 15127c478bd9Sstevel@tonic-gate } 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate int 15157c478bd9Sstevel@tonic-gate secpolicy_ponline(const cred_t *cr) 15167c478bd9Sstevel@tonic-gate { 15177c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 15187c478bd9Sstevel@tonic-gate } 15197c478bd9Sstevel@tonic-gate 15207c478bd9Sstevel@tonic-gate int 15217c478bd9Sstevel@tonic-gate secpolicy_pool(const cred_t *cr) 15227c478bd9Sstevel@tonic-gate { 15237c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 15247c478bd9Sstevel@tonic-gate } 15257c478bd9Sstevel@tonic-gate 15267c478bd9Sstevel@tonic-gate int 15277c478bd9Sstevel@tonic-gate secpolicy_blacklist(const cred_t *cr) 15287c478bd9Sstevel@tonic-gate { 15297c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 15307c478bd9Sstevel@tonic-gate } 15317c478bd9Sstevel@tonic-gate 15327c478bd9Sstevel@tonic-gate /* 15337c478bd9Sstevel@tonic-gate * Catch all system configuration. 15347c478bd9Sstevel@tonic-gate */ 15357c478bd9Sstevel@tonic-gate int 15367c478bd9Sstevel@tonic-gate secpolicy_sys_config(const cred_t *cr, boolean_t checkonly) 15377c478bd9Sstevel@tonic-gate { 15387c478bd9Sstevel@tonic-gate if (checkonly) { 15397c478bd9Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_CONFIG, B_FALSE) ? 0 : 15407c478bd9Sstevel@tonic-gate EPERM); 15417c478bd9Sstevel@tonic-gate } else { 15427c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 15437c478bd9Sstevel@tonic-gate } 15447c478bd9Sstevel@tonic-gate } 15457c478bd9Sstevel@tonic-gate 15467c478bd9Sstevel@tonic-gate /* 15477c478bd9Sstevel@tonic-gate * Zone administration (halt, reboot, etc.) from within zone. 15487c478bd9Sstevel@tonic-gate */ 15497c478bd9Sstevel@tonic-gate int 15507c478bd9Sstevel@tonic-gate secpolicy_zone_admin(const cred_t *cr, boolean_t checkonly) 15517c478bd9Sstevel@tonic-gate { 15527c478bd9Sstevel@tonic-gate if (checkonly) { 15537c478bd9Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_ADMIN, B_FALSE) ? 0 : 15547c478bd9Sstevel@tonic-gate EPERM); 15557c478bd9Sstevel@tonic-gate } else { 15567c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, 15577c478bd9Sstevel@tonic-gate NULL)); 15587c478bd9Sstevel@tonic-gate } 15597c478bd9Sstevel@tonic-gate } 15607c478bd9Sstevel@tonic-gate 15617c478bd9Sstevel@tonic-gate /* 15627c478bd9Sstevel@tonic-gate * Zone configuration (create, halt, enter). 15637c478bd9Sstevel@tonic-gate */ 15647c478bd9Sstevel@tonic-gate int 15657c478bd9Sstevel@tonic-gate secpolicy_zone_config(const cred_t *cr) 15667c478bd9Sstevel@tonic-gate { 15677c478bd9Sstevel@tonic-gate /* 15687c478bd9Sstevel@tonic-gate * Require all privileges to avoid possibility of privilege 15697c478bd9Sstevel@tonic-gate * escalation. 15707c478bd9Sstevel@tonic-gate */ 15717c478bd9Sstevel@tonic-gate return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); 15727c478bd9Sstevel@tonic-gate } 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate /* 15757c478bd9Sstevel@tonic-gate * Various other system configuration calls 15767c478bd9Sstevel@tonic-gate */ 15777c478bd9Sstevel@tonic-gate int 15787c478bd9Sstevel@tonic-gate secpolicy_coreadm(const cred_t *cr) 15797c478bd9Sstevel@tonic-gate { 15807c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, NULL)); 15817c478bd9Sstevel@tonic-gate } 15827c478bd9Sstevel@tonic-gate 15837c478bd9Sstevel@tonic-gate int 15847c478bd9Sstevel@tonic-gate secpolicy_systeminfo(const cred_t *cr) 15857c478bd9Sstevel@tonic-gate { 15867c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, NULL)); 15877c478bd9Sstevel@tonic-gate } 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate int 15907c478bd9Sstevel@tonic-gate secpolicy_dispadm(const cred_t *cr) 15917c478bd9Sstevel@tonic-gate { 15927c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 15937c478bd9Sstevel@tonic-gate } 15947c478bd9Sstevel@tonic-gate 15957c478bd9Sstevel@tonic-gate int 15967c478bd9Sstevel@tonic-gate secpolicy_settime(const cred_t *cr) 15977c478bd9Sstevel@tonic-gate { 15987c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_TIME, B_FALSE, EPERM, NULL)); 15997c478bd9Sstevel@tonic-gate } 16007c478bd9Sstevel@tonic-gate 16017c478bd9Sstevel@tonic-gate /* 16027c478bd9Sstevel@tonic-gate * For realtime users: high resolution clock. 16037c478bd9Sstevel@tonic-gate */ 16047c478bd9Sstevel@tonic-gate int 16057c478bd9Sstevel@tonic-gate secpolicy_clock_highres(const cred_t *cr) 16067c478bd9Sstevel@tonic-gate { 16077c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_CLOCK_HIGHRES, B_FALSE, EPERM, 16087c478bd9Sstevel@tonic-gate NULL)); 16097c478bd9Sstevel@tonic-gate } 16107c478bd9Sstevel@tonic-gate 16117c478bd9Sstevel@tonic-gate /* 16127c478bd9Sstevel@tonic-gate * drv_priv() is documented as callable from interrupt context, not that 16137c478bd9Sstevel@tonic-gate * anyone ever does, but still. No debugging or auditing can be done when 16147c478bd9Sstevel@tonic-gate * it is called from interrupt context. 16157c478bd9Sstevel@tonic-gate * returns 0 on succes, EPERM on failure. 16167c478bd9Sstevel@tonic-gate */ 16177c478bd9Sstevel@tonic-gate int 16187c478bd9Sstevel@tonic-gate drv_priv(cred_t *cr) 16197c478bd9Sstevel@tonic-gate { 16207c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 16217c478bd9Sstevel@tonic-gate } 16227c478bd9Sstevel@tonic-gate 16237c478bd9Sstevel@tonic-gate int 16247c478bd9Sstevel@tonic-gate secpolicy_sys_devices(const cred_t *cr) 16257c478bd9Sstevel@tonic-gate { 16267c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 16277c478bd9Sstevel@tonic-gate } 16287c478bd9Sstevel@tonic-gate 16297c478bd9Sstevel@tonic-gate int 16307c478bd9Sstevel@tonic-gate secpolicy_excl_open(const cred_t *cr) 16317c478bd9Sstevel@tonic-gate { 16327c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EBUSY, NULL)); 16337c478bd9Sstevel@tonic-gate } 16347c478bd9Sstevel@tonic-gate 16357c478bd9Sstevel@tonic-gate int 16367c478bd9Sstevel@tonic-gate secpolicy_rctlsys(const cred_t *cr, boolean_t is_zone_rctl) 16377c478bd9Sstevel@tonic-gate { 16387c478bd9Sstevel@tonic-gate /* zone.* rctls can only be set from the global zone */ 16397c478bd9Sstevel@tonic-gate if (is_zone_rctl && priv_policy_global(cr) != 0) 16407c478bd9Sstevel@tonic-gate return (EPERM); 16417c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 16427c478bd9Sstevel@tonic-gate } 16437c478bd9Sstevel@tonic-gate 16447c478bd9Sstevel@tonic-gate int 16457c478bd9Sstevel@tonic-gate secpolicy_resource(const cred_t *cr) 16467c478bd9Sstevel@tonic-gate { 16477c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 16487c478bd9Sstevel@tonic-gate } 16497c478bd9Sstevel@tonic-gate 16507c478bd9Sstevel@tonic-gate /* 16517c478bd9Sstevel@tonic-gate * Processes with a real uid of 0 escape any form of accounting, much 16527c478bd9Sstevel@tonic-gate * like before. 16537c478bd9Sstevel@tonic-gate */ 16547c478bd9Sstevel@tonic-gate int 16557c478bd9Sstevel@tonic-gate secpolicy_newproc(const cred_t *cr) 16567c478bd9Sstevel@tonic-gate { 16577c478bd9Sstevel@tonic-gate if (cr->cr_ruid == 0) 16587c478bd9Sstevel@tonic-gate return (0); 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 16617c478bd9Sstevel@tonic-gate } 16627c478bd9Sstevel@tonic-gate 16637c478bd9Sstevel@tonic-gate /* 16647c478bd9Sstevel@tonic-gate * Networking 16657c478bd9Sstevel@tonic-gate */ 16667c478bd9Sstevel@tonic-gate int 16677c478bd9Sstevel@tonic-gate secpolicy_net_rawaccess(const cred_t *cr) 16687c478bd9Sstevel@tonic-gate { 16697c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_NET_RAWACCESS, B_FALSE, EACCES, NULL)); 16707c478bd9Sstevel@tonic-gate } 16717c478bd9Sstevel@tonic-gate 16727c478bd9Sstevel@tonic-gate /* 16737c478bd9Sstevel@tonic-gate * Need this privilege for accessing the ICMP device 16747c478bd9Sstevel@tonic-gate */ 16757c478bd9Sstevel@tonic-gate int 16767c478bd9Sstevel@tonic-gate secpolicy_net_icmpaccess(const cred_t *cr) 16777c478bd9Sstevel@tonic-gate { 16787c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_NET_ICMPACCESS, B_FALSE, EACCES, NULL)); 16797c478bd9Sstevel@tonic-gate } 16807c478bd9Sstevel@tonic-gate 16817c478bd9Sstevel@tonic-gate /* 16827c478bd9Sstevel@tonic-gate * There are a few rare cases where the kernel generates ioctls() from 16837c478bd9Sstevel@tonic-gate * interrupt context with a credential of kcred rather than NULL. 16847c478bd9Sstevel@tonic-gate * In those cases, we take the safe and cheap test. 16857c478bd9Sstevel@tonic-gate */ 16867c478bd9Sstevel@tonic-gate int 16877c478bd9Sstevel@tonic-gate secpolicy_net_config(const cred_t *cr, boolean_t checkonly) 16887c478bd9Sstevel@tonic-gate { 16897c478bd9Sstevel@tonic-gate if (checkonly) { 16907c478bd9Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE) ? 16917c478bd9Sstevel@tonic-gate 0 : EPERM); 16927c478bd9Sstevel@tonic-gate } else { 16937c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_NET_CONFIG, B_FALSE, EPERM, 16947c478bd9Sstevel@tonic-gate NULL)); 16957c478bd9Sstevel@tonic-gate } 16967c478bd9Sstevel@tonic-gate } 16977c478bd9Sstevel@tonic-gate 16987c478bd9Sstevel@tonic-gate 16997c478bd9Sstevel@tonic-gate /* 1700e6bdcbd5Sdh155122 * PRIV_SYS_NET_CONFIG is a superset of PRIV_SYS_IP_CONFIG. 1701f4b3ec61Sdh155122 * 1702f4b3ec61Sdh155122 * There are a few rare cases where the kernel generates ioctls() from 1703f4b3ec61Sdh155122 * interrupt context with a credential of kcred rather than NULL. 1704f4b3ec61Sdh155122 * In those cases, we take the safe and cheap test. 1705f4b3ec61Sdh155122 */ 1706f4b3ec61Sdh155122 int 1707f4b3ec61Sdh155122 secpolicy_ip_config(const cred_t *cr, boolean_t checkonly) 1708f4b3ec61Sdh155122 { 1709f4b3ec61Sdh155122 if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE)) 1710f4b3ec61Sdh155122 return (secpolicy_net_config(cr, checkonly)); 1711f4b3ec61Sdh155122 1712f4b3ec61Sdh155122 if (checkonly) { 1713f4b3ec61Sdh155122 return (PRIV_POLICY_ONLY(cr, PRIV_SYS_IP_CONFIG, B_FALSE) ? 1714f4b3ec61Sdh155122 0 : EPERM); 1715f4b3ec61Sdh155122 } else { 1716f4b3ec61Sdh155122 return (PRIV_POLICY(cr, PRIV_SYS_IP_CONFIG, B_FALSE, EPERM, 1717f4b3ec61Sdh155122 NULL)); 1718f4b3ec61Sdh155122 } 1719f4b3ec61Sdh155122 } 1720f4b3ec61Sdh155122 1721eae72b5bSSebastien Roy /* 1722eae72b5bSSebastien Roy * PRIV_SYS_NET_CONFIG is a superset of PRIV_SYS_DL_CONFIG. 1723eae72b5bSSebastien Roy */ 1724eae72b5bSSebastien Roy int 1725eae72b5bSSebastien Roy secpolicy_dl_config(const cred_t *cr) 1726eae72b5bSSebastien Roy { 1727eae72b5bSSebastien Roy if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE)) 1728eae72b5bSSebastien Roy return (secpolicy_net_config(cr, B_FALSE)); 1729eae72b5bSSebastien Roy return (PRIV_POLICY(cr, PRIV_SYS_DL_CONFIG, B_FALSE, EPERM, 1730eae72b5bSSebastien Roy NULL)); 1731eae72b5bSSebastien Roy } 1732eae72b5bSSebastien Roy 1733f4b3ec61Sdh155122 1734f4b3ec61Sdh155122 /* 1735f4b3ec61Sdh155122 * Map IP pseudo privileges to actual privileges. 1736f4b3ec61Sdh155122 * So we don't need to recompile IP when we change the privileges. 1737f4b3ec61Sdh155122 */ 1738f4b3ec61Sdh155122 int 1739f4b3ec61Sdh155122 secpolicy_ip(const cred_t *cr, int netpriv, boolean_t checkonly) 1740f4b3ec61Sdh155122 { 1741f4b3ec61Sdh155122 int priv = PRIV_ALL; 1742f4b3ec61Sdh155122 1743f4b3ec61Sdh155122 switch (netpriv) { 1744f4b3ec61Sdh155122 case OP_CONFIG: 1745f4b3ec61Sdh155122 priv = PRIV_SYS_IP_CONFIG; 1746f4b3ec61Sdh155122 break; 1747f4b3ec61Sdh155122 case OP_RAW: 1748f4b3ec61Sdh155122 priv = PRIV_NET_RAWACCESS; 1749f4b3ec61Sdh155122 break; 1750f4b3ec61Sdh155122 case OP_PRIVPORT: 1751f4b3ec61Sdh155122 priv = PRIV_NET_PRIVADDR; 1752f4b3ec61Sdh155122 break; 1753f4b3ec61Sdh155122 } 1754f4b3ec61Sdh155122 ASSERT(priv != PRIV_ALL); 1755f4b3ec61Sdh155122 if (checkonly) 1756f4b3ec61Sdh155122 return (PRIV_POLICY_ONLY(cr, priv, B_FALSE) ? 0 : EPERM); 1757f4b3ec61Sdh155122 else 1758f4b3ec61Sdh155122 return (PRIV_POLICY(cr, priv, B_FALSE, EPERM, NULL)); 1759f4b3ec61Sdh155122 } 1760f4b3ec61Sdh155122 1761f4b3ec61Sdh155122 /* 17627c478bd9Sstevel@tonic-gate * Map network pseudo privileges to actual privileges. 17637c478bd9Sstevel@tonic-gate * So we don't need to recompile IP when we change the privileges. 17647c478bd9Sstevel@tonic-gate */ 17657c478bd9Sstevel@tonic-gate int 17667c478bd9Sstevel@tonic-gate secpolicy_net(const cred_t *cr, int netpriv, boolean_t checkonly) 17677c478bd9Sstevel@tonic-gate { 17687c478bd9Sstevel@tonic-gate int priv = PRIV_ALL; 17697c478bd9Sstevel@tonic-gate 17707c478bd9Sstevel@tonic-gate switch (netpriv) { 17717c478bd9Sstevel@tonic-gate case OP_CONFIG: 17727c478bd9Sstevel@tonic-gate priv = PRIV_SYS_NET_CONFIG; 17737c478bd9Sstevel@tonic-gate break; 17747c478bd9Sstevel@tonic-gate case OP_RAW: 17757c478bd9Sstevel@tonic-gate priv = PRIV_NET_RAWACCESS; 17767c478bd9Sstevel@tonic-gate break; 17777c478bd9Sstevel@tonic-gate case OP_PRIVPORT: 17787c478bd9Sstevel@tonic-gate priv = PRIV_NET_PRIVADDR; 17797c478bd9Sstevel@tonic-gate break; 17807c478bd9Sstevel@tonic-gate } 17817c478bd9Sstevel@tonic-gate ASSERT(priv != PRIV_ALL); 17827c478bd9Sstevel@tonic-gate if (checkonly) 17837c478bd9Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, priv, B_FALSE) ? 0 : EPERM); 17847c478bd9Sstevel@tonic-gate else 17857c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, priv, B_FALSE, EPERM, NULL)); 17867c478bd9Sstevel@tonic-gate } 17877c478bd9Sstevel@tonic-gate 17887c478bd9Sstevel@tonic-gate /* 17897c478bd9Sstevel@tonic-gate * Checks for operations that are either client-only or are used by 17907c478bd9Sstevel@tonic-gate * both clients and servers. 17917c478bd9Sstevel@tonic-gate */ 17927c478bd9Sstevel@tonic-gate int 17937c478bd9Sstevel@tonic-gate secpolicy_nfs(const cred_t *cr) 17947c478bd9Sstevel@tonic-gate { 17957c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_NFS, B_FALSE, EPERM, NULL)); 17967c478bd9Sstevel@tonic-gate } 17977c478bd9Sstevel@tonic-gate 17987c478bd9Sstevel@tonic-gate /* 17997c478bd9Sstevel@tonic-gate * Special case for opening rpcmod: have NFS privileges or network 18007c478bd9Sstevel@tonic-gate * config privileges. 18017c478bd9Sstevel@tonic-gate */ 18027c478bd9Sstevel@tonic-gate int 18037c478bd9Sstevel@tonic-gate secpolicy_rpcmod_open(const cred_t *cr) 18047c478bd9Sstevel@tonic-gate { 18057c478bd9Sstevel@tonic-gate if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NFS, B_FALSE)) 18067c478bd9Sstevel@tonic-gate return (secpolicy_nfs(cr)); 18077c478bd9Sstevel@tonic-gate else 18087c478bd9Sstevel@tonic-gate return (secpolicy_net_config(cr, NULL)); 18097c478bd9Sstevel@tonic-gate } 18107c478bd9Sstevel@tonic-gate 18117c478bd9Sstevel@tonic-gate int 18127c478bd9Sstevel@tonic-gate secpolicy_chroot(const cred_t *cr) 18137c478bd9Sstevel@tonic-gate { 18147c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_CHROOT, B_FALSE, EPERM, NULL)); 18157c478bd9Sstevel@tonic-gate } 18167c478bd9Sstevel@tonic-gate 18177c478bd9Sstevel@tonic-gate int 18187c478bd9Sstevel@tonic-gate secpolicy_tasksys(const cred_t *cr) 18197c478bd9Sstevel@tonic-gate { 18207c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_TASKID, B_FALSE, EPERM, NULL)); 18217c478bd9Sstevel@tonic-gate } 18227c478bd9Sstevel@tonic-gate 18237c478bd9Sstevel@tonic-gate /* 18247c478bd9Sstevel@tonic-gate * Basic privilege checks. 18257c478bd9Sstevel@tonic-gate */ 18267c478bd9Sstevel@tonic-gate int 1827ddf7fe95Scasper secpolicy_basic_exec(const cred_t *cr, vnode_t *vp) 18287c478bd9Sstevel@tonic-gate { 1829ddf7fe95Scasper return (priv_policy_va(cr, PRIV_PROC_EXEC, B_FALSE, EPERM, NULL, 1830ddf7fe95Scasper KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE)); 18317c478bd9Sstevel@tonic-gate } 18327c478bd9Sstevel@tonic-gate 18337c478bd9Sstevel@tonic-gate int 18347c478bd9Sstevel@tonic-gate secpolicy_basic_fork(const cred_t *cr) 18357c478bd9Sstevel@tonic-gate { 18367c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_FORK, B_FALSE, EPERM, NULL)); 18377c478bd9Sstevel@tonic-gate } 18387c478bd9Sstevel@tonic-gate 18397c478bd9Sstevel@tonic-gate int 18407c478bd9Sstevel@tonic-gate secpolicy_basic_proc(const cred_t *cr) 18417c478bd9Sstevel@tonic-gate { 18427c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_SESSION, B_FALSE, EPERM, NULL)); 18437c478bd9Sstevel@tonic-gate } 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate /* 18467c478bd9Sstevel@tonic-gate * Slightly complicated because we don't want to trigger the policy too 18477c478bd9Sstevel@tonic-gate * often. First we shortcircuit access to "self" (tp == sp) or if 18487c478bd9Sstevel@tonic-gate * we don't have the privilege but if we have permission 18497c478bd9Sstevel@tonic-gate * just return (0) and we don't flag the privilege as needed. 18507c478bd9Sstevel@tonic-gate * Else, we test for the privilege because we either have it or need it. 18517c478bd9Sstevel@tonic-gate */ 18527c478bd9Sstevel@tonic-gate int 18537c478bd9Sstevel@tonic-gate secpolicy_basic_procinfo(const cred_t *cr, proc_t *tp, proc_t *sp) 18547c478bd9Sstevel@tonic-gate { 18557c478bd9Sstevel@tonic-gate if (tp == sp || 18567c478bd9Sstevel@tonic-gate !HAS_PRIVILEGE(cr, PRIV_PROC_INFO) && prochasprocperm(tp, sp, cr)) { 18577c478bd9Sstevel@tonic-gate return (0); 18587c478bd9Sstevel@tonic-gate } else { 18597c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_INFO, B_FALSE, EPERM, NULL)); 18607c478bd9Sstevel@tonic-gate } 18617c478bd9Sstevel@tonic-gate } 18627c478bd9Sstevel@tonic-gate 18637c478bd9Sstevel@tonic-gate int 18647c478bd9Sstevel@tonic-gate secpolicy_basic_link(const cred_t *cr) 18657c478bd9Sstevel@tonic-gate { 18667c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_LINK_ANY, B_FALSE, EPERM, NULL)); 18677c478bd9Sstevel@tonic-gate } 18687c478bd9Sstevel@tonic-gate 18697c478bd9Sstevel@tonic-gate /* 18707c478bd9Sstevel@tonic-gate * Additional device protection. 18717c478bd9Sstevel@tonic-gate * 18727c478bd9Sstevel@tonic-gate * Traditionally, a device has specific permissions on the node in 18737c478bd9Sstevel@tonic-gate * the filesystem which govern which devices can be opened by what 18747c478bd9Sstevel@tonic-gate * processes. In certain cases, it is desirable to add extra 18757c478bd9Sstevel@tonic-gate * restrictions, as writing to certain devices is identical to 18767c478bd9Sstevel@tonic-gate * having a complete run of the system. 18777c478bd9Sstevel@tonic-gate * 18787c478bd9Sstevel@tonic-gate * This mechanism is called the device policy. 18797c478bd9Sstevel@tonic-gate * 18807c478bd9Sstevel@tonic-gate * When a device is opened, its policy entry is looked up in the 18817c478bd9Sstevel@tonic-gate * policy cache and checked. 18827c478bd9Sstevel@tonic-gate */ 18837c478bd9Sstevel@tonic-gate int 18847c478bd9Sstevel@tonic-gate secpolicy_spec_open(const cred_t *cr, struct vnode *vp, int oflag) 18857c478bd9Sstevel@tonic-gate { 18867c478bd9Sstevel@tonic-gate devplcy_t *plcy; 18877c478bd9Sstevel@tonic-gate int err; 18887c478bd9Sstevel@tonic-gate struct snode *csp = VTOS(common_specvp(vp)); 1889e6bdcbd5Sdh155122 priv_set_t pset; 18907c478bd9Sstevel@tonic-gate 18917c478bd9Sstevel@tonic-gate mutex_enter(&csp->s_lock); 18927c478bd9Sstevel@tonic-gate 18937c478bd9Sstevel@tonic-gate if (csp->s_plcy == NULL || csp->s_plcy->dp_gen != devplcy_gen) { 18947c478bd9Sstevel@tonic-gate plcy = devpolicy_find(vp); 18957c478bd9Sstevel@tonic-gate if (csp->s_plcy) 18967c478bd9Sstevel@tonic-gate dpfree(csp->s_plcy); 18977c478bd9Sstevel@tonic-gate csp->s_plcy = plcy; 18987c478bd9Sstevel@tonic-gate ASSERT(plcy != NULL); 18997c478bd9Sstevel@tonic-gate } else 19007c478bd9Sstevel@tonic-gate plcy = csp->s_plcy; 19017c478bd9Sstevel@tonic-gate 19027c478bd9Sstevel@tonic-gate if (plcy == nullpolicy) { 19037c478bd9Sstevel@tonic-gate mutex_exit(&csp->s_lock); 19047c478bd9Sstevel@tonic-gate return (0); 19057c478bd9Sstevel@tonic-gate } 19067c478bd9Sstevel@tonic-gate 19077c478bd9Sstevel@tonic-gate dphold(plcy); 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate mutex_exit(&csp->s_lock); 19107c478bd9Sstevel@tonic-gate 1911e6bdcbd5Sdh155122 if (oflag & FWRITE) 1912e6bdcbd5Sdh155122 pset = plcy->dp_wrp; 1913e6bdcbd5Sdh155122 else 1914e6bdcbd5Sdh155122 pset = plcy->dp_rdp; 1915e6bdcbd5Sdh155122 /* 1916e6bdcbd5Sdh155122 * Special case: 1917e6bdcbd5Sdh155122 * PRIV_SYS_NET_CONFIG is a superset of PRIV_SYS_IP_CONFIG. 1918e6bdcbd5Sdh155122 * If PRIV_SYS_NET_CONFIG is present and PRIV_SYS_IP_CONFIG is 1919e6bdcbd5Sdh155122 * required, replace PRIV_SYS_IP_CONFIG with PRIV_SYS_NET_CONFIG 1920e6bdcbd5Sdh155122 * in the required privilege set before doing the check. 1921e6bdcbd5Sdh155122 */ 1922e6bdcbd5Sdh155122 if (priv_ismember(&pset, PRIV_SYS_IP_CONFIG) && 1923e6bdcbd5Sdh155122 priv_ismember(&CR_OEPRIV(cr), PRIV_SYS_NET_CONFIG) && 1924e6bdcbd5Sdh155122 !priv_ismember(&CR_OEPRIV(cr), PRIV_SYS_IP_CONFIG)) { 1925e6bdcbd5Sdh155122 priv_delset(&pset, PRIV_SYS_IP_CONFIG); 1926e6bdcbd5Sdh155122 priv_addset(&pset, PRIV_SYS_NET_CONFIG); 1927e6bdcbd5Sdh155122 } 1928e6bdcbd5Sdh155122 1929e6bdcbd5Sdh155122 err = secpolicy_require_set(cr, &pset, "devpolicy"); 19307c478bd9Sstevel@tonic-gate dpfree(plcy); 19317c478bd9Sstevel@tonic-gate 19327c478bd9Sstevel@tonic-gate return (err); 19337c478bd9Sstevel@tonic-gate } 19347c478bd9Sstevel@tonic-gate 19357c478bd9Sstevel@tonic-gate int 19367c478bd9Sstevel@tonic-gate secpolicy_modctl(const cred_t *cr, int cmd) 19377c478bd9Sstevel@tonic-gate { 19387c478bd9Sstevel@tonic-gate switch (cmd) { 19397c478bd9Sstevel@tonic-gate case MODINFO: 1940a08731ecScth case MODGETMAJBIND: 19417c478bd9Sstevel@tonic-gate case MODGETPATH: 19427c478bd9Sstevel@tonic-gate case MODGETPATHLEN: 19437c478bd9Sstevel@tonic-gate case MODGETNAME: 1944a08731ecScth case MODGETFBNAME: 19457c478bd9Sstevel@tonic-gate case MODGETDEVPOLICY: 19467c478bd9Sstevel@tonic-gate case MODGETDEVPOLICYBYNAME: 1947a08731ecScth case MODDEVT2INSTANCE: 1948a08731ecScth case MODSIZEOF_DEVID: 1949a08731ecScth case MODGETDEVID: 1950a08731ecScth case MODSIZEOF_MINORNAME: 1951a08731ecScth case MODGETMINORNAME: 1952a08731ecScth case MODGETDEVFSPATH_LEN: 1953a08731ecScth case MODGETDEVFSPATH: 1954a08731ecScth case MODGETDEVFSPATH_MI_LEN: 1955a08731ecScth case MODGETDEVFSPATH_MI: 19567c478bd9Sstevel@tonic-gate /* Unprivileged */ 19577c478bd9Sstevel@tonic-gate return (0); 19587c478bd9Sstevel@tonic-gate case MODLOAD: 19597c478bd9Sstevel@tonic-gate case MODSETDEVPOLICY: 19607c478bd9Sstevel@tonic-gate return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); 19617c478bd9Sstevel@tonic-gate default: 19627c478bd9Sstevel@tonic-gate return (secpolicy_sys_config(cr, B_FALSE)); 19637c478bd9Sstevel@tonic-gate } 19647c478bd9Sstevel@tonic-gate } 19657c478bd9Sstevel@tonic-gate 19667c478bd9Sstevel@tonic-gate int 19677c478bd9Sstevel@tonic-gate secpolicy_console(const cred_t *cr) 19687c478bd9Sstevel@tonic-gate { 19697c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 19707c478bd9Sstevel@tonic-gate } 19717c478bd9Sstevel@tonic-gate 19727c478bd9Sstevel@tonic-gate int 19737c478bd9Sstevel@tonic-gate secpolicy_power_mgmt(const cred_t *cr) 19747c478bd9Sstevel@tonic-gate { 19757c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 19767c478bd9Sstevel@tonic-gate } 19777c478bd9Sstevel@tonic-gate 19787c478bd9Sstevel@tonic-gate /* 19797c478bd9Sstevel@tonic-gate * Simulate terminal input; another escalation of privileges avenue. 19807c478bd9Sstevel@tonic-gate */ 19817c478bd9Sstevel@tonic-gate 19827c478bd9Sstevel@tonic-gate int 19837c478bd9Sstevel@tonic-gate secpolicy_sti(const cred_t *cr) 19847c478bd9Sstevel@tonic-gate { 19857c478bd9Sstevel@tonic-gate return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); 19867c478bd9Sstevel@tonic-gate } 19877c478bd9Sstevel@tonic-gate 198845916cd2Sjpk boolean_t 198945916cd2Sjpk secpolicy_net_reply_equal(const cred_t *cr) 199045916cd2Sjpk { 199145916cd2Sjpk return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 199245916cd2Sjpk } 199345916cd2Sjpk 19947c478bd9Sstevel@tonic-gate int 19957c478bd9Sstevel@tonic-gate secpolicy_swapctl(const cred_t *cr) 19967c478bd9Sstevel@tonic-gate { 19977c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 19987c478bd9Sstevel@tonic-gate } 19997c478bd9Sstevel@tonic-gate 20007c478bd9Sstevel@tonic-gate int 20017c478bd9Sstevel@tonic-gate secpolicy_cpc_cpu(const cred_t *cr) 20027c478bd9Sstevel@tonic-gate { 20037c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CPC_CPU, B_FALSE, EACCES, NULL)); 20047c478bd9Sstevel@tonic-gate } 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate /* 20077b209c2cSacruz * secpolicy_contract_identity 20087b209c2cSacruz * 20097b209c2cSacruz * Determine if the subject may set the process contract FMRI value 20107b209c2cSacruz */ 20117b209c2cSacruz int 20127b209c2cSacruz secpolicy_contract_identity(const cred_t *cr) 20137b209c2cSacruz { 20147b209c2cSacruz return (PRIV_POLICY(cr, PRIV_CONTRACT_IDENTITY, B_FALSE, EPERM, NULL)); 20157b209c2cSacruz } 20167b209c2cSacruz 20177b209c2cSacruz /* 20187c478bd9Sstevel@tonic-gate * secpolicy_contract_observer 20197c478bd9Sstevel@tonic-gate * 20207c478bd9Sstevel@tonic-gate * Determine if the subject may observe a specific contract's events. 20217c478bd9Sstevel@tonic-gate */ 20227c478bd9Sstevel@tonic-gate int 20237c478bd9Sstevel@tonic-gate secpolicy_contract_observer(const cred_t *cr, struct contract *ct) 20247c478bd9Sstevel@tonic-gate { 20257c478bd9Sstevel@tonic-gate if (contract_owned(ct, cr, B_FALSE)) 20267c478bd9Sstevel@tonic-gate return (0); 20277c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CONTRACT_OBSERVER, B_FALSE, EPERM, NULL)); 20287c478bd9Sstevel@tonic-gate } 20297c478bd9Sstevel@tonic-gate 20307c478bd9Sstevel@tonic-gate /* 20317c478bd9Sstevel@tonic-gate * secpolicy_contract_observer_choice 20327c478bd9Sstevel@tonic-gate * 20337c478bd9Sstevel@tonic-gate * Determine if the subject may observe any contract's events. Just 20347c478bd9Sstevel@tonic-gate * tests privilege and audits on success. 20357c478bd9Sstevel@tonic-gate */ 20367c478bd9Sstevel@tonic-gate boolean_t 20377c478bd9Sstevel@tonic-gate secpolicy_contract_observer_choice(const cred_t *cr) 20387c478bd9Sstevel@tonic-gate { 20397c478bd9Sstevel@tonic-gate return (PRIV_POLICY_CHOICE(cr, PRIV_CONTRACT_OBSERVER, B_FALSE)); 20407c478bd9Sstevel@tonic-gate } 20417c478bd9Sstevel@tonic-gate 20427c478bd9Sstevel@tonic-gate /* 20437c478bd9Sstevel@tonic-gate * secpolicy_contract_event 20447c478bd9Sstevel@tonic-gate * 20457c478bd9Sstevel@tonic-gate * Determine if the subject may request critical contract events or 20467c478bd9Sstevel@tonic-gate * reliable contract event delivery. 20477c478bd9Sstevel@tonic-gate */ 20487c478bd9Sstevel@tonic-gate int 20497c478bd9Sstevel@tonic-gate secpolicy_contract_event(const cred_t *cr) 20507c478bd9Sstevel@tonic-gate { 20517c478bd9Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CONTRACT_EVENT, B_FALSE, EPERM, NULL)); 20527c478bd9Sstevel@tonic-gate } 20537c478bd9Sstevel@tonic-gate 20547c478bd9Sstevel@tonic-gate /* 20557c478bd9Sstevel@tonic-gate * secpolicy_contract_event_choice 20567c478bd9Sstevel@tonic-gate * 20577c478bd9Sstevel@tonic-gate * Determine if the subject may retain contract events in its critical 20587c478bd9Sstevel@tonic-gate * set when a change in other terms would normally require a change in 20597c478bd9Sstevel@tonic-gate * the critical set. Just tests privilege and audits on success. 20607c478bd9Sstevel@tonic-gate */ 20617c478bd9Sstevel@tonic-gate boolean_t 20627c478bd9Sstevel@tonic-gate secpolicy_contract_event_choice(const cred_t *cr) 20637c478bd9Sstevel@tonic-gate { 20647c478bd9Sstevel@tonic-gate return (PRIV_POLICY_CHOICE(cr, PRIV_CONTRACT_EVENT, B_FALSE)); 20657c478bd9Sstevel@tonic-gate } 20667c478bd9Sstevel@tonic-gate 20677c478bd9Sstevel@tonic-gate /* 2068ea8dc4b6Seschrock * secpolicy_gart_access 20697c478bd9Sstevel@tonic-gate * 2070ea8dc4b6Seschrock * Determine if the subject has sufficient priveleges to make ioctls to agpgart 2071ea8dc4b6Seschrock * device. 20727c478bd9Sstevel@tonic-gate */ 20737c478bd9Sstevel@tonic-gate int 20747c478bd9Sstevel@tonic-gate secpolicy_gart_access(const cred_t *cr) 20757c478bd9Sstevel@tonic-gate { 207626f24838Scasper return (PRIV_POLICY(cr, PRIV_GRAPHICS_ACCESS, B_FALSE, EPERM, NULL)); 20777c478bd9Sstevel@tonic-gate } 20787c478bd9Sstevel@tonic-gate 20797c478bd9Sstevel@tonic-gate /* 2080ea8dc4b6Seschrock * secpolicy_gart_map 20817c478bd9Sstevel@tonic-gate * 2082ea8dc4b6Seschrock * Determine if the subject has sufficient priveleges to map aperture range 2083ea8dc4b6Seschrock * through agpgart driver. 20847c478bd9Sstevel@tonic-gate */ 20857c478bd9Sstevel@tonic-gate int 20867c478bd9Sstevel@tonic-gate secpolicy_gart_map(const cred_t *cr) 20877c478bd9Sstevel@tonic-gate { 208826f24838Scasper if (PRIV_POLICY_ONLY(cr, PRIV_GRAPHICS_ACCESS, B_FALSE)) { 208926f24838Scasper return (PRIV_POLICY(cr, PRIV_GRAPHICS_ACCESS, B_FALSE, EPERM, 209026f24838Scasper NULL)); 209126f24838Scasper } else { 209226f24838Scasper return (PRIV_POLICY(cr, PRIV_GRAPHICS_MAP, B_FALSE, EPERM, 209326f24838Scasper NULL)); 20947c478bd9Sstevel@tonic-gate } 20957c478bd9Sstevel@tonic-gate } 2096fa9e4066Sahrens 2097fa9e4066Sahrens /* 2098ea8dc4b6Seschrock * secpolicy_zinject 2099ea8dc4b6Seschrock * 2100ea8dc4b6Seschrock * Determine if the subject can inject faults in the ZFS fault injection 2101ea8dc4b6Seschrock * framework. Requires all privileges. 2102ea8dc4b6Seschrock */ 2103ea8dc4b6Seschrock int 2104ea8dc4b6Seschrock secpolicy_zinject(const cred_t *cr) 2105ea8dc4b6Seschrock { 2106ea8dc4b6Seschrock return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); 2107ea8dc4b6Seschrock } 2108ea8dc4b6Seschrock 2109ea8dc4b6Seschrock /* 2110fa9e4066Sahrens * secpolicy_zfs 2111fa9e4066Sahrens * 2112ea8dc4b6Seschrock * Determine if the subject has permission to manipulate ZFS datasets 2113ea8dc4b6Seschrock * (not pools). Equivalent to the SYS_MOUNT privilege. 2114fa9e4066Sahrens */ 2115fa9e4066Sahrens int 2116fa9e4066Sahrens secpolicy_zfs(const cred_t *cr) 2117fa9e4066Sahrens { 2118fa9e4066Sahrens return (PRIV_POLICY(cr, PRIV_SYS_MOUNT, B_FALSE, EPERM, NULL)); 2119fa9e4066Sahrens } 2120f48205beScasper 2121f48205beScasper /* 2122f48205beScasper * secpolicy_idmap 2123f48205beScasper * 2124f48205beScasper * Determine if the calling process has permissions to register an SID 2125f48205beScasper * mapping daemon and allocate ephemeral IDs. 2126f48205beScasper */ 2127f48205beScasper int 2128f48205beScasper secpolicy_idmap(const cred_t *cr) 2129f48205beScasper { 2130bda89588Sjp151216 return (PRIV_POLICY(cr, PRIV_FILE_SETID, B_TRUE, EPERM, NULL)); 2131f48205beScasper } 21322449e17fSsherrym 21332449e17fSsherrym /* 21342449e17fSsherrym * secpolicy_ucode_update 21352449e17fSsherrym * 21362449e17fSsherrym * Determine if the subject has sufficient privilege to update microcode. 21372449e17fSsherrym */ 21382449e17fSsherrym int 21392449e17fSsherrym secpolicy_ucode_update(const cred_t *scr) 21402449e17fSsherrym { 21412449e17fSsherrym return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); 21422449e17fSsherrym } 2143e6bdcbd5Sdh155122 2144e6bdcbd5Sdh155122 /* 2145e6bdcbd5Sdh155122 * secpolicy_sadopen 2146e6bdcbd5Sdh155122 * 2147e6bdcbd5Sdh155122 * Determine if the subject has sufficient privilege to access /dev/sad/admin. 2148e6bdcbd5Sdh155122 * /dev/sad/admin appear in global zone and exclusive-IP zones only. 2149e6bdcbd5Sdh155122 * In global zone, sys_config is required. 2150e6bdcbd5Sdh155122 * In exclusive-IP zones, sys_ip_config is required. 2151e6bdcbd5Sdh155122 * Note that sys_config is prohibited in non-global zones. 2152e6bdcbd5Sdh155122 */ 2153e6bdcbd5Sdh155122 int 2154e6bdcbd5Sdh155122 secpolicy_sadopen(const cred_t *credp) 2155e6bdcbd5Sdh155122 { 2156e6bdcbd5Sdh155122 priv_set_t pset; 2157e6bdcbd5Sdh155122 2158e6bdcbd5Sdh155122 priv_emptyset(&pset); 2159e6bdcbd5Sdh155122 2160e6bdcbd5Sdh155122 if (crgetzoneid(credp) == GLOBAL_ZONEID) 2161e6bdcbd5Sdh155122 priv_addset(&pset, PRIV_SYS_CONFIG); 2162e6bdcbd5Sdh155122 else 2163e6bdcbd5Sdh155122 priv_addset(&pset, PRIV_SYS_IP_CONFIG); 2164e6bdcbd5Sdh155122 2165e6bdcbd5Sdh155122 return (secpolicy_require_set(credp, &pset, "devpolicy")); 2166e6bdcbd5Sdh155122 } 2167da6c28aaSamw 2168ddf7fe95Scasper 2169ddf7fe95Scasper /* 2170ddf7fe95Scasper * Add privileges to a particular privilege set; this is called when the 2171ddf7fe95Scasper * current sets of privileges are not sufficient. I.e., we should always 2172ddf7fe95Scasper * call the policy override functions from here. 2173ddf7fe95Scasper * What we are allowed to have is in the Observed Permitted set; so 2174ddf7fe95Scasper * we compute the difference between that and the newset. 2175ddf7fe95Scasper */ 2176ddf7fe95Scasper int 2177ddf7fe95Scasper secpolicy_require_privs(const cred_t *cr, const priv_set_t *nset) 2178ddf7fe95Scasper { 2179ddf7fe95Scasper priv_set_t rqd; 2180ddf7fe95Scasper 2181ddf7fe95Scasper rqd = CR_OPPRIV(cr); 2182ddf7fe95Scasper 2183ddf7fe95Scasper priv_inverse(&rqd); 2184ddf7fe95Scasper priv_intersect(nset, &rqd); 2185ddf7fe95Scasper 2186ddf7fe95Scasper return (secpolicy_require_set(cr, &rqd, NULL)); 2187ddf7fe95Scasper } 2188ddf7fe95Scasper 2189da6c28aaSamw /* 2190da6c28aaSamw * secpolicy_smb 2191da6c28aaSamw * 2192da6c28aaSamw * Determine if the cred_t has PRIV_SYS_SMB privilege, indicating 2193da6c28aaSamw * that it has permission to access the smbsrv kernel driver. 2194da6c28aaSamw * PRIV_POLICY checks the privilege and audits the check. 2195da6c28aaSamw * 2196da6c28aaSamw * Returns: 2197da6c28aaSamw * 0 Driver access is allowed. 2198da6c28aaSamw * EPERM Driver access is NOT permitted. 2199da6c28aaSamw */ 2200da6c28aaSamw int 2201da6c28aaSamw secpolicy_smb(const cred_t *cr) 2202da6c28aaSamw { 2203da6c28aaSamw return (PRIV_POLICY(cr, PRIV_SYS_SMB, B_FALSE, EPERM, NULL)); 2204da6c28aaSamw } 2205911106dfSjm199354 2206911106dfSjm199354 /* 2207911106dfSjm199354 * secpolicy_vscan 2208911106dfSjm199354 * 2209911106dfSjm199354 * Determine if cred_t has the necessary privileges to access a file 2210911106dfSjm199354 * for virus scanning and update its extended system attributes. 2211911106dfSjm199354 * PRIV_FILE_DAC_SEARCH, PRIV_FILE_DAC_READ - file access 2212911106dfSjm199354 * PRIV_FILE_FLAG_SET - set extended system attributes 2213911106dfSjm199354 * 2214911106dfSjm199354 * PRIV_POLICY checks the privilege and audits the check. 2215911106dfSjm199354 * 2216911106dfSjm199354 * Returns: 2217911106dfSjm199354 * 0 file access for virus scanning allowed. 2218911106dfSjm199354 * EPERM file access for virus scanning is NOT permitted. 2219911106dfSjm199354 */ 2220911106dfSjm199354 int 2221911106dfSjm199354 secpolicy_vscan(const cred_t *cr) 2222911106dfSjm199354 { 2223911106dfSjm199354 if ((PRIV_POLICY(cr, PRIV_FILE_DAC_SEARCH, B_FALSE, EPERM, NULL)) || 2224911106dfSjm199354 (PRIV_POLICY(cr, PRIV_FILE_DAC_READ, B_FALSE, EPERM, NULL)) || 2225911106dfSjm199354 (PRIV_POLICY(cr, PRIV_FILE_FLAG_SET, B_FALSE, EPERM, NULL))) { 2226911106dfSjm199354 return (EPERM); 2227911106dfSjm199354 } 2228911106dfSjm199354 2229911106dfSjm199354 return (0); 2230911106dfSjm199354 } 22314bff34e3Sthurlow 22324bff34e3Sthurlow /* 22334bff34e3Sthurlow * secpolicy_smbfs_login 22344bff34e3Sthurlow * 22354bff34e3Sthurlow * Determines if the caller can add and delete the smbfs login 22364bff34e3Sthurlow * password in the the nsmb kernel module for the CIFS client. 22374bff34e3Sthurlow * 22384bff34e3Sthurlow * Returns: 22394bff34e3Sthurlow * 0 access is allowed. 22404bff34e3Sthurlow * EPERM access is NOT allowed. 22414bff34e3Sthurlow */ 22424bff34e3Sthurlow int 22434bff34e3Sthurlow secpolicy_smbfs_login(const cred_t *cr, uid_t uid) 22444bff34e3Sthurlow { 22454bff34e3Sthurlow uid_t cruid = crgetruid(cr); 22464bff34e3Sthurlow 22474bff34e3Sthurlow if (cruid == uid) 22484bff34e3Sthurlow return (0); 22494bff34e3Sthurlow return (PRIV_POLICY(cr, PRIV_PROC_OWNER, B_FALSE, 22504bff34e3Sthurlow EPERM, NULL)); 22514bff34e3Sthurlow } 2252b26a64aeSjohnlev 2253b26a64aeSjohnlev /* 2254b26a64aeSjohnlev * secpolicy_xvm_control 2255b26a64aeSjohnlev * 2256b26a64aeSjohnlev * Determines if a caller can control the xVM hypervisor and/or running 2257b26a64aeSjohnlev * domains (x86 specific). 2258b26a64aeSjohnlev * 2259b26a64aeSjohnlev * Returns: 2260b26a64aeSjohnlev * 0 access is allowed. 2261b26a64aeSjohnlev * EPERM access is NOT allowed. 2262b26a64aeSjohnlev */ 2263b26a64aeSjohnlev int 2264b26a64aeSjohnlev secpolicy_xvm_control(const cred_t *cr) 2265b26a64aeSjohnlev { 2266b26a64aeSjohnlev if (PRIV_POLICY(cr, PRIV_XVM_CONTROL, B_FALSE, EPERM, NULL)) 2267b26a64aeSjohnlev return (EPERM); 2268b26a64aeSjohnlev return (0); 2269b26a64aeSjohnlev } 2270