#include <sys/param.h>
#include <sys/vnode.h>
#include <sys/vnode_internal.h>
#include <sys/kauth.h>
#include <sys/namei.h>
#include <sys/mount.h>
#include <sys/mount_internal.h>
#include <sys/uio_internal.h>
#include <sys/xattr.h>
#include <security/mac_internal.h>
int
vnode_label(struct mount *mp, struct vnode *dvp, struct vnode *vp,
struct componentname *cnp, int flags, vfs_context_t ctx)
{
int error;
error = 0;
vnode_lock(vp);
if (vp->v_lflag & VL_LABELED) {
if (!(flags & VNODE_LABEL_NEEDREF))
vnode_put_locked(vp);
vnode_unlock(vp);
return (0);
}
if ((flags & VNODE_LABEL_NEEDREF) && vnode_get_locked(vp)) {
vnode_unlock(vp);
return (ENOENT);
}
if ((vp->v_lflag & VL_LABEL) == 0) {
vp->v_lflag |= VL_LABEL;
vnode_unlock(vp);
if (flags & VNODE_LABEL_CREATE)
error = mac_vnode_notify_create(ctx,
mp, dvp, vp, cnp);
else
error = mac_vnode_label_associate(mp, vp, ctx);
vnode_lock(vp);
if ((error == 0) && (vp->v_flag & VNCACHEABLE))
vp->v_lflag |= VL_LABELED;
vp->v_lflag &= ~VL_LABEL;
if (vp->v_lflag & VL_LABELWAIT) {
vp->v_lflag &= ~VL_LABELWAIT;
wakeup(vp->v_label);
}
vnode_put_locked(vp);
vnode_unlock(vp);
} else {
struct timespec ts;
ts.tv_sec = 10;
ts.tv_nsec = 0;
while (vp->v_lflag & VL_LABEL) {
vp->v_lflag |= VL_LABELWAIT;
error = msleep(vp->v_label, &vp->v_lock, PVFS|PDROP,
"vnode_label", &ts);
vnode_lock(vp);
if (error == EWOULDBLOCK) {
vprint("vnode label timeout", vp);
break;
}
}
vnode_put_locked(vp);
vnode_unlock(vp);
}
return (error);
}
void
vnode_relabel(struct vnode *vp)
{
while (vp->v_lflag & VL_LABEL) {
vp->v_lflag |= VL_LABELWAIT;
(void)msleep(vp->v_label, &vp->v_lock, PVFS, "vnode_relabel", 0);
}
vp->v_lflag &= ~VL_LABELED;
return;
}
int
mac_vnop_setxattr (struct vnode *vp, const char *name, char *buf, size_t len)
{
vfs_context_t ctx;
int options = XATTR_NOSECURITY;
char uio_buf[ UIO_SIZEOF(1) ];
uio_t auio;
int error;
if (vfs_isrdonly(vp->v_mount))
return (EROFS);
ctx = vfs_context_current();
auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_WRITE,
&uio_buf[0], sizeof(uio_buf));
uio_addiov(auio, CAST_USER_ADDR_T(buf), len);
error = vn_setxattr(vp, name, auio, options, ctx);
return (error);
}
int
mac_vnop_getxattr (struct vnode *vp, const char *name, char *buf, size_t len,
size_t *attrlen)
{
vfs_context_t ctx = vfs_context_current();
int options = XATTR_NOSECURITY;
char uio_buf[ UIO_SIZEOF(1) ];
uio_t auio;
int error;
auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ,
&uio_buf[0], sizeof(uio_buf));
uio_addiov(auio, CAST_USER_ADDR_T(buf), len);
error = vn_getxattr(vp, name, auio, attrlen, options, ctx);
*attrlen = len - uio_resid(auio);
return (error);
}
int
mac_vnop_removexattr (struct vnode *vp, const char *name)
{
vfs_context_t ctx = vfs_context_current();
int options = XATTR_NOSECURITY;
int error;
if (vfs_isrdonly(vp->v_mount))
return (EROFS);
error = vn_removexattr(vp, name, options, ctx);
return (error);
}