int
xfs_cap_vget(
	vnode_t		*vp,
	void		*cap,
	size_t		size)
{
	int		error;
	int		len = sizeof(xfs_cap_set_t);
	int		flags = ATTR_ROOT;
	xfs_cap_set_t	xfs_cap = { 0 };
	posix_cap_xattr	*xattr_cap = cap;
	char		*data = (char *)&xfs_cap;

	VN_HOLD(vp);
	if ((error = _MAC_VACCESS(vp, NULL, VREAD)))
		goto out;

	if (!size) {
		flags |= ATTR_KERNOVAL;
		data = NULL;
	}
	VOP_ATTR_GET(vp, SGI_CAP_LINUX, data, &len, flags, sys_cred, error);
	if (error)
		goto out;
	ASSERT(len == sizeof(xfs_cap_set_t));

	error = (size)? -posix_cap_xattr_size() :
			-posix_cap_xfs_to_xattr(&xfs_cap, xattr_cap, size);
out:
	VN_RELE(vp);
	return -error;
}
STATIC int
xfs_attrmulti_attr_get(
	struct vnode		*vp,
	char			*name,
	char			__user *ubuf,
	__uint32_t		*len,
	__uint32_t		flags)
{
	char			*kbuf;
	int			error = EFAULT;
	
	if (*len > XATTR_SIZE_MAX)
		return EINVAL;
	kbuf = kmalloc(*len, GFP_KERNEL);
	if (!kbuf)
		return ENOMEM;

	VOP_ATTR_GET(vp, name, kbuf, len, flags, NULL, error);
	if (error)
		goto out_kfree;

	if (copy_to_user(ubuf, kbuf, *len))
		error = EFAULT;

 out_kfree:
	kfree(kbuf);
	return error;
}
/*
 * Test for the existence of a MAC label as efficiently as possible.
 */
int
xfs_mac_vhaslabel(
	vnode_t		*vp)
{
	int		error;
	int		len = sizeof(xfs_mac_label_t);
	int		flags = ATTR_KERNOVAL|ATTR_ROOT;

	VOP_ATTR_GET(vp, SGI_MAC_FILE, NULL, &len, flags, sys_cred, error);
	return (error == 0);
}
/*
 * Test for existence of capability attribute as efficiently as possible.
 */
int
xfs_cap_vhascap(
	vnode_t		*vp)
{
	int		error;
	int		len = sizeof(xfs_cap_set_t);
	int		flags = ATTR_KERNOVAL|ATTR_ROOT;

	VOP_ATTR_GET(vp, SGI_CAP_LINUX, NULL, &len, flags, sys_cred, error);
	return (error == 0);
}
/*
 * Get the ACL from the EA and do endian conversion.
 */
STATIC void
xfs_acl_get_attr(
	vnode_t		*vp,
	xfs_acl_t	*aclp,
	int		kind,
	int		flags,
	int		*error)
{
	int		len = sizeof(xfs_acl_t);

	ASSERT((flags & ATTR_KERNOVAL) ? (aclp == NULL) : 1);
	flags |= ATTR_ROOT;
	VOP_ATTR_GET(vp,
		kind == _ACL_TYPE_ACCESS ? SGI_ACL_FILE : SGI_ACL_DEFAULT,
		(char *)aclp, &len, flags, sys_cred, *error);
	if (*error || (flags & ATTR_KERNOVAL))
		return;
	xfs_acl_get_endian(aclp);
}
Exemple #6
0
STATIC int
xfs_attrmulti_by_handle(
	xfs_mount_t		*mp,
	unsigned long		arg,
	struct file		*parfilp,
	struct inode		*parinode)
{
	int			error;
	xfs_attr_multiop_t	*ops;
	xfs_fsop_attrmulti_handlereq_t am_hreq;
	struct inode		*inode;
	vnode_t			*vp;
	unsigned int		i, size;

	error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg,
					sizeof(xfs_fsop_attrmulti_handlereq_t),
					(xfs_fsop_handlereq_t *)&am_hreq,
					&vp, &inode);
	if (error)
		return -error;

	size = am_hreq.opcount * sizeof(attr_multiop_t);
	if (!size || size > 16 * PAGE_SIZE) {
		VN_RELE(vp);
		return -XFS_ERROR(E2BIG);
	}

	ops = (xfs_attr_multiop_t *)kmalloc(size, GFP_KERNEL);
	if (!ops) {
		VN_RELE(vp);
		return -XFS_ERROR(ENOMEM);
	}

	if (copy_from_user(ops, am_hreq.ops, size)) {
		kfree(ops);
		VN_RELE(vp);
		return -XFS_ERROR(EFAULT);
	}

	for (i = 0; i < am_hreq.opcount; i++) {
		switch(ops[i].am_opcode) {
		case ATTR_OP_GET:
			VOP_ATTR_GET(vp,ops[i].am_attrname, ops[i].am_attrvalue,
					&ops[i].am_length, ops[i].am_flags,
					NULL, ops[i].am_error);
			break;
		case ATTR_OP_SET:
			if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
				ops[i].am_error = EPERM;
				break;
			}
			VOP_ATTR_SET(vp,ops[i].am_attrname, ops[i].am_attrvalue,
					ops[i].am_length, ops[i].am_flags,
					NULL, ops[i].am_error);
			break;
		case ATTR_OP_REMOVE:
			if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
				ops[i].am_error = EPERM;
				break;
			}
			VOP_ATTR_REMOVE(vp, ops[i].am_attrname, ops[i].am_flags,
					NULL, ops[i].am_error);
			break;
		default:
			ops[i].am_error = EINVAL;
		}
	}

	if (copy_to_user(am_hreq.ops, ops, size))
		error = -XFS_ERROR(EFAULT);

	kfree(ops);
	VN_RELE(vp);
	return error;
}
Exemple #7
0
STATIC ssize_t
linvfs_getxattr(
	struct dentry	*dentry,
	const char	*name,
	void		*data,
	size_t		size)
{
	ssize_t		error;
	int		xflags = 0;
	char		*p = (char *)name;
	struct inode	*inode = dentry->d_inode;
	vnode_t		*vp = LINVFS_GET_VP(inode);

	if (strncmp(name, xfs_namespaces[SYSTEM_NAMES].name,
			xfs_namespaces[SYSTEM_NAMES].namelen) == 0) {
		error = -ENOATTR;
		p += xfs_namespaces[SYSTEM_NAMES].namelen;
		if (strcmp(p, POSIXACL_ACCESS) == 0) {
			if (vp->v_flag & VMODIFIED) {
				error = linvfs_revalidate_core(inode, 0);
				if (error)
					return error;
			}
			error = xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS);
		}
		else if (strcmp(p, POSIXACL_DEFAULT) == 0) {
			if (vp->v_flag & VMODIFIED) {
				error = linvfs_revalidate_core(inode, 0);
				if (error)
					return error;
			}
			error = xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT);
		}
		else if (strcmp(p, POSIXCAP) == 0) {
			error = xfs_cap_vget(vp, data, size);
		}
		return error;
	}

	/* Convert Linux syscall to XFS internal ATTR flags */
	if (!size)
		xflags |= ATTR_KERNOVAL;

	if (strncmp(name, xfs_namespaces[ROOT_NAMES].name,
			xfs_namespaces[ROOT_NAMES].namelen) == 0) {
		if (!capable(CAP_SYS_ADMIN))
			return -EPERM;
		xflags |= ATTR_ROOT;
		p += xfs_namespaces[ROOT_NAMES].namelen;
		VOP_ATTR_GET(vp, p, data, (int *)&size, xflags, NULL, error);
		if (!error)
			error = -size;
		return -error;
	}
	if (strncmp(name, xfs_namespaces[USER_NAMES].name,
			xfs_namespaces[USER_NAMES].namelen) == 0) {
		p += xfs_namespaces[USER_NAMES].namelen;
		if (!capable_user_xattr(inode))
			return -EPERM;
		VOP_ATTR_GET(vp, p, data, (int *)&size, xflags, NULL, error);
		if (!error)
			error = -size;
		return -error;
	}
	return -ENOATTR;
}