1/* 2 * Copyright (c) 2007 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28#include <sys/param.h> 29#include <sys/vnode.h> 30#include <sys/vnode_internal.h> 31#include <sys/kauth.h> 32#include <sys/namei.h> 33#include <sys/mount.h> 34#include <sys/mount_internal.h> 35#include <sys/uio_internal.h> 36#include <sys/xattr.h> 37#include "../bsd/sys/fsevents.h" 38 39#include <security/mac_internal.h> 40 41/* 42 * Caller holds I/O reference on vnode 43 */ 44int 45vnode_label(struct mount *mp, struct vnode *dvp, struct vnode *vp, 46 struct componentname *cnp, int flags, vfs_context_t ctx) 47{ 48 int error = 0; 49 50 51 /* fast path checks... */ 52 53 /* are we labeling vnodes? If not still notify of create */ 54 if (mac_label_vnodes == 0) { 55 if (flags & VNODE_LABEL_CREATE) 56 error = mac_vnode_notify_create(ctx, 57 mp, dvp, vp, cnp); 58 return 0; 59 } 60 61 /* if already VL_LABELED */ 62 if (vp->v_lflag & VL_LABELED) 63 return (0); 64 65 vnode_lock_spin(vp); 66 67 /* 68 * must revalidate state once we hold the lock 69 * since we could have blocked and someone else 70 * has since labeled this vnode 71 */ 72 if (vp->v_lflag & VL_LABELED) { 73 vnode_unlock(vp); 74 return (0); 75 } 76 77 if ((vp->v_lflag & VL_LABEL) == 0) { 78 vp->v_lflag |= VL_LABEL; 79 80 /* Could sleep on disk I/O, drop lock. */ 81 vnode_unlock(vp); 82 83 if (vp->v_label == NULL) 84 vp->v_label = mac_vnode_label_alloc(); 85 86 if (flags & VNODE_LABEL_CREATE) 87 error = mac_vnode_notify_create(ctx, 88 mp, dvp, vp, cnp); 89 else 90 error = mac_vnode_label_associate(mp, vp, ctx); 91 92 vnode_lock_spin(vp); 93 94 if ((error == 0) && (vp->v_flag & VNCACHEABLE)) 95 vp->v_lflag |= VL_LABELED; 96 vp->v_lflag &= ~VL_LABEL; 97 98 if (vp->v_lflag & VL_LABELWAIT) { 99 vp->v_lflag &= ~VL_LABELWAIT; 100 wakeup(&vp->v_label); 101 } 102 } else { 103 struct timespec ts; 104 105 ts.tv_sec = 10; 106 ts.tv_nsec = 0; 107 108 while (vp->v_lflag & VL_LABEL) { 109 vp->v_lflag |= VL_LABELWAIT; 110 111 error = msleep(&vp->v_label, &vp->v_lock, PVFS|PDROP, 112 "vnode_label", &ts); 113 vnode_lock_spin(vp); 114 115 if (error == EWOULDBLOCK) { 116 vprint("vnode label timeout", vp); 117 break; 118 } 119 } 120 /* XXX: what should be done if labeling failed (above)? */ 121 } 122 vnode_unlock(vp); 123 124 return (error); 125} 126 127 128/* 129 * Clear the "labeled" flag on a VNODE. 130 * VNODE will have label re-associated upon 131 * next call to lookup(). 132 * 133 * Caller verifies vfs_flags(vnode_mount(vp)) & MNT_MULTILABEL 134 * Caller holds vnode lock. 135 */ 136void 137vnode_relabel(struct vnode *vp) 138{ 139 140 /* Wait for any other labeling to complete. */ 141 while (vp->v_lflag & VL_LABEL) { 142 vp->v_lflag |= VL_LABELWAIT; 143 (void)msleep(&vp->v_label, &vp->v_lock, PVFS, "vnode_relabel", 0); 144 } 145 146 /* Clear labeled flag */ 147 vp->v_lflag &= ~VL_LABELED; 148 149 return; 150} 151 152/* 153 * VFS XATTR helpers. 154 */ 155 156int 157mac_vnop_setxattr (struct vnode *vp, const char *name, char *buf, size_t len) 158{ 159 vfs_context_t ctx; 160 int options = XATTR_NOSECURITY; 161 char uio_buf[ UIO_SIZEOF(1) ]; 162 uio_t auio; 163 int error; 164 165 if (vfs_isrdonly(vp->v_mount)) 166 return (EROFS); 167 168 ctx = vfs_context_current(); 169 auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_WRITE, 170 &uio_buf[0], sizeof(uio_buf)); 171 uio_addiov(auio, CAST_USER_ADDR_T(buf), len); 172 173 error = vn_setxattr(vp, name, auio, options, ctx); 174#if CONFIG_FSE 175 if (error == 0) { 176 add_fsevent(FSE_XATTR_MODIFIED, ctx, 177 FSE_ARG_VNODE, vp, 178 FSE_ARG_DONE); 179 } 180#endif 181 182 return (error); 183} 184 185int 186mac_vnop_getxattr (struct vnode *vp, const char *name, char *buf, size_t len, 187 size_t *attrlen) 188{ 189 vfs_context_t ctx = vfs_context_current(); 190 int options = XATTR_NOSECURITY; 191 char uio_buf[ UIO_SIZEOF(1) ]; 192 uio_t auio; 193 int error; 194 195 auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ, 196 &uio_buf[0], sizeof(uio_buf)); 197 uio_addiov(auio, CAST_USER_ADDR_T(buf), len); 198 199 error = vn_getxattr(vp, name, auio, attrlen, options, ctx); 200 *attrlen = len - uio_resid(auio); 201 202 return (error); 203} 204 205int 206mac_vnop_removexattr (struct vnode *vp, const char *name) 207{ 208 vfs_context_t ctx = vfs_context_current(); 209 int options = XATTR_NOSECURITY; 210 int error; 211 212 if (vfs_isrdonly(vp->v_mount)) 213 return (EROFS); 214 215 error = vn_removexattr(vp, name, options, ctx); 216#if CONFIG_FSE 217 if (error == 0) { 218 add_fsevent(FSE_XATTR_REMOVED, ctx, 219 FSE_ARG_VNODE, vp, 220 FSE_ARG_DONE); 221 } 222#endif 223 224 return (error); 225} 226