opensolaris_policy.c revision 184413
1168404Spjd/*- 2168404Spjd * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3168404Spjd * All rights reserved. 4168404Spjd * 5168404Spjd * Redistribution and use in source and binary forms, with or without 6168404Spjd * modification, are permitted provided that the following conditions 7168404Spjd * are met: 8168404Spjd * 1. Redistributions of source code must retain the above copyright 9168404Spjd * notice, this list of conditions and the following disclaimer. 10168404Spjd * 2. Redistributions in binary form must reproduce the above copyright 11168404Spjd * notice, this list of conditions and the following disclaimer in the 12168404Spjd * documentation and/or other materials provided with the distribution. 13168404Spjd * 14168404Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15168404Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16168404Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17168404Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18168404Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19168404Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20168404Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21168404Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22168404Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23168404Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24168404Spjd * SUCH DAMAGE. 25168404Spjd */ 26168404Spjd 27168404Spjd#include <sys/cdefs.h> 28168404Spjd__FBSDID("$FreeBSD: head/sys/cddl/compat/opensolaris/kern/opensolaris_policy.c 184413 2008-10-28 13:44:11Z trasz $"); 29168404Spjd 30168404Spjd#include <sys/param.h> 31168404Spjd#include <sys/priv.h> 32168404Spjd#include <sys/vnode.h> 33168404Spjd#include <sys/mount.h> 34168404Spjd#include <sys/stat.h> 35168404Spjd#include <sys/policy.h> 36168404Spjd 37168404Spjdint 38168404Spjdsecpolicy_zfs(struct ucred *cred) 39168404Spjd{ 40168404Spjd 41168404Spjd return (priv_check_cred(cred, PRIV_VFS_MOUNT, 0)); 42168404Spjd} 43168404Spjd 44168404Spjdint 45168404Spjdsecpolicy_sys_config(struct ucred *cred, int checkonly __unused) 46168404Spjd{ 47168404Spjd 48168404Spjd return (priv_check_cred(cred, PRIV_ZFS_POOL_CONFIG, 0)); 49168404Spjd} 50168404Spjd 51168404Spjdint 52168404Spjdsecpolicy_zinject(struct ucred *cred) 53168404Spjd{ 54168404Spjd 55168404Spjd return (priv_check_cred(cred, PRIV_ZFS_INJECT, 0)); 56168404Spjd} 57168404Spjd 58168404Spjdint 59168404Spjdsecpolicy_fs_unmount(struct ucred *cred, struct mount *vfsp __unused) 60168404Spjd{ 61168404Spjd 62168404Spjd return (priv_check_cred(cred, PRIV_VFS_UNMOUNT, 0)); 63168404Spjd} 64168404Spjd 65168404Spjd/* 66168404Spjd * This check is done in kern_link(), so we could just return 0 here. 67168404Spjd */ 68168404Spjdextern int hardlink_check_uid; 69168404Spjdint 70168404Spjdsecpolicy_basic_link(struct ucred *cred) 71168404Spjd{ 72168404Spjd 73168404Spjd if (!hardlink_check_uid) 74168404Spjd return (0); 75170587Srwatson return (priv_check_cred(cred, PRIV_VFS_LINK, 0)); 76168404Spjd} 77168404Spjd 78168404Spjdint 79168404Spjdsecpolicy_vnode_stky_modify(struct ucred *cred) 80168404Spjd{ 81168404Spjd 82168404Spjd return (EPERM); 83168404Spjd} 84168404Spjd 85168404Spjdint 86168404Spjdsecpolicy_vnode_remove(struct ucred *cred) 87168404Spjd{ 88168404Spjd 89170587Srwatson return (priv_check_cred(cred, PRIV_VFS_ADMIN, 0)); 90168404Spjd} 91168404Spjd 92168404Spjdint 93168404Spjdsecpolicy_vnode_access(struct ucred *cred, struct vnode *vp, uint64_t owner, 94184413Strasz accmode_t accmode) 95168404Spjd{ 96168404Spjd 97184413Strasz if ((accmode & VREAD) && priv_check_cred(cred, PRIV_VFS_READ, 0) != 0) { 98168404Spjd return (EACCES); 99168404Spjd } 100184413Strasz if ((accmode & VWRITE) && 101170587Srwatson priv_check_cred(cred, PRIV_VFS_WRITE, 0) != 0) { 102168404Spjd return (EACCES); 103168404Spjd } 104184413Strasz if (accmode & VEXEC) { 105168404Spjd if (vp->v_type == VDIR) { 106170587Srwatson if (priv_check_cred(cred, PRIV_VFS_LOOKUP, 0) != 0) { 107168404Spjd return (EACCES); 108168404Spjd } 109168404Spjd } else { 110170587Srwatson if (priv_check_cred(cred, PRIV_VFS_EXEC, 0) != 0) { 111168404Spjd return (EACCES); 112168404Spjd } 113168404Spjd } 114168404Spjd } 115168404Spjd return (0); 116168404Spjd} 117168404Spjd 118168404Spjdint 119168404Spjdsecpolicy_vnode_setdac(struct ucred *cred, uid_t owner) 120168404Spjd{ 121168404Spjd 122168404Spjd if (owner == cred->cr_uid) 123168404Spjd return (0); 124170587Srwatson return (priv_check_cred(cred, PRIV_VFS_ADMIN, 0)); 125168404Spjd} 126168404Spjd 127168404Spjdint 128168404Spjdsecpolicy_vnode_setattr(struct ucred *cred, struct vnode *vp, struct vattr *vap, 129168404Spjd const struct vattr *ovap, int flags, 130168404Spjd int unlocked_access(void *, int, struct ucred *), void *node) 131168404Spjd{ 132168404Spjd int mask = vap->va_mask; 133168404Spjd int error; 134168404Spjd 135168404Spjd if (mask & AT_SIZE) { 136168404Spjd if (vp->v_type == VDIR) 137168404Spjd return (EISDIR); 138168404Spjd error = unlocked_access(node, VWRITE, cred); 139168404Spjd if (error) 140168404Spjd return (error); 141168404Spjd } 142168404Spjd if (mask & AT_MODE) { 143168404Spjd /* 144168404Spjd * If not the owner of the file then check privilege 145168404Spjd * for two things: the privilege to set the mode at all 146168404Spjd * and, if we're setting setuid, we also need permissions 147168404Spjd * to add the set-uid bit, if we're not the owner. 148168404Spjd * In the specific case of creating a set-uid root 149168404Spjd * file, we need even more permissions. 150168404Spjd */ 151168404Spjd error = secpolicy_vnode_setdac(cred, ovap->va_uid); 152168404Spjd if (error) 153168404Spjd return (error); 154168404Spjd error = secpolicy_setid_setsticky_clear(vp, vap, ovap, cred); 155168404Spjd if (error) 156168404Spjd return (error); 157168404Spjd } else { 158168404Spjd vap->va_mode = ovap->va_mode; 159168404Spjd } 160168404Spjd if (mask & (AT_UID | AT_GID)) { 161168404Spjd error = secpolicy_vnode_setdac(cred, ovap->va_uid); 162168404Spjd if (error) 163168404Spjd return (error); 164168404Spjd 165168404Spjd /* 166168404Spjd * To change the owner of a file, or change the group of a file to a 167168404Spjd * group of which we are not a member, the caller must have 168168404Spjd * privilege. 169168404Spjd */ 170168404Spjd if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || 171168404Spjd ((mask & AT_GID) && vap->va_gid != ovap->va_gid && 172168404Spjd !groupmember(vap->va_gid, cred))) { 173170587Srwatson error = priv_check_cred(cred, PRIV_VFS_CHOWN, 0); 174168404Spjd if (error) 175168404Spjd return (error); 176168404Spjd } 177168404Spjd 178168404Spjd if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || 179168404Spjd ((mask & AT_GID) && vap->va_gid != ovap->va_gid)) { 180168404Spjd secpolicy_setid_clear(vap, cred); 181168404Spjd } 182168404Spjd } 183168404Spjd if (mask & (AT_ATIME | AT_MTIME)) { 184168404Spjd /* 185168404Spjd * From utimes(2): 186168404Spjd * If times is NULL, ... The caller must be the owner of 187168404Spjd * the file, have permission to write the file, or be the 188168404Spjd * super-user. 189168404Spjd * If times is non-NULL, ... The caller must be the owner of 190168404Spjd * the file or be the super-user. 191168404Spjd */ 192168404Spjd error = secpolicy_vnode_setdac(cred, ovap->va_uid); 193168404Spjd if (error && (vap->va_vaflags & VA_UTIMES_NULL)) 194168404Spjd error = unlocked_access(node, VWRITE, cred); 195168404Spjd if (error) 196168404Spjd return (error); 197168404Spjd } 198168404Spjd return (0); 199168404Spjd} 200168404Spjd 201168404Spjdint 202168404Spjdsecpolicy_vnode_create_gid(struct ucred *cred) 203168404Spjd{ 204168404Spjd 205168404Spjd return (EPERM); 206168404Spjd} 207168404Spjd 208168404Spjdint 209168404Spjdsecpolicy_vnode_setids_setgids(struct ucred *cred, gid_t gid) 210168404Spjd{ 211168404Spjd 212168404Spjd if (!groupmember(gid, cred)) 213170587Srwatson return (priv_check_cred(cred, PRIV_VFS_SETGID, 0)); 214168404Spjd return (0); 215168404Spjd} 216168404Spjd 217168404Spjdint 218168404Spjdsecpolicy_vnode_setid_retain(struct ucred *cred, boolean_t issuidroot __unused) 219168404Spjd{ 220168404Spjd 221170587Srwatson return (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0)); 222168404Spjd} 223168404Spjd 224168404Spjdvoid 225168404Spjdsecpolicy_setid_clear(struct vattr *vap, struct ucred *cred) 226168404Spjd{ 227168404Spjd 228168404Spjd if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0) { 229170587Srwatson if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0)) { 230168404Spjd vap->va_mask |= AT_MODE; 231168404Spjd vap->va_mode &= ~(S_ISUID|S_ISGID); 232168404Spjd } 233168404Spjd } 234168404Spjd} 235168404Spjd 236168404Spjdint 237168404Spjdsecpolicy_setid_setsticky_clear(struct vnode *vp, struct vattr *vap, 238168404Spjd const struct vattr *ovap, struct ucred *cred) 239168404Spjd{ 240168404Spjd int error; 241168404Spjd 242168404Spjd /* 243168404Spjd * Privileged processes may set the sticky bit on non-directories, 244168404Spjd * as well as set the setgid bit on a file with a group that the process 245168404Spjd * is not a member of. Both of these are allowed in jail(8). 246168404Spjd */ 247168404Spjd if (vp->v_type != VDIR && (vap->va_mode & S_ISTXT)) { 248170587Srwatson if (priv_check_cred(cred, PRIV_VFS_STICKYFILE, 0)) 249168404Spjd return (EFTYPE); 250168404Spjd } 251168404Spjd /* 252168404Spjd * Check for privilege if attempting to set the 253168404Spjd * group-id bit. 254168404Spjd */ 255168404Spjd if ((vap->va_mode & S_ISGID) != 0) { 256168404Spjd error = secpolicy_vnode_setids_setgids(cred, ovap->va_gid); 257168404Spjd if (error) 258168404Spjd return (error); 259168404Spjd } 260168404Spjd return (0); 261168404Spjd} 262