opensolaris_policy.c revision 192694
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 192694 2009-05-24 19:21:49Z trasz $"); 29 30#include <sys/param.h> 31#include <sys/priv.h> 32#include <sys/vnode.h> 33#include <sys/mntent.h> 34#include <sys/mount.h> 35#include <sys/stat.h> 36#include <sys/jail.h> 37#include <sys/policy.h> 38#include <sys/zfs_vfsops.h> 39 40int 41secpolicy_nfs(struct ucred *cred) 42{ 43 44 return (priv_check_cred(cred, PRIV_NFS_DAEMON, 0)); 45} 46 47int 48secpolicy_zfs(struct ucred *cred) 49{ 50 51 return (priv_check_cred(cred, PRIV_VFS_MOUNT, 0)); 52} 53 54int 55secpolicy_sys_config(struct ucred *cred, int checkonly __unused) 56{ 57 58 return (priv_check_cred(cred, PRIV_ZFS_POOL_CONFIG, 0)); 59} 60 61int 62secpolicy_zinject(struct ucred *cred) 63{ 64 65 return (priv_check_cred(cred, PRIV_ZFS_INJECT, 0)); 66} 67 68int 69secpolicy_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 (!jailed(cred) || 82 cred->cr_prison == mp->mnt_cred->cr_prison)) { 83 return (0); 84 } 85 } 86 return (priv_check_cred(cred, PRIV_VFS_MOUNT_OWNER, 0)); 87} 88 89/* 90 * This check is done in kern_link(), so we could just return 0 here. 91 */ 92extern int hardlink_check_uid; 93int 94secpolicy_basic_link(struct vnode *vp, struct ucred *cred) 95{ 96 97 if (!hardlink_check_uid) 98 return (0); 99 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 100 return (0); 101 return (priv_check_cred(cred, PRIV_VFS_LINK, 0)); 102} 103 104int 105secpolicy_vnode_stky_modify(struct ucred *cred) 106{ 107 108 return (EPERM); 109} 110 111int 112secpolicy_vnode_remove(struct vnode *vp, struct ucred *cred) 113{ 114 115 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 116 return (0); 117 return (priv_check_cred(cred, PRIV_VFS_ADMIN, 0)); 118} 119 120int 121secpolicy_vnode_access(struct ucred *cred, struct vnode *vp, uint64_t owner, 122 accmode_t accmode) 123{ 124 125 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 126 return (0); 127 128 if ((accmode & VREAD) && priv_check_cred(cred, PRIV_VFS_READ, 0) != 0) 129 return (EACCES); 130 if ((accmode & VWRITE) && 131 priv_check_cred(cred, PRIV_VFS_WRITE, 0) != 0) { 132 return (EACCES); 133 } 134 if (accmode & VEXEC) { 135 if (vp->v_type == VDIR) { 136 if (priv_check_cred(cred, PRIV_VFS_LOOKUP, 0) != 0) { 137 return (EACCES); 138 } 139 } else { 140 if (priv_check_cred(cred, PRIV_VFS_EXEC, 0) != 0) { 141 return (EACCES); 142 } 143 } 144 } 145 return (0); 146} 147 148int 149secpolicy_vnode_setdac(struct vnode *vp, struct ucred *cred, uid_t owner) 150{ 151 152 if (owner == cred->cr_uid) 153 return (0); 154 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 155 return (0); 156 return (priv_check_cred(cred, PRIV_VFS_ADMIN, 0)); 157} 158 159int 160secpolicy_vnode_setattr(struct ucred *cred, struct vnode *vp, struct vattr *vap, 161 const struct vattr *ovap, int flags, 162 int unlocked_access(void *, int, struct ucred *), void *node) 163{ 164 int mask = vap->va_mask; 165 int error; 166 167 if (mask & AT_SIZE) { 168 if (vp->v_type == VDIR) 169 return (EISDIR); 170 error = unlocked_access(node, VWRITE, cred); 171 if (error) 172 return (error); 173 } 174 if (mask & AT_MODE) { 175 /* 176 * If not the owner of the file then check privilege 177 * for two things: the privilege to set the mode at all 178 * and, if we're setting setuid, we also need permissions 179 * to add the set-uid bit, if we're not the owner. 180 * In the specific case of creating a set-uid root 181 * file, we need even more permissions. 182 */ 183 error = secpolicy_vnode_setdac(vp, cred, ovap->va_uid); 184 if (error) 185 return (error); 186 error = secpolicy_setid_setsticky_clear(vp, vap, ovap, cred); 187 if (error) 188 return (error); 189 } else { 190 vap->va_mode = ovap->va_mode; 191 } 192 if (mask & (AT_UID | AT_GID)) { 193 error = secpolicy_vnode_setdac(vp, cred, ovap->va_uid); 194 if (error) 195 return (error); 196 197 /* 198 * To change the owner of a file, or change the group of a file to a 199 * group of which we are not a member, the caller must have 200 * privilege. 201 */ 202 if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || 203 ((mask & AT_GID) && vap->va_gid != ovap->va_gid && 204 !groupmember(vap->va_gid, cred))) { 205 if (secpolicy_fs_owner(vp->v_mount, cred) != 0) { 206 error = priv_check_cred(cred, PRIV_VFS_CHOWN, 0); 207 if (error) 208 return (error); 209 } 210 } 211 212 if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || 213 ((mask & AT_GID) && vap->va_gid != ovap->va_gid)) { 214 secpolicy_setid_clear(vap, vp, cred); 215 } 216 } 217 if (mask & (AT_ATIME | AT_MTIME)) { 218 /* 219 * From utimes(2): 220 * If times is NULL, ... The caller must be the owner of 221 * the file, have permission to write the file, or be the 222 * super-user. 223 * If times is non-NULL, ... The caller must be the owner of 224 * the file or be the super-user. 225 */ 226 error = secpolicy_vnode_setdac(vp, cred, ovap->va_uid); 227 if (error && (vap->va_vaflags & VA_UTIMES_NULL)) 228 error = unlocked_access(node, VWRITE, cred); 229 if (error) 230 return (error); 231 } 232 return (0); 233} 234 235int 236secpolicy_vnode_create_gid(struct ucred *cred) 237{ 238 239 return (EPERM); 240} 241 242int 243secpolicy_vnode_setids_setgids(struct vnode *vp, struct ucred *cred, gid_t gid) 244{ 245 246 if (groupmember(gid, cred)) 247 return (0); 248 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 249 return (0); 250 return (priv_check_cred(cred, PRIV_VFS_SETGID, 0)); 251} 252 253int 254secpolicy_vnode_setid_retain(struct vnode *vp, struct ucred *cred, 255 boolean_t issuidroot __unused) 256{ 257 258 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 259 return (0); 260 return (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0)); 261} 262 263void 264secpolicy_setid_clear(struct vattr *vap, struct vnode *vp, struct ucred *cred) 265{ 266 267 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 268 return; 269 270 if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0) { 271 if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0)) { 272 vap->va_mask |= AT_MODE; 273 vap->va_mode &= ~(S_ISUID|S_ISGID); 274 } 275 } 276} 277 278int 279secpolicy_setid_setsticky_clear(struct vnode *vp, struct vattr *vap, 280 const struct vattr *ovap, struct ucred *cred) 281{ 282 int error; 283 284 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 285 return (0); 286 287 /* 288 * Privileged processes may set the sticky bit on non-directories, 289 * as well as set the setgid bit on a file with a group that the process 290 * is not a member of. Both of these are allowed in jail(8). 291 */ 292 if (vp->v_type != VDIR && (vap->va_mode & S_ISTXT)) { 293 if (priv_check_cred(cred, PRIV_VFS_STICKYFILE, 0)) 294 return (EFTYPE); 295 } 296 /* 297 * Check for privilege if attempting to set the 298 * group-id bit. 299 */ 300 if ((vap->va_mode & S_ISGID) != 0) { 301 error = secpolicy_vnode_setids_setgids(vp, cred, ovap->va_gid); 302 if (error) 303 return (error); 304 } 305 /* 306 * Deny setting setuid if we are not the file owner. 307 */ 308 if ((vap->va_mode & S_ISUID) && ovap->va_uid != cred->cr_uid) { 309 error = priv_check_cred(cred, PRIV_VFS_ADMIN, 0); 310 if (error) 311 return (error); 312 } 313 return (0); 314} 315 316int 317secpolicy_fs_mount(cred_t *cr, vnode_t *mvp, struct mount *vfsp) 318{ 319 320 return (priv_check_cred(cr, PRIV_VFS_MOUNT, 0)); 321} 322 323int 324secpolicy_vnode_owner(struct vnode *vp, cred_t *cred, uid_t owner) 325{ 326 327 if (owner == cred->cr_uid) 328 return (0); 329 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 330 return (0); 331 332 /* XXX: vfs_suser()? */ 333 return (priv_check_cred(cred, PRIV_VFS_MOUNT_OWNER, 0)); 334} 335 336int 337secpolicy_vnode_chown(struct vnode *vp, cred_t *cred, boolean_t check_self) 338{ 339 340 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 341 return (0); 342 return (priv_check_cred(cred, PRIV_VFS_CHOWN, 0)); 343} 344 345void 346secpolicy_fs_mount_clearopts(cred_t *cr, struct mount *vfsp) 347{ 348 349 if (priv_check_cred(cr, PRIV_VFS_MOUNT_NONUSER, 0) != 0) { 350 MNT_ILOCK(vfsp); 351 vfsp->vfs_flag |= VFS_NOSETUID | MNT_USER; 352 vfs_clearmntopt(vfsp, MNTOPT_SETUID); 353 vfs_setmntopt(vfsp, MNTOPT_NOSETUID, NULL, 0); 354 MNT_IUNLOCK(vfsp); 355 } 356} 357 358/* 359 * Check privileges for setting xvattr attributes 360 */ 361int 362secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype) 363{ 364 365 return (priv_check_cred(cr, PRIV_VFS_SYSFLAGS, 0)); 366} 367