opensolaris_policy.c revision 209962
1101242Srwatson/*- 2101242Srwatson * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3101242Srwatson * All rights reserved. 4101242Srwatson * 5101242Srwatson * Redistribution and use in source and binary forms, with or without 6101242Srwatson * modification, are permitted provided that the following conditions 7101242Srwatson * are met: 8101242Srwatson * 1. Redistributions of source code must retain the above copyright 9101242Srwatson * notice, this list of conditions and the following disclaimer. 10101242Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11101242Srwatson * notice, this list of conditions and the following disclaimer in the 12101242Srwatson * documentation and/or other materials provided with the distribution. 13101242Srwatson * 14101242Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15101242Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16101242Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17101242Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18101242Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19101242Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20101242Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21101242Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22101242Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23101242Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24101242Srwatson * SUCH DAMAGE. 25101242Srwatson */ 26101242Srwatson 27101242Srwatson#include <sys/cdefs.h> 28101242Srwatson__FBSDID("$FreeBSD: head/sys/cddl/compat/opensolaris/kern/opensolaris_policy.c 209962 2010-07-12 23:49:04Z mm $"); 29101242Srwatson 30101242Srwatson#include <sys/param.h> 31101242Srwatson#include <sys/priv.h> 32176901Srwatson#include <sys/vnode.h> 33176901Srwatson#include <sys/mntent.h> 34176901Srwatson#include <sys/mount.h> 35101242Srwatson#include <sys/stat.h> 36101242Srwatson#include <sys/jail.h> 37101242Srwatson#include <sys/policy.h> 38111618Snectar#include <sys/zfs_vfsops.h> 39111618Snectar 40111618Snectarint 41111618Snectarsecpolicy_nfs(struct ucred *cred) 42111618Snectar{ 43101242Srwatson 44105698Srwatson return (priv_check_cred(cred, PRIV_NFS_DAEMON, 0)); 45101242Srwatson} 46101242Srwatson 47105698Srwatsonint 48101242Srwatsonsecpolicy_zfs(struct ucred *cred) 49101242Srwatson{ 50101242Srwatson 51105698Srwatson return (priv_check_cred(cred, PRIV_VFS_MOUNT, 0)); 52101242Srwatson} 53101242Srwatson 54105698Srwatsonint 55101242Srwatsonsecpolicy_sys_config(struct ucred *cred, int checkonly __unused) 56101242Srwatson{ 57101242Srwatson 58105698Srwatson return (priv_check_cred(cred, PRIV_ZFS_POOL_CONFIG, 0)); 59101242Srwatson} 60101242Srwatson 61105698Srwatsonint 62105698Srwatsonsecpolicy_zinject(struct ucred *cred) 63105698Srwatson{ 64105698Srwatson 65105698Srwatson return (priv_check_cred(cred, PRIV_ZFS_INJECT, 0)); 66105698Srwatson} 67105698Srwatson 68101242Srwatsonint 69101242Srwatsonsecpolicy_fs_unmount(struct ucred *cred, struct mount *vfsp __unused) 70{ 71 72 return (priv_check_cred(cred, PRIV_VFS_UNMOUNT, 0)); 73} 74 75int 76secpolicy_fs_owner(struct mount *mp, struct ucred *cred) 77{ 78 79 if (zfs_super_owner) { 80 if (cred->cr_uid == mp->mnt_cred->cr_uid && 81 cred->cr_prison == mp->mnt_cred->cr_prison) { 82 return (0); 83 } 84 } 85 return (EPERM); 86} 87 88/* 89 * This check is done in kern_link(), so we could just return 0 here. 90 */ 91extern int hardlink_check_uid; 92int 93secpolicy_basic_link(struct vnode *vp, struct ucred *cred) 94{ 95 96 if (!hardlink_check_uid) 97 return (0); 98 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 99 return (0); 100 return (priv_check_cred(cred, PRIV_VFS_LINK, 0)); 101} 102 103int 104secpolicy_vnode_stky_modify(struct ucred *cred) 105{ 106 107 return (EPERM); 108} 109 110int 111secpolicy_vnode_remove(struct vnode *vp, struct ucred *cred) 112{ 113 114 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 115 return (0); 116 return (priv_check_cred(cred, PRIV_VFS_ADMIN, 0)); 117} 118 119int 120secpolicy_vnode_access(struct ucred *cred, struct vnode *vp, uint64_t owner, 121 accmode_t accmode) 122{ 123 124 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 125 return (0); 126 127 if ((accmode & VREAD) && priv_check_cred(cred, PRIV_VFS_READ, 0) != 0) 128 return (EACCES); 129 if ((accmode & VWRITE) && 130 priv_check_cred(cred, PRIV_VFS_WRITE, 0) != 0) { 131 return (EACCES); 132 } 133 if (accmode & VEXEC) { 134 if (vp->v_type == VDIR) { 135 if (priv_check_cred(cred, PRIV_VFS_LOOKUP, 0) != 0) { 136 return (EACCES); 137 } 138 } else { 139 if (priv_check_cred(cred, PRIV_VFS_EXEC, 0) != 0) { 140 return (EACCES); 141 } 142 } 143 } 144 return (0); 145} 146 147int 148secpolicy_vnode_setdac(struct vnode *vp, struct ucred *cred, uid_t owner) 149{ 150 151 if (owner == cred->cr_uid) 152 return (0); 153 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 154 return (0); 155 return (priv_check_cred(cred, PRIV_VFS_ADMIN, 0)); 156} 157 158int 159secpolicy_vnode_setattr(struct ucred *cred, struct vnode *vp, struct vattr *vap, 160 const struct vattr *ovap, int flags, 161 int unlocked_access(void *, int, struct ucred *), void *node) 162{ 163 int mask = vap->va_mask; 164 int error; 165 166 if (mask & AT_SIZE) { 167 if (vp->v_type == VDIR) 168 return (EISDIR); 169 error = unlocked_access(node, VWRITE, cred); 170 if (error) 171 return (error); 172 } 173 if (mask & AT_MODE) { 174 /* 175 * If not the owner of the file then check privilege 176 * for two things: the privilege to set the mode at all 177 * and, if we're setting setuid, we also need permissions 178 * to add the set-uid bit, if we're not the owner. 179 * In the specific case of creating a set-uid root 180 * file, we need even more permissions. 181 */ 182 error = secpolicy_vnode_setdac(vp, cred, ovap->va_uid); 183 if (error) 184 return (error); 185 error = secpolicy_setid_setsticky_clear(vp, vap, ovap, cred); 186 if (error) 187 return (error); 188 } else { 189 vap->va_mode = ovap->va_mode; 190 } 191 if (mask & (AT_UID | AT_GID)) { 192 error = secpolicy_vnode_setdac(vp, cred, ovap->va_uid); 193 if (error) 194 return (error); 195 196 /* 197 * To change the owner of a file, or change the group of a file to a 198 * group of which we are not a member, the caller must have 199 * privilege. 200 */ 201 if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || 202 ((mask & AT_GID) && vap->va_gid != ovap->va_gid && 203 !groupmember(vap->va_gid, cred))) { 204 if (secpolicy_fs_owner(vp->v_mount, cred) != 0) { 205 error = priv_check_cred(cred, PRIV_VFS_CHOWN, 0); 206 if (error) 207 return (error); 208 } 209 } 210 211 if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || 212 ((mask & AT_GID) && vap->va_gid != ovap->va_gid)) { 213 secpolicy_setid_clear(vap, vp, cred); 214 } 215 } 216 if (mask & (AT_ATIME | AT_MTIME)) { 217 /* 218 * From utimes(2): 219 * If times is NULL, ... The caller must be the owner of 220 * the file, have permission to write the file, or be the 221 * super-user. 222 * If times is non-NULL, ... The caller must be the owner of 223 * the file or be the super-user. 224 */ 225 error = secpolicy_vnode_setdac(vp, cred, ovap->va_uid); 226 if (error && (vap->va_vaflags & VA_UTIMES_NULL)) 227 error = unlocked_access(node, VWRITE, cred); 228 if (error) 229 return (error); 230 } 231 return (0); 232} 233 234int 235secpolicy_vnode_create_gid(struct ucred *cred) 236{ 237 238 return (EPERM); 239} 240 241int 242secpolicy_vnode_setids_setgids(vnode_t *vp, struct ucred *cred, gid_t gid) 243{ 244 if (groupmember(gid, cred)) 245 return (0); 246 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 247 return (0); 248 return (priv_check_cred(cred, PRIV_VFS_SETGID, 0)); 249} 250 251int 252secpolicy_vnode_setid_retain(struct vnode *vp, struct ucred *cred, 253 boolean_t issuidroot __unused) 254{ 255 256 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 257 return (0); 258 return (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0)); 259} 260 261void 262secpolicy_setid_clear(struct vattr *vap, struct vnode *vp, struct ucred *cred) 263{ 264 265 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 266 return; 267 268 if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0) { 269 if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0)) { 270 vap->va_mask |= AT_MODE; 271 vap->va_mode &= ~(S_ISUID|S_ISGID); 272 } 273 } 274} 275 276int 277secpolicy_setid_setsticky_clear(struct vnode *vp, struct vattr *vap, 278 const struct vattr *ovap, struct ucred *cred) 279{ 280 int error; 281 282 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 283 return (0); 284 285 /* 286 * Privileged processes may set the sticky bit on non-directories, 287 * as well as set the setgid bit on a file with a group that the process 288 * is not a member of. Both of these are allowed in jail(8). 289 */ 290 if (vp->v_type != VDIR && (vap->va_mode & S_ISTXT)) { 291 if (priv_check_cred(cred, PRIV_VFS_STICKYFILE, 0)) 292 return (EFTYPE); 293 } 294 /* 295 * Check for privilege if attempting to set the 296 * group-id bit. 297 */ 298 if ((vap->va_mode & S_ISGID) != 0) { 299 error = secpolicy_vnode_setids_setgids(vp, cred, ovap->va_gid); 300 if (error) 301 return (error); 302 } 303 /* 304 * Deny setting setuid if we are not the file owner. 305 */ 306 if ((vap->va_mode & S_ISUID) && ovap->va_uid != cred->cr_uid) { 307 error = priv_check_cred(cred, PRIV_VFS_ADMIN, 0); 308 if (error) 309 return (error); 310 } 311 return (0); 312} 313 314int 315secpolicy_fs_mount(cred_t *cr, vnode_t *mvp, struct mount *vfsp) 316{ 317 318 return (priv_check_cred(cr, PRIV_VFS_MOUNT, 0)); 319} 320 321int 322secpolicy_vnode_owner(struct vnode *vp, cred_t *cred, uid_t owner) 323{ 324 325 if (owner == cred->cr_uid) 326 return (0); 327 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 328 return (0); 329 330 /* XXX: vfs_suser()? */ 331 return (priv_check_cred(cred, PRIV_VFS_MOUNT_OWNER, 0)); 332} 333 334int 335secpolicy_vnode_chown(struct vnode *vp, cred_t *cred, boolean_t check_self) 336{ 337 338 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 339 return (0); 340 return (priv_check_cred(cred, PRIV_VFS_CHOWN, 0)); 341} 342 343void 344secpolicy_fs_mount_clearopts(cred_t *cr, struct mount *vfsp) 345{ 346 347 if (priv_check_cred(cr, PRIV_VFS_MOUNT_NONUSER, 0) != 0) { 348 MNT_ILOCK(vfsp); 349 vfsp->vfs_flag |= VFS_NOSETUID | MNT_USER; 350 vfs_clearmntopt(vfsp, MNTOPT_SETUID); 351 vfs_setmntopt(vfsp, MNTOPT_NOSETUID, NULL, 0); 352 MNT_IUNLOCK(vfsp); 353 } 354} 355 356/* 357 * Check privileges for setting xvattr attributes 358 */ 359int 360secpolicy_xvattr(struct vnode *vp, xvattr_t *xvap, uid_t owner, cred_t *cr, 361 vtype_t vtype) 362{ 363 364 if (secpolicy_fs_owner(vp->v_mount, cr) == 0) 365 return (0); 366 return (priv_check_cred(cr, PRIV_VFS_SYSFLAGS, 0)); 367} 368 369int 370secpolicy_smb(cred_t *cr) 371{ 372 373 return (priv_check_cred(cr, PRIV_NETSMB, 0)); 374} 375