opensolaris_policy.c revision 197860
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 197860 2009-10-08 16:03:19Z pjd $"); 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 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(struct vnode *vp, struct ucred *cred, gid_t gid) 243{ 244 245 if (groupmember(gid, cred)) 246 return (0); 247 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 248 return (0); 249 return (priv_check_cred(cred, PRIV_VFS_SETGID, 0)); 250} 251 252int 253secpolicy_vnode_setid_retain(struct vnode *vp, struct ucred *cred, 254 boolean_t issuidroot __unused) 255{ 256 257 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 258 return (0); 259 return (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0)); 260} 261 262void 263secpolicy_setid_clear(struct vattr *vap, struct vnode *vp, struct ucred *cred) 264{ 265 266 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 267 return; 268 269 if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0) { 270 if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0)) { 271 vap->va_mask |= AT_MODE; 272 vap->va_mode &= ~(S_ISUID|S_ISGID); 273 } 274 } 275} 276 277int 278secpolicy_setid_setsticky_clear(struct vnode *vp, struct vattr *vap, 279 const struct vattr *ovap, struct ucred *cred) 280{ 281 int error; 282 283 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 284 return (0); 285 286 /* 287 * Privileged processes may set the sticky bit on non-directories, 288 * as well as set the setgid bit on a file with a group that the process 289 * is not a member of. Both of these are allowed in jail(8). 290 */ 291 if (vp->v_type != VDIR && (vap->va_mode & S_ISTXT)) { 292 if (priv_check_cred(cred, PRIV_VFS_STICKYFILE, 0)) 293 return (EFTYPE); 294 } 295 /* 296 * Check for privilege if attempting to set the 297 * group-id bit. 298 */ 299 if ((vap->va_mode & S_ISGID) != 0) { 300 error = secpolicy_vnode_setids_setgids(vp, cred, ovap->va_gid); 301 if (error) 302 return (error); 303 } 304 /* 305 * Deny setting setuid if we are not the file owner. 306 */ 307 if ((vap->va_mode & S_ISUID) && ovap->va_uid != cred->cr_uid) { 308 error = priv_check_cred(cred, PRIV_VFS_ADMIN, 0); 309 if (error) 310 return (error); 311 } 312 return (0); 313} 314 315int 316secpolicy_fs_mount(cred_t *cr, vnode_t *mvp, struct mount *vfsp) 317{ 318 319 return (priv_check_cred(cr, PRIV_VFS_MOUNT, 0)); 320} 321 322int 323secpolicy_vnode_owner(struct vnode *vp, cred_t *cred, uid_t owner) 324{ 325 326 if (owner == cred->cr_uid) 327 return (0); 328 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 329 return (0); 330 331 /* XXX: vfs_suser()? */ 332 return (priv_check_cred(cred, PRIV_VFS_MOUNT_OWNER, 0)); 333} 334 335int 336secpolicy_vnode_chown(struct vnode *vp, cred_t *cred, boolean_t check_self) 337{ 338 339 if (secpolicy_fs_owner(vp->v_mount, cred) == 0) 340 return (0); 341 return (priv_check_cred(cred, PRIV_VFS_CHOWN, 0)); 342} 343 344void 345secpolicy_fs_mount_clearopts(cred_t *cr, struct mount *vfsp) 346{ 347 348 if (priv_check_cred(cr, PRIV_VFS_MOUNT_NONUSER, 0) != 0) { 349 MNT_ILOCK(vfsp); 350 vfsp->vfs_flag |= VFS_NOSETUID | MNT_USER; 351 vfs_clearmntopt(vfsp, MNTOPT_SETUID); 352 vfs_setmntopt(vfsp, MNTOPT_NOSETUID, NULL, 0); 353 MNT_IUNLOCK(vfsp); 354 } 355} 356 357/* 358 * Check privileges for setting xvattr attributes 359 */ 360int 361secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype) 362{ 363 364 return (priv_check_cred(cr, PRIV_VFS_SYSFLAGS, 0)); 365} 366