opensolaris_policy.c revision 168404
1/*- 2 * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/cddl/compat/opensolaris/kern/opensolaris_policy.c 168404 2007-04-06 01:09:06Z pjd $"); 29 30#include <sys/param.h> 31#include <sys/priv.h> 32#include <sys/vnode.h> 33#include <sys/mount.h> 34#include <sys/stat.h> 35#include <sys/policy.h> 36 37int 38secpolicy_zfs(struct ucred *cred) 39{ 40 41 return (priv_check_cred(cred, PRIV_VFS_MOUNT, 0)); 42} 43 44int 45secpolicy_sys_config(struct ucred *cred, int checkonly __unused) 46{ 47 48 return (priv_check_cred(cred, PRIV_ZFS_POOL_CONFIG, 0)); 49} 50 51int 52secpolicy_zinject(struct ucred *cred) 53{ 54 55 return (priv_check_cred(cred, PRIV_ZFS_INJECT, 0)); 56} 57 58int 59secpolicy_fs_unmount(struct ucred *cred, struct mount *vfsp __unused) 60{ 61 62 return (priv_check_cred(cred, PRIV_VFS_UNMOUNT, 0)); 63} 64 65/* 66 * This check is done in kern_link(), so we could just return 0 here. 67 */ 68extern int hardlink_check_uid; 69int 70secpolicy_basic_link(struct ucred *cred) 71{ 72 73 if (!hardlink_check_uid) 74 return (0); 75 return (priv_check_cred(cred, PRIV_VFS_LINK, SUSER_ALLOWJAIL)); 76} 77 78int 79secpolicy_vnode_stky_modify(struct ucred *cred) 80{ 81 82 return (EPERM); 83} 84 85int 86secpolicy_vnode_remove(struct ucred *cred) 87{ 88 89 return (priv_check_cred(cred, PRIV_VFS_ADMIN, SUSER_ALLOWJAIL)); 90} 91 92int 93secpolicy_vnode_access(struct ucred *cred, struct vnode *vp, uint64_t owner, 94 int mode) 95{ 96 97 if ((mode & VREAD) && 98 priv_check_cred(cred, PRIV_VFS_READ, SUSER_ALLOWJAIL) != 0) { 99 return (EACCES); 100 } 101 if ((mode & VWRITE) && 102 priv_check_cred(cred, PRIV_VFS_WRITE, SUSER_ALLOWJAIL) != 0) { 103 return (EACCES); 104 } 105 if (mode & VEXEC) { 106 if (vp->v_type == VDIR) { 107 if (priv_check_cred(cred, PRIV_VFS_LOOKUP, 108 SUSER_ALLOWJAIL) != 0) { 109 return (EACCES); 110 } 111 } else { 112 if (priv_check_cred(cred, PRIV_VFS_EXEC, 113 SUSER_ALLOWJAIL) != 0) { 114 return (EACCES); 115 } 116 } 117 } 118 return (0); 119} 120 121int 122secpolicy_vnode_setdac(struct ucred *cred, uid_t owner) 123{ 124 125 if (owner == cred->cr_uid) 126 return (0); 127 return (priv_check_cred(cred, PRIV_VFS_ADMIN, SUSER_ALLOWJAIL)); 128} 129 130int 131secpolicy_vnode_setattr(struct ucred *cred, struct vnode *vp, struct vattr *vap, 132 const struct vattr *ovap, int flags, 133 int unlocked_access(void *, int, struct ucred *), void *node) 134{ 135 int mask = vap->va_mask; 136 int error; 137 138 if (mask & AT_SIZE) { 139 if (vp->v_type == VDIR) 140 return (EISDIR); 141 error = unlocked_access(node, VWRITE, cred); 142 if (error) 143 return (error); 144 } 145 if (mask & AT_MODE) { 146 /* 147 * If not the owner of the file then check privilege 148 * for two things: the privilege to set the mode at all 149 * and, if we're setting setuid, we also need permissions 150 * to add the set-uid bit, if we're not the owner. 151 * In the specific case of creating a set-uid root 152 * file, we need even more permissions. 153 */ 154 error = secpolicy_vnode_setdac(cred, ovap->va_uid); 155 if (error) 156 return (error); 157 error = secpolicy_setid_setsticky_clear(vp, vap, ovap, cred); 158 if (error) 159 return (error); 160 } else { 161 vap->va_mode = ovap->va_mode; 162 } 163 if (mask & (AT_UID | AT_GID)) { 164 error = secpolicy_vnode_setdac(cred, ovap->va_uid); 165 if (error) 166 return (error); 167 168 /* 169 * To change the owner of a file, or change the group of a file to a 170 * group of which we are not a member, the caller must have 171 * privilege. 172 */ 173 if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || 174 ((mask & AT_GID) && vap->va_gid != ovap->va_gid && 175 !groupmember(vap->va_gid, cred))) { 176 error = priv_check_cred(cred, PRIV_VFS_CHOWN, 177 SUSER_ALLOWJAIL); 178 if (error) 179 return (error); 180 } 181 182 if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || 183 ((mask & AT_GID) && vap->va_gid != ovap->va_gid)) { 184 secpolicy_setid_clear(vap, cred); 185 } 186 } 187 if (mask & (AT_ATIME | AT_MTIME)) { 188 /* 189 * From utimes(2): 190 * If times is NULL, ... The caller must be the owner of 191 * the file, have permission to write the file, or be the 192 * super-user. 193 * If times is non-NULL, ... The caller must be the owner of 194 * the file or be the super-user. 195 */ 196 error = secpolicy_vnode_setdac(cred, ovap->va_uid); 197 if (error && (vap->va_vaflags & VA_UTIMES_NULL)) 198 error = unlocked_access(node, VWRITE, cred); 199 if (error) 200 return (error); 201 } 202 return (0); 203} 204 205int 206secpolicy_vnode_create_gid(struct ucred *cred) 207{ 208 209 return (EPERM); 210} 211 212int 213secpolicy_vnode_setids_setgids(struct ucred *cred, gid_t gid) 214{ 215 216 if (!groupmember(gid, cred)) 217 return (priv_check_cred(cred, PRIV_VFS_SETGID, SUSER_ALLOWJAIL)); 218 return (0); 219} 220 221int 222secpolicy_vnode_setid_retain(struct ucred *cred, boolean_t issuidroot __unused) 223{ 224 225 return (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, SUSER_ALLOWJAIL)); 226} 227 228void 229secpolicy_setid_clear(struct vattr *vap, struct ucred *cred) 230{ 231 232 if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0) { 233 if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 234 SUSER_ALLOWJAIL)) { 235 vap->va_mask |= AT_MODE; 236 vap->va_mode &= ~(S_ISUID|S_ISGID); 237 } 238 } 239} 240 241int 242secpolicy_setid_setsticky_clear(struct vnode *vp, struct vattr *vap, 243 const struct vattr *ovap, struct ucred *cred) 244{ 245 int error; 246 247 /* 248 * Privileged processes may set the sticky bit on non-directories, 249 * as well as set the setgid bit on a file with a group that the process 250 * is not a member of. Both of these are allowed in jail(8). 251 */ 252 if (vp->v_type != VDIR && (vap->va_mode & S_ISTXT)) { 253 if (priv_check_cred(cred, PRIV_VFS_STICKYFILE, SUSER_ALLOWJAIL)) 254 return (EFTYPE); 255 } 256 /* 257 * Check for privilege if attempting to set the 258 * group-id bit. 259 */ 260 if ((vap->va_mode & S_ISGID) != 0) { 261 error = secpolicy_vnode_setids_setgids(cred, ovap->va_gid); 262 if (error) 263 return (error); 264 } 265 return (0); 266} 267