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); }
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; }
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; }